diff --git a/CHANGELOG.md b/CHANGELOG.md index 838a4365..6fd564b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,42 @@ ### [@coreui/angular](https://coreui.io/angular/) changelog +--- + +#### `5.3.8` + +- chore(dependencies): update to `Angular 19.1` +- refactor(form-control): signal inputs, host bindings, cleanup +- refactor(form-select): signal inputs, host bindings, cleanup +- refactor(form-label): signal inputs, host bindings, cleanup +- refactor(form-feedback): signal inputs, host bindings, cleanup +- refactor(form-check): signal inputs, host bindings, cleanup +- refactor(form): signal inputs, host bindings, cleanup +- refactor(input-group): cleanup +- refactor(nav): signal inputs, host bindings, cleanup, tests +- refactor(modal): signal inputs, host bindings, cleanup, +- refactor(progress): signal inputs, host bindings, cleanup, tests, service introduction +- refactor(table-active): signal inputs, host bindings, cleanup, tests +- refactor(table-color): signal inputs, host bindings, cleanup, tests +- refactor(table): signal inputs, host bindings, cleanup, tests +- refactor(tab): signal inputs, host bindings, cleanup, tests +- refactor(toast): signal inputs, host bindings, cleanup +- refactor(align): signal inputs, host bindings, cleanup, tests +- refactor(bg-color): signal inputs, host bindings, cleanup, tests +- refactor(border): signal inputs, host bindings, cleanup, tests +- refactor(rounded): signal inputs, host bindings, cleanup, tests +- refactor(shadow-on-scroll): signal inputs, host bindings, cleanup +- refactor(visible): signal inputs, cleanup +- refactor: make EffectRef #private + +--- + +#### `5.3.7` + +- fix(collapse): collapse not expanded when initial visible=true +- fix(offcanvas): use `inert` attribute instead of `aria-hidden` +- chore(dependencies): update + --- #### `5.3.5` diff --git a/CLI.md b/CLI.md index fcbbd5c5..cd0a31a1 100644 --- a/CLI.md +++ b/CLI.md @@ -1,6 +1,6 @@ # @coreui/angular v5 -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 18.0.2. +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 19.1.0. ## Development server diff --git a/LICENSE b/LICENSE index 94e4f4d1..fbb053e0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 creativeLabs Łukasz Holeczek +Copyright (c) 2025 creativeLabs Łukasz Holeczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index c5f8d2a4..3f430044 100644 --- a/README.md +++ b/README.md @@ -215,11 +215,11 @@ Thanks to all the backers and sponsors! Support this project by [becoming a back ## Copyright and license -Copyright 2024 creativeLabs Łukasz Holeczek. Code released under the [MIT License](https://github.com/coreui/coreui-angular/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). +Copyright 2025 creativeLabs Łukasz Holeczek. Code released under the [MIT License](https://github.com/coreui/coreui-angular/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). [npm-coreui-angular-badge-v5-ng19]: https://img.shields.io/npm/v/@coreui/angular/v5-ng19?style=flat-square&color=brightgreen [npm-coreui-angular-badge-latest]: https://img.shields.io/npm/v/@coreui/angular/latest?style=flat-square&color=brightgreen [npm-coreui-angular-badge-next]: https://img.shields.io/npm/v/@coreui/angular/next?style=flat-square&color=red [npm-coreui-angular]: https://www.npmjs.com/package/@coreui/angular [npm-coreui-angular-download]: https://img.shields.io/npm/dm/@coreui/angular.svg?style=flat-square -[angular-badge]: https://img.shields.io/badge/angular-^19.0.0-lightgrey.svg?style=flat-square&logo=angular +[angular-badge]: https://img.shields.io/badge/angular-^19.1.0-lightgrey.svg?style=flat-square&logo=angular diff --git a/package-lock.json b/package-lock.json index 01f96c94..8191d22d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,24 +1,24 @@ { "name": "coreui-angular-dev", - "version": "5.3.5", + "version": "5.3.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "coreui-angular-dev", - "version": "5.3.5", - "license": "MIT", - "dependencies": { - "@angular/animations": "^19.0.5", - "@angular/cdk": "^19.0.4", - "@angular/common": "^19.0.5", - "@angular/compiler": "^19.0.5", - "@angular/core": "^19.0.5", - "@angular/forms": "^19.0.5", - "@angular/localize": "^19.0.5", - "@angular/platform-browser": "^19.0.5", - "@angular/platform-browser-dynamic": "^19.0.5", - "@angular/router": "^19.0.5", + "version": "5.3.7", + "license": "MIT", + "dependencies": { + "@angular/animations": "^19.1.1", + "@angular/cdk": "^19.1.0", + "@angular/common": "^19.1.1", + "@angular/compiler": "^19.1.1", + "@angular/core": "^19.1.1", + "@angular/forms": "^19.1.1", + "@angular/localize": "^19.1.1", + "@angular/platform-browser": "^19.1.1", + "@angular/platform-browser-dynamic": "^19.1.1", + "@angular/router": "^19.1.1", "@coreui/chartjs": "^4.0.0", "@coreui/icons": "^3.0.1", "@popperjs/core": "~2.11.8", @@ -29,27 +29,27 @@ "zone.js": "~0.15.0" }, "devDependencies": { - "@angular-devkit/build-angular": "^19.0.6", - "@angular-devkit/schematics": "^19.0.6", - "@angular/cli": "^19.0.6", - "@angular/compiler-cli": "^19.0.5", - "@angular/language-service": "^19.0.5", + "@angular-devkit/build-angular": "^19.1.1", + "@angular-devkit/schematics": "^19.1.1", + "@angular/cli": "^19.1.1", + "@angular/compiler-cli": "^19.1.1", + "@angular/language-service": "^19.1.1", "@types/jasmine": "^5.1.5", "@types/lodash-es": "^4.17.12", - "@types/node": "^22.10.2", + "@types/node": "^22.10.7", "angular-eslint": "^19.0.2", "copyfiles": "^2.4.1", - "eslint": "^9.17.0", + "eslint": "^9.18.0", "jasmine-core": "^5.5.0", "karma": "^6.4.4", "karma-chrome-launcher": "^3.2.0", "karma-coverage": "^2.2.1", "karma-jasmine": "^5.1.0", "karma-jasmine-html-reporter": "^2.1.0", - "ng-packagr": "^19.0.1", + "ng-packagr": "^19.1.0", "prettier": "^3.4.2", "typescript": "~5.6.3", - "typescript-eslint": "^8.18.1" + "typescript-eslint": "^8.20.0" }, "engines": { "node": "^20.11.1 || ^22.0.0", @@ -70,13 +70,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1900.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1900.6.tgz", - "integrity": "sha512-w11bAXQnNWBawTJfQPjvaTRrzrqsOUm9tK9WNvaia/xjiRFpmO0CfmKtn3axNSEJM8jb/czaNQrgTwG+TGc/8g==", + "version": "0.1901.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1901.1.tgz", + "integrity": "sha512-fhRID3z4Va1nvP4QS7iraMP+J0zpvsqax0MtoaHXiaSvruwcPbcYSvWj9aO/oo9cq2XTd1zVigrKUwfhabXRVw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.0.6", + "@angular-devkit/core": "19.1.1", "rxjs": "7.8.1" }, "engines": { @@ -86,19 +86,19 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "19.0.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-19.0.6.tgz", - "integrity": "sha512-dWTAsE6BSI8z0xglQdYBdqTBwg1Q+RWE3OrmlGs+520Dcoq/F0Z41Y1F3MiuHuQPdDAIQr88iB0APkIRW4clMg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-19.1.1.tgz", + "integrity": "sha512-hpldWNWWvALDOzWodoRBXJtOBwZfIgvN8isuLHzSbmA4IeHh2WsTUfLFaWUstiJC9mapi9JT+p1dGwxXlaI/8Q==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1900.6", - "@angular-devkit/build-webpack": "0.1900.6", - "@angular-devkit/core": "19.0.6", - "@angular/build": "19.0.6", + "@angular-devkit/architect": "0.1901.1", + "@angular-devkit/build-webpack": "0.1901.1", + "@angular-devkit/core": "19.1.1", + "@angular/build": "19.1.1", "@babel/core": "7.26.0", - "@babel/generator": "7.26.2", + "@babel/generator": "7.26.3", "@babel/helper-annotate-as-pure": "7.25.9", "@babel/helper-split-export-declaration": "7.24.7", "@babel/plugin-transform-async-generator-functions": "7.25.9", @@ -107,21 +107,21 @@ "@babel/preset-env": "7.26.0", "@babel/runtime": "7.26.0", "@discoveryjs/json-ext": "0.6.3", - "@ngtools/webpack": "19.0.6", - "@vitejs/plugin-basic-ssl": "1.1.0", + "@ngtools/webpack": "19.1.1", + "@vitejs/plugin-basic-ssl": "1.2.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", "babel-loader": "9.2.1", "browserslist": "^4.21.5", "copy-webpack-plugin": "12.0.2", "css-loader": "7.1.2", - "esbuild-wasm": "0.24.0", - "fast-glob": "3.3.2", + "esbuild-wasm": "0.24.2", + "fast-glob": "3.3.3", "http-proxy-middleware": "3.0.3", "istanbul-lib-instrument": "6.0.3", "jsonc-parser": "3.3.1", "karma-source-map-support": "1.4.0", - "less": "4.2.0", + "less": "4.2.1", "less-loader": "12.2.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.3.1", @@ -129,22 +129,22 @@ "open": "10.1.0", "ora": "5.4.1", "picomatch": "4.0.2", - "piscina": "4.7.0", + "piscina": "4.8.0", "postcss": "8.4.49", "postcss-loader": "8.1.1", "resolve-url-loader": "5.0.0", "rxjs": "7.8.1", - "sass": "1.80.7", - "sass-loader": "16.0.3", + "sass": "1.83.1", + "sass-loader": "16.0.4", "semver": "7.6.3", "source-map-loader": "5.0.0", "source-map-support": "0.5.21", - "terser": "5.36.0", + "terser": "5.37.0", "tree-kill": "1.2.2", "tslib": "2.8.1", - "webpack": "5.96.1", + "webpack": "5.97.1", "webpack-dev-middleware": "7.4.2", - "webpack-dev-server": "5.1.0", + "webpack-dev-server": "5.2.0", "webpack-merge": "6.0.1", "webpack-subresource-integrity": "5.1.0" }, @@ -154,14 +154,14 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.24.0" + "esbuild": "0.24.2" }, "peerDependencies": { "@angular/compiler-cli": "^19.0.0", "@angular/localize": "^19.0.0", "@angular/platform-server": "^19.0.0", "@angular/service-worker": "^19.0.0", - "@angular/ssr": "^19.0.6", + "@angular/ssr": "^19.1.1", "@web/test-runner": "^0.19.0", "browser-sync": "^3.0.2", "jest": "^29.5.0", @@ -170,7 +170,7 @@ "ng-packagr": "^19.0.0", "protractor": "^7.0.0", "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": ">=5.5 <5.7" + "typescript": ">=5.5 <5.8" }, "peerDependenciesMeta": { "@angular/localize": { @@ -212,13 +212,13 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1900.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1900.6.tgz", - "integrity": "sha512-WehtVrbBow4fc7hsaUKb+BZ6MDE5lO98/tgv7GR5PkRdGKnyLA0pW1AfPLJJQDgcaKjneramMhDFNc1eGSX0mQ==", + "version": "0.1901.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1901.1.tgz", + "integrity": "sha512-WKh0uA7TNfGeOFLAfHS4yCRx3pPtsFrQJTOeYLU/r/scJS/xvDfvFNE0P1CZeL0G6V0O80V/Kj0ZoTS8zBac0g==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1900.6", + "@angular-devkit/architect": "0.1901.1", "rxjs": "7.8.1" }, "engines": { @@ -232,9 +232,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "19.0.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.0.6.tgz", - "integrity": "sha512-WUWJhzQDsovfMY6jtb9Ktz/5sJszsaErj+XV2aXab85f1OweI/Iv2urPZnJwUSilvVN5Ok/fy3IJ6SuihK4Ceg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.1.1.tgz", + "integrity": "sha512-CAqst7WEasPHR4OFdbxxX3+NVqNTvYk3vtPbXT/jZ0L2EZRICQta2EClkdhSIiMkiMf0/2LNT05rYD7k4NHIQA==", "dev": true, "license": "MIT", "dependencies": { @@ -260,15 +260,15 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "19.0.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.0.6.tgz", - "integrity": "sha512-R9hlHfAh1HKoIWgnYJlOEKhUezhTNl0fpUmHxG2252JSY5FLRxmYArTtJYYmbNdBbsBLNg3UHyM/GBPvJSA3NQ==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.1.1.tgz", + "integrity": "sha512-4xodirv/kErn7L5N6NhIDfuVuNgNDmGX1+Pdu3yG2c1moOTyRBV684lv2qQJClNctOpELDM55IuX3MXud2qQaw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.0.6", + "@angular-devkit/core": "19.1.1", "jsonc-parser": "3.3.1", - "magic-string": "0.30.12", + "magic-string": "0.30.17", "ora": "5.4.1", "rxjs": "7.8.1" }, @@ -382,9 +382,9 @@ } }, "node_modules/@angular/animations": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-19.0.5.tgz", - "integrity": "sha512-HCOF2CrhUvjoZWusd4nh32VOxpUrg6bV+3Z8Q36Ix3aZdni8v0qoP2rl5wGbotaPtYg5RtyDH60Z2AOPKqlrZg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-19.1.1.tgz", + "integrity": "sha512-MWZKQSFBr7iEfLH4tSpsjjC/Afq8Udp4v6kv4YGRcXuJKn8cL6KZ+8nPFkZACYPNrB/5jrWN27HGjWWlO2Z2Hg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -393,40 +393,40 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "19.0.5" + "@angular/core": "19.1.1" } }, "node_modules/@angular/build": { - "version": "19.0.6", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-19.0.6.tgz", - "integrity": "sha512-KEVNLgTZUF2dfpOYQn+yR2HONHUTxq/2rFVhiK9qAvrm/m+uKJNEXx7hGtbRyoqenZff4ScJq+7feITUldfX8g==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-19.1.1.tgz", + "integrity": "sha512-E4jvi48zRCLkwcThQQm1Q1vq9aypf3+xSMQQMDcHzvt/89sucWTKkwgNHSW/Fi8qH23GhijCLXBHa4dHSoCB/A==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1900.6", + "@angular-devkit/architect": "0.1901.1", "@babel/core": "7.26.0", "@babel/helper-annotate-as-pure": "7.25.9", "@babel/helper-split-export-declaration": "7.24.7", "@babel/plugin-syntax-import-attributes": "7.26.0", - "@inquirer/confirm": "5.0.2", - "@vitejs/plugin-basic-ssl": "1.1.0", - "beasties": "0.1.0", + "@inquirer/confirm": "5.1.1", + "@vitejs/plugin-basic-ssl": "1.2.0", + "beasties": "0.2.0", "browserslist": "^4.23.0", - "esbuild": "0.24.0", - "fast-glob": "3.3.2", - "https-proxy-agent": "7.0.5", + "esbuild": "0.24.2", + "fast-glob": "3.3.3", + "https-proxy-agent": "7.0.6", "istanbul-lib-instrument": "6.0.3", "listr2": "8.2.5", - "magic-string": "0.30.12", + "magic-string": "0.30.17", "mrmime": "2.0.0", "parse5-html-rewriting-stream": "7.0.0", "picomatch": "4.0.2", - "piscina": "4.7.0", - "rollup": "4.26.0", - "sass": "1.80.7", + "piscina": "4.8.0", + "rollup": "4.30.1", + "sass": "1.83.1", "semver": "7.6.3", - "vite": "5.4.11", + "vite": "6.0.7", "watchpack": "2.4.2" }, "engines": { @@ -435,7 +435,7 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "lmdb": "3.1.5" + "lmdb": "3.2.2" }, "peerDependencies": { "@angular/compiler": "^19.0.0", @@ -443,11 +443,12 @@ "@angular/localize": "^19.0.0", "@angular/platform-server": "^19.0.0", "@angular/service-worker": "^19.0.0", - "@angular/ssr": "^19.0.6", + "@angular/ssr": "^19.1.1", "less": "^4.2.0", + "ng-packagr": "^19.0.0", "postcss": "^8.4.0", "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": ">=5.5 <5.7" + "typescript": ">=5.5 <5.8" }, "peerDependenciesMeta": { "@angular/localize": { @@ -465,6 +466,9 @@ "less": { "optional": true }, + "ng-packagr": { + "optional": true + }, "postcss": { "optional": true }, @@ -474,9 +478,9 @@ } }, "node_modules/@angular/cdk": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-19.0.4.tgz", - "integrity": "sha512-P8V1n6AFFjBUJG3YRgw8DiiNDWPZVrwQ42wbwgZxd4s2TQAuNFg3YY8h/DSMVxt2sXpavrshZsoLtP9yLKZjHA==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-19.1.0.tgz", + "integrity": "sha512-h7VSaMA/vFHb7u1bwoHKl3L3mZLIcXNZw6v7Nei9ITfEo1PfSKbrYhleeqpNikzE+LxNDKJrbZtpAckSYHblmA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -491,26 +495,26 @@ } }, "node_modules/@angular/cli": { - "version": "19.0.6", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-19.0.6.tgz", - "integrity": "sha512-ZEHhgRRVIdn10dbsAjB8TE9Co32hfuL9/im5Jcfa1yrn6KJefmigz6KN8Xu7FXMH5FkdqfQ11QpLBxJSPb9aww==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-19.1.1.tgz", + "integrity": "sha512-eggTJ6jaGtSlvq0qbncLvOGVFCvSUaHJarpnLUJhZKX6F3zXtc4gPGvW4za4yp2+IbeXWYbOhdqeDkwgEomNHg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1900.6", - "@angular-devkit/core": "19.0.6", - "@angular-devkit/schematics": "19.0.6", - "@inquirer/prompts": "7.1.0", + "@angular-devkit/architect": "0.1901.1", + "@angular-devkit/core": "19.1.1", + "@angular-devkit/schematics": "19.1.1", + "@inquirer/prompts": "7.2.1", "@listr2/prompt-adapter-inquirer": "2.0.18", - "@schematics/angular": "19.0.6", + "@schematics/angular": "19.1.1", "@yarnpkg/lockfile": "1.1.0", "ini": "5.0.0", "jsonc-parser": "3.3.1", "listr2": "8.2.5", - "npm-package-arg": "12.0.0", + "npm-package-arg": "12.0.1", "npm-pick-manifest": "10.0.0", "pacote": "20.0.0", - "resolve": "1.22.8", + "resolve": "1.22.10", "semver": "7.6.3", "symbol-observable": "4.0.0", "yargs": "17.7.2" @@ -525,9 +529,9 @@ } }, "node_modules/@angular/common": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-19.0.5.tgz", - "integrity": "sha512-fFK+euCj1AjBHBCpj9VnduMSeqoMRhZZHbhPYiND7tucRRJ8vwGU0sYK2KI/Ko+fsrNIXL/0O4F36jVPl09Smg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-19.1.1.tgz", + "integrity": "sha512-2ZbnV8lM81ekLjRMRufRho7N8adz+Yjwj+3y5RB7+GW8fX5f9mm740ifyieBCXPLtiWb8ZK1i9gime6y64BEBQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -536,14 +540,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "19.0.5", + "@angular/core": "19.1.1", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-19.0.5.tgz", - "integrity": "sha512-S8ku5Ljp0kqX3shfmE9DVo09629jeYJSlBRGbj2Glb92dd+VQZPOz7KxqKRTwmAl7lQIV/+4Lr6G/GVTsoC4vg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-19.1.1.tgz", + "integrity": "sha512-bXPiJKQYjH6kSBnlVHx8aLzYY7YhWw1cidthWwqNaXyZ4YYILom1lN3C7nJYOVDX8W64QCMimHqf8iD4guByxA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -552,7 +556,7 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "19.0.5" + "@angular/core": "19.1.1" }, "peerDependenciesMeta": { "@angular/core": { @@ -561,9 +565,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-19.0.5.tgz", - "integrity": "sha512-KSzuWCTZlvJsoAenxM9cjTOzNM8mrFxDBInj0KVPz7QU83amGS4rcv1pWO/QGYQcErfskcN84TAdMegaRWWCmA==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-19.1.1.tgz", + "integrity": "sha512-mk+CIV98WtZPfk4R0cdo7Jx8bZZewCO5K0dcG7/AMck+e2dDl2pjtXz1wYJi8NpUUAtcrr9HWlvxQ2L8IJMIag==", "license": "MIT", "dependencies": { "@babel/core": "7.26.0", @@ -584,14 +588,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "19.0.5", - "typescript": ">=5.5 <5.7" + "@angular/compiler": "19.1.1", + "typescript": ">=5.5 <5.8" } }, "node_modules/@angular/core": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-19.0.5.tgz", - "integrity": "sha512-Ywc6sPO6G/Y1stfk3y/MallV/h0yzQ0vdOHRWueLrk5kD1DTdbolV4X03Cs3PuVvravgcSVE3nnuuHFuH32emQ==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-19.1.1.tgz", + "integrity": "sha512-uEDnomaIh7yUPx6hHWMFcWrUMOwishkkPToSFMltVLfRrfmAQL+WMpOGtR6qiFG6PIppsADIxXPRWVzfnYOYZg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -605,9 +609,9 @@ } }, "node_modules/@angular/forms": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-19.0.5.tgz", - "integrity": "sha512-OhNFkfOoguqCDq07vNBV28FFrmTM8S11Z3Cd6PQZJJF9TgAtpV5KtF7A3eXBCN92W4pmqluomPjfK7YyImzIYQ==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-19.1.1.tgz", + "integrity": "sha512-MtvoAeOXa2v+24U+5BMwmJpbQs/SQ296u+mJiZ/hIuuB/XBZdlPMzGg0U9ENDg6kwwoZIypcgiQ0/+gIwxlCSw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -616,16 +620,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "19.0.5", - "@angular/core": "19.0.5", - "@angular/platform-browser": "19.0.5", + "@angular/common": "19.1.1", + "@angular/core": "19.1.1", + "@angular/platform-browser": "19.1.1", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-19.0.5.tgz", - "integrity": "sha512-E4WFEsCzHuF3DYe4EfOCiMGW1zWmq3UYi5XXOBNLyzWDvwU5xTfdme6ECXGawHMc2kCaWMVNL4DzYpVsUgLG0w==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-19.1.1.tgz", + "integrity": "sha512-W2NDVvDVMcVcQ7cfl1fUFRWoOpsPO9YXcbFNoBlANfamAcu4gR7cssaAWh3o3UPchdxQui9Ka8X+UhrF5bGxVA==", "dev": true, "license": "MIT", "engines": { @@ -633,14 +637,14 @@ } }, "node_modules/@angular/localize": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-19.0.5.tgz", - "integrity": "sha512-4Uk0cNYXZpjPvUXo5gAy0rjCcemyAVOG319q5BJyLSeCV0DJ+MTIR6ylGK3oLSXqKACpF3r3+Wa235xj7vxk3Q==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-19.1.1.tgz", + "integrity": "sha512-MHrCE8bxNEp2BkSoLeuGJE0PMBF+Xu3zV52VpUaCrMQRHvHpq4ie+qosinQSDX72DKUUJUZuv0unApFCvhr2HA==", "license": "MIT", "dependencies": { "@babel/core": "7.26.0", "@types/babel__core": "7.20.5", - "fast-glob": "3.3.2", + "fast-glob": "3.3.3", "yargs": "^17.2.1" }, "bin": { @@ -652,14 +656,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "19.0.5", - "@angular/compiler-cli": "19.0.5" + "@angular/compiler": "19.1.1", + "@angular/compiler-cli": "19.1.1" } }, "node_modules/@angular/platform-browser": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-19.0.5.tgz", - "integrity": "sha512-41+Jo5DEil4Ifvv+UE/p1l9YJtYN+xfhx+/C9cahVgvV5D2q+givyK73d0Mnb6XOfe1q+hoV5lZ+XhQYp21//g==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-19.1.1.tgz", + "integrity": "sha512-L33rk7j3FepDqHo29iqp7ucL1tBjGQed+e22ei9bCsj7CG0GNi5w8id3nyNImhwN26wtg++4cu4la+XxKWIkXg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -668,9 +672,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "19.0.5", - "@angular/common": "19.0.5", - "@angular/core": "19.0.5" + "@angular/animations": "19.1.1", + "@angular/common": "19.1.1", + "@angular/core": "19.1.1" }, "peerDependenciesMeta": { "@angular/animations": { @@ -679,9 +683,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-19.0.5.tgz", - "integrity": "sha512-KKFdue/uJVxkWdrntRAXkz+ycp4nD3SuGOH5pPf2svCBxieuHuFlWDi+DYVuFSEpC/ICCmlhrtzIAm44A4qzzQ==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-19.1.1.tgz", + "integrity": "sha512-iEVOFKpBEFXKDqQb42xhEXpseQc2vpl16kuT9gbjuvBC8KJLsTdvE34HIoZN1Igm22wZzp+PBzSWYa8WiQK83A==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -690,16 +694,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "19.0.5", - "@angular/compiler": "19.0.5", - "@angular/core": "19.0.5", - "@angular/platform-browser": "19.0.5" + "@angular/common": "19.1.1", + "@angular/compiler": "19.1.1", + "@angular/core": "19.1.1", + "@angular/platform-browser": "19.1.1" } }, "node_modules/@angular/router": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-19.0.5.tgz", - "integrity": "sha512-6tNubVVj/rRyTg+OXjQxACfufvCLHAwDQtv9wqt6q/3OYSnysHTik3ho3FaFPwu7fXJ+6p9Rjzkh2VY9QMk4bw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-19.1.1.tgz", + "integrity": "sha512-DbgluW4P0AfZ01kaoSJK+4eKrYnBvP5yGVSx+rhZhXOPpoVx76IOn691cdwC9CQuDIG9RqQWZL5TLfS959K0cA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -708,9 +712,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "19.0.5", - "@angular/core": "19.0.5", - "@angular/platform-browser": "19.0.5", + "@angular/common": "19.1.1", + "@angular/core": "19.1.1", + "@angular/platform-browser": "19.1.1", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -783,13 +787,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", - "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", + "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", + "@babel/parser": "^7.26.3", + "@babel/types": "^7.26.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -2281,22 +2285,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", - "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.26.3", - "@babel/types": "^7.26.3", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/types": { "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", @@ -2362,9 +2350,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz", - "integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", "cpu": [ "ppc64" ], @@ -2379,9 +2367,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.0.tgz", - "integrity": "sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", "cpu": [ "arm" ], @@ -2396,9 +2384,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz", - "integrity": "sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", "cpu": [ "arm64" ], @@ -2413,9 +2401,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.0.tgz", - "integrity": "sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", "cpu": [ "x64" ], @@ -2430,9 +2418,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz", - "integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", "cpu": [ "arm64" ], @@ -2447,9 +2435,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz", - "integrity": "sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", "cpu": [ "x64" ], @@ -2464,9 +2452,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz", - "integrity": "sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", "cpu": [ "arm64" ], @@ -2481,9 +2469,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz", - "integrity": "sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", "cpu": [ "x64" ], @@ -2498,9 +2486,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz", - "integrity": "sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", "cpu": [ "arm" ], @@ -2515,9 +2503,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz", - "integrity": "sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", "cpu": [ "arm64" ], @@ -2532,9 +2520,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz", - "integrity": "sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", "cpu": [ "ia32" ], @@ -2549,9 +2537,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz", - "integrity": "sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", "cpu": [ "loong64" ], @@ -2566,9 +2554,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz", - "integrity": "sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", "cpu": [ "mips64el" ], @@ -2583,9 +2571,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz", - "integrity": "sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", "cpu": [ "ppc64" ], @@ -2600,9 +2588,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz", - "integrity": "sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", "cpu": [ "riscv64" ], @@ -2617,9 +2605,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz", - "integrity": "sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", "cpu": [ "s390x" ], @@ -2634,9 +2622,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz", - "integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", "cpu": [ "x64" ], @@ -2650,10 +2638,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz", - "integrity": "sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", "cpu": [ "x64" ], @@ -2668,9 +2673,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz", - "integrity": "sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", "cpu": [ "arm64" ], @@ -2685,9 +2690,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz", - "integrity": "sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", "cpu": [ "x64" ], @@ -2702,9 +2707,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz", - "integrity": "sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", "cpu": [ "x64" ], @@ -2719,9 +2724,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz", - "integrity": "sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", "cpu": [ "arm64" ], @@ -2736,9 +2741,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz", - "integrity": "sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", "cpu": [ "ia32" ], @@ -2753,9 +2758,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz", - "integrity": "sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", "cpu": [ "x64" ], @@ -2838,9 +2843,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", - "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", + "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2946,9 +2951,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.17.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", - "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz", + "integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==", "dev": true, "license": "MIT", "engines": { @@ -2966,12 +2971,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", - "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", + "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", "dev": true, "license": "Apache-2.0", "dependencies": { + "@eslint/core": "^0.10.0", "levn": "^0.4.1" }, "engines": { @@ -3065,14 +3071,14 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.0.2.tgz", - "integrity": "sha512-KJLUHOaKnNCYzwVbryj3TNBxyZIrr56fR5N45v6K9IPrbT6B7DcudBMfylkV1A8PUdJE15mybkEQyp2/ZUpxUA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.1.tgz", + "integrity": "sha512-vVLSbGci+IKQvDOtzpPTCOiEJCNidHcAq9JYVoWTW0svb5FiwSLotkM+JXNXejfjnzVYV9n0DTBythl9+XgTxg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.0", - "@inquirer/type": "^3.0.1" + "@inquirer/core": "^10.1.2", + "@inquirer/type": "^3.0.2" }, "engines": { "node": ">=18" @@ -3201,22 +3207,22 @@ } }, "node_modules/@inquirer/prompts": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.1.0.tgz", - "integrity": "sha512-5U/XiVRH2pp1X6gpNAjWOglMf38/Ys522ncEHIKT1voRUvSj/DQnR22OVxHnwu5S+rCFaUiPQ57JOtMFQayqYA==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.2.1.tgz", + "integrity": "sha512-v2JSGri6/HXSfoGIwuKEn8sNCQK6nsB2BNpy2lSX6QH9bsECrMv93QHnj5+f+1ZWpF/VNioIV2B/PDox8EvGuQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.0.2", - "@inquirer/confirm": "^5.0.2", - "@inquirer/editor": "^4.1.0", - "@inquirer/expand": "^4.0.2", - "@inquirer/input": "^4.0.2", - "@inquirer/number": "^3.0.2", - "@inquirer/password": "^4.0.2", - "@inquirer/rawlist": "^4.0.2", - "@inquirer/search": "^3.0.2", - "@inquirer/select": "^4.0.2" + "@inquirer/checkbox": "^4.0.4", + "@inquirer/confirm": "^5.1.1", + "@inquirer/editor": "^4.2.1", + "@inquirer/expand": "^4.0.4", + "@inquirer/input": "^4.1.1", + "@inquirer/number": "^3.0.4", + "@inquirer/password": "^4.0.4", + "@inquirer/rawlist": "^4.0.4", + "@inquirer/search": "^3.0.4", + "@inquirer/select": "^4.0.4" }, "engines": { "node": ">=18" @@ -3590,9 +3596,9 @@ } }, "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.1.5.tgz", - "integrity": "sha512-ue5PSOzHMCIYrfvPP/MRS6hsKKLzqqhcdAvJCO8uFlDdj598EhgnacuOTuqA6uBK5rgiZXfDWyb7DVZSiBKxBA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.2.2.tgz", + "integrity": "sha512-WBSJT9Z7DTol5viq+DZD2TapeWOw7mlwXxiSBHgAzqVwsaVb0h/ekMD9iu/jDD8MUA20tO9N0WEdnT06fsUp+g==", "cpu": [ "arm64" ], @@ -3604,9 +3610,9 @@ ] }, "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.1.5.tgz", - "integrity": "sha512-CGhsb0R5vE6mMNCoSfxHFD8QTvBHM51gs4DBeigTYHWnYv2V5YpJkC4rMo5qAAFifuUcc0+a8a3SIU0c9NrfNw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.2.2.tgz", + "integrity": "sha512-4S13kUtR7c/j/MzkTIBJCXv52hQ41LG2ukeaqw4Eng9K0pNKLFjo1sDSz96/yKhwykxrWDb13ddJ/ZqD3rAhUA==", "cpu": [ "x64" ], @@ -3618,9 +3624,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.1.5.tgz", - "integrity": "sha512-3WeW328DN+xB5PZdhSWmqE+t3+44xWXEbqQ+caWJEZfOFdLp9yklBZEbVqVdqzznkoaXJYxTCp996KD6HmANeg==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.2.2.tgz", + "integrity": "sha512-uW31JmfuPAaLUYW7NsEU8gzwgDAzpGPwjvkxnKlcWd8iDutoPKDJi8Wk9lFmPEZRxVSB0j1/wDQ7N2qliR9UFA==", "cpu": [ "arm" ], @@ -3632,9 +3638,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.1.5.tgz", - "integrity": "sha512-LAjaoOcBHGj6fiYB8ureiqPoph4eygbXu4vcOF+hsxiY74n8ilA7rJMmGUT0K0JOB5lmRQHSmor3mytRjS4qeQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.2.2.tgz", + "integrity": "sha512-4hdgZtWI1idQlWRp+eleWXD9KLvObgboRaVoBj2POdPEYvsKANllvMW0El8tEQwtw74yB9NT6P8ENBB5UJf5+g==", "cpu": [ "arm64" ], @@ -3646,9 +3652,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.1.5.tgz", - "integrity": "sha512-k/IklElP70qdCXOQixclSl2GPLFiopynGoKX1FqDd1/H0E3Fo1oPwjY2rEVu+0nS3AOw1sryStdXk8CW3cVIsw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.2.2.tgz", + "integrity": "sha512-A0zjf4a2vM4B4GAx78ncuOTZ8Ka1DbTaG1Axf1e00Sa7f5coqlWiLg1PX7Gxvyibc2YqtqB+8tg1KKrE8guZVw==", "cpu": [ "x64" ], @@ -3660,9 +3666,9 @@ ] }, "node_modules/@lmdb/lmdb-win32-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.1.5.tgz", - "integrity": "sha512-KYar6W8nraZfSJspcK7Kp7hdj238X/FNauYbZyrqPBrtsXI1hvI4/KcRcRGP50aQoV7fkKDyJERlrQGMGTZUsA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.2.2.tgz", + "integrity": "sha512-Y0qoSCAja+xZE7QQ0LCHoYAuyI1n9ZqukQJa8lv9X3yCvWahFF7OYHAgVH1ejp43XWstj3U89/PAAzcowgF/uQ==", "cpu": [ "x64" ], @@ -4063,9 +4069,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "19.0.6", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-19.0.6.tgz", - "integrity": "sha512-eWrIb0tS1CK6+JvFS4GgTD4fN9TtmApKrlaj3pPQXKXKKd42361ec85fuQQXdb4G8eEEq0vyd/bn4NJllh/3vw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-19.1.1.tgz", + "integrity": "sha512-FKtKRiXTmfLfRFLNScyNNCQpazC9CylUFSCQmFjd02jChfC0IH2WYh4zPrWKYDbOgv2H1oerRD2fZDmFaBi5Ew==", "dev": true, "license": "MIT", "engines": { @@ -4075,7 +4081,7 @@ }, "peerDependencies": { "@angular/compiler-cli": "^19.0.0", - "typescript": ">=5.5 <5.7", + "typescript": ">=5.5 <5.8", "webpack": "^5.54.0" } }, @@ -4763,9 +4769,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.26.0.tgz", - "integrity": "sha512-gJNwtPDGEaOEgejbaseY6xMFu+CPltsc8/T+diUTTbOQLqD+bnrJq9ulH6WD69TqwqWmrfRAtUv30cCFZlbGTQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", + "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", "cpu": [ "arm" ], @@ -4777,9 +4783,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.26.0.tgz", - "integrity": "sha512-YJa5Gy8mEZgz5JquFruhJODMq3lTHWLm1fOy+HIANquLzfIOzE9RA5ie3JjCdVb9r46qfAQY/l947V0zfGJ0OQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", + "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", "cpu": [ "arm64" ], @@ -4791,9 +4797,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.26.0.tgz", - "integrity": "sha512-ErTASs8YKbqTBoPLp/kA1B1Um5YSom8QAc4rKhg7b9tyyVqDBlQxy7Bf2wW7yIlPGPg2UODDQcbkTlruPzDosw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", + "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", "cpu": [ "arm64" ], @@ -4805,9 +4811,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.26.0.tgz", - "integrity": "sha512-wbgkYDHcdWW+NqP2mnf2NOuEbOLzDblalrOWcPyY6+BRbVhliavon15UploG7PpBRQ2bZJnbmh8o3yLoBvDIHA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", + "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", "cpu": [ "x64" ], @@ -4819,9 +4825,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.26.0.tgz", - "integrity": "sha512-Y9vpjfp9CDkAG4q/uwuhZk96LP11fBz/bYdyg9oaHYhtGZp7NrbkQrj/66DYMMP2Yo/QPAsVHkV891KyO52fhg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", + "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", "cpu": [ "arm64" ], @@ -4833,9 +4839,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.26.0.tgz", - "integrity": "sha512-A/jvfCZ55EYPsqeaAt/yDAG4q5tt1ZboWMHEvKAH9Zl92DWvMIbnZe/f/eOXze65aJaaKbL+YeM0Hz4kLQvdwg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", + "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", "cpu": [ "x64" ], @@ -4847,9 +4853,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.26.0.tgz", - "integrity": "sha512-paHF1bMXKDuizaMODm2bBTjRiHxESWiIyIdMugKeLnjuS1TCS54MF5+Y5Dx8Ui/1RBPVRE09i5OUlaLnv8OGnA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", + "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", "cpu": [ "arm" ], @@ -4861,9 +4867,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.26.0.tgz", - "integrity": "sha512-cwxiHZU1GAs+TMxvgPfUDtVZjdBdTsQwVnNlzRXC5QzIJ6nhfB4I1ahKoe9yPmoaA/Vhf7m9dB1chGPpDRdGXg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", + "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", "cpu": [ "arm" ], @@ -4875,9 +4881,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.26.0.tgz", - "integrity": "sha512-4daeEUQutGRCW/9zEo8JtdAgtJ1q2g5oHaoQaZbMSKaIWKDQwQ3Yx0/3jJNmpzrsScIPtx/V+1AfibLisb3AMQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", + "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", "cpu": [ "arm64" ], @@ -4889,9 +4895,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.26.0.tgz", - "integrity": "sha512-eGkX7zzkNxvvS05ROzJ/cO/AKqNvR/7t1jA3VZDi2vRniLKwAWxUr85fH3NsvtxU5vnUUKFHKh8flIBdlo2b3Q==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", + "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", "cpu": [ "arm64" ], @@ -4902,10 +4908,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", + "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.26.0.tgz", - "integrity": "sha512-Odp/lgHbW/mAqw/pU21goo5ruWsytP7/HCC/liOt0zcGG0llYWKrd10k9Fj0pdj3prQ63N5yQLCLiE7HTX+MYw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", + "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", "cpu": [ "ppc64" ], @@ -4917,9 +4937,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.26.0.tgz", - "integrity": "sha512-MBR2ZhCTzUgVD0OJdTzNeF4+zsVogIR1U/FsyuFerwcqjZGvg2nYe24SAHp8O5sN8ZkRVbHwlYeHqcSQ8tcYew==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", + "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", "cpu": [ "riscv64" ], @@ -4931,9 +4951,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.26.0.tgz", - "integrity": "sha512-YYcg8MkbN17fMbRMZuxwmxWqsmQufh3ZJFxFGoHjrE7bv0X+T6l3glcdzd7IKLiwhT+PZOJCblpnNlz1/C3kGQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", + "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", "cpu": [ "s390x" ], @@ -4945,9 +4965,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.26.0.tgz", - "integrity": "sha512-ZuwpfjCwjPkAOxpjAEjabg6LRSfL7cAJb6gSQGZYjGhadlzKKywDkCUnJ+KEfrNY1jH5EEoSIKLCb572jSiglA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", + "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", "cpu": [ "x64" ], @@ -4959,9 +4979,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.26.0.tgz", - "integrity": "sha512-+HJD2lFS86qkeF8kNu0kALtifMpPCZU80HvwztIKnYwym3KnA1os6nsX4BGSTLtS2QVAGG1P3guRgsYyMA0Yhg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", + "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", "cpu": [ "x64" ], @@ -4973,9 +4993,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.26.0.tgz", - "integrity": "sha512-WUQzVFWPSw2uJzX4j6YEbMAiLbs0BUysgysh8s817doAYhR5ybqTI1wtKARQKo6cGop3pHnrUJPFCsXdoFaimQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", + "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", "cpu": [ "arm64" ], @@ -4987,9 +5007,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.26.0.tgz", - "integrity": "sha512-D4CxkazFKBfN1akAIY6ieyOqzoOoBV1OICxgUblWxff/pSjCA2khXlASUx7mK6W1oP4McqhgcCsu6QaLj3WMWg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", + "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", "cpu": [ "ia32" ], @@ -5001,9 +5021,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.26.0.tgz", - "integrity": "sha512-2x8MO1rm4PGEP0xWbubJW5RtbNLk3puzAMaLQd3B3JHVw4KcHlmXcO+Wewx9zCoo7EUFiMlu/aZbCJ7VjMzAag==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", + "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", "cpu": [ "x64" ], @@ -5035,14 +5055,14 @@ } }, "node_modules/@schematics/angular": { - "version": "19.0.6", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-19.0.6.tgz", - "integrity": "sha512-HicclmbW/+mlljU7a4PzbyIWG+7tognoL5LsgMFJQUDzJXHNjRt1riL0vk57o8Pcprnz9FheeWZXO1KRhXkQuw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-19.1.1.tgz", + "integrity": "sha512-XrnmSbCcDPePCbEVhgEPFZFiL/fowvkPJ8qOa1m9tWHSPYb739Vk3g+VDrAqNMm7FULcRzQzqHBq/IBB8qYfIg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.0.6", - "@angular-devkit/schematics": "19.0.6", + "@angular-devkit/core": "19.1.1", + "@angular-devkit/schematics": "19.1.1", "jsonc-parser": "3.3.1" }, "engines": { @@ -5318,9 +5338,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.2.tgz", - "integrity": "sha512-vluaspfvWEtE4vcSDlKRNer52DvOGrB2xv6diXy6UKyKW0lqZiWHGNApSyxOv+8DE5Z27IzVvE7hNkxg7EXIcg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.5.tgz", + "integrity": "sha512-GLZPrd9ckqEBFMcVM/qRFAP0Hg3qiVEojgEFsx/N/zKXsBzbGF6z5FBDpZ0+Xhp1xr+qRZYjfGr1cWHB9oFHSA==", "dev": true, "license": "MIT", "dependencies": { @@ -5399,9 +5419,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "version": "22.10.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz", + "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==", "dev": true, "license": "MIT", "dependencies": { @@ -5419,9 +5439,9 @@ } }, "node_modules/@types/qs": { - "version": "6.9.17", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", - "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", + "version": "6.9.18", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", + "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", "dev": true, "license": "MIT" }, @@ -5493,21 +5513,21 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz", - "integrity": "sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.20.0.tgz", + "integrity": "sha512-naduuphVw5StFfqp4Gq4WhIBE2gN1GEmMUExpJYknZJdRnc+2gDzB8Z3+5+/Kv33hPQRDGzQO/0opHE72lZZ6A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.18.1", - "@typescript-eslint/type-utils": "8.18.1", - "@typescript-eslint/utils": "8.18.1", - "@typescript-eslint/visitor-keys": "8.18.1", + "@typescript-eslint/scope-manager": "8.20.0", + "@typescript-eslint/type-utils": "8.20.0", + "@typescript-eslint/utils": "8.20.0", + "@typescript-eslint/visitor-keys": "8.20.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5533,16 +5553,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.1.tgz", - "integrity": "sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.20.0.tgz", + "integrity": "sha512-gKXG7A5HMyjDIedBi6bUrDcun8GIjnI8qOwVLiY3rx6T/sHP/19XLJOnIq/FgQvWLHja5JN/LSE7eklNBr612g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.18.1", - "@typescript-eslint/types": "8.18.1", - "@typescript-eslint/typescript-estree": "8.18.1", - "@typescript-eslint/visitor-keys": "8.18.1", + "@typescript-eslint/scope-manager": "8.20.0", + "@typescript-eslint/types": "8.20.0", + "@typescript-eslint/typescript-estree": "8.20.0", + "@typescript-eslint/visitor-keys": "8.20.0", "debug": "^4.3.4" }, "engines": { @@ -5558,14 +5578,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.1.tgz", - "integrity": "sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.20.0.tgz", + "integrity": "sha512-J7+VkpeGzhOt3FeG1+SzhiMj9NzGD/M6KoGn9f4dbz3YzK9hvbhVTmLj/HiTp9DazIzJ8B4XcM80LrR9Dm1rJw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.1", - "@typescript-eslint/visitor-keys": "8.18.1" + "@typescript-eslint/types": "8.20.0", + "@typescript-eslint/visitor-keys": "8.20.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5576,16 +5596,16 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.1.tgz", - "integrity": "sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.20.0.tgz", + "integrity": "sha512-bPC+j71GGvA7rVNAHAtOjbVXbLN5PkwqMvy1cwGeaxUoRQXVuKCebRoLzm+IPW/NtFFpstn1ummSIasD5t60GA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.18.1", - "@typescript-eslint/utils": "8.18.1", + "@typescript-eslint/typescript-estree": "8.20.0", + "@typescript-eslint/utils": "8.20.0", "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5600,9 +5620,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.1.tgz", - "integrity": "sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.20.0.tgz", + "integrity": "sha512-cqaMiY72CkP+2xZRrFt3ExRBu0WmVitN/rYPZErA80mHjHx/Svgp8yfbzkJmDoQ/whcytOPO9/IZXnOc+wigRA==", "dev": true, "license": "MIT", "engines": { @@ -5614,20 +5634,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.1.tgz", - "integrity": "sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.20.0.tgz", + "integrity": "sha512-Y7ncuy78bJqHI35NwzWol8E0X7XkRVS4K4P4TCyzWkOJih5NDvtoRDW4Ba9YJJoB2igm9yXDdYI/+fkiiAxPzA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.1", - "@typescript-eslint/visitor-keys": "8.18.1", + "@typescript-eslint/types": "8.20.0", + "@typescript-eslint/visitor-keys": "8.20.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5641,16 +5661,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.1.tgz", - "integrity": "sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.20.0.tgz", + "integrity": "sha512-dq70RUw6UK9ei7vxc4KQtBRk7qkHZv447OUZ6RPQMQl71I3NZxQJX/f32Smr+iqWrB02pHKn2yAdHBb0KNrRMA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.18.1", - "@typescript-eslint/types": "8.18.1", - "@typescript-eslint/typescript-estree": "8.18.1" + "@typescript-eslint/scope-manager": "8.20.0", + "@typescript-eslint/types": "8.20.0", + "@typescript-eslint/typescript-estree": "8.20.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5665,13 +5685,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.1.tgz", - "integrity": "sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.20.0.tgz", + "integrity": "sha512-v/BpkeeYAsPkKCkR8BDwcno0llhzWVqPOamQrAEMdpZav2Y9OVjd9dwJyBLJWwf335B5DmlifECIkZRJCaGaHA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.1", + "@typescript-eslint/types": "8.20.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -5696,16 +5716,16 @@ } }, "node_modules/@vitejs/plugin-basic-ssl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", - "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.2.0.tgz", + "integrity": "sha512-mkQnxTkcldAzIsomk1UuLfAu9n+kpQ3JbHcpCp7d2Oo6ITtji8pHS3QToOWjhPFvNQSnhlkAjmGbhv2QvwO/7Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=14.6.0" + "node": ">=14.21.3" }, "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" } }, "node_modules/@webassemblyjs/ast": { @@ -6335,9 +6355,9 @@ "license": "MIT" }, "node_modules/beasties": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.1.0.tgz", - "integrity": "sha512-+Ssscd2gVG24qRNC+E2g88D+xsQW4xwakWtKAiGEQ3Pw54/FGdyo9RrfxhGhEv6ilFVbB7r3Lgx+QnAxnSpECw==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.2.0.tgz", + "integrity": "sha512-Ljqskqx/tbZagIglYoJIMzH5zgssyp+in9+9sAyh15N22AornBeIDnb8EZ6Rk+6ShfMxd92uO3gfpT0NtZbpow==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -6345,10 +6365,13 @@ "css-what": "^6.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", - "htmlparser2": "^9.0.0", + "htmlparser2": "^9.1.0", "picocolors": "^1.1.1", - "postcss": "^8.4.47", + "postcss": "^8.4.49", "postcss-media-query-parser": "^0.2.3" + }, + "engines": { + "node": ">=14.0.0" } }, "node_modules/big.js": { @@ -7001,9 +7024,9 @@ "license": "MIT" }, "node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.0.0.tgz", + "integrity": "sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ==", "dev": true, "license": "MIT", "engines": { @@ -7732,9 +7755,9 @@ } }, "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -7776,9 +7799,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.75", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.75.tgz", - "integrity": "sha512-Lf3++DumRE/QmweGjU+ZcKqQ+3bKkU/qjaKYhIJKEOhgIO9Xs6IiAQFkfFoj+RhgDk4LUeNsLo6plExHqSyu6Q==", + "version": "1.5.76", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz", + "integrity": "sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -8001,9 +8024,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", + "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", "dev": true, "license": "MIT" }, @@ -8021,9 +8044,9 @@ } }, "node_modules/esbuild": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz", - "integrity": "sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -8034,36 +8057,37 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.0", - "@esbuild/android-arm": "0.24.0", - "@esbuild/android-arm64": "0.24.0", - "@esbuild/android-x64": "0.24.0", - "@esbuild/darwin-arm64": "0.24.0", - "@esbuild/darwin-x64": "0.24.0", - "@esbuild/freebsd-arm64": "0.24.0", - "@esbuild/freebsd-x64": "0.24.0", - "@esbuild/linux-arm": "0.24.0", - "@esbuild/linux-arm64": "0.24.0", - "@esbuild/linux-ia32": "0.24.0", - "@esbuild/linux-loong64": "0.24.0", - "@esbuild/linux-mips64el": "0.24.0", - "@esbuild/linux-ppc64": "0.24.0", - "@esbuild/linux-riscv64": "0.24.0", - "@esbuild/linux-s390x": "0.24.0", - "@esbuild/linux-x64": "0.24.0", - "@esbuild/netbsd-x64": "0.24.0", - "@esbuild/openbsd-arm64": "0.24.0", - "@esbuild/openbsd-x64": "0.24.0", - "@esbuild/sunos-x64": "0.24.0", - "@esbuild/win32-arm64": "0.24.0", - "@esbuild/win32-ia32": "0.24.0", - "@esbuild/win32-x64": "0.24.0" + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" } }, "node_modules/esbuild-wasm": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.24.0.tgz", - "integrity": "sha512-xhNn5tL1AhkPg4ft59yXT6FkwKXiPSYyz1IeinJHUJpjvOHOIPvdmFQc0pGdjxlKSbzZc2mNmtVOWAR1EF/JAg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.24.2.tgz", + "integrity": "sha512-03/7Z1gD+ohDnScFztvI4XddTAbKVmMEzCvvkBpQdWKEXJ+73dTyeNrmdxP1Q0zpDMFjzUJwtK4rLjqwiHbzkw==", "dev": true, "license": "MIT", "bin": { @@ -8103,19 +8127,19 @@ } }, "node_modules/eslint": { - "version": "9.17.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", - "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz", + "integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", - "@eslint/core": "^0.9.0", + "@eslint/core": "^0.10.0", "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.17.0", - "@eslint/plugin-kit": "^0.2.3", + "@eslint/js": "9.18.0", + "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.1", @@ -8524,16 +8548,16 @@ "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -8573,9 +8597,9 @@ "license": "BSD-3-Clause" }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", + "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -9186,23 +9210,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/html-entities": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ], - "license": "MIT" - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -9272,9 +9279,9 @@ } }, "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.9.tgz", + "integrity": "sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==", "dev": true, "license": "MIT" }, @@ -9326,13 +9333,13 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { @@ -9551,9 +9558,9 @@ } }, "node_modules/is-core-module": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.0.tgz", - "integrity": "sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", "dependencies": { @@ -10455,9 +10462,9 @@ } }, "node_modules/less": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", - "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.1.tgz", + "integrity": "sha512-CasaJidTIhWmjcqv0Uj5vccMI7pJgfD9lMkKtlnTHAdJdYK/7l8pM9tumLyJ0zhbD4KJLo/YvTj+xznQd5NBhg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -10684,9 +10691,9 @@ } }, "node_modules/lmdb": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.1.5.tgz", - "integrity": "sha512-46Mch5Drq+A93Ss3gtbg+Xuvf5BOgIuvhKDWoGa3HcPHI6BL2NCOkRdSx1D4VfzwrxhnsjbyIVsLRlQHu6URvw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.2.2.tgz", + "integrity": "sha512-LriG93la4PbmPMwI7Hbv8W+0ncLK7549w4sbZSi4QGDjnnxnmNMgxUkaQTEMzH8TpwsfFvgEjpLX7V8B/I9e3g==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -10702,12 +10709,12 @@ "download-lmdb-prebuilds": "bin/download-prebuilds.js" }, "optionalDependencies": { - "@lmdb/lmdb-darwin-arm64": "3.1.5", - "@lmdb/lmdb-darwin-x64": "3.1.5", - "@lmdb/lmdb-linux-arm": "3.1.5", - "@lmdb/lmdb-linux-arm64": "3.1.5", - "@lmdb/lmdb-linux-x64": "3.1.5", - "@lmdb/lmdb-win32-x64": "3.1.5" + "@lmdb/lmdb-darwin-arm64": "3.2.2", + "@lmdb/lmdb-darwin-x64": "3.2.2", + "@lmdb/lmdb-linux-arm": "3.2.2", + "@lmdb/lmdb-linux-arm64": "3.2.2", + "@lmdb/lmdb-linux-x64": "3.2.2", + "@lmdb/lmdb-win32-x64": "3.2.2" } }, "node_modules/loader-runner": { @@ -10946,9 +10953,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.12", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", - "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, "license": "MIT", "dependencies": { @@ -11015,9 +11022,9 @@ } }, "node_modules/memfs": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.15.0.tgz", - "integrity": "sha512-q9MmZXd2rRWHS6GU3WEm3HyiXZyyoA1DqdOhEq0lxPBmKb5S7IAOwX0RgUCwJfqjelDCySa5h8ujOy24LqsWcw==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.17.0.tgz", + "integrity": "sha512-4eirfZ7thblFmqFjywlTmuWVSvccHAJbn1r8qQLzmTO11qcqpohOjmY2mFce6x7x7WtskzRqApPD0hv+Oa74jg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -11562,9 +11569,9 @@ "license": "MIT" }, "node_modules/ng-packagr": { - "version": "19.0.1", - "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-19.0.1.tgz", - "integrity": "sha512-PnXa/y3ce3v4bKJNtUBS7qcNoyv5g/tSthoMe23NyMV5kjNY4+hJT7h64zK+8tnJWTelCbIpoep7tmSPsOifBA==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-19.1.0.tgz", + "integrity": "sha512-i2S0tj2sQNOQGW+0bYViEftrnvzGSxW+/kDELVwEjnRh6KgAL0p6wH2w+aslCcELhruuGGCk96AaOfYwGPVsgQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11574,7 +11581,7 @@ "ansi-colors": "^4.1.3", "browserslist": "^4.22.1", "chokidar": "^4.0.1", - "commander": "^12.1.0", + "commander": "^13.0.0", "convert-source-map": "^2.0.0", "dependency-graph": "^1.0.0", "esbuild": "^0.24.0", @@ -11587,7 +11594,7 @@ "piscina": "^4.7.0", "postcss": "^8.4.47", "rxjs": "^7.8.1", - "sass": "^1.79.5" + "sass": "^1.81.0" }, "bin": { "ng-packagr": "cli/main.js" @@ -11599,10 +11606,10 @@ "rollup": "^4.24.0" }, "peerDependencies": { - "@angular/compiler-cli": "^19.0.0-next.0", + "@angular/compiler-cli": "^19.0.0 || ^19.1.0-next.0 || ^19.2.0-next.0", "tailwindcss": "^2.0.0 || ^3.0.0", "tslib": "^2.3.0", - "typescript": ">=5.5 <5.7" + "typescript": ">=5.5 <5.8" }, "peerDependenciesMeta": { "tailwindcss": { @@ -11995,9 +12002,9 @@ } }, "node_modules/npm-package-arg": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.0.tgz", - "integrity": "sha512-ZTE0hbwSdTNL+Stx2zxSqdu2KZfNDcrtrLdIk7XGnQFYBWYDho/ORvXtn5XEePcL3tFpGjHCV3X3xrtDh7eZ+A==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.1.tgz", + "integrity": "sha512-aDxjFfPV3Liw0WOBWlyZLMBqtbgbg03rmGvHDJa2Ttv7tIz+1oB5qWec4psCDFZcZi9b5XdGkPdQiJxOPzvQRQ==", "dev": true, "license": "ISC", "dependencies": { @@ -12614,9 +12621,9 @@ } }, "node_modules/piscina": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.7.0.tgz", - "integrity": "sha512-b8hvkpp9zS0zsfa939b/jXbe64Z2gZv0Ha7FYPNUiDIB1y2AtxcOZdfP8xN8HFjUaqQiT9gRlfjAsoL8vdJ1Iw==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.8.0.tgz", + "integrity": "sha512-EZJb+ZxDrQf3dihsUL7p42pjNyrNIFJCrRHPMgxu/svsj+P3xS3fuEWp7k2+rfsavfl1N0G29b1HGs7J0m8rZA==", "dev": true, "license": "MIT", "optionalDependencies": { @@ -13218,19 +13225,22 @@ "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -13349,9 +13359,9 @@ } }, "node_modules/rollup": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.26.0.tgz", - "integrity": "sha512-ilcl12hnWonG8f+NxU6BlgysVA0gvY2l8N0R84S1HcINbW20bvwuCngJkkInV6LXhwRpucsW5k1ovDwEdBVrNg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", + "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", "dev": true, "license": "MIT", "dependencies": { @@ -13365,24 +13375,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.26.0", - "@rollup/rollup-android-arm64": "4.26.0", - "@rollup/rollup-darwin-arm64": "4.26.0", - "@rollup/rollup-darwin-x64": "4.26.0", - "@rollup/rollup-freebsd-arm64": "4.26.0", - "@rollup/rollup-freebsd-x64": "4.26.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.26.0", - "@rollup/rollup-linux-arm-musleabihf": "4.26.0", - "@rollup/rollup-linux-arm64-gnu": "4.26.0", - "@rollup/rollup-linux-arm64-musl": "4.26.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.26.0", - "@rollup/rollup-linux-riscv64-gnu": "4.26.0", - "@rollup/rollup-linux-s390x-gnu": "4.26.0", - "@rollup/rollup-linux-x64-gnu": "4.26.0", - "@rollup/rollup-linux-x64-musl": "4.26.0", - "@rollup/rollup-win32-arm64-msvc": "4.26.0", - "@rollup/rollup-win32-ia32-msvc": "4.26.0", - "@rollup/rollup-win32-x64-msvc": "4.26.0", + "@rollup/rollup-android-arm-eabi": "4.30.1", + "@rollup/rollup-android-arm64": "4.30.1", + "@rollup/rollup-darwin-arm64": "4.30.1", + "@rollup/rollup-darwin-x64": "4.30.1", + "@rollup/rollup-freebsd-arm64": "4.30.1", + "@rollup/rollup-freebsd-x64": "4.30.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.30.1", + "@rollup/rollup-linux-arm-musleabihf": "4.30.1", + "@rollup/rollup-linux-arm64-gnu": "4.30.1", + "@rollup/rollup-linux-arm64-musl": "4.30.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.30.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", + "@rollup/rollup-linux-riscv64-gnu": "4.30.1", + "@rollup/rollup-linux-s390x-gnu": "4.30.1", + "@rollup/rollup-linux-x64-gnu": "4.30.1", + "@rollup/rollup-linux-x64-musl": "4.30.1", + "@rollup/rollup-win32-arm64-msvc": "4.30.1", + "@rollup/rollup-win32-ia32-msvc": "4.30.1", + "@rollup/rollup-win32-x64-msvc": "4.30.1", "fsevents": "~2.3.2" } }, @@ -13478,9 +13489,9 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.80.7", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.80.7.tgz", - "integrity": "sha512-MVWvN0u5meytrSjsU7AWsbhoXi1sc58zADXFllfZzbsBT1GHjjar6JwBINYPRrkx/zqnQ6uqbQuHgE95O+C+eQ==", + "version": "1.83.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.83.1.tgz", + "integrity": "sha512-EVJbDaEs4Rr3F0glJzFSOvtg2/oy2V/YrGFPqPY24UqcLDWcI9ZY5sN+qyO3c/QCZwzgfirvhXvINiJCE/OLcA==", "dev": true, "license": "MIT", "dependencies": { @@ -13499,9 +13510,9 @@ } }, "node_modules/sass-loader": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.3.tgz", - "integrity": "sha512-gosNorT1RCkuCMyihv6FBRR7BMV06oKRAs+l4UMp1mlcVg9rWN6KMmUj3igjQwmYys4mDP3etEYJgiHRbgHCHA==", + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.4.tgz", + "integrity": "sha512-LavLbgbBGUt3wCiYzhuLLu65+fWXaXLmq7YxivLhEqmiupCFZ5sKUAipK3do6V80YSU0jvSxNhEdT13IXNr3rg==", "dev": true, "license": "MIT", "dependencies": { @@ -14626,9 +14637,9 @@ "license": "ISC" }, "node_modules/terser": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", - "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", + "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -14820,16 +14831,16 @@ } }, "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", + "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=4.2.0" + "typescript": ">=4.8.4" } }, "node_modules/tslib": { @@ -14914,15 +14925,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.18.1.tgz", - "integrity": "sha512-Mlaw6yxuaDEPQvb/2Qwu3/TfgeBHy9iTJ3mTwe7OvpPmF6KPQjVOfGyEJpPv6Ez2C34OODChhXrzYw/9phI0MQ==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.20.0.tgz", + "integrity": "sha512-Kxz2QRFsgbWj6Xcftlw3Dd154b3cEPFqQC+qMZrMypSijPd4UanKKvoKDrJ4o8AIfZFKAF+7sMaEIR8mTElozA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.18.1", - "@typescript-eslint/parser": "8.18.1", - "@typescript-eslint/utils": "8.18.1" + "@typescript-eslint/eslint-plugin": "8.20.0", + "@typescript-eslint/parser": "8.20.0", + "@typescript-eslint/utils": "8.20.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -15192,21 +15203,21 @@ } }, "node_modules/vite": { - "version": "5.4.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", - "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.7.tgz", + "integrity": "sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.24.2", + "postcss": "^8.4.49", + "rollup": "^4.23.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -15215,19 +15226,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.4.0" + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -15248,439 +15265,15 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", @@ -15734,17 +15327,17 @@ "optional": true }, "node_modules/webpack": { - "version": "5.96.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", - "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "version": "5.97.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", + "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.14.0", "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", @@ -15811,9 +15404,9 @@ } }, "node_modules/webpack-dev-server": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.1.0.tgz", - "integrity": "sha512-aQpaN81X6tXie1FoOB7xlMfCsN19pSvRAeYUHOdFWOlhpQ/LlbfTqYwwmEDFV0h8GGuqmCmKmT+pxcUV/Nt2gQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.0.tgz", + "integrity": "sha512-90SqqYXA2SK36KcT6o1bvwvZfJFcmoamqeJY7+boioffX9g9C0wjjJRGUrQIuh43pb0ttX7+ssavmj/WN2RHtA==", "dev": true, "license": "MIT", "dependencies": { @@ -15830,10 +15423,9 @@ "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", - "express": "^4.19.2", + "express": "^4.21.2", "graceful-fs": "^4.2.6", - "html-entities": "^2.4.0", - "http-proxy-middleware": "^2.0.3", + "http-proxy-middleware": "^2.0.7", "ipaddr.js": "^2.1.0", "launch-editor": "^2.6.1", "open": "^10.0.3", diff --git a/package.json b/package.json index 44cc7432..62016a11 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "coreui-angular-dev", - "version": "5.3.5", + "version": "5.3.8", "description": "CoreUI Components Library for Angular", - "copyright": "Copyright 2024 creativeLabs Łukasz Holeczek", + "copyright": "Copyright 2025 creativeLabs Łukasz Holeczek", "license": "MIT", "author": "The CoreUI Team (https://github.com/orgs/coreui/people)", "scripts": { @@ -10,7 +10,7 @@ "watch:lib:dev": "ng build coreui-angular --watch --configuration production", "build:lib:prod": "ng build coreui-angular", "postbuild:lib:prod": "npm run build --prefix projects/coreui-angular", - "test:lib:dev": "ng test coreui-angular", + "test:lib:dev": "ng test --no-watch --code-coverage coreui-angular ", "test:lib:prod": "ng test coreui-angular --karma-config=projects/coreui-angular/karma.conf.github.js", "prepublish:lib": "npm run prepublish:icons && ng lint coreui-angular && ng test coreui-angular --watch=false && npm run build:lib:prod", "publish:lib": "cd dist/coreui-angular/ && npm publish --tag next --dry-run", @@ -39,16 +39,16 @@ }, "private": true, "dependencies": { - "@angular/animations": "^19.0.5", - "@angular/cdk": "^19.0.4", - "@angular/common": "^19.0.5", - "@angular/compiler": "^19.0.5", - "@angular/core": "^19.0.5", - "@angular/forms": "^19.0.5", - "@angular/localize": "^19.0.5", - "@angular/platform-browser": "^19.0.5", - "@angular/platform-browser-dynamic": "^19.0.5", - "@angular/router": "^19.0.5", + "@angular/animations": "^19.1.1", + "@angular/cdk": "^19.1.0", + "@angular/common": "^19.1.1", + "@angular/compiler": "^19.1.1", + "@angular/core": "^19.1.1", + "@angular/forms": "^19.1.1", + "@angular/localize": "^19.1.1", + "@angular/platform-browser": "^19.1.1", + "@angular/platform-browser-dynamic": "^19.1.1", + "@angular/router": "^19.1.1", "@coreui/chartjs": "^4.0.0", "@coreui/icons": "^3.0.1", "@popperjs/core": "~2.11.8", @@ -59,27 +59,27 @@ "zone.js": "~0.15.0" }, "devDependencies": { - "@angular-devkit/build-angular": "^19.0.6", - "@angular-devkit/schematics": "^19.0.6", - "@angular/cli": "^19.0.6", - "@angular/compiler-cli": "^19.0.5", - "@angular/language-service": "^19.0.5", + "@angular-devkit/build-angular": "^19.1.1", + "@angular-devkit/schematics": "^19.1.1", + "@angular/cli": "^19.1.1", + "@angular/compiler-cli": "^19.1.1", + "@angular/language-service": "^19.1.1", "@types/jasmine": "^5.1.5", "@types/lodash-es": "^4.17.12", - "@types/node": "^22.10.2", + "@types/node": "^22.10.7", "angular-eslint": "^19.0.2", "copyfiles": "^2.4.1", - "eslint": "^9.17.0", + "eslint": "^9.18.0", "jasmine-core": "^5.5.0", "karma": "^6.4.4", "karma-chrome-launcher": "^3.2.0", "karma-coverage": "^2.2.1", "karma-jasmine": "^5.1.0", "karma-jasmine-html-reporter": "^2.1.0", - "ng-packagr": "^19.0.1", + "ng-packagr": "^19.1.0", "prettier": "^3.4.2", "typescript": "~5.6.3", - "typescript-eslint": "^8.18.1" + "typescript-eslint": "^8.20.0" }, "keywords": [ "angular", diff --git a/projects/coreui-angular-chartjs/LICENSE b/projects/coreui-angular-chartjs/LICENSE index 94e4f4d1..fbb053e0 100644 --- a/projects/coreui-angular-chartjs/LICENSE +++ b/projects/coreui-angular-chartjs/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 creativeLabs Łukasz Holeczek +Copyright (c) 2025 creativeLabs Łukasz Holeczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/projects/coreui-angular-chartjs/README.md b/projects/coreui-angular-chartjs/README.md index 95d7b350..b2efd45d 100644 --- a/projects/coreui-angular-chartjs/README.md +++ b/projects/coreui-angular-chartjs/README.md @@ -35,7 +35,7 @@ [npm-badge-next]: https://img.shields.io/npm/v/@coreui/angular-chartjs/next?style=flat-square&color=red [npm]: https://www.npmjs.com/package/@coreui/angular-chartjs [npm-download]: https://img.shields.io/npm/dm/@coreui/angular-chartjs.svg?style=flat-square -[angular-badge]: https://img.shields.io/badge/angular-^19.0.0-lightgrey.svg?style=flat-square&logo=angular +[angular-badge]: https://img.shields.io/badge/angular-^19.1.0-lightgrey.svg?style=flat-square&logo=angular ##### install: @@ -189,4 +189,4 @@ Thanks to all the backers and sponsors! Support this project by [becoming a back ## Copyright and license -Copyright 2024 creativeLabs Łukasz Holeczek. Code released under the [MIT License](https://github.com/coreui/coreui-angular/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). +Copyright 2025 creativeLabs Łukasz Holeczek. Code released under the [MIT License](https://github.com/coreui/coreui-angular/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). diff --git a/projects/coreui-angular-chartjs/package.json b/projects/coreui-angular-chartjs/package.json index 216e4ea5..5087ae5c 100644 --- a/projects/coreui-angular-chartjs/package.json +++ b/projects/coreui-angular-chartjs/package.json @@ -1,8 +1,8 @@ { "name": "@coreui/angular-chartjs", - "version": "5.3.5", + "version": "5.3.8", "description": "Angular wrapper component for Chart.js", - "copyright": "Copyright 2024 creativeLabs Łukasz Holeczek", + "copyright": "Copyright 2025 creativeLabs Łukasz Holeczek", "license": "MIT", "homepage": "https://coreui.io/angular", "author": { @@ -25,7 +25,7 @@ "url": "https://github.com/coreui/coreui-angular/issues" }, "peerDependencies": { - "@angular/core": "^19.0.0", + "@angular/core": "^19.1.1", "@coreui/chartjs": "^4.0.0", "chart.js": "^4.4.7" }, diff --git a/projects/coreui-angular/CLI.md b/projects/coreui-angular/CLI.md index fcbbd5c5..cd0a31a1 100644 --- a/projects/coreui-angular/CLI.md +++ b/projects/coreui-angular/CLI.md @@ -1,6 +1,6 @@ # @coreui/angular v5 -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 18.0.2. +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 19.1.0. ## Development server diff --git a/projects/coreui-angular/LICENSE b/projects/coreui-angular/LICENSE index 94e4f4d1..fbb053e0 100644 --- a/projects/coreui-angular/LICENSE +++ b/projects/coreui-angular/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 creativeLabs Łukasz Holeczek +Copyright (c) 2025 creativeLabs Łukasz Holeczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/projects/coreui-angular/README.md b/projects/coreui-angular/README.md index c5f8d2a4..3f430044 100644 --- a/projects/coreui-angular/README.md +++ b/projects/coreui-angular/README.md @@ -215,11 +215,11 @@ Thanks to all the backers and sponsors! Support this project by [becoming a back ## Copyright and license -Copyright 2024 creativeLabs Łukasz Holeczek. Code released under the [MIT License](https://github.com/coreui/coreui-angular/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). +Copyright 2025 creativeLabs Łukasz Holeczek. Code released under the [MIT License](https://github.com/coreui/coreui-angular/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). [npm-coreui-angular-badge-v5-ng19]: https://img.shields.io/npm/v/@coreui/angular/v5-ng19?style=flat-square&color=brightgreen [npm-coreui-angular-badge-latest]: https://img.shields.io/npm/v/@coreui/angular/latest?style=flat-square&color=brightgreen [npm-coreui-angular-badge-next]: https://img.shields.io/npm/v/@coreui/angular/next?style=flat-square&color=red [npm-coreui-angular]: https://www.npmjs.com/package/@coreui/angular [npm-coreui-angular-download]: https://img.shields.io/npm/dm/@coreui/angular.svg?style=flat-square -[angular-badge]: https://img.shields.io/badge/angular-^19.0.0-lightgrey.svg?style=flat-square&logo=angular +[angular-badge]: https://img.shields.io/badge/angular-^19.1.0-lightgrey.svg?style=flat-square&logo=angular diff --git a/projects/coreui-angular/package.json b/projects/coreui-angular/package.json index 55197104..d32ebaf6 100644 --- a/projects/coreui-angular/package.json +++ b/projects/coreui-angular/package.json @@ -1,8 +1,8 @@ { "name": "@coreui/angular", - "version": "5.3.5", + "version": "5.3.8", "description": "CoreUI Components Library for Angular", - "copyright": "Copyright 2024 creativeLabs Łukasz Holeczek", + "copyright": "Copyright 2025 creativeLabs Łukasz Holeczek", "license": "MIT", "homepage": "https://coreui.io/angular", "author": { @@ -23,13 +23,13 @@ }, "sideEffects": false, "peerDependencies": { - "@angular/animations": "^19.0.0", - "@angular/cdk": "^19.0.0", - "@angular/common": "^19.0.0", - "@angular/core": "^19.0.0", - "@angular/router": "^19.0.0", + "@angular/animations": "^19.1.1", + "@angular/cdk": "^19.1.0", + "@angular/common": "^19.1.1", + "@angular/core": "^19.1.1", + "@angular/router": "^19.1.1", "@coreui/coreui": "^5.2.0", - "@coreui/icons-angular": "~5.3.5", + "@coreui/icons-angular": "~5.3.8", "rxjs": "^7.8.1" }, "repository": { diff --git a/projects/coreui-angular/src/lib/accordion/accordion-button/accordion-button.directive.ts b/projects/coreui-angular/src/lib/accordion/accordion-button/accordion-button.directive.ts index d009bf03..308ddf76 100644 --- a/projects/coreui-angular/src/lib/accordion/accordion-button/accordion-button.directive.ts +++ b/projects/coreui-angular/src/lib/accordion/accordion-button/accordion-button.directive.ts @@ -22,7 +22,7 @@ export class AccordionButtonDirective { return { 'accordion-button': true, collapsed: this.collapsed() - }; + } as Record; }); readonly ariaExpanded = computed(() => !this.collapsed()); diff --git a/projects/coreui-angular/src/lib/accordion/accordion-item/accordion-item.component.ts b/projects/coreui-angular/src/lib/accordion/accordion-item/accordion-item.component.ts index 1cf9806c..8085652f 100644 --- a/projects/coreui-angular/src/lib/accordion/accordion-item/accordion-item.component.ts +++ b/projects/coreui-angular/src/lib/accordion/accordion-item/accordion-item.component.ts @@ -41,7 +41,7 @@ export class AccordionItemComponent implements OnInit, OnDestroy { readonly itemVisible = signal(false); - visibleInputChange = effect(() => { + readonly #visibleInputChange = effect(() => { setTimeout(() => { this.itemVisible.set(this.visibleInput()); }); diff --git a/projects/coreui-angular/src/lib/accordion/accordion/accordion.component.ts b/projects/coreui-angular/src/lib/accordion/accordion/accordion.component.ts index 918d4e4d..8abcf01f 100644 --- a/projects/coreui-angular/src/lib/accordion/accordion/accordion.component.ts +++ b/projects/coreui-angular/src/lib/accordion/accordion/accordion.component.ts @@ -29,8 +29,8 @@ export class AccordionComponent { this.#accordionService.alwaysOpen = this.alwaysOpen(); }); - readonly hostClasses = computed>(() => ({ + readonly hostClasses = computed(() => ({ accordion: true, 'accordion-flush': this.flush() - })); + }) as Record); } diff --git a/projects/coreui-angular/src/lib/button-group/button-group/button-group.component.ts b/projects/coreui-angular/src/lib/button-group/button-group/button-group.component.ts index 18504269..4425bf45 100644 --- a/projects/coreui-angular/src/lib/button-group/button-group/button-group.component.ts +++ b/projects/coreui-angular/src/lib/button-group/button-group/button-group.component.ts @@ -30,6 +30,6 @@ export class ButtonGroupComponent { 'btn-group': !this.vertical(), 'btn-group-vertical': this.vertical(), [`btn-group-${this.size()}`]: !!this.size() - }; + } as Record; }); } diff --git a/projects/coreui-angular/src/lib/button/button-close.directive.spec.ts b/projects/coreui-angular/src/lib/button/button-close.directive.spec.ts index 80178e1f..ddcc5691 100644 --- a/projects/coreui-angular/src/lib/button/button-close.directive.spec.ts +++ b/projects/coreui-angular/src/lib/button/button-close.directive.spec.ts @@ -1,13 +1,13 @@ -import { ButtonCloseDirective } from './button-close.directive'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Component, DebugElement, ElementRef } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; +import { ButtonCloseDirective } from './button-close.directive'; class MockElementRef extends ElementRef {} @Component({ - template: '', - imports: [ButtonCloseDirective] + template: '', + imports: [ButtonCloseDirective] }) class TestComponent {} diff --git a/projects/coreui-angular/src/lib/collapse/collapse.directive.ts b/projects/coreui-angular/src/lib/collapse/collapse.directive.ts index 82a7d7a8..6d711d6b 100644 --- a/projects/coreui-angular/src/lib/collapse/collapse.directive.ts +++ b/projects/coreui-angular/src/lib/collapse/collapse.directive.ts @@ -1,4 +1,7 @@ +import { AnimationBuilder, AnimationPlayer, useAnimation } from '@angular/animations'; + import { + afterNextRender, booleanAttribute, computed, Directive, @@ -11,7 +14,6 @@ import { Renderer2, signal } from '@angular/core'; -import { AnimationBuilder, AnimationPlayer, useAnimation } from '@angular/animations'; import { collapseAnimation, @@ -23,7 +25,7 @@ import { @Directive({ selector: '[cCollapse]', exportAs: 'cCollapse', - host: { '[class]': 'hostClasses()', '[style]': '{display: "none"}' } + host: { '[class]': 'hostClasses()', '[style]': '{ display: "none" }' } }) export class CollapseDirective implements OnDestroy { readonly #hostElement = inject(ElementRef); @@ -31,6 +33,14 @@ export class CollapseDirective implements OnDestroy { readonly #animationBuilder = inject(AnimationBuilder); #player: AnimationPlayer | undefined = undefined; + constructor() { + afterNextRender({ + read: () => { + this.#initialized.set(true); + } + }); + } + /** * @ignore */ @@ -38,7 +48,7 @@ export class CollapseDirective implements OnDestroy { readonly animate = signal(true); - readonly animateInputEffect = effect(() => { + readonly #animateInputEffect = effect(() => { this.animate.set(this.animateInput()); }); @@ -58,19 +68,18 @@ export class CollapseDirective implements OnDestroy { readonly visibleChange = output(); - readonly visibleInputEffect = effect(() => { + readonly #visibleInputEffect = effect(() => { this.visible.set(this.visibleInput()); }); - readonly visible = signal(false); + readonly visible = signal(false); - #init = false; + readonly #initialized = signal(false); - readonly visibleEffect = effect(() => { - const visible = this.visible(); - - (this.#init || visible) && this.createPlayer(visible); - this.#init = true; + readonly #visibleEffect = effect(() => { + if (this.#initialized()) { + this.createPlayer(this.visible()); + } }); /** diff --git a/projects/coreui-angular/src/lib/form/form-check/form-check-input.directive.spec.ts b/projects/coreui-angular/src/lib/form/form-check/form-check-input.directive.spec.ts index 272ff433..f2ee6dc6 100644 --- a/projects/coreui-angular/src/lib/form/form-check/form-check-input.directive.spec.ts +++ b/projects/coreui-angular/src/lib/form/form-check/form-check-input.directive.spec.ts @@ -1,4 +1,4 @@ -import { Component, DebugElement, ElementRef, Renderer2, Type } from '@angular/core'; +import { Component, DebugElement, ElementRef, Renderer2 } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { FormCheckInputDirective } from './form-check-input.directive'; @@ -15,7 +15,7 @@ describe('FormCheckInputDirective', () => { let component: TestComponent; let fixture: ComponentFixture; let inputEl: DebugElement; - let renderer: Renderer2; + // let renderer: Renderer2; beforeEach(() => { TestBed.configureTestingModule({ @@ -24,8 +24,8 @@ describe('FormCheckInputDirective', () => { }); fixture = TestBed.createComponent(TestComponent); component = fixture.componentInstance; - inputEl = fixture.debugElement.query(By.css('input')); - renderer = fixture.componentRef.injector.get(Renderer2 as Type); + inputEl = fixture.debugElement.query(By.directive(FormCheckInputDirective)); + // renderer = fixture.componentRef.injector.get(Renderer2 as Type); }); it('should create an instance', () => { @@ -34,4 +34,8 @@ describe('FormCheckInputDirective', () => { expect(directive).toBeTruthy(); }); }); + + it('should have css classes', () => { + expect(inputEl.nativeElement).toHaveClass('form-check-input'); + }); }); diff --git a/projects/coreui-angular/src/lib/form/form-check/form-check-input.directive.ts b/projects/coreui-angular/src/lib/form/form-check/form-check-input.directive.ts index bcdd11fc..f7bf9395 100644 --- a/projects/coreui-angular/src/lib/form/form-check/form-check-input.directive.ts +++ b/projects/coreui-angular/src/lib/form/form-check/form-check-input.directive.ts @@ -1,8 +1,23 @@ -import { booleanAttribute, Directive, ElementRef, HostBinding, inject, Input, Renderer2 } from '@angular/core'; +import { + booleanAttribute, + computed, + Directive, + effect, + ElementRef, + inject, + input, + Renderer2, + signal, + untracked +} from '@angular/core'; @Directive({ selector: 'input[cFormCheckInput]', - host: { class: 'form-check-input' } + host: { + class: 'form-check-input', + '[class]': 'hostClasses()', + '[attr.type]': 'type()' + } }) export class FormCheckInputDirective { readonly #renderer = inject(Renderer2); @@ -10,61 +25,62 @@ export class FormCheckInputDirective { /** * Specifies the type of component. - * @type {'checkbox' | 'radio'} * @default 'checkbox' */ - @HostBinding('attr.type') - @Input() - type: 'checkbox' | 'radio' = 'checkbox'; + readonly type = input<'checkbox' | 'radio'>('checkbox'); /** * Set component indeterminate state. - * @type boolean * @default false */ - @Input({ transform: booleanAttribute }) - set indeterminate(value: boolean) { - const indeterminate = value; - if (this._indeterminate !== indeterminate) { - this._indeterminate = indeterminate; + readonly indeterminateInput = input(false, { transform: booleanAttribute, alias: 'indeterminate' }); + + readonly #indeterminateEffect = effect(() => { + const indeterminate = this.indeterminateInput(); + if (untracked(this.#indeterminate) !== indeterminate) { const htmlInputElement = this.#hostElement.nativeElement as HTMLInputElement; if (indeterminate) { this.#renderer.setProperty(htmlInputElement, 'checked', false); } this.#renderer.setProperty(htmlInputElement, 'indeterminate', indeterminate); + this.#indeterminate.set(indeterminate); } - } + }); get indeterminate() { - return this._indeterminate; + return this.#indeterminate(); } - private _indeterminate = false; + readonly #indeterminate = signal(false); /** * Set component validation state to valid. - * @type boolean * @default undefined */ - @Input() valid?: boolean; + readonly valid = input(); - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { + const valid = this.valid(); return { 'form-check-input': true, - 'is-valid': this.valid === true, - 'is-invalid': this.valid === false - }; - } + 'is-valid': valid === true, + 'is-invalid': valid === false + } as Record; + }); - @Input({ transform: booleanAttribute }) - set checked(value: boolean) { - const checked = value; + /** + * Set component checked state. + * @default false + */ + readonly checkedInput = input(false, { transform: booleanAttribute, alias: 'checked' }); + + readonly #checkedEffect = effect(() => { + const checked = this.checkedInput(); const htmlInputElement = this.#hostElement?.nativeElement as HTMLInputElement; if (htmlInputElement) { this.#renderer.setProperty(htmlInputElement, 'checked', checked); } - } + }); get checked(): boolean { return this.#hostElement?.nativeElement?.checked; diff --git a/projects/coreui-angular/src/lib/form/form-check/form-check-label.directive.spec.ts b/projects/coreui-angular/src/lib/form/form-check/form-check-label.directive.spec.ts index 2ebc6583..f5af4330 100644 --- a/projects/coreui-angular/src/lib/form/form-check/form-check-label.directive.spec.ts +++ b/projects/coreui-angular/src/lib/form/form-check/form-check-label.directive.spec.ts @@ -1,8 +1,33 @@ import { FormCheckLabelDirective } from './form-check-label.directive'; +import { Component, DebugElement } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; + +@Component({ + template: '', + imports: [FormCheckLabelDirective] +}) +class TestComponent {} describe('FormCheckLabelDirective', () => { + let component: TestComponent; + let fixture: ComponentFixture; + let debugElement: DebugElement; + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TestComponent] + }); + fixture = TestBed.createComponent(TestComponent); + component = fixture.componentInstance; + debugElement = fixture.debugElement.query(By.directive(FormCheckLabelDirective)); + }); + it('should create an instance', () => { const directive = new FormCheckLabelDirective(); expect(directive).toBeTruthy(); }); + + it('should have css classes', () => { + expect(debugElement.nativeElement).toHaveClass('form-check-label'); + }); }); diff --git a/projects/coreui-angular/src/lib/form/form-check/form-check.component.spec.ts b/projects/coreui-angular/src/lib/form/form-check/form-check.component.spec.ts index 32a027b0..fc5d48af 100644 --- a/projects/coreui-angular/src/lib/form/form-check/form-check.component.spec.ts +++ b/projects/coreui-angular/src/lib/form/form-check/form-check.component.spec.ts @@ -1,28 +1,41 @@ +import { Component, ComponentRef, DebugElement } from '@angular/core'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; - import { FormCheckComponent } from './form-check.component'; -import { Renderer2 } from '@angular/core'; +import { FormCheckInputDirective } from './form-check-input.directive'; +import { FormCheckLabelDirective } from './form-check-label.directive'; +import { By } from '@angular/platform-browser'; + +@Component({ + template: ` + + + + + `, + imports: [FormCheckInputDirective, FormCheckComponent, FormCheckLabelDirective] +}) +class TestComponent { + inline = true; + reverse = true; + switch = false; +} describe('FormCheckComponent', () => { let component: FormCheckComponent; let fixture: ComponentFixture; - let renderer: Renderer2; + let componentRef: ComponentRef; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - imports: [FormCheckComponent], - providers: [Renderer2] - }) - .compileComponents(); - })); + imports: [FormCheckComponent] + }).compileComponents(); - beforeEach(() => { fixture = TestBed.createComponent(FormCheckComponent); - renderer = fixture.debugElement.injector.get(Renderer2); component = fixture.componentInstance; - component.switch = true; + componentRef = fixture.componentRef; + componentRef.setInput('switch', true); fixture.detectChanges(); - }); + })); it('should create', () => { expect(component).toBeTruthy(); @@ -30,6 +43,36 @@ describe('FormCheckComponent', () => { it('should have css classes', () => { expect(fixture.nativeElement).toHaveClass('form-switch'); + expect(fixture.nativeElement).not.toHaveClass('form-check'); }); +}); + +describe('FormCheckComponent Test', () => { + let testFixture: ComponentFixture; + let debugElement: DebugElement; + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + imports: [TestComponent] + }).compileComponents(); + testFixture = TestBed.createComponent(TestComponent); + debugElement = testFixture.debugElement.query(By.directive(FormCheckComponent)); + testFixture.detectChanges(); // initial binding + })); + + it('should have css classes', () => { + expect(debugElement.nativeElement).not.toHaveClass('form-switch'); + expect(debugElement.nativeElement).not.toHaveClass('form-switch-xl'); + expect(debugElement.nativeElement).toHaveClass('form-check-inline'); + expect(debugElement.nativeElement).toHaveClass('form-check-reverse'); + testFixture.componentInstance.switch = true; + testFixture.componentInstance.inline = false; + testFixture.componentInstance.reverse = false; + testFixture.detectChanges(); + expect(debugElement.nativeElement).toHaveClass('form-switch'); + expect(debugElement.nativeElement).toHaveClass('form-switch-xl'); + expect(debugElement.nativeElement).not.toHaveClass('form-check-inline'); + expect(debugElement.nativeElement).not.toHaveClass('form-check-reverse'); + expect(debugElement.nativeElement).toHaveClass('form-check'); + }); }); diff --git a/projects/coreui-angular/src/lib/form/form-check/form-check.component.ts b/projects/coreui-angular/src/lib/form/form-check/form-check.component.ts index a5c903eb..667ca0d4 100644 --- a/projects/coreui-angular/src/lib/form/form-check/form-check.component.ts +++ b/projects/coreui-angular/src/lib/form/form-check/form-check.component.ts @@ -1,60 +1,54 @@ -import { AfterContentInit, booleanAttribute, Component, ContentChild, HostBinding, Input } from '@angular/core'; +import { booleanAttribute, Component, computed, contentChild, input } from '@angular/core'; import { FormCheckLabelDirective } from './form-check-label.directive'; @Component({ selector: 'c-form-check', template: '', - exportAs: 'cFormCheck' + exportAs: 'cFormCheck', + host: { '[class]': 'hostClasses()' } }) -export class FormCheckComponent implements AfterContentInit { +export class FormCheckComponent { /** * Group checkboxes or radios on the same horizontal row. - * @type boolean * @default false */ - @Input({ transform: booleanAttribute }) inline: string | boolean = false; + readonly inline = input(false, { transform: booleanAttribute }); /** * Put checkboxes or radios on the opposite side. - * @type boolean * @default false * @since 4.4.7 */ - @Input({ transform: booleanAttribute }) reverse: string | boolean = false; + readonly reverse = input(false, { transform: booleanAttribute }); /** * Size the component large or extra large. Works only with `[switch]="true"` [docs] - * @type {'lg' | 'xl' | ''} + * @default undefined */ - @Input() sizing?: 'lg' | 'xl' | '' = ''; + readonly sizing = input<'' | 'lg' | 'xl' | string>(); /** * Render a toggle switch on for checkbox. * @type boolean * @default false */ - @Input({ transform: booleanAttribute }) switch: string | boolean = false; + readonly switch = input(false, { transform: booleanAttribute }); + + readonly formCheckLabel = contentChild(FormCheckLabelDirective); + + readonly formCheckClass = computed(() => !!this.formCheckLabel()); + + readonly hostClasses = computed(() => { + const sizing = this.sizing(); + const isSwitch = this.switch(); - @HostBinding('class') - get hostClasses(): any { return { - 'form-check': this.formCheckClass, - 'form-switch': this.switch, - [`form-switch-${this.sizing}`]: this.switch && !!this.sizing, - 'form-check-inline': this.inline, - 'form-check-reverse': this.reverse - }; - } - - @ContentChild(FormCheckLabelDirective) formCheckLabel!: FormCheckLabelDirective; - - #formCheckClass = true; - get formCheckClass() { - return this.#formCheckClass; - } - - ngAfterContentInit(): void { - this.#formCheckClass = !!this.formCheckLabel; - } + 'form-check': !!this.formCheckLabel(), + 'form-switch': isSwitch, + [`form-switch-${sizing}`]: isSwitch && !!sizing, + 'form-check-inline': this.inline(), + 'form-check-reverse': this.reverse() + } as Record; + }); } diff --git a/projects/coreui-angular/src/lib/form/form-control/form-control.directive.ts b/projects/coreui-angular/src/lib/form/form-control/form-control.directive.ts index d5835d5c..42d118d0 100644 --- a/projects/coreui-angular/src/lib/form/form-control/form-control.directive.ts +++ b/projects/coreui-angular/src/lib/form/form-control/form-control.directive.ts @@ -1,50 +1,57 @@ -import { booleanAttribute, Directive, ElementRef, HostBinding, inject, Input, OnInit } from '@angular/core'; +import { booleanAttribute, computed, Directive, ElementRef, inject, input, OnInit } from '@angular/core'; import { InputType } from '../../coreui.types'; @Directive({ - selector: 'input[cFormControl], textarea[cFormControl]' + selector: 'input[cFormControl], textarea[cFormControl]', + host: { + '[class]': 'hostClasses()', + '[attr.type]': 'type()' + } }) export class FormControlDirective implements OnInit { readonly #hostElement = inject(ElementRef); /** * Size the component small or large. - * @type {'sm' | 'lg'} + * @default undefined */ - @Input() sizing?: '' | 'sm' | 'lg' | string = ''; + readonly sizing = input<'' | 'sm' | 'lg' | string>(); + /** * Set component validation state to valid. - * @type boolean | undefined + * @default undefined */ - @Input() valid?: boolean; + readonly valid = input(); /** * Specifies the type of input element. */ - @HostBinding('attr.type') - @Input() - type: Omit = 'text'; + readonly type = input>('text'); /** - * Render the component styled as plain text. Removes the default form field styling and preserve the correct margin and padding. Recommend to use alongside `readonly` [docs] + * Render the component styled as plain text. Removes the default form field styling and preserve the correct margin and padding. Recommend to use alongside `readonly` + * @default false */ - @Input({ transform: booleanAttribute }) plaintext: string | boolean = false; + readonly plaintext = input(false, { transform: booleanAttribute }); - @HostBinding('class') - get hostClasses(): any { - const isRangeType = this.type === 'range'; + readonly hostClasses = computed(() => { + const type = this.type(); + const isRange = type === 'range'; + const plaintext = this.plaintext(); + const sizing = this.sizing(); + const valid = this.valid(); return { - 'form-control': !isRangeType && !this.plaintext, - 'form-control-plaintext': !isRangeType && this.plaintext, - 'form-control-color': this.type === 'color', - 'form-range': isRangeType, - [`form-control-${this.sizing}`]: !!this.sizing && !isRangeType, - 'is-valid': this.valid === true, - 'is-invalid': this.valid === false - }; - } + 'form-control': !isRange && !plaintext, + 'form-control-plaintext': !isRange && plaintext, + 'form-control-color': type === 'color', + 'form-range': isRange, + [`form-control-${sizing}`]: !!sizing && !isRange, + 'is-valid': valid === true, + 'is-invalid': valid === false + } as Record; + }); get hostTag(): string { return this.#hostElement.nativeElement.tagName; diff --git a/projects/coreui-angular/src/lib/form/form-feedback/form-feedback.component.spec.ts b/projects/coreui-angular/src/lib/form/form-feedback/form-feedback.component.spec.ts index 147d3c6e..0aafedf7 100644 --- a/projects/coreui-angular/src/lib/form/form-feedback/form-feedback.component.spec.ts +++ b/projects/coreui-angular/src/lib/form/form-feedback/form-feedback.component.spec.ts @@ -1,21 +1,23 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { FormFeedbackComponent } from './form-feedback.component'; +import { ComponentRef } from '@angular/core'; describe('FormFeedbackComponent', () => { let component: FormFeedbackComponent; let fixture: ComponentFixture; + let componentRef: ComponentRef; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [FormFeedbackComponent] - }) - .compileComponents(); + }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(FormFeedbackComponent); component = fixture.componentInstance; + componentRef = fixture.componentRef; fixture.detectChanges(); }); @@ -24,10 +26,10 @@ describe('FormFeedbackComponent', () => { }); it('should have css classes', () => { - component.valid = true; + componentRef.setInput('valid', true); fixture.detectChanges(); expect(fixture.nativeElement).toHaveClass('valid-feedback'); - component.valid = false; + componentRef.setInput('valid', false); fixture.detectChanges(); expect(fixture.nativeElement).toHaveClass('invalid-feedback'); }); diff --git a/projects/coreui-angular/src/lib/form/form-feedback/form-feedback.component.ts b/projects/coreui-angular/src/lib/form/form-feedback/form-feedback.component.ts index cd315b69..7ea37c1b 100644 --- a/projects/coreui-angular/src/lib/form/form-feedback/form-feedback.component.ts +++ b/projects/coreui-angular/src/lib/form/form-feedback/form-feedback.component.ts @@ -1,29 +1,32 @@ -import { booleanAttribute, Component, HostBinding, Input } from '@angular/core'; +import { booleanAttribute, Component, computed, input } from '@angular/core'; @Component({ selector: 'c-form-feedback', - template: '' + template: '', + host: { '[class]': 'hostClasses()' } }) export class FormFeedbackComponent { /** * If your form layout allows it, you can display validation feedback in a styled tooltip. - * @type boolean + * @default false */ - @Input({ transform: booleanAttribute }) tooltip: string | boolean = false; + readonly tooltip = input(false, { transform: booleanAttribute }); /** * Set component validation state to valid. - * @type boolean + * @default undefined */ - @Input() valid?: boolean; + readonly valid = input(); - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { + const status = this.valid() === true ? 'valid' : 'invalid'; + const type = this.tooltip() ? 'tooltip' : 'feedback'; return { - 'valid-feedback': this.valid === true && !this.tooltip, - 'valid-tooltip': this.valid === true && this.tooltip, - 'invalid-feedback': this.valid !== true && !this.tooltip, - 'invalid-tooltip': this.valid !== true && this.tooltip - }; - } + [`${status}-${type}`]: true + // 'valid-feedback': valid === true && !tooltip, + // 'valid-tooltip': valid === true && tooltip, + // 'invalid-feedback': valid !== true && !tooltip, + // 'invalid-tooltip': valid !== true && tooltip + } as Record; + }); } diff --git a/projects/coreui-angular/src/lib/form/form-floating/form-floating.directive.ts b/projects/coreui-angular/src/lib/form/form-floating/form-floating.directive.ts index 3e13244c..0fbccd57 100644 --- a/projects/coreui-angular/src/lib/form/form-floating/form-floating.directive.ts +++ b/projects/coreui-angular/src/lib/form/form-floating/form-floating.directive.ts @@ -14,6 +14,6 @@ export class FormFloatingDirective { readonly hostClasses = computed(() => { return { 'form-floating': this.floating() - }; + } as Record; }); } diff --git a/projects/coreui-angular/src/lib/form/form-label/form-label.directive.spec.ts b/projects/coreui-angular/src/lib/form/form-label/form-label.directive.spec.ts index b993759a..94ba1c23 100644 --- a/projects/coreui-angular/src/lib/form/form-label/form-label.directive.spec.ts +++ b/projects/coreui-angular/src/lib/form/form-label/form-label.directive.spec.ts @@ -1,8 +1,11 @@ import { FormLabelDirective } from './form-label.directive'; +import { TestBed } from '@angular/core/testing'; describe('LabelDirective', () => { it('should create an instance', () => { - const directive = new FormLabelDirective(); - expect(directive).toBeTruthy(); + TestBed.runInInjectionContext(() => { + const directive = new FormLabelDirective(); + expect(directive).toBeTruthy(); + }); }); }); diff --git a/projects/coreui-angular/src/lib/form/form-label/form-label.directive.ts b/projects/coreui-angular/src/lib/form/form-label/form-label.directive.ts index 9d24f8e5..0f520989 100644 --- a/projects/coreui-angular/src/lib/form/form-label/form-label.directive.ts +++ b/projects/coreui-angular/src/lib/form/form-label/form-label.directive.ts @@ -1,26 +1,28 @@ -import { Directive, HostBinding, Input } from '@angular/core'; +import { computed, Directive, input } from '@angular/core'; @Directive({ selector: '[cLabel]', - host: { class: 'form-label' } + host: { class: 'form-label', '[class]': 'hostClasses()' } }) export class FormLabelDirective { /** * For horizontal forms set labels to 'col' and make them vertically centered with their associated form controls. - * @type 'col' + * @default '' */ - @Input('cLabel') col: 'col' | '' = ''; + readonly col = input<'col' | ''>('', { alias: 'cLabel' }); /** * Size the label small or large. + * @default '' */ - @Input() sizing: '' | 'sm' | 'lg' | string = ''; + readonly sizing = input<'' | 'sm' | 'lg' | string>(); - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { + const col = this.col(); + const sizing = this.sizing(); return { 'form-label': true, - 'col-form-label': this.col === 'col', - [`col-form-label-${this.sizing}`]: !!this.sizing && this.col === 'col' - }; - } + 'col-form-label': col === 'col', + [`col-form-label-${sizing}`]: !!sizing && col === 'col' + } as Record; + }); } diff --git a/projects/coreui-angular/src/lib/form/form-select/form-select.directive.spec.ts b/projects/coreui-angular/src/lib/form/form-select/form-select.directive.spec.ts index ddec0519..d6f86ddf 100644 --- a/projects/coreui-angular/src/lib/form/form-select/form-select.directive.spec.ts +++ b/projects/coreui-angular/src/lib/form/form-select/form-select.directive.spec.ts @@ -1,8 +1,11 @@ import { FormSelectDirective } from './form-select.directive'; +import { TestBed } from '@angular/core/testing'; describe('FormSelectDirective', () => { it('should create an instance', () => { - const directive = new FormSelectDirective(); - expect(directive).toBeTruthy(); + TestBed.runInInjectionContext(() => { + const directive = new FormSelectDirective(); + expect(directive).toBeTruthy(); + }); }); }); diff --git a/projects/coreui-angular/src/lib/form/form-select/form-select.directive.ts b/projects/coreui-angular/src/lib/form/form-select/form-select.directive.ts index ecf4a55e..5530df29 100644 --- a/projects/coreui-angular/src/lib/form/form-select/form-select.directive.ts +++ b/projects/coreui-angular/src/lib/form/form-select/form-select.directive.ts @@ -1,28 +1,30 @@ -import { Directive, HostBinding, Input } from '@angular/core'; +import { computed, Directive, input } from '@angular/core'; @Directive({ selector: 'select[cSelect]', - host: { class: 'form-select' } + host: { class: 'form-select', '[class]': 'hostClasses()' } }) export class FormSelectDirective { /** * Size the component small or large. + * @default undefined */ - @Input() sizing?: '' | 'sm' | 'lg' | string = ''; + readonly sizing = input<'' | 'sm' | 'lg' | string>(); /** * Set component validation state to valid. - * @type {boolean | undefined} + * @default undefined */ - @Input() valid?: boolean; + readonly valid = input(); - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { + const sizing = this.sizing(); + const valid = this.valid(); return { 'form-select': true, - [`form-select-${this.sizing}`]: !!this.sizing, - 'is-valid': this.valid === true, - 'is-invalid': this.valid === false - }; - } + [`form-select-${sizing}`]: !!sizing, + 'is-valid': valid === true, + 'is-invalid': valid === false + } as Record; + }); } diff --git a/projects/coreui-angular/src/lib/form/form/form.directive.spec.ts b/projects/coreui-angular/src/lib/form/form/form.directive.spec.ts index 540defde..ddf26d5a 100644 --- a/projects/coreui-angular/src/lib/form/form/form.directive.spec.ts +++ b/projects/coreui-angular/src/lib/form/form/form.directive.spec.ts @@ -1,8 +1,11 @@ import { FormDirective } from './form.directive'; +import { TestBed } from '@angular/core/testing'; describe('FormDirective', () => { it('should create an instance', () => { - const directive = new FormDirective(); - expect(directive).toBeTruthy(); + TestBed.runInInjectionContext(() => { + const directive = new FormDirective(); + expect(directive).toBeTruthy(); + }); }); }); diff --git a/projects/coreui-angular/src/lib/form/form/form.directive.ts b/projects/coreui-angular/src/lib/form/form/form.directive.ts index 4e37b63f..b12fe5bd 100644 --- a/projects/coreui-angular/src/lib/form/form/form.directive.ts +++ b/projects/coreui-angular/src/lib/form/form/form.directive.ts @@ -1,7 +1,8 @@ -import { booleanAttribute, Directive, HostBinding, Input } from '@angular/core'; +import { booleanAttribute, computed, Directive, input } from '@angular/core'; @Directive({ - selector: 'form[cForm]' + selector: 'form[cForm]', + host: { '[class]': 'hostClasses()' } }) export class FormDirective { /** @@ -9,12 +10,11 @@ export class FormDirective { * @type boolean * @default false */ - @Input({ transform: booleanAttribute }) validated: string | boolean = false; + readonly validated = input(false, { transform: booleanAttribute }); - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { return { - 'was-validated': this.validated - }; - } + 'was-validated': this.validated() + } as Record; + }); } diff --git a/projects/coreui-angular/src/lib/form/input-group/input-group.component.ts b/projects/coreui-angular/src/lib/form/input-group/input-group.component.ts index 353b9c41..9b27436f 100644 --- a/projects/coreui-angular/src/lib/form/input-group/input-group.component.ts +++ b/projects/coreui-angular/src/lib/form/input-group/input-group.component.ts @@ -9,7 +9,7 @@ export class InputGroupComponent { /** * Size the component small or large. */ - readonly sizing = input(''); + readonly sizing = input(); readonly hostClasses = computed(() => { const sizing = this.sizing(); diff --git a/projects/coreui-angular/src/lib/list-group/list-group-item.directive.ts b/projects/coreui-angular/src/lib/list-group/list-group-item.directive.ts index 15fa6744..3cdafc6e 100644 --- a/projects/coreui-angular/src/lib/list-group/list-group-item.directive.ts +++ b/projects/coreui-angular/src/lib/list-group/list-group-item.directive.ts @@ -50,7 +50,7 @@ export class ListGroupItemDirective { active: !!this.active(), disabled: this._disabled(), [`list-group-item-${this.color()}`]: !!this.color() - }; + } as Record; }); readonly _disabled = computed(() => this.disabled()); diff --git a/projects/coreui-angular/src/lib/modal/modal-dialog/modal-dialog.component.spec.ts b/projects/coreui-angular/src/lib/modal/modal-dialog/modal-dialog.component.spec.ts index 8a064e29..dfbf52c6 100644 --- a/projects/coreui-angular/src/lib/modal/modal-dialog/modal-dialog.component.spec.ts +++ b/projects/coreui-angular/src/lib/modal/modal-dialog/modal-dialog.component.spec.ts @@ -1,21 +1,23 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentRef } from '@angular/core'; import { ModalDialogComponent } from './modal-dialog.component'; describe('ModalDialogComponent', () => { let component: ModalDialogComponent; + let componentRef: ComponentRef; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ModalDialogComponent] - }) - .compileComponents(); + }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(ModalDialogComponent); component = fixture.componentInstance; + componentRef = fixture.componentRef; fixture.detectChanges(); }); @@ -26,4 +28,54 @@ describe('ModalDialogComponent', () => { it('should have css classes', () => { expect(fixture.nativeElement).toHaveClass('modal-dialog'); }); + + it('should have css classes for alignment prop', () => { + componentRef.setInput('alignment', 'center'); + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveClass('modal-dialog-centered'); + componentRef.setInput('alignment', 'top'); + fixture.detectChanges(); + expect(fixture.nativeElement).not.toHaveClass('modal-dialog-centered'); + expect(fixture.nativeElement).toHaveClass('modal-dialog'); + }); + + it('should have css classes for fullscreen prop', () => { + componentRef.setInput('fullscreen', true); + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveClass('modal-fullscreen'); + for (const size of ['sm', 'md', 'lg', 'xl', 'xxl']) { + componentRef.setInput('fullscreen', size); + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveClass(`modal-fullscreen-${size}-down`); + } + componentRef.setInput('fullscreen', false); + fixture.detectChanges(); + expect(fixture.nativeElement).not.toHaveClass('modal-fullscreen'); + expect(fixture.nativeElement).toHaveClass('modal-dialog'); + }); + + it('should have css classes for scrollable prop', () => { + expect(fixture.nativeElement).not.toHaveClass('modal-dialog-scrollable'); + componentRef.setInput('scrollable', true); + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveClass('modal-dialog-scrollable'); + componentRef.setInput('scrollable', false); + fixture.detectChanges(); + expect(fixture.nativeElement).not.toHaveClass('modal-dialog-scrollable'); + expect(fixture.nativeElement).toHaveClass('modal-dialog'); + }); + + it('should have css classes for size prop', () => { + for (const size of ['sm', 'lg', 'xl']) { + componentRef.setInput('size', size); + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveClass(`modal-${size}`); + } + componentRef.setInput('size', undefined); + fixture.detectChanges(); + expect(fixture.nativeElement).not.toHaveClass('modal-sm'); + expect(fixture.nativeElement).not.toHaveClass('modal-lg'); + expect(fixture.nativeElement).not.toHaveClass('modal-xl'); + expect(fixture.nativeElement).toHaveClass('modal-dialog'); + }); }); diff --git a/projects/coreui-angular/src/lib/modal/modal-dialog/modal-dialog.component.ts b/projects/coreui-angular/src/lib/modal/modal-dialog/modal-dialog.component.ts index ee8492a7..878850d1 100644 --- a/projects/coreui-angular/src/lib/modal/modal-dialog/modal-dialog.component.ts +++ b/projects/coreui-angular/src/lib/modal/modal-dialog/modal-dialog.component.ts @@ -1,41 +1,48 @@ -import { Component, HostBinding, Input } from '@angular/core'; +import { booleanAttribute, Component, computed, input } from '@angular/core'; @Component({ selector: 'c-modal-dialog', template: '', styleUrls: ['./modal-dialog.component.scss'], - host: { class: 'modal-dialog' } + host: { class: 'modal-dialog', '[class]': 'hostClasses()' } }) export class ModalDialogComponent { /** * Align the modal in the center or top of the screen. - * @type {'top' | 'center'} + * @default undefined */ - @Input() alignment?: 'top' | 'center'; + readonly alignment = input<'top' | 'center'>(); + /** * Set modal to covers the entire user viewport. - * @type {boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'} + * @return {boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'} */ - @Input() fullscreen?: boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'; + readonly fullscreen = input(); + /** * Does the modal dialog itself scroll, or does the whole dialog scroll within the window. - * @type boolean + * @default false + * @return {boolean} */ - @Input() scrollable?: boolean; + readonly scrollable = input(false, { transform: booleanAttribute }); + /** * Size the component small, large, or extra large. + * @default undefined + * @return {'sm' | 'lg' | 'xl'} */ - @Input() size?: 'sm' | 'lg' | 'xl'; + readonly size = input<'sm' | 'lg' | 'xl'>(); - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { + const fullscreen = this.fullscreen(); + const size = this.size(); return { 'modal-dialog': true, - 'modal-dialog-centered': this.alignment === 'center', - 'modal-fullscreen': this.fullscreen === true, - [`modal-fullscreen-${this.fullscreen}-down`]: this.fullscreen, - 'modal-dialog-scrollable': this.scrollable, - [`modal-${this.size}`]: this.size - }; - } + 'modal-dialog-centered': this.alignment() === 'center', + 'modal-fullscreen': fullscreen === true, + [`modal-fullscreen-${fullscreen}-down`]: typeof fullscreen === 'string', + 'modal-dialog-scrollable': this.scrollable(), + [`modal-${size}`]: !!size + } as Record; + }); } diff --git a/projects/coreui-angular/src/lib/modal/modal-dismiss/modal-toggle.directive.ts b/projects/coreui-angular/src/lib/modal/modal-dismiss/modal-toggle.directive.ts index b6cdfd83..3b8e1186 100644 --- a/projects/coreui-angular/src/lib/modal/modal-dismiss/modal-toggle.directive.ts +++ b/projects/coreui-angular/src/lib/modal/modal-dismiss/modal-toggle.directive.ts @@ -1,4 +1,4 @@ -import { Directive, HostListener, inject, Input } from '@angular/core'; +import { Directive, HostListener, inject, input } from '@angular/core'; import { ModalService } from '../modal.service'; @@ -10,12 +10,13 @@ export class ModalToggleDirective { /** * Html id attr of modal to dismiss. + * @default undefined */ - @Input('cModalToggle') id: string | undefined; + readonly toggle = input(undefined, { alias: 'cModalToggle' }); @HostListener('click', ['$event']) dismiss($event: any): void { $event.preventDefault(); - this.#modalService.toggle({ show: 'toggle', id: this.id }); + this.#modalService.toggle({ show: 'toggle', id: this.toggle() }); } } diff --git a/projects/coreui-angular/src/lib/modal/modal.service.ts b/projects/coreui-angular/src/lib/modal/modal.service.ts index 9bdba06a..12ced01e 100644 --- a/projects/coreui-angular/src/lib/modal/modal.service.ts +++ b/projects/coreui-angular/src/lib/modal/modal.service.ts @@ -12,10 +12,10 @@ export interface IModalAction { providedIn: 'root' }) export class ModalService { - private modalState = new Subject(); - modalState$ = this.modalState.asObservable(); + readonly #modalState = new Subject(); + readonly modalState$ = this.#modalState.asObservable(); toggle(action: IModalAction): void { - this.modalState.next(action); + this.#modalState.next(action); } } diff --git a/projects/coreui-angular/src/lib/modal/modal/modal.component.html b/projects/coreui-angular/src/lib/modal/modal/modal.component.html index 194fe867..c060ce9e 100644 --- a/projects/coreui-angular/src/lib/modal/modal/modal.component.html +++ b/projects/coreui-angular/src/lib/modal/modal/modal.component.html @@ -1,8 +1,8 @@ + [alignment]="alignment()" + [fullscreen]="fullscreen()" + [scrollable]="scrollable()" + [size]="size()">
diff --git a/projects/coreui-angular/src/lib/modal/modal/modal.component.ts b/projects/coreui-angular/src/lib/modal/modal/modal.component.ts index 3242badd..6a6811eb 100644 --- a/projects/coreui-angular/src/lib/modal/modal/modal.component.ts +++ b/projects/coreui-angular/src/lib/modal/modal/modal.component.ts @@ -4,20 +4,19 @@ import { AfterViewInit, booleanAttribute, Component, + computed, DestroyRef, effect, ElementRef, - EventEmitter, - HostBinding, - HostListener, inject, - Input, + input, OnDestroy, OnInit, - Output, + output, Renderer2, signal, - ViewChild, + untracked, + viewChild, WritableSignal } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @@ -50,7 +49,21 @@ import { ModalDialogComponent } from '../modal-dialog/modal-dialog.component'; templateUrl: './modal.component.html', exportAs: 'cModal', imports: [ModalDialogComponent, ModalContentComponent, A11yModule], - host: { class: 'modal' } + host: { + class: 'modal', + '[class]': 'hostClasses()', + '[attr.role]': 'role()', + '[attr.inert]': 'ariaHidden', + '[attr.id]': 'id', + '[attr.aria-modal]': 'ariaModal()', + '[attr.tabindex]': '-1', + '[@showHide]': 'animateTrigger()', + '(@showHide.start)': 'animateStart($event)', + '(@showHide.done)': 'animateDone($event)', + '(mousedown)': 'onMouseDownHandler($event)', + '(click)': 'onClickHandler($event)', + '(document:keyup)': 'onKeyUpHandler($event)' + } }) export class ModalComponent implements OnInit, OnDestroy, AfterViewInit { readonly #document = inject(DOCUMENT); @@ -64,81 +77,94 @@ export class ModalComponent implements OnInit, OnDestroy, AfterViewInit { /** * Align the modal in the center or top of the screen. - * @type {'top' | 'center'} + * @return {'top' | 'center'} * @default 'top' */ - @Input() alignment?: 'top' | 'center' = 'top'; + readonly alignment = input<'top' | 'center'>('top'); + /** * Apply a backdrop on body while modal is open. - * @type boolean | 'static' + * @return boolean | 'static' * @default true */ - @Input() backdrop: boolean | 'static' = true; + readonly backdrop = input(true); + /** * Set modal to cover the entire user viewport. - * @type {boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'} + * @return {boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'} * @default undefined */ - @Input() fullscreen?: boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'; + readonly fullscreen = input(); + /** * Closes the modal when escape key is pressed. - * @type boolean + * @return boolean * @default true */ - @Input({ transform: booleanAttribute }) keyboard: boolean = true; + readonly keyboard = input(true, { transform: booleanAttribute }); + + readonly attrId = input(undefined, { alias: 'id' }); - @Input() id?: string; + get id() { + return this.attrId(); + } /** * Size the component small, large, or extra large. + * @return {'sm' | 'lg' | 'xl'} + * @default undefined */ - @Input() size?: 'sm' | 'lg' | 'xl'; + readonly size = input<'sm' | 'lg' | 'xl'>(); /** * Remove animation to create modal that simply appear rather than fade in to view. */ - @Input({ transform: booleanAttribute }) transition = true; + readonly transition = input(true, { transform: booleanAttribute }); /** - * Default role for modal. [docs] - * @type string + * Default role for modal + * @return string * @default 'dialog' */ - @Input() @HostBinding('attr.role') role: string = 'dialog'; + readonly role = input('dialog'); /** - * Set aria-modal html attr for modal. [docs] + * Set aria-modal html attr for modal * @type boolean * @default null */ - @Input() - @HostBinding('attr.aria-modal') - set ariaModal(value: boolean | null) { - this.#ariaModal = value; - } - - get ariaModal(): boolean | null { - return this.visible || this.#ariaModal ? true : null; - } + readonly ariaModalInput = input(false, { transform: booleanAttribute, alias: 'ariaModal' }); - #ariaModal: boolean | null = null; + readonly ariaModal = computed(() => { + return this.visible || this.ariaModalInput() ? true : null; + }); /** * Create a scrollable modal that allows scrolling the modal body. - * @type boolean + * @return boolean + * @default false */ - @Input({ transform: booleanAttribute }) scrollable: boolean = false; + readonly scrollable = input(false, { transform: booleanAttribute }); /** * Toggle the visibility of modal component. - * @type boolean + * @return boolean + * @default false */ - @Input({ transform: booleanAttribute }) + readonly visibleInput = input(false, { transform: booleanAttribute, alias: 'visible' }); + + readonly #visibleInputEffect = effect(() => { + const visible = this.visibleInput(); + untracked(() => { + this.visible = visible; + }); + }); + set visible(value: boolean) { if (this.#visible() !== value) { this.#visible.set(value); - this.setBackdrop(this.backdrop !== false && value); this.setBodyStyles(value); + this.setBackdrop(this.backdrop() !== false && value); this.visibleChange.emit(value); } } @@ -149,89 +175,88 @@ export class ModalComponent implements OnInit, OnDestroy, AfterViewInit { readonly #visible: WritableSignal = signal(false); - #activeElement: HTMLElement | null = null; + readonly #activeElement = signal(null); readonly #visibleEffect = effect(() => { - if (this.#visible() && this.#afterViewInit()) { - this.#activeElement = this.#document.activeElement as HTMLElement; - // this.#activeElement?.blur(); - setTimeout(() => { - const focusable = this.modalContentRef.nativeElement.querySelectorAll( - '[tabindex]:not([tabindex="-1"]), button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled])' - ); - if (focusable.length) { - this.#focusMonitor.focusVia(focusable[0], 'keyboard'); - } - }); - } else { - if (this.#document.contains(this.#activeElement)) { + const visible = this.#visible(); + const afterViewInit = this.#afterViewInit(); + untracked(() => { + if (visible && afterViewInit) { + this.#activeElement.set(this.#document.activeElement as HTMLElement); + // this.#activeElement()?.blur(); setTimeout(() => { - this.#activeElement?.focus(); - this.#activeElement = null; + const focusable = this.modalContentRef()?.nativeElement.querySelectorAll( + '[tabindex]:not([tabindex="-1"]), button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled])' + ); + if (focusable?.length) { + this.#focusMonitor.focusVia(focusable[0], 'keyboard'); + } }); + } else { + const activeElement = this.#activeElement(); + if (activeElement && this.#document.contains(activeElement)) { + this.#focusMonitor.focusVia(activeElement, 'keyboard'); + setTimeout(() => { + // this.#activeElement()?.focus(); + this.#activeElement.set(null); + }); + } } - } + }); }); /** * Event triggered on modal dismiss. + * @return boolean */ - @Output() visibleChange = new EventEmitter(); + readonly visibleChange = output(); - @ViewChild(ModalContentComponent, { read: ElementRef }) modalContent!: ElementRef; - @ViewChild('modalContentRef', { read: ElementRef }) modalContentRef!: ElementRef; + // @ViewChild(ModalContentComponent, { read: ElementRef }) modalContent!: ElementRef; + // @ViewChild('modalContentRef', { read: ElementRef }) modalContentRef!: ElementRef; + // readonly modalContentRef = viewChild(ModalContentComponent, { read: ElementRef }); + readonly modalContentRef = viewChild('modalContentRef', { read: ElementRef }); #activeBackdrop!: any; // private inBoundingClientRect!: boolean; - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { return { modal: true, - fade: this.transition, + fade: this.transition(), show: this.show - }; - } + } as Record; + }); - @HostBinding('attr.aria-hidden') get ariaHidden(): boolean | null { return this.visible ? null : true; } - @HostBinding('attr.tabindex') - get tabIndex(): string | null { - return '-1'; - } - - @HostBinding('@showHide') - get animateTrigger(): string { + readonly animateTrigger = computed(() => { return this.visible ? 'visible' : 'hidden'; - } + }); get show(): boolean { - return this.visible && this._show; + return this.visible && this.#show(); } set show(value: boolean) { - this._show = value; + this.#show.set(value); } - private _show = true; + readonly #show = signal(true); - @HostListener('@showHide.start', ['$event']) animateStart(event: AnimationEvent) { if (event.toState === 'visible') { this.#backdropService.hideScrollbar(); this.#renderer.setStyle(this.#hostElement.nativeElement, 'display', 'block'); } else { - if (!this.transition) { + if (!this.transition()) { this.#renderer.setStyle(this.#hostElement.nativeElement, 'display', 'none'); } } } - @HostListener('@showHide.done', ['$event']) animateDone(event: AnimationEvent) { setTimeout(() => { if (event.toState === 'hidden') { @@ -241,10 +266,9 @@ export class ModalComponent implements OnInit, OnDestroy, AfterViewInit { this.show = this.visible; } - @HostListener('document:keyup', ['$event']) - onKeyDownHandler(event: KeyboardEvent): void { - if (event.key === 'Escape' && this.keyboard && this.visible) { - if (this.backdrop === 'static') { + onKeyUpHandler(event: KeyboardEvent): void { + if (event.key === 'Escape' && this.keyboard() && this.visible) { + if (this.backdrop() === 'static') { this.setStaticBackdrop(); } else { this.#modalService.toggle({ show: false, modal: this }); @@ -254,12 +278,10 @@ export class ModalComponent implements OnInit, OnDestroy, AfterViewInit { private mouseDownTarget: EventTarget | null = null; - @HostListener('mousedown', ['$event']) public onMouseDownHandler($event: MouseEvent): void { this.mouseDownTarget = $event.target; } - @HostListener('click', ['$event']) public onClickHandler($event: MouseEvent): void { if (this.mouseDownTarget !== $event.target) { this.mouseDownTarget = null; @@ -268,7 +290,7 @@ export class ModalComponent implements OnInit, OnDestroy, AfterViewInit { const targetElement = $event.target; if (targetElement === this.#hostElement.nativeElement) { - if (this.backdrop === 'static') { + if (this.backdrop() === 'static') { this.setStaticBackdrop(); return; } @@ -314,7 +336,7 @@ export class ModalComponent implements OnInit, OnDestroy, AfterViewInit { private setBodyStyles(open: boolean): void { if (open) { - if (this.backdrop === true) { + if (this.backdrop() === true) { this.#renderer.addClass(this.#document.body, 'modal-open'); } } else { @@ -323,7 +345,7 @@ export class ModalComponent implements OnInit, OnDestroy, AfterViewInit { } private setStaticBackdrop(): void { - if (this.transition) { + if (this.transition()) { this.#renderer.addClass(this.#hostElement.nativeElement, 'modal-static'); this.#renderer.setStyle(this.#hostElement.nativeElement, 'overflow-y', 'hidden'); setTimeout(() => { diff --git a/projects/coreui-angular/src/lib/nav/nav-link.directive.spec.ts b/projects/coreui-angular/src/lib/nav/nav-link.directive.spec.ts index 656438ff..1d130b31 100644 --- a/projects/coreui-angular/src/lib/nav/nav-link.directive.spec.ts +++ b/projects/coreui-angular/src/lib/nav/nav-link.directive.spec.ts @@ -1,8 +1,85 @@ import { NavLinkDirective } from './nav-link.directive'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { Component, ComponentRef, DebugElement, input } from '@angular/core'; +import { By } from '@angular/platform-browser'; + +@Component({ + template: 'test', + imports: [NavLinkDirective] +}) +class TestComponent { + readonly active = input(false); + readonly disabled = input(false); +} describe('NavLinkDirective', () => { + let fixture: ComponentFixture; + let component: TestComponent; + let componentRef: ComponentRef; + let debugElement: DebugElement; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TestComponent] + }).compileComponents(); + + fixture = TestBed.createComponent(TestComponent); + component = fixture.componentInstance; + componentRef = fixture.componentRef; + debugElement = fixture.debugElement.query(By.directive(NavLinkDirective)); + fixture.detectChanges(); + }); + it('should create an instance', () => { - const directive = new NavLinkDirective(); - expect(directive).toBeTruthy(); + TestBed.runInInjectionContext(() => { + const directive = new NavLinkDirective(); + expect(directive).toBeTruthy(); + }); + }); + + it('should have css classes', () => { + expect(debugElement.nativeElement).toHaveClass('nav-link'); + }); + + it('should have css classes for active', () => { + expect(debugElement.nativeElement).not.toHaveClass('active'); + componentRef.setInput('active', true); + fixture.detectChanges(); + expect(debugElement.nativeElement).toHaveClass('active'); + componentRef.setInput('active', false); + fixture.detectChanges(); + expect(debugElement.nativeElement).not.toHaveClass('active'); + }); + + it('should have css classes for disabled', () => { + expect(debugElement.nativeElement).not.toHaveClass('disabled'); + componentRef.setInput('disabled', true); + fixture.detectChanges(); + expect(debugElement.nativeElement).toHaveClass('disabled'); + componentRef.setInput('disabled', false); + fixture.detectChanges(); + expect(debugElement.nativeElement).not.toHaveClass('disabled'); + }); + + it('should have aria-* attr for active', () => { + expect(debugElement.nativeElement.getAttribute('aria-current')).not.toBe('page'); + componentRef.setInput('active', true); + fixture.detectChanges(); + expect(debugElement.nativeElement.getAttribute('aria-current')).toBe('page'); + }); + + it('should have attributes for disabled', () => { + expect(debugElement.nativeElement.getAttribute('disabled')).toBeNull(); + expect(debugElement.nativeElement.getAttribute('aria-disabled')).not.toBeTruthy(); + expect(debugElement.nativeElement.getAttribute('tabindex')).not.toBe('-1'); + expect(debugElement.nativeElement.style.cursor).toBe('pointer'); + componentRef.setInput('disabled', true); + fixture.detectChanges(); + expect(debugElement.nativeElement.getAttribute('disabled')).not.toBeNull(); + expect(debugElement.nativeElement.getAttribute('aria-disabled')).toBeTruthy(); + expect(debugElement.nativeElement.getAttribute('tabindex')).toBe('-1'); + expect(debugElement.nativeElement.style.cursor).not.toBe('pointer'); + componentRef.setInput('disabled', false); + fixture.detectChanges(); }); }); diff --git a/projects/coreui-angular/src/lib/nav/nav-link.directive.ts b/projects/coreui-angular/src/lib/nav/nav-link.directive.ts index 8e7617a5..e32e7d00 100644 --- a/projects/coreui-angular/src/lib/nav/nav-link.directive.ts +++ b/projects/coreui-angular/src/lib/nav/nav-link.directive.ts @@ -1,58 +1,57 @@ -import { booleanAttribute, Directive, HostBinding, Input } from '@angular/core'; +import { booleanAttribute, computed, Directive, effect, input } from '@angular/core'; @Directive({ - selector: '[cNavLink]' + selector: '[cNavLink]', + host: { + '[class]': 'hostClasses()', + '[attr.aria-current]': 'ariaCurrent()', + '[attr.aria-disabled]': 'ariaDisabled', + '[attr.disabled]': 'attrDisabled', + '[attr.tabindex]': 'attrTabindex', + '[style.cursor]': 'styleCursor' + } }) export class NavLinkDirective { /** * Sets .nav-link class to the host. [docs] - * @type boolean * @default true */ - @Input({ transform: booleanAttribute }) cNavLink: string | boolean = true; + readonly cNavLink = input(true, { transform: booleanAttribute }); /** * Toggle the active state for the component. [docs] - * @type boolean + * @default undefined */ - @Input() active?: boolean; + readonly active = input(); + /** * Set disabled attr for the host element. [docs] - * @type boolean + * @default false */ - @Input({ transform: booleanAttribute }) disabled: string | boolean = false; - - @HostBinding('attr.aria-current') - get ariaCurrent(): string | null { - return this.active ? 'page' : null; - } - - @HostBinding('attr.aria-disabled') - get isDisabled(): boolean | null { - return this.disabled || null; - } - - @HostBinding('attr.disabled') - get attrDisabled() { - return this.disabled ? '' : null; - } - - @HostBinding('attr.tabindex') - get getTabindex(): string | null { - return this.disabled ? '-1' : null; - } - - @HostBinding('style.cursor') - get getCursorStyle(): string | null { - return this.disabled ? null : 'pointer'; - } - - @HostBinding('class') - get hostClasses(): any { + readonly disabled = input(false, { transform: booleanAttribute }); + + readonly ariaCurrent = computed(() => { + return this.active() ? 'page' : null; + }); + + ariaDisabled: boolean | null = null; + attrDisabled: boolean | string | null = null; + attrTabindex: '-1' | null = null; + styleCursor: 'pointer' | null = null; + + readonly #disabledEffect = effect(() => { + const disabled = this.disabled(); + this.ariaDisabled = disabled || null; + this.attrDisabled = disabled ? '' : null; + this.attrTabindex = disabled ? '-1' : null; + this.styleCursor = disabled ? null : 'pointer'; + }); + + readonly hostClasses = computed(() => { return { - 'nav-link': this.cNavLink, - disabled: this.disabled, - active: this.active - }; - } + 'nav-link': this.cNavLink(), + disabled: this.disabled(), + active: this.active() + } as Record; + }); } diff --git a/projects/coreui-angular/src/lib/nav/nav.component.spec.ts b/projects/coreui-angular/src/lib/nav/nav.component.spec.ts index f5bf5388..5d400f13 100644 --- a/projects/coreui-angular/src/lib/nav/nav.component.spec.ts +++ b/projects/coreui-angular/src/lib/nav/nav.component.spec.ts @@ -1,21 +1,23 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { NavComponent } from './nav.component'; +import { ComponentRef } from '@angular/core'; describe('NavComponent', () => { let component: NavComponent; let fixture: ComponentFixture; + let componentRef: ComponentRef; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [NavComponent] - }) - .compileComponents(); + }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(NavComponent); component = fixture.componentInstance; + componentRef = fixture.componentRef; fixture.detectChanges(); }); @@ -26,4 +28,60 @@ describe('NavComponent', () => { it('should have css classes', () => { expect(fixture.nativeElement).toHaveClass('nav'); }); + + it('should have css classes for layout', () => { + componentRef.setInput('layout', 'fill'); + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveClass('nav-fill'); + componentRef.setInput('layout', 'justified'); + fixture.detectChanges(); + expect(fixture.nativeElement).not.toHaveClass('nav-fill'); + expect(fixture.nativeElement).toHaveClass('nav-justified'); + componentRef.setInput('layout', undefined); + fixture.detectChanges(); + expect(fixture.nativeElement).not.toHaveClass('nav-fill'); + expect(fixture.nativeElement).not.toHaveClass('nav-justified'); + }); + + it('should have css classes for variant', () => { + expect(fixture.nativeElement).not.toHaveClass('nav-tabs'); + expect(fixture.nativeElement).not.toHaveClass('nav-pills'); + expect(fixture.nativeElement).not.toHaveClass('nav-underline'); + expect(fixture.nativeElement).not.toHaveClass('nav-underline-border'); + + componentRef.setInput('variant', 'tabs'); + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveClass('nav-tabs'); + expect(fixture.nativeElement).not.toHaveClass('nav-pills'); + expect(fixture.nativeElement).not.toHaveClass('nav-underline'); + expect(fixture.nativeElement).not.toHaveClass('nav-underline-border'); + + componentRef.setInput('variant', 'pills'); + fixture.detectChanges(); + expect(fixture.nativeElement).not.toHaveClass('nav-tabs'); + expect(fixture.nativeElement).toHaveClass('nav-pills'); + expect(fixture.nativeElement).not.toHaveClass('nav-underline'); + expect(fixture.nativeElement).not.toHaveClass('nav-underline-border'); + + componentRef.setInput('variant', 'underline'); + fixture.detectChanges(); + expect(fixture.nativeElement).not.toHaveClass('nav-tabs'); + expect(fixture.nativeElement).not.toHaveClass('nav-pills'); + expect(fixture.nativeElement).toHaveClass('nav-underline'); + expect(fixture.nativeElement).not.toHaveClass('nav-underline-border'); + + componentRef.setInput('variant', 'underline-border'); + fixture.detectChanges(); + expect(fixture.nativeElement).not.toHaveClass('nav-tabs'); + expect(fixture.nativeElement).not.toHaveClass('nav-pills'); + expect(fixture.nativeElement).not.toHaveClass('nav-underline'); + expect(fixture.nativeElement).toHaveClass('nav-underline-border'); + + componentRef.setInput('variant', undefined); + fixture.detectChanges(); + expect(fixture.nativeElement).not.toHaveClass('nav-tabs'); + expect(fixture.nativeElement).not.toHaveClass('nav-pills'); + expect(fixture.nativeElement).not.toHaveClass('nav-underline'); + expect(fixture.nativeElement).not.toHaveClass('nav-underline-border'); + }); }); diff --git a/projects/coreui-angular/src/lib/nav/nav.component.ts b/projects/coreui-angular/src/lib/nav/nav.component.ts index 48f87dbd..5cfcece9 100644 --- a/projects/coreui-angular/src/lib/nav/nav.component.ts +++ b/projects/coreui-angular/src/lib/nav/nav.component.ts @@ -1,29 +1,31 @@ -import { Component, HostBinding, Input } from '@angular/core'; +import { Component, computed, input } from '@angular/core'; @Component({ selector: 'c-nav', template: '', styleUrls: ['./nav.component.scss'], - host: { class: 'nav' } + host: { class: 'nav', '[class]': 'hostClasses()' } }) export class NavComponent { /** * Specify a layout type for component. - * @type {'fill' | 'justified'} + * @default undefined */ - @Input() layout?: 'fill' | 'justified'; + readonly layout = input<'fill' | 'justified'>(); + /** * Set the nav variant to tabs or pills. - * @type 'tabs' | 'pills' | 'underline' | 'underline-border' + * @default undefined */ - @Input() variant?: '' | 'tabs' | 'pills' | 'underline' | 'underline-border'; + readonly variant = input<'tabs' | 'pills' | 'underline' | 'underline-border' | ''>(); - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { + const layout = this.layout(); + const variant = this.variant(); return { nav: true, - [`nav-${this.layout}`]: !!this.layout, - [`nav-${this.variant}`]: !!this.variant - }; - } + [`nav-${layout}`]: !!layout, + [`nav-${variant}`]: !!variant + } as Record; + }); } diff --git a/projects/coreui-angular/src/lib/offcanvas/offcanvas/offcanvas.component.ts b/projects/coreui-angular/src/lib/offcanvas/offcanvas/offcanvas.component.ts index b25cdcb5..dc9e34cc 100644 --- a/projects/coreui-angular/src/lib/offcanvas/offcanvas/offcanvas.component.ts +++ b/projects/coreui-angular/src/lib/offcanvas/offcanvas/offcanvas.component.ts @@ -52,7 +52,7 @@ let nextId = 0; exportAs: 'cOffcanvas', imports: [A11yModule], hostDirectives: [{ directive: ThemeDirective, inputs: ['dark'] }], - host: { ngSkipHydration: 'true' } + host: { ngSkipHydration: 'true', '[attr.inert]': 'ariaHidden || null' } }) export class OffcanvasComponent implements OnInit, OnDestroy { readonly #document = inject(DOCUMENT); @@ -158,7 +158,7 @@ export class OffcanvasComponent implements OnInit, OnDestroy { }; } - @HostBinding('attr.aria-hidden') + // @HostBinding('attr.aria-hidden') get ariaHidden(): boolean | null { return this.visible ? null : true; } diff --git a/projects/coreui-angular/src/lib/placeholder/placeholder-animation.directive.ts b/projects/coreui-angular/src/lib/placeholder/placeholder-animation.directive.ts index de06eb66..212ff46f 100644 --- a/projects/coreui-angular/src/lib/placeholder/placeholder-animation.directive.ts +++ b/projects/coreui-angular/src/lib/placeholder/placeholder-animation.directive.ts @@ -22,6 +22,6 @@ export class PlaceholderAnimationDirective { readonly hostClasses = computed(() => { return { [`placeholder-${this.animation()}`]: this.placeholder()?.visible() && !!this.animation() - }; + } as Record; }); } diff --git a/projects/coreui-angular/src/lib/placeholder/placeholder.directive.ts b/projects/coreui-angular/src/lib/placeholder/placeholder.directive.ts index 17d5a415..637d0d4c 100644 --- a/projects/coreui-angular/src/lib/placeholder/placeholder.directive.ts +++ b/projects/coreui-angular/src/lib/placeholder/placeholder.directive.ts @@ -32,6 +32,6 @@ export class PlaceholderDirective { return { placeholder: this.visible(), [`placeholder-${this.size()}`]: !!this.size() - }; + } as Record; }); } diff --git a/projects/coreui-angular/src/lib/popover/popover.directive.ts b/projects/coreui-angular/src/lib/popover/popover.directive.ts index d2da48fd..541e0f30 100644 --- a/projects/coreui-angular/src/lib/popover/popover.directive.ts +++ b/projects/coreui-angular/src/lib/popover/popover.directive.ts @@ -48,7 +48,7 @@ export class PopoverDirective implements OnDestroy, OnInit, AfterViewInit { */ readonly content = input | undefined>(undefined, { alias: 'cPopover' }); - readonly contentEffect = effect(() => { + readonly #contentEffect = effect(() => { if (this.content()) { this.destroyTooltipElement(); } @@ -56,11 +56,11 @@ export class PopoverDirective implements OnDestroy, OnInit, AfterViewInit { /** * Optional popper Options object, takes precedence over cPopoverPlacement prop - * @type Partial + * @return Partial */ readonly popperOptions = input>({}, { alias: 'cPopoverOptions' }); - readonly popperOptionsEffect = effect(() => { + readonly #popperOptionsEffect = effect(() => { this._popperOptions = { ...this._popperOptions, placement: this.placement(), @@ -100,7 +100,7 @@ export class PopoverDirective implements OnDestroy, OnInit, AfterViewInit { */ readonly visible = model(false, { alias: 'cPopoverVisible' }); - readonly visibleEffect = effect(() => { + readonly #visibleEffect = effect(() => { this.visible() ? this.addTooltipElement() : this.removeTooltipElement(); }); diff --git a/projects/coreui-angular/src/lib/popover/popover/popover.component.ts b/projects/coreui-angular/src/lib/popover/popover/popover.component.ts index d4019428..f2ca1893 100644 --- a/projects/coreui-angular/src/lib/popover/popover/popover.component.ts +++ b/projects/coreui-angular/src/lib/popover/popover/popover.component.ts @@ -14,15 +14,15 @@ import { import { NgClass } from '@angular/common'; @Component({ - selector: 'c-popover', - templateUrl: './popover.component.html', - imports: [NgClass], - host: { - class: 'popover fade bs-popover-auto', - '[class]': 'hostClasses()', - '[attr.role]': 'role()', - '[attr.id]': 'id()' - } + selector: 'c-popover', + templateUrl: './popover.component.html', + imports: [NgClass], + host: { + class: 'popover fade bs-popover-auto', + '[class]': 'hostClasses()', + '[attr.role]': 'role()', + '[attr.id]': 'id()' + } }) export class PopoverComponent implements OnDestroy { readonly renderer = inject(Renderer2); @@ -33,7 +33,7 @@ export class PopoverComponent implements OnDestroy { */ readonly content = input>(''); - readonly contentEffect = effect(() => { + readonly #contentEffect = effect(() => { this.updateView(this.content()); }); @@ -48,13 +48,13 @@ export class PopoverComponent implements OnDestroy { readonly viewContainerRef = viewChild('popoverTemplate', { read: ViewContainerRef }); private textNode!: Text; - readonly hostClasses = computed>(() => { + readonly hostClasses = computed(() => { return { popover: true, fade: true, show: this.visible(), 'bs-popover-auto': true - }; + } as Record; }); ngOnDestroy(): void { diff --git a/projects/coreui-angular/src/lib/progress/progress-bar.component.spec.ts b/projects/coreui-angular/src/lib/progress/progress-bar.component.spec.ts index 08d4c6bd..6441107e 100644 --- a/projects/coreui-angular/src/lib/progress/progress-bar.component.spec.ts +++ b/projects/coreui-angular/src/lib/progress/progress-bar.component.spec.ts @@ -1,24 +1,31 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { ComponentRef } from '@angular/core'; import { ProgressBarComponent } from './progress-bar.component'; import { ProgressBarDirective } from './progress-bar.directive'; +import { ProgressService } from './progress.service'; describe('ProgressBarComponent', () => { let component: ProgressBarComponent; + let componentRef: ComponentRef; let fixture: ComponentFixture; + let directive: ProgressBarDirective; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - imports: [ProgressBarComponent, ProgressBarDirective] + imports: [ProgressBarComponent], + providers: [ProgressService] }).compileComponents(); fixture = TestBed.createComponent(ProgressBarComponent); component = fixture.componentInstance; - fixture.debugElement.injector.get(ProgressBarDirective).value = 42; - fixture.debugElement.injector.get(ProgressBarDirective).color = 'success'; - fixture.debugElement.injector.get(ProgressBarDirective).variant = 'striped'; - fixture.debugElement.injector.get(ProgressBarDirective).animated = true; + componentRef = fixture.componentRef; + directive = fixture.debugElement.injector.get(ProgressBarDirective); + componentRef.setInput('value', 42); + componentRef.setInput('color', 'success'); + componentRef.setInput('variant', 'striped'); + componentRef.setInput('animated', true); fixture.detectChanges(); })); @@ -45,7 +52,7 @@ describe('ProgressBarComponent', () => { }); it('should not have aria-* attributes', () => { - fixture.debugElement.injector.get(ProgressBarDirective).value = undefined; + componentRef.setInput('value', undefined); fixture.detectChanges(); expect(fixture.nativeElement.getAttribute('aria-valuenow')).toBeFalsy(); expect(fixture.nativeElement.getAttribute('aria-valuemin')).toBeFalsy(); @@ -54,15 +61,4 @@ describe('ProgressBarComponent', () => { // expect(fixture.nativeElement.style.width).toBeFalsy(); expect(fixture.nativeElement.style.width).toBe('0%'); }); - - it('should not have aria-* attributes', () => { - fixture.debugElement.injector.get(ProgressBarDirective).value = undefined; - fixture.debugElement.injector.get(ProgressBarDirective).width = 84; - fixture.detectChanges(); - expect(fixture.nativeElement.getAttribute('aria-valuenow')).toBeFalsy(); - expect(fixture.nativeElement.getAttribute('aria-valuemin')).toBeFalsy(); - expect(fixture.nativeElement.getAttribute('aria-valuemax')).toBeFalsy(); - expect(fixture.nativeElement.getAttribute('role')).toBeFalsy(); - expect(fixture.nativeElement.style.width).toBe('84%'); - }); }); diff --git a/projects/coreui-angular/src/lib/progress/progress-bar.component.ts b/projects/coreui-angular/src/lib/progress/progress-bar.component.ts index 040abad1..6d61a885 100644 --- a/projects/coreui-angular/src/lib/progress/progress-bar.component.ts +++ b/projects/coreui-angular/src/lib/progress/progress-bar.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, HostBinding, inject } from '@angular/core'; +import { Component, computed, inject } from '@angular/core'; import { ProgressBarDirective } from './progress-bar.directive'; @Component({ @@ -7,25 +7,23 @@ import { ProgressBarDirective } from './progress-bar.directive'; hostDirectives: [ { directive: ProgressBarDirective, - inputs: ['animated', 'color', 'max', 'role', 'stacked', 'value', 'variant', 'width'] + inputs: ['animated', 'color', 'max', 'role', 'value', 'variant'] } ], - changeDetection: ChangeDetectionStrategy.OnPush, - host: { class: 'progress-bar' } + host: { class: 'progress-bar', '[class]': 'hostClasses()' } }) export class ProgressBarComponent { readonly #progressBarDirective: ProgressBarDirective | null = inject(ProgressBarDirective, { optional: true }); - @HostBinding('class') - get hostClasses(): Record { - const animated = this.#progressBarDirective?.animated; - const color = this.#progressBarDirective?.color; - const variant = this.#progressBarDirective?.variant; + readonly hostClasses = computed(() => { + const animated = this.#progressBarDirective?.animated(); + const color = this.#progressBarDirective?.color(); + const variant = this.#progressBarDirective?.variant(); return { 'progress-bar': true, 'progress-bar-animated': !!animated, [`progress-bar-${variant}`]: !!variant, [`bg-${color}`]: !!color - }; - } + } as Record; + }); } diff --git a/projects/coreui-angular/src/lib/progress/progress-bar.directive.spec.ts b/projects/coreui-angular/src/lib/progress/progress-bar.directive.spec.ts index b50ef6db..35b7967a 100644 --- a/projects/coreui-angular/src/lib/progress/progress-bar.directive.spec.ts +++ b/projects/coreui-angular/src/lib/progress/progress-bar.directive.spec.ts @@ -1,33 +1,81 @@ -import { ElementRef, Renderer2 } from '@angular/core'; -import { TestBed } from '@angular/core/testing'; +import { Component, ComponentRef, DebugElement, ElementRef, input, Renderer2 } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ProgressBarDirective } from './progress-bar.directive'; +import { By } from '@angular/platform-browser'; +import { ProgressService } from './progress.service'; class MockElementRef extends ElementRef {} +@Component({ + template: `
`, + selector: 'c-test', + imports: [ProgressBarDirective] +}) +export class TestComponent { + readonly value = input(42); + readonly color = input('success'); +} + describe('ProgressBarDirective', () => { let directive: ProgressBarDirective; + let debugElement: DebugElement; + let fixture: ComponentFixture; + let componentRef: ComponentRef; beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ - Renderer2, - { provide: ElementRef, useClass: MockElementRef } - ] + providers: [Renderer2, { provide: ElementRef, useClass: MockElementRef }, ProgressService], + imports: [TestComponent] }); + fixture = TestBed.createComponent(TestComponent); + componentRef = fixture.componentRef; + debugElement = fixture.debugElement.query(By.directive(ProgressBarDirective)); + directive = debugElement.injector.get(ProgressBarDirective); + fixture.detectChanges(); - TestBed.runInInjectionContext(() => { - directive = new ProgressBarDirective(); - }); + // TestBed.runInInjectionContext(() => { + // directive = new ProgressBarDirective(); + // }); }); it('should create an instance', () => { expect(directive).toBeDefined(); }); - it('should have percent value', () => { - directive.value = 42; - expect(directive.percent()).toBe(42); + it('should have color value', () => { + expect(directive.color()).toBe('success'); + }); + + it('should have max value', () => { + expect(directive.max()).toBe(100); + }); + + it('should have variant value', () => { + expect(directive.variant()).toBe('striped'); }); + it('should have role value', () => { + expect(directive.role()).toBe('progressbar'); + }); + + it('should have precision value', () => { + expect(directive.precision()).toBe(0); + }); + + it('should have animated value', () => { + expect(directive.animated()).toBe(true); + }); + + it('should have aria-* attributes', () => { + expect(debugElement.nativeElement.getAttribute('aria-valuenow')).toBe('42'); + expect(debugElement.nativeElement.getAttribute('aria-valuemin')).toBe('0'); + expect(debugElement.nativeElement.getAttribute('aria-valuemax')).toBe('100'); + expect(debugElement.nativeElement.getAttribute('role')).toBe('progressbar'); + componentRef.setInput('value', undefined); + fixture.detectChanges(); + expect(debugElement.nativeElement.getAttribute('aria-valuenow')).toBeNull(); + expect(debugElement.nativeElement.getAttribute('aria-valuemin')).toBeNull(); + expect(debugElement.nativeElement.getAttribute('aria-valuemax')).toBeNull(); + expect(debugElement.nativeElement.getAttribute('role')).toBeNull(); + }); }); diff --git a/projects/coreui-angular/src/lib/progress/progress-bar.directive.ts b/projects/coreui-angular/src/lib/progress/progress-bar.directive.ts index 5d4d48f7..31fb2baa 100644 --- a/projects/coreui-angular/src/lib/progress/progress-bar.directive.ts +++ b/projects/coreui-angular/src/lib/progress/progress-bar.directive.ts @@ -1,56 +1,45 @@ import { booleanAttribute, - computed, Directive, effect, EffectRef, ElementRef, inject, - Input, + input, numberAttribute, - Renderer2, - signal, - WritableSignal + Renderer2 } from '@angular/core'; import { Colors } from '../coreui.types'; -import { IProgressBar } from './progress.type'; +import { ProgressService } from './progress.service'; @Directive({ - selector: '[cProgressBar]' + selector: '[cProgressBar]', + exportAs: 'cProgressBar' }) -export class ProgressBarDirective implements IProgressBar { +export class ProgressBarDirective { readonly #renderer = inject(Renderer2); readonly #hostElement = inject(ElementRef); - - readonly #max = signal(100); - readonly #min = 0; - readonly #value: WritableSignal = signal(undefined); - readonly #width: WritableSignal = signal(undefined); - - readonly percent = computed(() => { - return +((((this.#value() ?? this.#width() ?? 0) - this.#min) / (this.#max() - this.#min)) * 100).toFixed( - this.precision - ); - }); + readonly #progressService = inject(ProgressService); readonly #valuesEffect: EffectRef = effect(() => { const host: HTMLElement = this.#hostElement.nativeElement; - if (this.#value() === undefined || this.#width()) { + const value = this.#progressService.value(); + const percent = this.#progressService.percent(); + const stacked = this.#progressService.stacked(); + if (value === undefined) { for (const name of ['aria-valuenow', 'aria-valuemax', 'aria-valuemin', 'role']) { this.#renderer.removeAttribute(host, name); } } else { - this.#renderer.setAttribute(host, 'aria-valuenow', String(this.#value())); - this.#renderer.setAttribute(host, 'aria-valuemin', String(this.#min)); - this.#renderer.setAttribute(host, 'aria-valuemax', String(this.#max())); - this.#renderer.setAttribute(host, 'role', this.role); + const { min, max } = this.#progressService; + this.#renderer.setAttribute(host, 'aria-valuenow', String(value)); + this.#renderer.setAttribute(host, 'aria-valuemin', String(min())); + this.#renderer.setAttribute(host, 'aria-valuemax', String(max())); + this.#renderer.setAttribute(host, 'role', this.role()); } const tagName = host.tagName; - if ( - this.percent() >= 0 && - ((this.stacked && tagName === 'C-PROGRESS') || (!this.stacked && tagName !== 'C-PROGRESS')) - ) { - this.#renderer.setStyle(host, 'width', `${this.percent()}%`); + if (percent >= 0 && ((stacked && tagName === 'C-PROGRESS') || (!stacked && tagName !== 'C-PROGRESS'))) { + this.#renderer.setStyle(host, 'width', `${percent}%`); } else { this.#renderer.removeStyle(host, 'width'); } @@ -58,65 +47,50 @@ export class ProgressBarDirective implements IProgressBar { /** * Use to animate the stripes right to left via CSS3 animations. - * @type boolean + * @return boolean */ - @Input({ transform: booleanAttribute }) animated?: boolean; + readonly animated = input(undefined, { transform: booleanAttribute }); /** * Sets the color context of the component to one of CoreUI’s themed colors. * @values 'primary', 'secondary', 'success', 'danger', 'warning', 'info', 'dark', 'light' */ - @Input() color?: Colors; + readonly color = input(); - // TODO: check if this is necessary. - @Input({ transform: numberAttribute }) precision: number = 0; + readonly precision = input(0, { transform: numberAttribute }); /** * The percent value the ProgressBar. - * @type number + * @return number * @default 0 */ - @Input({ transform: numberAttribute }) - set value(value: number | undefined) { - this.#value.set(value); - } - - get value() { - return this.#value(); - } - - @Input({ transform: numberAttribute }) - set width(value: number | undefined) { - this.#width.set(value); - } + readonly value = input(undefined, { transform: numberAttribute }); /** * Set the progress bar variant to optional striped. * @values 'striped' * @default undefined */ - @Input() variant?: 'striped'; + readonly variant = input<'striped'>(); /** * The max value of the ProgressBar. - * @type number + * @return number * @default 100 */ - @Input({ transform: numberAttribute }) - set max(max: number) { - this.#max.set(isNaN(max) || max <= 0 ? 100 : max); - } - - /** - * Stacked ProgressBars. - * @type boolean - * @default false - */ - @Input({ transform: booleanAttribute }) stacked?: boolean = false; + readonly max = input(100, { transform: numberAttribute }); /** * Set default html role attribute. - * @type string + * @return string */ - @Input() role: string = 'progressbar'; + readonly role = input('progressbar'); + + readonly #serviceEffect = effect(() => { + this.#progressService.precision.set(this.precision()); + const max = this.max(); + this.#progressService.max.set(isNaN(max) || max <= 0 ? 100 : max); + const value = this.value(); + this.#progressService.value.set(value && !isNaN(value) ? value : undefined); + }); } diff --git a/projects/coreui-angular/src/lib/progress/progress-stacked.component.ts b/projects/coreui-angular/src/lib/progress/progress-stacked.component.ts index e59d1a55..b5cd17af 100644 --- a/projects/coreui-angular/src/lib/progress/progress-stacked.component.ts +++ b/projects/coreui-angular/src/lib/progress/progress-stacked.component.ts @@ -1,18 +1,16 @@ -import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core'; -import { IProgressBarStacked } from './progress.type'; +import { Component, input } from '@angular/core'; @Component({ selector: 'c-progress-stacked', + exportAs: 'cProgressStacked', template: '', styles: ` :host { display: flex; } `, - changeDetection: ChangeDetectionStrategy.OnPush + host: { '[class.progress-stacked]': 'stacked()' } }) -export class ProgressStackedComponent implements IProgressBarStacked { - @Input() - @HostBinding('class.progress-stacked') - stacked = true; +export class ProgressStackedComponent { + readonly stacked = input(true); } diff --git a/projects/coreui-angular/src/lib/progress/progress.component.html b/projects/coreui-angular/src/lib/progress/progress.component.html index e07f417e..f1f7d393 100644 --- a/projects/coreui-angular/src/lib/progress/progress.component.html +++ b/projects/coreui-angular/src/lib/progress/progress.component.html @@ -1,11 +1,8 @@ -@if (contentProgressBars.length) { +@if (contentProgressBars()?.length) { -} @else if (pbd?.stacked) { - - - } @else { - + @let pbd = progressBarDirective; + } diff --git a/projects/coreui-angular/src/lib/progress/progress.component.spec.ts b/projects/coreui-angular/src/lib/progress/progress.component.spec.ts index c94836f1..24f9d3b9 100644 --- a/projects/coreui-angular/src/lib/progress/progress.component.spec.ts +++ b/projects/coreui-angular/src/lib/progress/progress.component.spec.ts @@ -26,7 +26,6 @@ describe('ProgressComponent', () => { component = fixture.componentInstance; progress = fixture.debugElement.childNodes.find((v) => ProgressComponent); // let x= fixture.debugElement.queryAll(By.directive(ProgressBarDirective)) - // console.log(x) fixture.detectChanges(); })); diff --git a/projects/coreui-angular/src/lib/progress/progress.component.ts b/projects/coreui-angular/src/lib/progress/progress.component.ts index 6c98db03..b38324f6 100644 --- a/projects/coreui-angular/src/lib/progress/progress.component.ts +++ b/projects/coreui-angular/src/lib/progress/progress.component.ts @@ -1,75 +1,84 @@ import { NgTemplateOutlet } from '@angular/common'; import { booleanAttribute, - ChangeDetectionStrategy, Component, - ContentChildren, + computed, + contentChildren, ElementRef, - HostBinding, inject, - Input, - numberAttribute, - QueryList + input, + numberAttribute } from '@angular/core'; -import { IProgress } from './progress.type'; import { ProgressBarComponent } from './progress-bar.component'; import { ProgressBarDirective } from './progress-bar.directive'; import { ProgressStackedComponent } from './progress-stacked.component'; +import { ProgressService } from './progress.service'; @Component({ - selector: 'c-progress', - templateUrl: './progress.component.html', - imports: [ProgressBarComponent, NgTemplateOutlet], - styleUrl: './progress.component.scss', - hostDirectives: [ - { - directive: ProgressBarDirective, - inputs: ['animated', 'color', 'max', 'role', 'value', 'variant'] - } - ], - changeDetection: ChangeDetectionStrategy.OnPush, - host: { class: 'progress' } + selector: 'c-progress', + exportAs: 'cProgress', + templateUrl: './progress.component.html', + imports: [ProgressBarComponent, NgTemplateOutlet], + styleUrl: './progress.component.scss', + hostDirectives: [ + { + directive: ProgressBarDirective, + inputs: ['animated', 'color', 'max', 'role', 'value', 'variant'] + } + ], + host: { + class: 'progress', + '[class]': 'hostClasses()', + '[style.height]': 'hostStyle()' + }, + providers: [ProgressService] }) -export class ProgressComponent implements IProgress { - protected readonly pbd: ProgressBarDirective | null = inject(ProgressBarDirective, { optional: true }); - readonly #stacked?: boolean = inject(ProgressStackedComponent, { optional: true })?.stacked; - readonly #elementRef = inject(ElementRef); +export class ProgressComponent { + readonly #hostElement = inject(ElementRef); + protected readonly progressBarDirective: ProgressBarDirective | null = inject(ProgressBarDirective, { + optional: true + }); + readonly #stacked: boolean = inject(ProgressStackedComponent, { optional: true })?.stacked() ?? false; + readonly #progressService = inject(ProgressService); constructor() { - if (this.pbd) { - this.pbd.stacked = this.#stacked; - } + this.#progressService.stacked.set(this.#stacked); } - @ContentChildren(ProgressBarComponent) contentProgressBars!: QueryList; + readonly stacked = this.#progressService.stacked; + readonly percent = this.#progressService.percent; + readonly value = this.#progressService.value; + + readonly contentProgressBars = contentChildren(ProgressBarComponent); + /** * Sets the height of the component. If you set that value the inner `` will automatically resize accordingly. - * @type number + * @return number */ - @Input({ transform: numberAttribute }) height: number = 0; + readonly height = input(0, { transform: numberAttribute }); /** * Displays thin progress. - * @type boolean + * @return boolean */ - @Input({ transform: booleanAttribute }) thin: boolean = false; + readonly thin = input(false, { transform: booleanAttribute }); /** * Change the default color to white. - * @type boolean + * @return boolean */ - @Input({ transform: booleanAttribute }) white: boolean = false; + readonly white = input(false, { transform: booleanAttribute }); - @HostBinding('class') - get hostClasses(): Record { + readonly hostClasses = computed(() => { return { progress: true, - 'progress-thin': this.thin, - 'progress-white': this.white - }; - } + 'progress-thin': this.thin(), + 'progress-white': this.white() + } as Record; + }); - @HostBinding('style.height') get hostStyle(): any { - return !!this.height ? `${this.height}px` : (this.#elementRef?.nativeElement?.style?.height ?? undefined); - } + readonly hostStyle = computed(() => { + const height = this.height(); + return !!height ? `${height}px` : (this.#hostElement?.nativeElement?.style?.height ?? undefined); + }); } diff --git a/projects/coreui-angular/src/lib/progress/progress.service.spec.ts b/projects/coreui-angular/src/lib/progress/progress.service.spec.ts new file mode 100644 index 00000000..fe751942 --- /dev/null +++ b/projects/coreui-angular/src/lib/progress/progress.service.spec.ts @@ -0,0 +1,32 @@ +import { TestBed } from '@angular/core/testing'; + +import { ProgressService } from './progress.service'; + +describe('ProgressService', () => { + let service: ProgressService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ProgressService] + }); + service = TestBed.inject(ProgressService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('should expose values', () => { + service.value.set(42); + expect(service.percent()).toBe(42); + expect(service.min()).toBe(0); + expect(service.max()).toBe(100); + expect(service.value()).toBe(42); + service.max.set(200); + expect(service.max()).toBe(200); + service.value.set(84); + expect(service.percent()).toBe(42); + service.value.set(undefined); + expect(service.percent()).toBe(0); + }); +}); diff --git a/projects/coreui-angular/src/lib/progress/progress.service.ts b/projects/coreui-angular/src/lib/progress/progress.service.ts new file mode 100644 index 00000000..1a43dac0 --- /dev/null +++ b/projects/coreui-angular/src/lib/progress/progress.service.ts @@ -0,0 +1,14 @@ +import { computed, Injectable, signal } from '@angular/core'; + +@Injectable() +export class ProgressService { + readonly stacked = signal(false); + readonly value = signal(undefined); + readonly precision = signal(0); + readonly min = signal(0); + readonly max = signal(100); + + readonly percent = computed(() => { + return +((((this.value() ?? 0) - this.min()) / (this.max() - this.min())) * 100).toFixed(this.precision()); + }); +} diff --git a/projects/coreui-angular/src/lib/services/color-mode.service.ts b/projects/coreui-angular/src/lib/services/color-mode.service.ts index fad4518b..a3148a95 100644 --- a/projects/coreui-angular/src/lib/services/color-mode.service.ts +++ b/projects/coreui-angular/src/lib/services/color-mode.service.ts @@ -19,7 +19,7 @@ export class ColorModeService { readonly localStorageItemName$ = toObservable(this.localStorageItemName); readonly colorMode: WritableSignal = signal(undefined); - readonly colorModeEffect = effect(() => { + readonly #colorModeEffect = effect(() => { const colorMode = this.colorMode(); if (colorMode) { const localStorageItemName = this.localStorageItemName(); diff --git a/projects/coreui-angular/src/lib/shared/html-attr.directive.ts b/projects/coreui-angular/src/lib/shared/html-attr.directive.ts index b5b9dfb6..28141a9f 100644 --- a/projects/coreui-angular/src/lib/shared/html-attr.directive.ts +++ b/projects/coreui-angular/src/lib/shared/html-attr.directive.ts @@ -10,7 +10,7 @@ export class HtmlAttributesDirective { readonly #renderer = inject(Renderer2); readonly #elementRef = inject(ElementRef); - readonly attrEffect = effect(() => { + readonly #attrEffect = effect(() => { const attribs = this.cHtmlAttr(); for (const attr in attribs) { if (attr === 'style' && typeof attribs[attr] === 'object') { diff --git a/projects/coreui-angular/src/lib/sidebar/sidebar-nav/sidebar-nav.component.ts b/projects/coreui-angular/src/lib/sidebar/sidebar-nav/sidebar-nav.component.ts index 0019293e..f8e96985 100644 --- a/projects/coreui-angular/src/lib/sidebar/sidebar-nav/sidebar-nav.component.ts +++ b/projects/coreui-angular/src/lib/sidebar/sidebar-nav/sidebar-nav.component.ts @@ -194,7 +194,7 @@ export class SidebarNavGroupComponent implements OnInit, OnDestroy { SidebarNavLabelComponent, SidebarNavTitleComponent, SidebarNavDividerComponent, - SidebarNavGroupComponent, + forwardRef(() => SidebarNavGroupComponent), SidebarNavItemClassPipe, RouterModule ] diff --git a/projects/coreui-angular/src/lib/spinner/spinner.component.ts b/projects/coreui-angular/src/lib/spinner/spinner.component.ts index 3ff8867e..10df157c 100644 --- a/projects/coreui-angular/src/lib/spinner/spinner.component.ts +++ b/projects/coreui-angular/src/lib/spinner/spinner.component.ts @@ -49,6 +49,6 @@ export class SpinnerComponent { [`spinner-${this.variant()}`]: true, [`text-${this.color()}`]: !!this.color(), [`spinner-${this.variant()}-${this.size()}`]: !!this.size() - }; + } as Record; }); } diff --git a/projects/coreui-angular/src/lib/table/table-active.directive.spec.ts b/projects/coreui-angular/src/lib/table/table-active.directive.spec.ts index 244f205b..0dc9649f 100644 --- a/projects/coreui-angular/src/lib/table/table-active.directive.spec.ts +++ b/projects/coreui-angular/src/lib/table/table-active.directive.spec.ts @@ -1,8 +1,48 @@ +import { Component, DebugElement } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; import { TableActiveDirective } from './table-active.directive'; +@Component({ + imports: [TableActiveDirective], + template: ` ` +}) +class TestComponent { + active = false; +} + describe('TableActiveDirective', () => { + let fixture: ComponentFixture; + let debugElement: DebugElement; + let directive: TableActiveDirective; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TestComponent] + }); + fixture = TestBed.createComponent(TestComponent); + debugElement = fixture.debugElement.query(By.directive(TableActiveDirective)); + directive = debugElement.injector.get(TableActiveDirective); + fixture.detectChanges(); + }); + it('should create an instance', () => { - const directive = new TableActiveDirective(); expect(directive).toBeTruthy(); + TestBed.runInInjectionContext(() => { + const directive = new TableActiveDirective(); + expect(directive).toBeTruthy(); + }); + }); + + it('should add class "table-active" when active is true', () => { + fixture.componentInstance.active = true; + fixture.detectChanges(); + expect(debugElement.nativeElement.classList).toContain('table-active'); + }); + + it('should not add class "table-active" when active is false', () => { + fixture.componentInstance.active = false; + fixture.detectChanges(); + expect(debugElement.nativeElement.classList).not.toContain('table-active'); }); }); diff --git a/projects/coreui-angular/src/lib/table/table-active.directive.ts b/projects/coreui-angular/src/lib/table/table-active.directive.ts index f061dd68..25397c75 100644 --- a/projects/coreui-angular/src/lib/table/table-active.directive.ts +++ b/projects/coreui-angular/src/lib/table/table-active.directive.ts @@ -1,19 +1,16 @@ -import { booleanAttribute, Directive, HostBinding, Input } from '@angular/core'; +import { booleanAttribute, Directive, input } from '@angular/core'; @Directive({ - selector: '[cTableActive]' + selector: '[cTableActive]', + exportAs: 'cTableActive', + host: { + '[class.table-active]': 'active()' + } }) export class TableActiveDirective { /** * Highlight a table row or cell - * @type boolean + * @return boolean */ - @Input({ alias: 'cTableActive', transform: booleanAttribute }) active: string | boolean = false; - - @HostBinding('class') - get hostClasses(): any { - return { - 'table-active': this.active - }; - } + readonly active = input(false, { alias: "cTableActive", transform: booleanAttribute }); } diff --git a/projects/coreui-angular/src/lib/table/table-color.directive.spec.ts b/projects/coreui-angular/src/lib/table/table-color.directive.spec.ts index f2807dc1..ee2664b2 100644 --- a/projects/coreui-angular/src/lib/table/table-color.directive.spec.ts +++ b/projects/coreui-angular/src/lib/table/table-color.directive.spec.ts @@ -1,8 +1,11 @@ +import { TestBed } from '@angular/core/testing'; import { TableColorDirective } from './table-color.directive'; describe('TableColorDirective', () => { it('should create an instance', () => { - const directive = new TableColorDirective(); - expect(directive).toBeTruthy(); + TestBed.runInInjectionContext(() => { + const directive = new TableColorDirective(); + expect(directive).toBeTruthy(); + }); }); }); diff --git a/projects/coreui-angular/src/lib/table/table-color.directive.ts b/projects/coreui-angular/src/lib/table/table-color.directive.ts index 6b651111..cbe26c01 100644 --- a/projects/coreui-angular/src/lib/table/table-color.directive.ts +++ b/projects/coreui-angular/src/lib/table/table-color.directive.ts @@ -1,20 +1,23 @@ -import { Directive, HostBinding, Input } from '@angular/core'; +import { computed, Directive, input } from '@angular/core'; import { Colors } from '../coreui.types'; @Directive({ - selector: '[cTableColor]' + selector: '[cTableColor]', + exportAs: 'cTableColor', + host: { + '[class]': 'hostClasses()' + } }) export class TableColorDirective { /** * Use contextual color for tables, table rows or individual cells. - * @type Colors + * @return Colors */ - @Input('cTableColor') color?: Colors; + readonly color = input(undefined, { alias: 'cTableColor' }); - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { return { - [`table-${this.color}`]: !!this.color - }; - } + [`table-${this.color()}`]: !!this.color() + } as Record; + }); } diff --git a/projects/coreui-angular/src/lib/table/table.directive.spec.ts b/projects/coreui-angular/src/lib/table/table.directive.spec.ts index d3096fd7..0d1fcaa2 100644 --- a/projects/coreui-angular/src/lib/table/table.directive.spec.ts +++ b/projects/coreui-angular/src/lib/table/table.directive.spec.ts @@ -1,21 +1,113 @@ -import { TestBed } from '@angular/core/testing'; -import { ElementRef, Renderer2 } from '@angular/core'; +import { Component, DebugElement, ElementRef, Renderer2 } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; import { TableDirective } from './table.directive'; +import { Colors } from '../coreui.types'; +import { TableActiveDirective } from './table-active.directive'; + +@Component({ + template: ` +
+ `, + imports: [TableDirective] +}) +class TestComponent { + align: 'bottom' | 'middle' | 'top' = 'middle'; + borderColor: Colors = 'primary'; + bordered: boolean = true; + borderless: boolean = false; + caption = 'top' as const; + color: Colors = 'secondary'; + hover: boolean = true; + small: boolean = true; + striped: boolean = true; + stripedColumns: boolean = true; +} class MockElementRef extends ElementRef {} describe('TableDirective', () => { + let component: TestComponent; + let fixture: ComponentFixture; + let debugElement: DebugElement; + let directive: TableDirective; + beforeEach(() => { TestBed.configureTestingModule({ + imports: [TestComponent], providers: [Renderer2, { provide: ElementRef, useClass: MockElementRef }] }); + fixture = TestBed.createComponent(TestComponent); + debugElement = fixture.debugElement.query(By.directive(TableDirective)); + directive = debugElement.injector.get(TableDirective); + component = fixture.componentInstance; + fixture.detectChanges(); }); it('should create an instance', () => { + expect(directive).toBeTruthy(); TestBed.runInInjectionContext(() => { - const directive = new TableDirective(); + const directive = new TableActiveDirective(); expect(directive).toBeTruthy(); }); }); + + it('should apply align input', () => { + expect(directive.align()).toBe('middle'); + }); + + it('should apply borderColor input', () => { + expect(directive.borderColor()).toBe('primary'); + }); + + it('should apply bordered input', () => { + expect(directive.bordered()).toBe(true); + }); + + it('should apply borderless input', () => { + expect(directive.borderless()).toBe(false); + }); + + it('should apply caption input', () => { + expect(directive.caption()).toBe('top'); + }); + + it('should apply color input', () => { + expect(directive.color()).toBe('secondary'); + }); + + it('should have responsive wrapper', () => { + const parentElement = debugElement.nativeElement.parentElement; + const classes = parentElement.classList; + expect(classes).toContain('table-responsive'); + }); + + it('should apply correct host classes', () => { + const classes = debugElement.nativeElement.classList; + + expect(classes).toContain('table'); + expect(classes).toContain('align-middle'); + expect(classes).toContain('caption-top'); + expect(classes).toContain('border-primary'); + expect(classes).toContain('table-bordered'); + expect(classes).toContain('table-secondary'); + expect(classes).toContain('table-hover'); + expect(classes).toContain('table-sm'); + expect(classes).toContain('table-striped'); + expect(classes).toContain('table-striped-columns'); + }); }); diff --git a/projects/coreui-angular/src/lib/table/table.directive.ts b/projects/coreui-angular/src/lib/table/table.directive.ts index b4c60ce4..13ed3a2f 100644 --- a/projects/coreui-angular/src/lib/table/table.directive.ts +++ b/projects/coreui-angular/src/lib/table/table.directive.ts @@ -1,115 +1,125 @@ -import { booleanAttribute, Directive, ElementRef, HostBinding, inject, Input, OnInit, Renderer2 } from '@angular/core'; +import { booleanAttribute, computed, Directive, effect, ElementRef, inject, input, Renderer2 } from '@angular/core'; import { Breakpoints, Colors } from '../coreui.types'; -import { ITable } from './table.type'; @Directive({ selector: 'table[cTable]', - host: { class: 'table' } + exportAs: 'cTable', + host: { + class: 'table', + '[class]': 'hostClasses()' + } }) -export class TableDirective implements ITable, OnInit { +export class TableDirective { readonly #renderer = inject(Renderer2); readonly #hostElement = inject(ElementRef); /** * Set the vertical alignment. - * @type string + * @return string * @values 'bottom' | 'middle' | 'top' */ - @Input() align?: 'bottom' | 'middle' | 'top'; + readonly align = input<'bottom' | 'middle' | 'top'>(); /** * Sets the border color of the component to one of CoreUI’s themed colors. - * @type Colors + * @return Colors */ - @Input() borderColor?: Colors; + readonly borderColor = input(); /** * Add borders on all sides of the table and cells. - * @type boolean + * @return boolean */ - @Input({ transform: booleanAttribute }) bordered: string | boolean = false; + readonly bordered = input(false, { transform: booleanAttribute }); /** * Remove borders on all sides of the table and cells. - * @type boolean + * @return boolean */ - @Input({ transform: booleanAttribute }) borderless: string | boolean = false; + readonly borderless = input(false, { transform: booleanAttribute }); /** * Put the `` on the top of the table. + * @return 'top' * @values 'top' */ - @Input() caption?: 'top'; + readonly caption = input<'top'>(); /** * Sets the color context of the component to one of CoreUI’s themed colors. - * @type Colors + * @return Colors */ - @Input() color?: Colors; + readonly color = input(); /** * Enable a hover state on table rows within table body. - * @type boolean + * @return boolean */ - @Input({ transform: booleanAttribute }) hover: string | boolean = false; + readonly hover = input(false, { transform: booleanAttribute }); /** * Make table responsive across all viewports or pick a maximum breakpoint with which to have a responsive table up to. - * @type: {boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'} + * @values: {boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'} */ - @Input() responsive?: boolean | Omit; + readonly responsive = input>(); /** * Make table more compact by cutting all cell `padding` in half. - * @type boolean + * @return boolean */ - @Input({ transform: booleanAttribute }) small: string | boolean = false; + readonly small = input(false, { transform: booleanAttribute }); /** * Add zebra-striping to any table row within the table body. - * @type boolean + * @return boolean */ - @Input({ transform: booleanAttribute }) striped: string | boolean = false; + readonly striped = input(false, { transform: booleanAttribute }); /** * Add zebra-striping to any table column. - * @type boolean + * @return boolean * @since 4.2.4 */ - @Input({ transform: booleanAttribute }) stripedColumns: string | boolean = false; + readonly stripedColumns = input(false, { transform: booleanAttribute }); + + readonly hostClasses = computed(() => { + const align = this.align(); + const caption = this.caption(); + const borderColor = this.borderColor(); + const bordered = this.bordered(); + const borderless = this.borderless(); + const color = this.color(); + const hover = this.hover(); + const small = this.small(); + const striped = this.striped(); + const stripedColumns = this.stripedColumns(); - @HostBinding('class') - get hostClasses(): any { return { table: true, - [`align-${this.align}`]: !!this.align, - [`caption-${this.caption}`]: !!this.caption, - [`border-${this.borderColor}`]: !!this.borderColor, - 'table-bordered': this.bordered, - 'table-borderless': this.borderless, - [`table-${this.color}`]: !!this.color, - 'table-hover': this.hover, - 'table-sm': this.small, - 'table-striped': this.striped, - 'table-striped-columns': this.stripedColumns - }; - } + [`align-${align}`]: !!align, + [`caption-${caption}`]: !!caption, + [`border-${borderColor}`]: !!borderColor, + 'table-bordered': bordered, + 'table-borderless': borderless, + [`table-${color}`]: !!color, + 'table-hover': hover, + 'table-sm': small, + 'table-striped': striped, + 'table-striped-columns': stripedColumns + } as Record; + }); - ngOnInit(): void { - this.setResponsiveWrapper(); - } - - // todo - setResponsiveWrapper(): void { - if (!!this.responsive) { + readonly #responsiveWrapperEffect = effect(() => { + const responsive = this.responsive(); + if (!!responsive) { const nativeElement: HTMLElement = this.#hostElement.nativeElement; const wrapper = this.#renderer.createElement('div'); - const className = this.responsive === true ? 'table-responsive' : `table-responsive-${this.responsive}`; + const className = responsive === true ? 'table-responsive' : `table-responsive-${responsive}`; this.#renderer.addClass(wrapper, className); const parentNode = this.#renderer.parentNode(nativeElement); this.#renderer.appendChild(parentNode, wrapper); this.#renderer.insertBefore(parentNode, wrapper, nativeElement); this.#renderer.appendChild(wrapper, nativeElement); } - } + }); } diff --git a/projects/coreui-angular/src/lib/tabs-2/tab-panel/tab-panel.component.ts b/projects/coreui-angular/src/lib/tabs-2/tab-panel/tab-panel.component.ts index e4f11789..a3826cff 100644 --- a/projects/coreui-angular/src/lib/tabs-2/tab-panel/tab-panel.component.ts +++ b/projects/coreui-angular/src/lib/tabs-2/tab-panel/tab-panel.component.ts @@ -104,7 +104,7 @@ export class TabPanelComponent { fade: this.transition(), show: this.show(), invisible: this.tabsService.activeItem()?.disabled - })); + }) as Record); @HostBinding('@.disabled') get animationDisabled(): boolean { diff --git a/projects/coreui-angular/src/lib/tabs-2/tab/tab.directive.ts b/projects/coreui-angular/src/lib/tabs-2/tab/tab.directive.ts index ff153b89..67d2128e 100644 --- a/projects/coreui-angular/src/lib/tabs-2/tab/tab.directive.ts +++ b/projects/coreui-angular/src/lib/tabs-2/tab/tab.directive.ts @@ -8,7 +8,6 @@ import { ElementRef, inject, Injector, - Input, input, InputSignal, OnInit, @@ -43,10 +42,21 @@ export class TabDirective implements FocusableOption, OnInit { /** * Disabled attribute - * @type boolean + * @return boolean * @default false */ - @Input({ transform: booleanAttribute }) + readonly disabledInput = input(false, { transform: booleanAttribute, alias: 'disabled' }); + + readonly #disabled = signal(false); + readonly attrDisabled = computed(() => this.#disabled() || null); + + readonly #disabledEffect = effect(() => { + const disabled = this.disabledInput(); + untracked(() => { + this.disabled = disabled; + }); + }); + set disabled(value: boolean) { this.#disabled.set(value); } @@ -55,9 +65,6 @@ export class TabDirective implements FocusableOption, OnInit { return this.#disabled(); } - readonly #disabled = signal(false); - readonly attrDisabled = computed(() => this.#disabled() || null); - /** * Item key. * @type string | number @@ -87,7 +94,7 @@ export class TabDirective implements FocusableOption, OnInit { 'nav-link': true, active: this.isActive(), disabled: this.#disabled() - })); + }) as Record); readonly propId = computed(() => this.id() ?? `${this.#tabsService.id()}-tab-${this.itemKey()}`); @@ -95,18 +102,19 @@ export class TabDirective implements FocusableOption, OnInit { () => this.ariaControls() ?? `${this.#tabsService.id()}-panel-${this.itemKey()}` ); - disabledEffect = effect(() => { - if (!this.#disabled()) { + readonly #disabledSignalEffect = effect(() => { + const disabled = this.#disabled(); + if (!disabled) { const click$ = fromEvent(this.#elementRef.nativeElement, 'click'); const focusIn$ = fromEvent(this.#elementRef.nativeElement, 'focusin'); merge(focusIn$, click$) .pipe( - filter(($event) => !this.#disabled()), + filter(($event) => !disabled), tap(($event) => { this.#tabsService.activeItemKey.set(untracked(this.itemKey)); }), - takeWhile(() => !this.#disabled()), + takeWhile(() => !disabled), takeUntilDestroyed(this.#destroyRef) ) .subscribe(); diff --git a/projects/coreui-angular/src/lib/tabs-2/tabs-list/tabs-list.component.ts b/projects/coreui-angular/src/lib/tabs-2/tabs-list/tabs-list.component.ts index 33df8fc5..f0d47731 100644 --- a/projects/coreui-angular/src/lib/tabs-2/tabs-list/tabs-list.component.ts +++ b/projects/coreui-angular/src/lib/tabs-2/tabs-list/tabs-list.component.ts @@ -54,12 +54,12 @@ export class TabsListComponent { nav: true, [`nav-${this.layout()}`]: this.layout(), [`nav-${this.variant()}`]: this.variant() - })); + }) as Record); readonly tabs = contentChildren(TabDirective); #focusKeyManager!: FocusKeyManager; - readonly tabsEffect = effect(() => { + readonly #tabsEffect = effect(() => { const tabs = this.tabs(); if (tabs.length === 0) { return; @@ -91,7 +91,7 @@ export class TabsListComponent { }); }); - readonly tabsServiceEffect = effect(() => { + readonly #tabsServiceEffect = effect(() => { const activeItemIndex = this.tabs().findIndex( (tab) => untracked(tab.isActive) && untracked(tab.itemKey) === this.tabsService.activeItemKey() ); diff --git a/projects/coreui-angular/src/lib/tabs-2/tabs.component.ts b/projects/coreui-angular/src/lib/tabs-2/tabs.component.ts index 1897fc36..bb501665 100644 --- a/projects/coreui-angular/src/lib/tabs-2/tabs.component.ts +++ b/projects/coreui-angular/src/lib/tabs-2/tabs.component.ts @@ -31,12 +31,12 @@ export class TabsComponent { tabsId = `tabs-${nextId++}`; readonly id = input(this.tabsId); - readonly activeItemEffect = effect(() => { + readonly #activeItemEffect = effect(() => { this.tabsService.id.set(this.id()); this.tabsService.activeItemKey.set(this.activeItemKey()); }); - readonly tabsServiceEffect = effect(() => { + readonly #tabsServiceEffect = effect(() => { this.activeItemKey.set(this.tabsService.activeItemKey()); }); } diff --git a/projects/coreui-angular/src/lib/toast/toast-body/toast-body.component.ts b/projects/coreui-angular/src/lib/toast/toast-body/toast-body.component.ts index 0e9b1605..1e1f3166 100644 --- a/projects/coreui-angular/src/lib/toast/toast-body/toast-body.component.ts +++ b/projects/coreui-angular/src/lib/toast/toast-body/toast-body.component.ts @@ -1,14 +1,16 @@ -import { Component, HostBinding, inject } from '@angular/core'; +import { Component, inject } from '@angular/core'; import { ToastComponent } from '../toast/toast.component'; @Component({ selector: 'c-toast-body', template: '', styleUrls: ['./toast-body.component.scss'], - exportAs: 'cToastBody' + exportAs: 'cToastBody', + host: { + class: 'toast-body', + } }) export class ToastBodyComponent { - toast? = inject(ToastComponent, { optional: true }); + readonly toast? = inject(ToastComponent, { optional: true }); - @HostBinding('class.toast-body') toastBodyClass = true; } diff --git a/projects/coreui-angular/src/lib/toast/toast-close.directive.ts b/projects/coreui-angular/src/lib/toast/toast-close.directive.ts index 125641f3..16ba62e6 100644 --- a/projects/coreui-angular/src/lib/toast/toast-close.directive.ts +++ b/projects/coreui-angular/src/lib/toast/toast-close.directive.ts @@ -1,18 +1,21 @@ -import { Directive, HostListener, inject, Input } from '@angular/core'; +import { Directive, inject, input } from '@angular/core'; import { ToasterService } from './toaster/toaster.service'; +import type { ToastComponent } from './toast/toast.component'; @Directive({ selector: '[cToastClose]', - exportAs: 'cToastClose' + exportAs: 'cToastClose', + host: { + '(click)': 'toggleOpen($event)' + } }) export class ToastCloseDirective { readonly #toasterService = inject(ToasterService); - @Input('cToastClose') toast: any; + readonly cToastClose = input(); - @HostListener('click', ['$event']) - toggleOpen($event: any): void { + toggleOpen($event: MouseEvent): void { $event.preventDefault(); - this.#toasterService.setState({ show: false, toast: this.toast }); + this.#toasterService.setState({ show: false, toast: this.cToastClose() }); } } diff --git a/projects/coreui-angular/src/lib/toast/toast-header/toast-header.component.html b/projects/coreui-angular/src/lib/toast/toast-header/toast-header.component.html index 1537b670..c18e0458 100644 --- a/projects/coreui-angular/src/lib/toast/toast-header/toast-header.component.html +++ b/projects/coreui-angular/src/lib/toast/toast-header/toast-header.component.html @@ -1,6 +1,6 @@ - @if (closeButton) { - + @if (closeButton()) { + } diff --git a/projects/coreui-angular/src/lib/toast/toast-header/toast-header.component.ts b/projects/coreui-angular/src/lib/toast/toast-header/toast-header.component.ts index 4c31af19..6addf3a8 100644 --- a/projects/coreui-angular/src/lib/toast/toast-header/toast-header.component.ts +++ b/projects/coreui-angular/src/lib/toast/toast-header/toast-header.component.ts @@ -1,4 +1,4 @@ -import { Component, HostBinding, inject, Input } from '@angular/core'; +import { Component, inject, input, signal } from '@angular/core'; import { ButtonCloseDirective } from '../../button'; import { ToastComponent } from '../toast/toast.component'; @@ -8,16 +8,19 @@ import { ToastCloseDirective } from '../toast-close.directive'; selector: 'c-toast-header', templateUrl: './toast-header.component.html', exportAs: 'cToastHeader', - imports: [ToastCloseDirective, ButtonCloseDirective] + imports: [ToastCloseDirective, ButtonCloseDirective], + host: { + class: 'toast-header' + } }) export class ToastHeaderComponent { - toast? = inject(ToastComponent, { optional: true }); + readonly #toast = inject(ToastComponent, { optional: true }); + + readonly toast = signal(this.#toast ?? undefined); /** * Add close button to a toast header - * @type boolean + * @return boolean */ - @Input() closeButton = true; - - @HostBinding('class.toast-header') toastHeaderClass = true; + readonly closeButton = input(true); } diff --git a/projects/coreui-angular/src/lib/toast/toast/toast.component.ts b/projects/coreui-angular/src/lib/toast/toast/toast.component.ts index 0fc10e01..5d99dbd9 100644 --- a/projects/coreui-angular/src/lib/toast/toast/toast.component.ts +++ b/projects/coreui-angular/src/lib/toast/toast/toast.component.ts @@ -2,11 +2,10 @@ import { booleanAttribute, ChangeDetectorRef, Component, + computed, + effect, ElementRef, - HostBinding, - HostListener, inject, - Input, input, numberAttribute, OnDestroy, @@ -47,47 +46,62 @@ type AnimateType = 'hide' | 'show'; }) ]) ], - host: { class: 'toast show' } + host: { + class: 'toast show', + '[class]': 'hostClasses()', + '(mouseover)': 'clearTimer()', + '(mouseout)': 'setTimer()', + '[@fadeInOut]': 'animateType', + '[@.disabled]': 'animationDisabled()' + } }) export class ToastComponent implements OnInit, OnDestroy { + readonly changeDetectorRef = inject(ChangeDetectorRef); readonly hostElement = inject(ElementRef); readonly renderer = inject(Renderer2); readonly toasterService = inject(ToasterService); - readonly changeDetectorRef = inject(ChangeDetectorRef); readonly dynamic = input(); - readonly placement = input(); + readonly placementInput = input(undefined, { alias: 'placement' }); + + get placement() { + return this.placementInput(); + } /** * Auto hide the toast. - * @type boolean + * @return boolean */ readonly autohide = input(true); /** * Sets the color context of the component to one of CoreUI’s themed colors. - * @type Colors + * @return Colors */ readonly color = input(''); /** * Delay hiding the toast (ms). - * @type number + * @return number */ readonly delay = input(5000, { transform: numberAttribute }); /** * Apply fade transition to the toast. - * @type boolean + * @return boolean */ readonly fade = input(true); /** * Toggle the visibility of component. - * @type boolean + * @return boolean */ + readonly visibleInput = input(false, { transform: booleanAttribute, alias: 'visible' }); + + readonly #visibleInputEffect = effect(() => { + this.visible = this.visibleInput(); + }); - @Input({ transform: booleanAttribute }) set visible(value: boolean) { const newValue = value; if (this.#visible !== newValue) { @@ -111,13 +125,13 @@ export class ToastComponent implements OnInit, OnDestroy { /** * Event emitted on visibility change. [docs] - * @type + * @return */ readonly visibleChange = output(); /** * Event emitted on timer tick. [docs] - * @type number + * @return number */ readonly timer = output(); @@ -137,40 +151,30 @@ export class ToastComponent implements OnInit, OnDestroy { this.changeDetectorRef.markForCheck(); } - @HostBinding('@.disabled') - get animationDisabled(): boolean { + readonly animationDisabled = computed(() => { return !this.fade(); - } + }); - @HostBinding('@fadeInOut') get animateType(): AnimateType { return this.visible ? 'show' : 'hide'; } - @HostListener('mouseover') onMouseOver(): void { - this.clearTimer(); - } - - @HostListener('mouseout') onMouseOut(): void { - this.setTimer(); - } - - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { + const color = this.color(); return { toast: true, show: true, - [`bg-${this.color()}`]: !!this.color(), - 'border-0': !!this.color() - }; - } + [`bg-${color}`]: !!color, + 'border-0': !!color + } as Record; + }); ngOnInit(): void { if (this.visible) { this.toasterService.setState({ toast: this, show: this.visible, - placement: this.placement() + placement: this.placement }); this.clearTimer(); this.setTimer(); @@ -200,7 +204,7 @@ export class ToastComponent implements OnInit, OnDestroy { this.toasterService.setState({ toast: this, show: false, - placement: this.placement() + placement: this.placement }); } diff --git a/projects/coreui-angular/src/lib/toast/toaster/toaster.component.ts b/projects/coreui-angular/src/lib/toast/toaster/toaster.component.ts index e3f24e6b..5b902bed 100644 --- a/projects/coreui-angular/src/lib/toast/toaster/toaster.component.ts +++ b/projects/coreui-angular/src/lib/toast/toaster/toaster.component.ts @@ -1,19 +1,17 @@ import { - AfterContentChecked, Component, ComponentRef, - ContentChildren, + computed, + contentChildren, DestroyRef, ElementRef, - HostBinding, inject, Injector, - Input, + input, NgModuleRef, OnInit, - QueryList, Renderer2, - ViewChild, + viewChild, ViewContainerRef } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @@ -53,59 +51,62 @@ export type TToasterPlacement = templateUrl: './toaster.component.html', exportAs: 'cToaster', imports: [ToasterHostDirective], - host: { class: 'toaster toast-container' } + host: { + class: 'toaster toast-container', + '[class]': 'hostClasses()' + } }) -export class ToasterComponent implements OnInit, AfterContentChecked { +export class ToasterComponent implements OnInit { readonly #hostElement = inject(ElementRef); readonly #renderer = inject(Renderer2); readonly #toasterService = inject(ToasterService); readonly #destroyRef = inject(DestroyRef); placements = Object.values(ToasterPlacement); - toasts!: QueryList; - toastsDynamic: any[] = []; + toastsDynamic: ComponentRef[] = []; /** * Toaster placement - * @type TToasterPlacement + * @return TToasterPlacement */ - @Input() placement: TToasterPlacement = ToasterPlacement.TopEnd; + readonly placementInput = input(ToasterPlacement.TopEnd, { alias: 'placement' }); + + get placement() { + return this.placementInput(); + } /** * Toaster position - * @type (string | 'absolute' | 'fixed' | 'static') + * @return (string | 'absolute' | 'fixed' | 'static') */ - @Input() position: string | 'absolute' | 'fixed' | 'static' = 'absolute'; + readonly position = input('absolute'); - @ViewChild(ToasterHostDirective, { static: true }) toasterHost!: ToasterHostDirective; - @ContentChildren(ToastComponent, { read: ViewContainerRef }) contentToasts!: QueryList; + readonly toasterHost = viewChild.required(ToasterHostDirective); + readonly contentToasts = contentChildren(ToastComponent, { read: ViewContainerRef }); - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { + const placement = this.placement; + const position = this.position(); return { toaster: true, 'toast-container': true, - [`position-${this.position}`]: !!this.position, - 'top-0': this.placement.includes('top'), - 'top-50': this.placement.includes('middle'), - 'bottom-0': this.placement.includes('bottom'), - 'start-0': this.placement.includes('start'), - 'start-50': this.placement.includes('center'), - 'end-0': this.placement.includes('end'), - 'translate-middle-x': this.placement.includes('center') && !this.placement.includes('middle'), - 'translate-middle-y': this.placement.includes('middle') && !this.placement.includes('center'), - 'translate-middle': this.placement.includes('middle') && this.placement.includes('center') - }; - } + [`position-${position}`]: !!position, + 'top-0': placement.includes('top'), + 'top-50': placement.includes('middle'), + 'bottom-0': placement.includes('bottom'), + 'start-0': placement.includes('start'), + 'start-50': placement.includes('center'), + 'end-0': placement.includes('end'), + 'translate-middle-x': placement.includes('center') && !placement.includes('middle'), + 'translate-middle-y': placement.includes('middle') && !placement.includes('center'), + 'translate-middle': placement.includes('middle') && placement.includes('center') + } as Record; + }); ngOnInit(): void { this.stateToasterSubscribe(); } - ngAfterContentChecked(): void { - this.toasts = this.contentToasts; - } - public addToast( toast: any, props: any, @@ -116,7 +117,7 @@ export class ToasterComponent implements OnInit, AfterContentChecked { projectableNodes?: Node[][]; } ): ComponentRef { - const componentRef: ComponentRef = this.toasterHost.viewContainerRef.createComponent(toast, options); + const componentRef: ComponentRef = this.toasterHost().viewContainerRef.createComponent(toast, options); this.toastsDynamic.push(componentRef); const index = this.toastsDynamic.indexOf(componentRef); for (const [key, value] of Object.entries(props)) { @@ -139,8 +140,7 @@ export class ToasterComponent implements OnInit, AfterContentChecked { item.destroy(); } }); - - this.toasts?.forEach((item) => { + this.contentToasts()?.forEach((item) => { if (state.toast && item.element.nativeElement === state.toast.hostElement.nativeElement) { if (!state.toast.dynamic()) { state.toast['visible'] = false; diff --git a/projects/coreui-angular/src/lib/toast/toaster/toaster.service.ts b/projects/coreui-angular/src/lib/toast/toaster/toaster.service.ts index 4118cca1..ba21f320 100644 --- a/projects/coreui-angular/src/lib/toast/toaster/toaster.service.ts +++ b/projects/coreui-angular/src/lib/toast/toaster/toaster.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { TToasterPlacement } from './toaster.component'; -import { ToastComponent } from '../toast/toast.component'; +import { type ToastComponent } from '../toast/toast.component'; export interface IToasterAction { placement?: TToasterPlacement; diff --git a/projects/coreui-angular/src/lib/tooltip/tooltip.directive.ts b/projects/coreui-angular/src/lib/tooltip/tooltip.directive.ts index 405a6efc..9457db9e 100644 --- a/projects/coreui-angular/src/lib/tooltip/tooltip.directive.ts +++ b/projects/coreui-angular/src/lib/tooltip/tooltip.directive.ts @@ -48,7 +48,7 @@ export class TooltipDirective implements OnDestroy, OnInit, AfterViewInit { */ readonly content = input | undefined>(undefined, { alias: 'cTooltip' }); - readonly contentEffect = effect(() => { + readonly #contentEffect = effect(() => { if (this.content()) { this.destroyTooltipElement(); } @@ -60,7 +60,7 @@ export class TooltipDirective implements OnDestroy, OnInit, AfterViewInit { */ readonly popperOptions = input>({}, { alias: 'cTooltipOptions' }); - readonly popperOptionsEffect = effect(() => { + readonly #popperOptionsEffect = effect(() => { this._popperOptions = { ...this._popperOptions, placement: this.placement(), @@ -100,7 +100,7 @@ export class TooltipDirective implements OnDestroy, OnInit, AfterViewInit { */ readonly visible = model(false, { alias: 'cTooltipVisible' }); - readonly visibleEffect = effect(() => { + readonly #visibleEffect = effect(() => { this.visible() ? this.addTooltipElement() : this.removeTooltipElement(); }); diff --git a/projects/coreui-angular/src/lib/tooltip/tooltip/tooltip.component.ts b/projects/coreui-angular/src/lib/tooltip/tooltip/tooltip.component.ts index ca659b7f..3fd614bc 100644 --- a/projects/coreui-angular/src/lib/tooltip/tooltip/tooltip.component.ts +++ b/projects/coreui-angular/src/lib/tooltip/tooltip/tooltip.component.ts @@ -31,7 +31,7 @@ export class TooltipComponent implements OnDestroy { */ readonly content = input>(''); - readonly contentEffect = effect(() => { + readonly #contentEffect = effect(() => { this.updateView(this.content()); }); @@ -46,13 +46,13 @@ export class TooltipComponent implements OnDestroy { readonly viewContainerRef = viewChild('tooltipTemplate', { read: ViewContainerRef }); private textNode!: Text; - readonly hostClasses = computed>(() => { + readonly hostClasses = computed(() => { return { tooltip: true, fade: true, show: this.visible(), 'bs-tooltip-auto': true - }; + } as Record; }); ngOnDestroy(): void { diff --git a/projects/coreui-angular/src/lib/utilities/align.directive.spec.ts b/projects/coreui-angular/src/lib/utilities/align.directive.spec.ts index 13e35f90..bc7f8f75 100644 --- a/projects/coreui-angular/src/lib/utilities/align.directive.spec.ts +++ b/projects/coreui-angular/src/lib/utilities/align.directive.spec.ts @@ -1,8 +1,11 @@ +import { TestBed } from '@angular/core/testing'; import { AlignDirective } from './align.directive'; describe('AlignDirective', () => { it('should create an instance', () => { + TestBed.runInInjectionContext(() => { const directive = new AlignDirective(); expect(directive).toBeTruthy(); + }); }); }); diff --git a/projects/coreui-angular/src/lib/utilities/align.directive.ts b/projects/coreui-angular/src/lib/utilities/align.directive.ts index 639d315d..f7184c40 100644 --- a/projects/coreui-angular/src/lib/utilities/align.directive.ts +++ b/projects/coreui-angular/src/lib/utilities/align.directive.ts @@ -1,20 +1,22 @@ -import { Directive, HostBinding, Input } from '@angular/core'; +import { computed, Directive, input } from '@angular/core'; import { Alignment } from '../coreui.types'; @Directive({ - selector: '[cAlign]' + selector: '[cAlign]', + exportAs: 'cAlign', + host: { '[class]': 'hostClasses()' } }) export class AlignDirective { /** * Set vertical alignment of inline, inline-block, inline-table, and table cell elements - * @type Alignment + * @return Alignment */ - @Input('cAlign') align?: Alignment; + readonly align = input(undefined, { alias: 'cAlign' }); - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { + const align = this.align(); return { - [`align-${this.align}`]: !!this.align - }; - } + [`align-${align}`]: !!align + } as Record; + }); } diff --git a/projects/coreui-angular/src/lib/utilities/bg-color.directive.spec.ts b/projects/coreui-angular/src/lib/utilities/bg-color.directive.spec.ts index 9fa8fa8b..a42b4224 100644 --- a/projects/coreui-angular/src/lib/utilities/bg-color.directive.spec.ts +++ b/projects/coreui-angular/src/lib/utilities/bg-color.directive.spec.ts @@ -1,8 +1,11 @@ +import { TestBed } from '@angular/core/testing'; import { BgColorDirective } from './bg-color.directive'; describe('BgColorDirective', () => { it('should create an instance', () => { + TestBed.runInInjectionContext(() => { const directive = new BgColorDirective(); expect(directive).toBeTruthy(); + }); }); }); diff --git a/projects/coreui-angular/src/lib/utilities/bg-color.directive.ts b/projects/coreui-angular/src/lib/utilities/bg-color.directive.ts index 203fee22..dfbc261e 100644 --- a/projects/coreui-angular/src/lib/utilities/bg-color.directive.ts +++ b/projects/coreui-angular/src/lib/utilities/bg-color.directive.ts @@ -1,25 +1,28 @@ -import { Directive, HostBinding, Input } from '@angular/core'; +import { computed, Directive, input } from '@angular/core'; import { BackgroundColors } from '../coreui.types'; @Directive({ - selector: '[cBgColor]' + selector: '[cBgColor]', + exportAs: 'cBgColor', + host: { '[class]': 'hostClasses()' } }) export class BgColorDirective { /** * Set the background of an element to any contextual class */ - @Input('cBgColor') color: BackgroundColors = ''; + readonly cBgColor = input(''); + /** * Add linear gradient as background image to the backgrounds. - * @type boolean + * @return boolean */ - @Input() gradient?: boolean; + readonly gradient = input(); - @HostBinding('class') - get hostClasses(): any { + readonly hostClasses = computed(() => { + const color = this.cBgColor(); return { - [`bg-${this.color}`]: !!this.color, - 'bg-gradient': this.gradient - }; - } + [`bg-${color}`]: !!color, + 'bg-gradient': this.gradient() + } as Record; + }); } diff --git a/projects/coreui-angular/src/lib/utilities/border.directive.spec.ts b/projects/coreui-angular/src/lib/utilities/border.directive.spec.ts index de88e38d..b514230e 100644 --- a/projects/coreui-angular/src/lib/utilities/border.directive.spec.ts +++ b/projects/coreui-angular/src/lib/utilities/border.directive.spec.ts @@ -1,8 +1,11 @@ +import { TestBed } from '@angular/core/testing'; import { BorderDirective } from './border.directive'; describe('BorderDirective', () => { it('should create an instance', () => { + TestBed.runInInjectionContext(() => { const directive = new BorderDirective(); expect(directive).toBeTruthy(); + }); }); }); diff --git a/projects/coreui-angular/src/lib/utilities/border.directive.ts b/projects/coreui-angular/src/lib/utilities/border.directive.ts index 739b0231..c0c87632 100644 --- a/projects/coreui-angular/src/lib/utilities/border.directive.ts +++ b/projects/coreui-angular/src/lib/utilities/border.directive.ts @@ -1,35 +1,37 @@ -import { Directive, HostBinding, Input } from '@angular/core'; +import { computed, Directive, input } from '@angular/core'; import { Border } from './border.type'; @Directive({ - selector: '[cBorder]' + selector: '[cBorder]', + exportAs: 'cBorder', + host: { '[class]': 'hostClasses()' } }) export class BorderDirective { /** * Add or remove an element’s borders - * @type Border + * @return Border */ - @Input('cBorder') border: Border = true; + readonly cBorder = input(true); - @HostBinding('class') - get hostClasses(): any { - if (typeof this.border === 'boolean') { + readonly hostClasses = computed>(() => { + const border = this.cBorder(); + if (typeof border === 'boolean') { return { border: true }; } - if (typeof this.border === 'number' || typeof this.border === 'string') { + if (typeof border === 'number' || typeof border === 'string') { return { border: true, - [`border-${this.border}`]: true + [`border-${border}`]: true }; } - if (typeof this.border === 'object') { + if (typeof border === 'object') { const borderObj = { top: undefined, end: undefined, bottom: undefined, start: undefined, color: undefined, - ...this.border + ...border }; // @ts-ignore const keys = Object.keys(borderObj).filter((key) => borderObj[key] !== undefined); @@ -56,5 +58,6 @@ export class BorderDirective { }); return Object.entries(classes).length === 0 ? { border: false } : classes; } - } + return { border: false }; + }); } diff --git a/projects/coreui-angular/src/lib/utilities/rounded.directive.spec.ts b/projects/coreui-angular/src/lib/utilities/rounded.directive.spec.ts index 986e6ad2..78939ed5 100644 --- a/projects/coreui-angular/src/lib/utilities/rounded.directive.spec.ts +++ b/projects/coreui-angular/src/lib/utilities/rounded.directive.spec.ts @@ -1,8 +1,11 @@ +import { TestBed } from '@angular/core/testing'; import { RoundedDirective } from './rounded.directive'; describe('RoundedDirective', () => { it('should create an instance', () => { + TestBed.runInInjectionContext(() => { const directive = new RoundedDirective(); expect(directive).toBeTruthy(); + }); }); }); diff --git a/projects/coreui-angular/src/lib/utilities/rounded.directive.ts b/projects/coreui-angular/src/lib/utilities/rounded.directive.ts index e35a30ef..fc8b5c83 100644 --- a/projects/coreui-angular/src/lib/utilities/rounded.directive.ts +++ b/projects/coreui-angular/src/lib/utilities/rounded.directive.ts @@ -1,27 +1,29 @@ -import { Directive, HostBinding, Input } from '@angular/core'; +import { computed, Directive, input } from '@angular/core'; import { Rounded } from './rounded.type'; @Directive({ - selector: '[cRounded]' + selector: '[cRounded]', + exportAs: 'cRounded', + host: { '[class]': 'hostClasses()' } }) export class RoundedDirective { /** * Set border radius variant and radius size * @type Rounded */ - @Input('cRounded') rounded: Rounded = true; + readonly cRounded = input(true); - @HostBinding('class') - get hostClasses(): any { - if (typeof this.rounded === 'boolean') { + readonly hostClasses = computed>(() => { + const rounded = this.cRounded(); + if (typeof rounded === 'boolean') { return { rounded: true }; } - if (typeof this.rounded === 'number' || typeof this.rounded === 'string') { + if (typeof rounded === 'number' || typeof rounded === 'string') { return { - [`rounded-${this.rounded}`]: true + [`rounded-${rounded}`]: true }; } - if (typeof this.rounded === 'object') { + if (typeof rounded === 'object') { const roundedObj = { top: undefined, end: undefined, @@ -30,7 +32,7 @@ export class RoundedDirective { circle: undefined, pill: undefined, size: undefined, - ...this.rounded + ...rounded }; // @ts-ignore const keys = Object.keys(roundedObj).filter((key) => roundedObj[key] !== undefined); @@ -49,5 +51,6 @@ export class RoundedDirective { // console.log('rounded keys', keys, classes); return Object.entries(classes).length === 0 ? { rounded: false } : classes; } - } + return { rounded: false }; + }); } diff --git a/projects/coreui-angular/src/lib/utilities/shadow-on-scroll.directive.ts b/projects/coreui-angular/src/lib/utilities/shadow-on-scroll.directive.ts index abe6fd7d..fc865753 100644 --- a/projects/coreui-angular/src/lib/utilities/shadow-on-scroll.directive.ts +++ b/projects/coreui-angular/src/lib/utilities/shadow-on-scroll.directive.ts @@ -1,10 +1,11 @@ import { DOCUMENT } from '@angular/common'; -import { DestroyRef, Directive, effect, ElementRef, inject, Input, signal, WritableSignal } from '@angular/core'; +import { DestroyRef, Directive, effect, ElementRef, inject, input, signal, untracked, WritableSignal } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { fromEvent, Subscription } from 'rxjs'; @Directive({ - selector: '[cShadowOnScroll]' + selector: '[cShadowOnScroll]', + exportAs: 'cShadowOnScroll' }) export class ShadowOnScrollDirective { readonly #destroyRef: DestroyRef = inject(DestroyRef); @@ -25,18 +26,22 @@ export class ShadowOnScrollDirective { }); } - @Input() - set cShadowOnScroll(value: 'sm' | 'lg' | 'none' | boolean) { - this.#scrolled.set(false); - if (value) { - this.#shadowClass = value === true ? 'shadow' : `shadow-${value}`; - this.#observable = fromEvent(this.#document, 'scroll') - .pipe(takeUntilDestroyed(this.#destroyRef)) - .subscribe((scrolled) => { - this.#scrolled.set(this.#document.documentElement.scrollTop > 0); - }); - } else { - this.#observable?.unsubscribe(); - } - } + readonly cShadowOnScroll = input<'sm' | 'lg' | 'none' | boolean>(true); + + readonly #shadowOnScrollEffect = effect(() => { + const value = this.cShadowOnScroll(); + untracked(() => { + this.#scrolled.set(false); + if (value) { + this.#shadowClass = value === true ? 'shadow' : `shadow-${value}`; + this.#observable = fromEvent(this.#document, 'scroll') + .pipe(takeUntilDestroyed(this.#destroyRef)) + .subscribe((scrolled) => { + this.#scrolled.set(this.#document.documentElement.scrollTop > 0); + }); + } else { + this.#observable?.unsubscribe(); + } + }); + }); } diff --git a/projects/coreui-angular/src/lib/utilities/visible.directive.ts b/projects/coreui-angular/src/lib/utilities/visible.directive.ts index 34b73b1f..e1d14e11 100644 --- a/projects/coreui-angular/src/lib/utilities/visible.directive.ts +++ b/projects/coreui-angular/src/lib/utilities/visible.directive.ts @@ -1,15 +1,31 @@ -import { Directive, inject, Input, TemplateRef, ViewContainerRef } from '@angular/core'; +import { Directive, effect, inject, input, TemplateRef, ViewContainerRef } from '@angular/core'; @Directive({ - selector: '[cVisible]' + selector: '[cVisible]', + exportAs: 'cVisible' }) +/** + * A directive that conditionally includes a template based on the value of an input boolean. + * + * @example + * ```html + * Content to display + * ``` + * + * @remarks + * This directive uses Angular's dependency injection to get references to `TemplateRef` and `ViewContainerRef`. + * It creates or clears the embedded view based on the value of the `cVisible` input. + */ export class VisibleDirective { readonly #templateRef = inject>(TemplateRef); readonly #viewContainer = inject(ViewContainerRef); #hasView!: boolean; - @Input() set cVisible(condition: boolean) { + readonly cVisible = input(); + + readonly #visibleEffect = effect(() => { + const condition = this.cVisible(); if (condition && !this.#hasView) { this.#viewContainer.createEmbeddedView(this.#templateRef); this.#hasView = true; @@ -17,5 +33,5 @@ export class VisibleDirective { this.#viewContainer.clear(); this.#hasView = false; } - } + }); } diff --git a/projects/coreui-angular/src/lib/widget/widget-stat-a/widget-stat-a.component.ts b/projects/coreui-angular/src/lib/widget/widget-stat-a/widget-stat-a.component.ts index b2af92bd..184684bb 100644 --- a/projects/coreui-angular/src/lib/widget/widget-stat-a/widget-stat-a.component.ts +++ b/projects/coreui-angular/src/lib/widget/widget-stat-a/widget-stat-a.component.ts @@ -6,11 +6,11 @@ import { CardBodyComponent, CardComponent } from '../../card'; import { NgClass, NgTemplateOutlet } from '@angular/common'; @Component({ - selector: 'c-widget-stat-a', - templateUrl: './widget-stat-a.component.html', - exportAs: 'cWidgetStatA', - imports: [CardBodyComponent, NgClass, NgTemplateOutlet], - host: { class: 'card', '[class]': 'hostClasses()' } + selector: 'c-widget-stat-a', + templateUrl: './widget-stat-a.component.html', + exportAs: 'cWidgetStatA', + imports: [CardBodyComponent, NgClass, NgTemplateOutlet], + host: { class: 'card', '[class]': 'hostClasses()' } }) export class WidgetStatAComponent extends CardComponent { /** @@ -35,7 +35,7 @@ export class WidgetStatAComponent extends CardComponent { readonly contentTemplates = contentChildren(TemplateIdDirective, { descendants: true }); - readonly contentTemplatesEffect = effect(() => { + readonly #contentTemplatesEffect = effect(() => { this.contentTemplates().forEach((child: TemplateIdDirective) => { this.templates[child.id] = child.templateRef; }); diff --git a/projects/coreui-angular/src/lib/widget/widget-stat-c/widget-stat-c.component.ts b/projects/coreui-angular/src/lib/widget/widget-stat-c/widget-stat-c.component.ts index bcaee3b4..8c1b3592 100644 --- a/projects/coreui-angular/src/lib/widget/widget-stat-c/widget-stat-c.component.ts +++ b/projects/coreui-angular/src/lib/widget/widget-stat-c/widget-stat-c.component.ts @@ -5,11 +5,11 @@ import { TemplateIdDirective } from '../../shared'; import { NgClass, NgTemplateOutlet } from '@angular/common'; @Component({ - selector: 'c-widget-stat-c', - templateUrl: './widget-stat-c.component.html', - exportAs: 'cWidgetStatC', - imports: [CardBodyComponent, NgClass, NgTemplateOutlet], - host: { '[class]': 'hostExtendedClass()' } + selector: 'c-widget-stat-c', + templateUrl: './widget-stat-c.component.html', + exportAs: 'cWidgetStatC', + imports: [CardBodyComponent, NgClass, NgTemplateOutlet], + host: { '[class]': 'hostExtendedClass()' } }) export class WidgetStatCComponent extends CardComponent { constructor() { @@ -43,7 +43,7 @@ export class WidgetStatCComponent extends CardComponent { templates: Record> = {}; readonly contentTemplates = contentChildren(TemplateIdDirective, { descendants: true }); - readonly contentTemplatesEffect = effect(() => { + readonly #contentTemplatesEffect = effect(() => { this.contentTemplates().forEach((child: TemplateIdDirective) => { this.templates[child.id] = child.templateRef; }); diff --git a/projects/coreui-angular/src/lib/widget/widget-stat-f/widget-stat-f.component.ts b/projects/coreui-angular/src/lib/widget/widget-stat-f/widget-stat-f.component.ts index a79438a2..cdf2bb31 100644 --- a/projects/coreui-angular/src/lib/widget/widget-stat-f/widget-stat-f.component.ts +++ b/projects/coreui-angular/src/lib/widget/widget-stat-f/widget-stat-f.component.ts @@ -6,11 +6,11 @@ import { TemplateIdDirective } from '../../shared'; import { CardBodyComponent, CardComponent, CardFooterComponent } from '../../card'; @Component({ - selector: 'c-widget-stat-f', - templateUrl: './widget-stat-f.component.html', - exportAs: 'cWidgetStatB', - imports: [CardBodyComponent, CardFooterComponent, NgClass, NgTemplateOutlet], - host: { class: 'card', '[class]': 'hostClasses()' } + selector: 'c-widget-stat-f', + templateUrl: './widget-stat-f.component.html', + exportAs: 'cWidgetStatB', + imports: [CardBodyComponent, CardFooterComponent, NgClass, NgTemplateOutlet], + host: { class: 'card', '[class]': 'hostClasses()' } }) export class WidgetStatFComponent extends CardComponent { /** @@ -58,7 +58,7 @@ export class WidgetStatFComponent extends CardComponent { templates: Record> = {}; readonly contentTemplates = contentChildren(TemplateIdDirective, { descendants: true }); - readonly contentTemplatesEffect = effect(() => { + readonly #contentTemplatesEffect = effect(() => { this.contentTemplates().forEach((child: TemplateIdDirective) => { this.templates[child.id] = child.templateRef; }); diff --git a/projects/coreui-icons-angular/LICENSE b/projects/coreui-icons-angular/LICENSE index 94e4f4d1..fbb053e0 100644 --- a/projects/coreui-icons-angular/LICENSE +++ b/projects/coreui-icons-angular/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 creativeLabs Łukasz Holeczek +Copyright (c) 2025 creativeLabs Łukasz Holeczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/projects/coreui-icons-angular/README.md b/projects/coreui-icons-angular/README.md index 5c2b0322..441225a0 100644 --- a/projects/coreui-icons-angular/README.md +++ b/projects/coreui-icons-angular/README.md @@ -39,7 +39,7 @@ [npm-coreui-icons-angular-v5-ng19]: https://img.shields.io/npm/v/@coreui/icons-angular/v5-ng19?style=flat-square&color=brightgreen [npm-coreui-icons-angular-latest]: https://img.shields.io/npm/v/@coreui/icons-angular/latest?style=flat-square&color=brightgreen [npm-coreui-icons-angular-next]: https://img.shields.io/npm/v/@coreui/icons-angular/next?style=flat-square&color=red -[angular-badge]: https://img.shields.io/badge/angular-^19.0.0-lightgrey.svg?style=flat-square&logo=angular +[angular-badge]: https://img.shields.io/badge/angular-^19.1.0-lightgrey.svg?style=flat-square&logo=angular ## `cIcon` directive @@ -172,5 +172,5 @@ Thanks to all the backers and sponsors! Support this project by [becoming a back ## Copyright and license -Copyright 2024 creativeLabs Łukasz Holeczek. Code released under the [MIT License](https://github.com/coreui/coreui-angular/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). +Copyright 2025 creativeLabs Łukasz Holeczek. Code released under the [MIT License](https://github.com/coreui/coreui-angular/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). diff --git a/projects/coreui-icons-angular/package.json b/projects/coreui-icons-angular/package.json index e99ac711..3899ccc0 100644 --- a/projects/coreui-icons-angular/package.json +++ b/projects/coreui-icons-angular/package.json @@ -1,8 +1,8 @@ { "name": "@coreui/icons-angular", - "version": "5.3.5", + "version": "5.3.8", "description": "CoreUI Icons Angular component and service", - "copyright": "Copyright 2024 creativeLabs Łukasz Holeczek", + "copyright": "Copyright 2025 creativeLabs Łukasz Holeczek", "license": "MIT", "homepage": "https://coreui.io/angular", "author": { @@ -25,9 +25,9 @@ "url": "https://github.com/coreui/coreui-angular/issues" }, "peerDependencies": { - "@angular/common": "^19.0.0", - "@angular/core": "^19.0.0", - "@angular/platform-browser": "^19.0.0" + "@angular/common": "^19.1.1", + "@angular/core": "^19.1.1", + "@angular/platform-browser": "^19.1.1" }, "dependencies": { "tslib": "^2.3.0" diff --git a/projects/coreui-icons-angular/src/lib/icon/icon.directive.ts b/projects/coreui-icons-angular/src/lib/icon/icon.directive.ts index 9723c931..58ccdfd4 100644 --- a/projects/coreui-icons-angular/src/lib/icon/icon.directive.ts +++ b/projects/coreui-icons-angular/src/lib/icon/icon.directive.ts @@ -35,7 +35,7 @@ export class IconDirective implements IIcon { readonly pointerEvents = input('none', { alias: 'pointer-events' }); readonly role = input('img'); - readonly hostClasses = computed(() => { + readonly hostClasses = computed(() => { const computedSize = this.computedSize(); const classes = { icon: true,