From 690ea4101b14e16903b3f4ba448b80e100e2a7f6 Mon Sep 17 00:00:00 2001 From: Murhaf Sousli Date: Fri, 15 Nov 2024 02:51:00 +0100 Subject: [PATCH] Update --- CHANGELOG.md | 15 + LICENSE | 2 +- README.md | 12 +- package-lock.json | 762 ++++++++++-------- package.json | 30 +- .../src/app/app.component.ts | 2 +- .../src/app/custom/custom.component.html | 2 +- .../src/app/custom/custom.component.ts | 4 +- .../src/app/home/home.component.html | 3 +- .../src/app/home/home.component.ts | 1 + .../src/app/home/lab/lab.component.html | 5 + .../src/app/home/lab/lab.component.ts | 2 +- projects/ngx-progressbar/README.md | 12 +- .../ngx-progressbar/docs/Global-options.md | 34 + .../docs/HttpClient-requests.md | 140 ++++ projects/ngx-progressbar/docs/Integration.md | 78 ++ .../ngx-progressbar/docs/Router-events.md | 54 ++ projects/ngx-progressbar/docs/Styling.md | 28 + projects/ngx-progressbar/docs/Usage.md | 95 +++ .../http/src/ng-progress-http.directive.ts | 7 + projects/ngx-progressbar/ng-package.json | 5 +- projects/ngx-progressbar/package.json | 2 +- .../src/ng-progress-router.directive.ts | 49 +- .../src/lib/ng-progress-default.ts | 1 + .../src/lib/ng-progress-ref.ts | 89 +- .../src/lib/ng-progress.component.scss | 7 +- .../src/lib/ng-progress.component.ts | 62 +- .../src/lib/ng-progress.model.ts | 16 +- .../src/lib/tests/ng-progress-ref.spec.ts | 75 +- .../src/lib/tests/ng-progress-router.spec.ts | 7 +- .../lib/tests/ng-progress.component.spec.ts | 57 +- 31 files changed, 1114 insertions(+), 544 deletions(-) create mode 100644 projects/ngx-progressbar/docs/Global-options.md create mode 100644 projects/ngx-progressbar/docs/HttpClient-requests.md create mode 100644 projects/ngx-progressbar/docs/Integration.md create mode 100644 projects/ngx-progressbar/docs/Router-events.md create mode 100644 projects/ngx-progressbar/docs/Styling.md create mode 100644 projects/ngx-progressbar/docs/Usage.md diff --git a/CHANGELOG.md b/CHANGELOG.md index b2e0edc..4f7b9b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 13.0.0 + +- feat: `NgProgressRef` directive has `(started)` and `(completed)` outputs, instead of subjects. +- feat: `NgProgressRef` directive has all `NgProgress` component inputs excepts the irrelevant styling inputs. +- feat: Add `fadeOutSpeed` input to set the fade out transition after the progress completes. +- feat: Add `--ng-progress-spinner-speed` CSS variable to set the spinner speed. +- enhance: Use `NgProgressRef` as *hostDirective* in `NgProgress` component and forward its inputs and outputs. +- enhance: avoid triggering the main effects twice in `ProgressRef` directive due to config update. +- refactor: Use transform function for `min` and `max` inputs. + +### Breaking changes + +- Remove `setConfig()` function from `ProgressRef` directive, you can now set the inputs directly. +- Remove `start()`, `complete()`, `inc()` and `set()` functions from the component reference. + ## 12.0.2 - refactor: Use `untracked` in effects instead of `allowSignalWrites` and `setTimeout`. diff --git a/LICENSE b/LICENSE index 089357f..1c5531e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016-2024 Murhaf Sousli +Copyright (c) 2016-2025 Murhaf Sousli 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 80c7ee6..e93aede 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,17 @@ A nanoscopic progress bar. Featuring realistic trickle animations to convince yo ___ -### The documentation is available at the [wiki page](https://github.com/MurhafSousli/ngx-progressbar/wiki) 📚 +## Documentations + +### Table of contents + +* [Usage](projects/ngx-progressbar/docs/Usage.md) +* [Styling](projects/ngx-progressbar/docs/Styling.md) +* [Global Options](projects/ngx-progressbar/docs/Global-options.md) +* [Smooth Scroll Functions](projects/ngx-progressbar/docs/Integration.md) +* Automagic features + * [HttpClient Requests](projects/ngx-progressbar/docs/HttpClient-requests.md) + * [Router Events](projects/ngx-progressbar/docs/Router-events.md) ___ diff --git a/package-lock.json b/package-lock.json index 3bc4b12..88f3e3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,26 +8,26 @@ "name": "ngx-progressbar-demo", "version": "0.0.0", "dependencies": { - "@angular/animations": "^18.2.3", - "@angular/cdk": "^18.2.3", - "@angular/common": "^18.2.3", - "@angular/compiler": "^18.2.3", - "@angular/core": "^18.2.3", - "@angular/forms": "^18.2.3", - "@angular/material": "^18.2.3", - "@angular/platform-browser": "^18.2.3", - "@angular/platform-browser-dynamic": "^18.2.3", - "@angular/router": "^18.2.3", + "@angular/animations": "^18.2.12", + "@angular/cdk": "^18.2.13", + "@angular/common": "^18.2.12", + "@angular/compiler": "^18.2.12", + "@angular/core": "^18.2.12", + "@angular/forms": "^18.2.12", + "@angular/material": "^18.2.13", + "@angular/platform-browser": "^18.2.12", + "@angular/platform-browser-dynamic": "^18.2.12", + "@angular/router": "^18.2.12", "rxjs": "~7.8.1", "zone.js": "~0.14.10" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.2.3", - "@angular/cli": "^18.2.3", - "@angular/compiler-cli": "^18.2.3", - "@angular/language-service": "^18.2.3", + "@angular-devkit/build-angular": "^18.2.12", + "@angular/cli": "^18.2.12", + "@angular/compiler-cli": "^18.2.12", + "@angular/language-service": "^18.2.12", "@types/jasmine": "^5.1.4", - "jasmine-core": "^5.3.0", + "jasmine-core": "^5.4.0", "karma": "~6.4.4", "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.0", @@ -52,12 +52,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1802.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.3.tgz", - "integrity": "sha512-WQ2AmkUKy1bqrDlNfozW8+VT2Tv/Fdmu4GIXps3ytZANyAKiIvTzmmql2cRCXXraa9FNMjLWNvz+qolDxWVdYQ==", + "version": "0.1802.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.12.tgz", + "integrity": "sha512-bepVb2/GtJppYKaeW8yTGE6egmoWZ7zagFDsmBdbF+BYp+HmeoPsclARcdryBPVq68zedyTRdvhWSUTbw1AYuw==", "dev": true, "dependencies": { - "@angular-devkit/core": "18.2.3", + "@angular-devkit/core": "18.2.12", "rxjs": "7.8.1" }, "engines": { @@ -67,16 +67,16 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.3.tgz", - "integrity": "sha512-uUQba0SIskKORHcPayt7LpqPRKD//48EW92SgGHEArn2KklM+FSYBOA9OtrJeZ/UAcoJpdLDtvyY4+S7oFzomg==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.12.tgz", + "integrity": "sha512-quVUi7eqTq9OHumQFNl9Y8t2opm8miu4rlYnuF6rbujmmBDvdUvR6trFChueRczl2p5HWqTOr6NPoDGQm8AyNw==", "dev": true, "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.3", - "@angular-devkit/build-webpack": "0.1802.3", - "@angular-devkit/core": "18.2.3", - "@angular/build": "18.2.3", + "@angular-devkit/architect": "0.1802.12", + "@angular-devkit/build-webpack": "0.1802.12", + "@angular-devkit/core": "18.2.12", + "@angular/build": "18.2.12", "@babel/core": "7.25.2", "@babel/generator": "7.25.0", "@babel/helper-annotate-as-pure": "7.24.7", @@ -87,7 +87,7 @@ "@babel/preset-env": "7.25.3", "@babel/runtime": "7.25.0", "@discoveryjs/json-ext": "0.6.1", - "@ngtools/webpack": "18.2.3", + "@ngtools/webpack": "18.2.12", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", @@ -98,7 +98,7 @@ "css-loader": "7.1.2", "esbuild-wasm": "0.23.0", "fast-glob": "3.3.2", - "http-proxy-middleware": "3.0.0", + "http-proxy-middleware": "3.0.3", "https-proxy-agent": "7.0.5", "istanbul-lib-instrument": "6.0.3", "jsonc-parser": "3.3.1", @@ -127,7 +127,7 @@ "terser": "5.31.6", "tree-kill": "1.2.2", "tslib": "2.6.3", - "vite": "5.4.0", + "vite": "5.4.6", "watchpack": "2.4.1", "webpack": "5.94.0", "webpack-dev-middleware": "7.4.2", @@ -246,12 +246,12 @@ "dev": true }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1802.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.3.tgz", - "integrity": "sha512-/Nixv9uAg6v/OPoZa0PB0zi+iezzBkgLrnrJnestny5B536l9WRtsw97RjeQDu+x2BClQsxNe8NL2A7EvjVD6w==", + "version": "0.1802.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.12.tgz", + "integrity": "sha512-0Z3fdbZVRnjYWE2/VYyfy+uieY+6YZyEp4ylzklVkc+fmLNsnz4Zw6cK1LzzcBqAwKIyh1IdW20Cg7o8b0sONA==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1802.3", + "@angular-devkit/architect": "0.1802.12", "rxjs": "7.8.1" }, "engines": { @@ -265,9 +265,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.3.tgz", - "integrity": "sha512-vbFs+ofNK9OWeMIcFarFjegXVklhtSdLTEFKZ9trDVr8alTJdjI9AiYa6OOUTDAyq0hqYxV26xlCisWAPe7s5w==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.12.tgz", + "integrity": "sha512-NtB6ypsaDyPE6/fqWOdfTmACs+yK5RqfH5tStEzWFeeDsIEDYKsJ06ypuRep7qTjYus5Rmttk0Ds+cFgz8JdUQ==", "dev": true, "dependencies": { "ajv": "8.17.1", @@ -321,12 +321,12 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.3.tgz", - "integrity": "sha512-N3tRAzBW2yWQhebvc1Ha18XTMSXOQTfr8HNjx7Fasx0Fg1tNyGR612MJNZw6je/PqyItKeUHOhztvFMfCQjRyg==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.12.tgz", + "integrity": "sha512-mMea9txHbnCX5lXLHlo0RAgfhFHDio45/jMsREM2PA8UtVf2S8ltXz7ZwUrUyMQRv8vaSfn4ijDstF4hDMnRgQ==", "dev": true, "dependencies": { - "@angular-devkit/core": "18.2.3", + "@angular-devkit/core": "18.2.12", "jsonc-parser": "3.3.1", "magic-string": "0.30.11", "ora": "5.4.1", @@ -339,9 +339,9 @@ } }, "node_modules/@angular/animations": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.3.tgz", - "integrity": "sha512-rIATopHr83lYR0X05buHeHssq9CGw0I0YPIQcpUTGnlqIpJcQVCf7jCFn4KGZrE9V55hFY3MD4S28njlwCToQQ==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.12.tgz", + "integrity": "sha512-XcWH/VFQ1Rddhdqi/iU8lW3Qg96yVx1NPfrO5lhcSSvVUzYWTZ5r+jh3GqYqUgPWyEp1Kpw3FLsOgVcGcBWQkQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -349,17 +349,17 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.2.3" + "@angular/core": "18.2.12" } }, "node_modules/@angular/build": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.3.tgz", - "integrity": "sha512-USrD2Zvcb1te2dnqhH7JZ5XeJDg/t7fjUHR4f93vvMrnrncwCjLoHbHpz01HCHfcIVRgsYUdAmAi1iG7vpak7w==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.12.tgz", + "integrity": "sha512-4Ohz+OSILoL+cCAQ4UTiCT5v6pctu3fXNoNpTEUK46OmxELk9jDITO5rNyNS7TxBn9wY69kjX5VcDf7MenquFQ==", "dev": true, "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.3", + "@angular-devkit/architect": "0.1802.12", "@babel/core": "7.25.2", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", @@ -378,10 +378,10 @@ "parse5-html-rewriting-stream": "7.0.0", "picomatch": "4.0.2", "piscina": "4.6.1", - "rollup": "4.20.0", + "rollup": "4.22.4", "sass": "1.77.6", "semver": "7.6.3", - "vite": "5.4.0", + "vite": "5.4.6", "watchpack": "2.4.1" }, "engines": { @@ -450,9 +450,9 @@ } }, "node_modules/@angular/cdk": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.3.tgz", - "integrity": "sha512-lUcpYTxPZuntJ1FK7V2ugapCGMIhT6TUDjIGgXfS9AxGSSKgwr8HNs6Ze9pcjYC44UhP40sYAZuiaFwmE60A2A==", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.13.tgz", + "integrity": "sha512-yBKoqcOwmwXnc5phFMEEMO130/Bz9beQLJrKzIS87f6TXaGCeBs4xrPHq2i7Xx/2TqvMiOD9ucjmlVbtGvNG3w==", "dependencies": { "tslib": "^2.3.0" }, @@ -466,17 +466,17 @@ } }, "node_modules/@angular/cli": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.3.tgz", - "integrity": "sha512-40258vuliH6+p8QSByZe5EcIXSj0iR3PNF6yuusClR/ByToHOnmuPw7WC+AYr0ooozmqlim/EjQe4/037OUB3w==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.12.tgz", + "integrity": "sha512-xhuZ/b7IhqNw1MgXf+arWf4x+GfUSt/IwbdWU4+CO8A7h0Y46zQywouP/KUK3cMQZfVdHdciTBvlpF3vFacA6Q==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1802.3", - "@angular-devkit/core": "18.2.3", - "@angular-devkit/schematics": "18.2.3", + "@angular-devkit/architect": "0.1802.12", + "@angular-devkit/core": "18.2.12", + "@angular-devkit/schematics": "18.2.12", "@inquirer/prompts": "5.3.8", "@listr2/prompt-adapter-inquirer": "2.0.15", - "@schematics/angular": "18.2.3", + "@schematics/angular": "18.2.12", "@yarnpkg/lockfile": "1.1.0", "ini": "4.1.3", "jsonc-parser": "3.3.1", @@ -499,9 +499,9 @@ } }, "node_modules/@angular/common": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.3.tgz", - "integrity": "sha512-NFL4yXXImSCH7i1xnHykUjHa9vl9827fGiwSV2mnf7LjSUsyDzFD8/54dNuYN9OY8AUD+PnK0YdNro6cczVyIA==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.12.tgz", + "integrity": "sha512-gI5o8Bccsi8ow8Wk2vG4Tw/Rw9LoHEA9j8+qHKNR/55SCBsz68Syg310dSyxy+sApJO2WiqIadr5VP36dlSUFw==", "dependencies": { "tslib": "^2.3.0" }, @@ -509,14 +509,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.2.3", + "@angular/core": "18.2.12", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.2.3.tgz", - "integrity": "sha512-Il3ljs0j1GaYoqYFdShjUP1ryck5xTOaA8uQuRgqwU0FOwEDfugSAM3Qf7nJx/sgxTM0Lm/Nrdv2u6i1gZWeuQ==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.2.12.tgz", + "integrity": "sha512-D5d5dLrjQal5DbAXJJNSsCC3UxzjOI2wbc+Iv+LOpRM1gpNwuYfZMX5W7cj62Ce4G2++78CJSppdKBp8D4HErQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -524,7 +524,7 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.2.3" + "@angular/core": "18.2.12" }, "peerDependenciesMeta": { "@angular/core": { @@ -533,14 +533,14 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.2.3.tgz", - "integrity": "sha512-BcmqYKnkcJTkGjuPztClZNQve7tdI290J5F3iZBx6c7/vaw8EU8EGZtpWYZpgiVn5S6jhcKyc1dLF9ggO9vftg==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.2.12.tgz", + "integrity": "sha512-IWimTNq5Q+i2Wxev6HLqnN4iYbPvLz04W1BBycT1LfGUsHcjFYLuUqbeUzHbk2snmBAzXkixgVpo8SF6P4Y5Pg==", "dev": true, "dependencies": { "@babel/core": "7.25.2", "@jridgewell/sourcemap-codec": "^1.4.14", - "chokidar": "^3.0.0", + "chokidar": "^4.0.0", "convert-source-map": "^1.5.1", "reflect-metadata": "^0.2.0", "semver": "^7.0.0", @@ -556,14 +556,42 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.2.3", + "@angular/compiler": "18.2.12", "typescript": ">=5.4 <5.6" } }, + "node_modules/@angular/compiler-cli/node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "dev": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular/compiler-cli/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular/core": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.3.tgz", - "integrity": "sha512-VGhMJxj7d0rYpqVfQrcGRB7EE/BCziotft/I/YPl6bOMPSAvMukG7DXQuJdYpNrr62ks78mlzHlZX/cdmB9Prw==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.12.tgz", + "integrity": "sha512-wCf/OObwS6bpM60rk6bpMpCRGp0DlMLB1WNAMtfcaPNyqimVV5Bm98mWRhkOuRyvU3fU7iHhM/10ePVaoyu9+A==", "dependencies": { "tslib": "^2.3.0" }, @@ -576,9 +604,9 @@ } }, "node_modules/@angular/forms": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.3.tgz", - "integrity": "sha512-+OBaAH0e8hue9eyLnbgpxg1/X9fps6bwXECfJ0nL5BDPU5itZ428YJbEnj5bTx0hEbqfTRiV4LgexdI+D9eOpw==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.12.tgz", + "integrity": "sha512-FsukBJEU6jfAmht7TrODTkct/o4iwCZvGozuThOp0tYUPD/E1rZZzuKjEyTnT5Azpfkf0Wqx1nmpz80cczELOQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -586,31 +614,31 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.2.3", - "@angular/core": "18.2.3", - "@angular/platform-browser": "18.2.3", + "@angular/common": "18.2.12", + "@angular/core": "18.2.12", + "@angular/platform-browser": "18.2.12", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.2.3.tgz", - "integrity": "sha512-bTZ1O7s0uJqKdd9ImCleRS9Wg6yVy2ZXchnS5ap2gYJx51MJgwOM/fL6is0OsovtZG/UJaKK5FeEqUUxNqZJVA==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.2.12.tgz", + "integrity": "sha512-oaiVAnGzmPZvrXdGh8XnosaqfEPbZxO2225MxbbrD49XTqUgpaS2zrz1Uf5j42e8qytA2kj8tckLq7PAMm0D1w==", "dev": true, "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0" } }, "node_modules/@angular/material": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.2.3.tgz", - "integrity": "sha512-JFfvXaMHMhskncaxxus4sDvie9VYdMkfYgfinkLXpZlPFyn1IzjDw0c1BcrcsuD7UxQVZ/v5tucCgq1FQfGRpA==", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.2.13.tgz", + "integrity": "sha512-Gxyyo6G+IXJwgf6zDTjPfFJ2PnjC2YXWKGkKKG2oR0jfiYiovDvNR4oXxhsztTwkaxLwck/gscoVTSQXMkU5fg==", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "^18.0.0 || ^19.0.0", - "@angular/cdk": "18.2.3", + "@angular/cdk": "18.2.13", "@angular/common": "^18.0.0 || ^19.0.0", "@angular/core": "^18.0.0 || ^19.0.0", "@angular/forms": "^18.0.0 || ^19.0.0", @@ -619,9 +647,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.3.tgz", - "integrity": "sha512-M2ob4zN7tAcL2mx7U6KnZNqNFPFl9MlPBE0FrjQjIzAjU0wSYPIJXmaPu9aMUp9niyo+He5iX98I+URi2Yc99g==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.12.tgz", + "integrity": "sha512-DRSMznuxuecrs+v5BRyd60/R4vjkQtuYUEPfzdo+rqxM83Dmr3PGtnqPRgd5oAFUbATxf02hQXijRD27K7rZRg==", "dependencies": { "tslib": "^2.3.0" }, @@ -629,9 +657,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "18.2.3", - "@angular/common": "18.2.3", - "@angular/core": "18.2.3" + "@angular/animations": "18.2.12", + "@angular/common": "18.2.12", + "@angular/core": "18.2.12" }, "peerDependenciesMeta": { "@angular/animations": { @@ -640,9 +668,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.2.3.tgz", - "integrity": "sha512-nWi9ZxN4KpbJkttIckFO1PCoW0+gb/18xFO+JWyLBAtcbsudj/Mv0P/fdOaSfQdLkPhZfORr3ZcfiTkhmuGyEg==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.2.12.tgz", + "integrity": "sha512-dv1QEjYpcFno6+oUeGEDRWpB5g2Ufb0XkUbLJQIgrOk1Qbyzb8tmpDpTjok8jcKdquigMRWolr6Y1EOicfRlLw==", "dependencies": { "tslib": "^2.3.0" }, @@ -650,16 +678,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.2.3", - "@angular/compiler": "18.2.3", - "@angular/core": "18.2.3", - "@angular/platform-browser": "18.2.3" + "@angular/common": "18.2.12", + "@angular/compiler": "18.2.12", + "@angular/core": "18.2.12", + "@angular/platform-browser": "18.2.12" } }, "node_modules/@angular/router": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.2.3.tgz", - "integrity": "sha512-fvD9eSDIiIbeYoUokoWkXzu7/ZaxlzKPUHFqX1JuKuH5ciQDeT/d7lp4mj31Bxammhohzi3+z12THJYsCkj/iQ==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.2.12.tgz", + "integrity": "sha512-cz/1YWOZadAT35PPPYmpK3HSzKOE56nlUHue5bFkw73VSZr2iBn03ALLpd9YKzWgRmx3y7DqnlQtCkDu9JPGKQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -667,9 +695,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.2.3", - "@angular/core": "18.2.3", - "@angular/platform-browser": "18.2.3", + "@angular/common": "18.2.12", + "@angular/core": "18.2.12", + "@angular/platform-browser": "18.2.12", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -3281,9 +3309,9 @@ } }, "node_modules/@jsonjoy.com/util": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", - "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.5.0.tgz", + "integrity": "sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==", "dev": true, "engines": { "node": ">=10.0" @@ -3474,9 +3502,9 @@ ] }, "node_modules/@ngtools/webpack": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.3.tgz", - "integrity": "sha512-DDuBHcu23qckt43SexBJaPEIeMc/HKaFOidILZM9D4gU4C9VroMActdR218dvQ802QfL0S46t5Ykz8ENprIfjA==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.12.tgz", + "integrity": "sha512-FFJAwtWbtpncMOVNuULPBwFJB7GSjiUwO93eGTzRp8O4EPQ8lCQeFbezQm/NP34+T0+GBLGzPSuQT+muob8YKw==", "dev": true, "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", @@ -3829,9 +3857,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", - "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz", + "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==", "cpu": [ "arm" ], @@ -3842,9 +3870,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", - "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz", + "integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==", "cpu": [ "arm64" ], @@ -3855,9 +3883,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", - "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz", + "integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==", "cpu": [ "arm64" ], @@ -3868,9 +3896,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", - "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz", + "integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==", "cpu": [ "x64" ], @@ -3881,9 +3909,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", - "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz", + "integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==", "cpu": [ "arm" ], @@ -3894,9 +3922,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", - "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz", + "integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==", "cpu": [ "arm" ], @@ -3907,9 +3935,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", - "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz", + "integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==", "cpu": [ "arm64" ], @@ -3920,9 +3948,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", - "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz", + "integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==", "cpu": [ "arm64" ], @@ -3933,9 +3961,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", - "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz", + "integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==", "cpu": [ "ppc64" ], @@ -3946,9 +3974,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", - "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz", + "integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==", "cpu": [ "riscv64" ], @@ -3959,9 +3987,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", - "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz", + "integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==", "cpu": [ "s390x" ], @@ -3972,9 +4000,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", - "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz", + "integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==", "cpu": [ "x64" ], @@ -3985,9 +4013,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", - "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz", + "integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==", "cpu": [ "x64" ], @@ -3998,9 +4026,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", - "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz", + "integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==", "cpu": [ "arm64" ], @@ -4011,9 +4039,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", - "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz", + "integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==", "cpu": [ "ia32" ], @@ -4024,9 +4052,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", - "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz", + "integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==", "cpu": [ "x64" ], @@ -4056,13 +4084,13 @@ } }, "node_modules/@schematics/angular": { - "version": "18.2.3", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.3.tgz", - "integrity": "sha512-whSON70z9HYb4WboVXmPFE/RLKJJQLWNzNcUyi8OSDZkQbJnYgPp0///n738m26Y/XeJDv11q1gESy+Zl2AdUw==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.12.tgz", + "integrity": "sha512-sIoeipsisK5eTLW3XuNZYcal83AfslBbgI7LnV+3VrXwpasKPGHwo2ZdwhCd2IXAkuJ02Iyu7MyV0aQRM9i/3g==", "dev": true, "dependencies": { - "@angular-devkit/core": "18.2.3", - "@angular-devkit/schematics": "18.2.3", + "@angular-devkit/core": "18.2.12", + "@angular-devkit/schematics": "18.2.12", "jsonc-parser": "3.3.1" }, "engines": { @@ -4257,9 +4285,21 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.1.tgz", + "integrity": "sha512-CRICJIl0N5cXDONAdlTv5ShATZ4HEwk6kDDIW2/w9qOWKg+NU/5F8wYRWCrONad0/UKkloNSmmyN/wX4rtpbVA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", "dev": true, "dependencies": { "@types/node": "*", @@ -4275,9 +4315,9 @@ "dev": true }, "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", "dev": true, "dependencies": { "@types/node": "*" @@ -4329,9 +4369,9 @@ } }, "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "version": "6.9.17", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", + "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", "dev": true }, "node_modules/@types/range-parser": { @@ -4398,9 +4438,9 @@ "dev": true }, "node_modules/@types/ws": { - "version": "8.5.12", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", - "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", "dev": true, "dependencies": { "@types/node": "*" @@ -4971,9 +5011,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -4984,7 +5024,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -5486,32 +5526,23 @@ } }, "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", "dev": true, "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", + "bytes": "3.1.2", + "compressible": "~2.0.18", "debug": "2.6.9", + "negotiator": "~0.6.4", "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", + "safe-buffer": "5.2.1", "vary": "~1.1.2" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/compression/node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/compression/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -5527,11 +5558,14 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -5606,9 +5640,9 @@ "dev": true }, "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "engines": { "node": ">= 0.6" @@ -5748,6 +5782,7 @@ "version": "0.0.24", "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.24.tgz", "integrity": "sha512-Oyqew0FGM0wYUSNqR0L6AteO5MpMoUU0rhKRieXeiKs+PmRTxiJMyaunYB2KF6fQ3dzChXKCpbFOEJx3OQ1v/Q==", + "deprecated": "Ownership of Critters has moved to the Nuxt team, who will be maintaining the project going forward. If you'd like to keep using Critters, please switch to the actively-maintained fork at https://github.com/danielroe/beasties", "dev": true, "dependencies": { "chalk": "^4.1.0", @@ -5934,12 +5969,12 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -6234,9 +6269,9 @@ } }, "node_modules/engine.io": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", - "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz", + "integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==", "dev": true, "dependencies": { "@types/cookie": "^0.4.1", @@ -6244,7 +6279,7 @@ "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", - "cookie": "~0.4.1", + "cookie": "~0.7.2", "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", @@ -6563,37 +6598,37 @@ "dev": true }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -6605,9 +6640,9 @@ } }, "node_modules/express/node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, "engines": { "node": ">= 0.6" @@ -6622,14 +6657,23 @@ "ms": "2.0.0" } }, + "node_modules/express/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/express/node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -7129,9 +7173,9 @@ } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, "engines": { "node": ">= 0.4" @@ -7339,22 +7383,31 @@ } }, "node_modules/http-proxy-middleware": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz", - "integrity": "sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz", + "integrity": "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==", "dev": true, "dependencies": { - "@types/http-proxy": "^1.17.10", - "debug": "^4.3.4", + "@types/http-proxy": "^1.17.15", + "debug": "^4.3.6", "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.5" + "is-glob": "^4.0.3", + "is-plain-object": "^5.0.0", + "micromatch": "^4.0.8" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/http-proxy-middleware/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", @@ -7951,9 +8004,9 @@ } }, "node_modules/jasmine-core": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.3.0.tgz", - "integrity": "sha512-zsOmeBKESky4toybvWEikRiZ0jHoBEu79wNArLfMdSnlLMZx3Xcp6CSm2sUcYyoJC+Uyj8LBJap/MUbVSfJ27g==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.4.0.tgz", + "integrity": "sha512-T4fio3W++llLd7LGSGsioriDHgWyhoL6YTu4k37uwJLF7DzOzspz7mNxRoM3cQdLWtL/ebazQpIf/yZGJx/gzg==", "dev": true }, "node_modules/jest-worker": { @@ -8992,9 +9045,9 @@ } }, "node_modules/memfs": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.11.1.tgz", - "integrity": "sha512-LZcMTBAgqUUKNXZagcZxvXXfgF1bHX7Y7nQ0QyEiNbRJgE29GhgPd8Yna1VQcLlPiHt/5RFJMWYN9Uv/VPNvjQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.14.0.tgz", + "integrity": "sha512-JUeY0F/fQZgIod31Ja1eJgiSxLn7BfQlCnqhwXFBzFHEw63OdLK7VJUJ7bnzNsWgCyoUP5tEp1VRY8rDaYzqOA==", "dev": true, "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", @@ -9011,10 +9064,13 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -9366,15 +9422,15 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "node_modules/msgpackr": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.0.tgz", - "integrity": "sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.2.tgz", + "integrity": "sha512-F9UngXRlPyWCDEASDpTf6c9uNhGPTqnTeLVt7bN+bU1eajoR/8V9ys2BRaV5C/e5ihE6sJ9uPIKaYt6bFuO32g==", "dev": true, "optionalDependencies": { "msgpackr-extract": "^3.0.2" @@ -9885,10 +9941,13 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -10056,9 +10115,9 @@ } }, "node_modules/ordered-binary": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", - "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.3.tgz", + "integrity": "sha512-oGFr3T+pYdTGJ+YFEILMpS3es+GiIbs9h/XQrclBXUtd44ey7XwfsMzM31f64I1SQOawDoDr/D823kNCADI8TA==", "dev": true }, "node_modules/os-tmpdir": { @@ -10113,9 +10172,9 @@ } }, "node_modules/p-retry": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", - "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", "dev": true, "dependencies": { "@types/retry": "0.12.2", @@ -10323,9 +10382,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", "dev": true }, "node_modules/path-type": { @@ -10341,9 +10400,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true }, "node_modules/picomatch": { @@ -10687,12 +10746,12 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -11045,9 +11104,9 @@ } }, "node_modules/rollup": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", - "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz", + "integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -11060,22 +11119,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.20.0", - "@rollup/rollup-android-arm64": "4.20.0", - "@rollup/rollup-darwin-arm64": "4.20.0", - "@rollup/rollup-darwin-x64": "4.20.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", - "@rollup/rollup-linux-arm-musleabihf": "4.20.0", - "@rollup/rollup-linux-arm64-gnu": "4.20.0", - "@rollup/rollup-linux-arm64-musl": "4.20.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", - "@rollup/rollup-linux-riscv64-gnu": "4.20.0", - "@rollup/rollup-linux-s390x-gnu": "4.20.0", - "@rollup/rollup-linux-x64-gnu": "4.20.0", - "@rollup/rollup-linux-x64-musl": "4.20.0", - "@rollup/rollup-win32-arm64-msvc": "4.20.0", - "@rollup/rollup-win32-ia32-msvc": "4.20.0", - "@rollup/rollup-win32-x64-msvc": "4.20.0", + "@rollup/rollup-android-arm-eabi": "4.22.4", + "@rollup/rollup-android-arm64": "4.22.4", + "@rollup/rollup-darwin-arm64": "4.22.4", + "@rollup/rollup-darwin-x64": "4.22.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.22.4", + "@rollup/rollup-linux-arm-musleabihf": "4.22.4", + "@rollup/rollup-linux-arm64-gnu": "4.22.4", + "@rollup/rollup-linux-arm64-musl": "4.22.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.22.4", + "@rollup/rollup-linux-riscv64-gnu": "4.22.4", + "@rollup/rollup-linux-s390x-gnu": "4.22.4", + "@rollup/rollup-linux-x64-gnu": "4.22.4", + "@rollup/rollup-linux-x64-musl": "4.22.4", + "@rollup/rollup-win32-arm64-msvc": "4.22.4", + "@rollup/rollup-win32-ia32-msvc": "4.22.4", + "@rollup/rollup-win32-x64-msvc": "4.22.4", "fsevents": "~2.3.2" } }, @@ -11263,9 +11322,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "dependencies": { "debug": "2.6.9", @@ -11313,12 +11372,6 @@ "node": ">=4" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/send/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -11407,20 +11460,29 @@ "dev": true }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -11487,14 +11549,18 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -11592,16 +11658,16 @@ } }, "node_modules/socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", "dev": true, "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", - "engine.io": "~6.5.2", + "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" }, @@ -11681,9 +11747,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12485,14 +12551,14 @@ } }, "node_modules/vite": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz", - "integrity": "sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz", + "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==", "dev": true, "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.40", - "rollup": "^4.13.0" + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" @@ -12949,6 +13015,34 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/vite/node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", @@ -13130,9 +13224,9 @@ } }, "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dev": true, "dependencies": { "@types/http-proxy": "^1.17.8", diff --git a/package.json b/package.json index fd36995..42333dd 100644 --- a/package.json +++ b/package.json @@ -10,26 +10,26 @@ }, "private": true, "dependencies": { - "@angular/animations": "^18.2.3", - "@angular/cdk": "^18.2.3", - "@angular/common": "^18.2.3", - "@angular/compiler": "^18.2.3", - "@angular/core": "^18.2.3", - "@angular/forms": "^18.2.3", - "@angular/material": "^18.2.3", - "@angular/platform-browser": "^18.2.3", - "@angular/platform-browser-dynamic": "^18.2.3", - "@angular/router": "^18.2.3", + "@angular/animations": "^18.2.12", + "@angular/cdk": "^18.2.13", + "@angular/common": "^18.2.12", + "@angular/compiler": "^18.2.12", + "@angular/core": "^18.2.12", + "@angular/forms": "^18.2.12", + "@angular/material": "^18.2.13", + "@angular/platform-browser": "^18.2.12", + "@angular/platform-browser-dynamic": "^18.2.12", + "@angular/router": "^18.2.12", "rxjs": "~7.8.1", "zone.js": "~0.14.10" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.2.3", - "@angular/cli": "^18.2.3", - "@angular/compiler-cli": "^18.2.3", - "@angular/language-service": "^18.2.3", + "@angular-devkit/build-angular": "^18.2.12", + "@angular/cli": "^18.2.12", + "@angular/compiler-cli": "^18.2.12", + "@angular/language-service": "^18.2.12", "@types/jasmine": "^5.1.4", - "jasmine-core": "^5.3.0", + "jasmine-core": "^5.4.0", "karma": "~6.4.4", "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.0", diff --git a/projects/ngx-progressbar-demo/src/app/app.component.ts b/projects/ngx-progressbar-demo/src/app/app.component.ts index 2e63176..e84bac0 100644 --- a/projects/ngx-progressbar-demo/src/app/app.component.ts +++ b/projects/ngx-progressbar-demo/src/app/app.component.ts @@ -8,7 +8,7 @@ import { HeaderComponent } from './header/header.component'; standalone: true, selector: 'app-root', templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'], + styleUrl: './app.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, imports: [RouterModule, HeaderComponent, NgProgressbar, NgProgressRouter] }) diff --git a/projects/ngx-progressbar-demo/src/app/custom/custom.component.html b/projects/ngx-progressbar-demo/src/app/custom/custom.component.html index 4fca3be..2514a2e 100644 --- a/projects/ngx-progressbar-demo/src/app/custom/custom.component.html +++ b/projects/ngx-progressbar-demo/src/app/custom/custom.component.html @@ -4,7 +4,7 @@
diff --git a/projects/ngx-progressbar-demo/src/app/custom/custom.component.ts b/projects/ngx-progressbar-demo/src/app/custom/custom.component.ts index 3466a4c..9aff044 100644 --- a/projects/ngx-progressbar-demo/src/app/custom/custom.component.ts +++ b/projects/ngx-progressbar-demo/src/app/custom/custom.component.ts @@ -11,13 +11,13 @@ import { NgProgressRef } from 'ngx-progressbar'; standalone: true, selector: 'app-custom', templateUrl: './custom.component.html', - styleUrls: ['./custom.component.scss'], + styleUrl: './custom.component.scss', animations: [ trigger('fadeInOut', [ state('false', style({ opacity: 0, visibility: 'hidden' })), transition('true => false', [ style({ opacity: 1, visibility: 'visible' }), - animate(280, style({ opacity: 0 })) + animate(50, style({ opacity: 0 })) ]) ]) ], diff --git a/projects/ngx-progressbar-demo/src/app/home/home.component.html b/projects/ngx-progressbar-demo/src/app/home/home.component.html index 1c741f6..6faf759 100644 --- a/projects/ngx-progressbar-demo/src/app/home/home.component.html +++ b/projects/ngx-progressbar-demo/src/app/home/home.component.html @@ -1,5 +1,5 @@
- + + fadeOutSpeed = + + debounceTime = diff --git a/projects/ngx-progressbar-demo/src/app/home/lab/lab.component.ts b/projects/ngx-progressbar-demo/src/app/home/lab/lab.component.ts index df4e32e..f2147ef 100644 --- a/projects/ngx-progressbar-demo/src/app/home/lab/lab.component.ts +++ b/projects/ngx-progressbar-demo/src/app/home/lab/lab.component.ts @@ -6,7 +6,7 @@ import { NgProgressOptions } from 'ngx-progressbar'; standalone: true, selector: 'app-lab', templateUrl: './lab.component.html', - styleUrls: ['./lab.component.scss'], + styleUrl: './lab.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, imports: [FormsModule] }) diff --git a/projects/ngx-progressbar/README.md b/projects/ngx-progressbar/README.md index 80c7ee6..a96b8e6 100644 --- a/projects/ngx-progressbar/README.md +++ b/projects/ngx-progressbar/README.md @@ -17,7 +17,17 @@ A nanoscopic progress bar. Featuring realistic trickle animations to convince yo ___ -### The documentation is available at the [wiki page](https://github.com/MurhafSousli/ngx-progressbar/wiki) 📚 +## Documentations + +### Table of contents + +* [Usage](docs/Usage.md) +* [Styling](docs/Styling.md) +* [Global Options](docs/Global-options.md) +* [Smooth Scroll Functions](docs/Integration.md) +* Automagic features + * [HttpClient Requests](docs/HttpClient-requests.md) + * [Router Events](docs/Router-events.md) ___ diff --git a/projects/ngx-progressbar/docs/Global-options.md b/projects/ngx-progressbar/docs/Global-options.md new file mode 100644 index 0000000..780a18b --- /dev/null +++ b/projects/ngx-progressbar/docs/Global-options.md @@ -0,0 +1,34 @@ +You can customize the default configuration for all progress bars using the `provideNgProgressOptions` function. + +**Example:** + +```ts +import { provideNgProgressOptions } from '@ngx-progressbar'; + +bootstrapApplication(AppComponent, { + providers: [ + provideNgProgressOptions({ + trickleSpeed: 200, + min: 20, + flat: true + }) + ] +}) +``` + +**NgProgressOptions API** + +| Name | Default | Description | +|---------------------|:--------:|------------------------------------------------------------| +| **direction** | ltr+ | *Progress bar direction (`ltr+`, `ltr-`, `rtl+`, `rtl-`).* | +| **trickleSpeed** | 300 | *Progress trickling speed in ms.* | +| **fadeOutSpeed** | 50 | *Progress fade out speed in ms.* | +| **trickleFunc** | Function | *A **function** that returns the trickling amount.* | +| **debounceTime** | 0 | *Debounce time before starting the progress bar in ms.* | +| **speed** | 200 | *Transition speed in ms.* | +| **min** | 8 | *Progress initial starting value.* | +| **max** | 100 | *Progress maximum value.* | +| **spinner** | false | *Display spinner.* | +| **spinnerPosition** | right | *Spinner position. (`right`, `left`).* | +| **relative** | false | *Position the progress bar relative to parent.* | +| **flat** | false | *Flat style (disables meteor style).* | diff --git a/projects/ngx-progressbar/docs/HttpClient-requests.md b/projects/ngx-progressbar/docs/HttpClient-requests.md new file mode 100644 index 0000000..0933951 --- /dev/null +++ b/projects/ngx-progressbar/docs/HttpClient-requests.md @@ -0,0 +1,140 @@ +The `ngProgressHttp` directive allows you to easily integrate the progress bar with your HTTP requests. + +### Usage + +To use the `ngProgressHttp` directive, simply add it to your component along with the `NgProgressbar` component: + +```typescript +import { Component } from '@angular/core'; +import { NgProgressbar } from 'ngx-progressbar'; +import { NgProgressHttp } from 'ngx-progressbar/http'; + +@Component({ + standalone: true, + selector: 'app-root', + imports: [NgProgressbar, NgProgressHttp], + template: ` + + ` +}) +export class AppComponent { +} +``` + +However, in order for the `ngProgressHttp` directive to work, you need to provide the `progressInterceptor` in your application's bootstrap process: + +```typescript +import { provideNgProgressHttp, progressInterceptor } from 'ngx-progressbar/http'; + +bootstrapApplication(AppComponent, { + providers: [ + provideHttpClient(withInterceptors([progressInterceptor])) + ] +}); +``` + +This interceptor is responsible for tracking the progress of your HTTP requests and updating the progress bar accordingly. + + +### Ignoring HTTP Requests + +There are three ways to ignore HTTP requests from being tracked by the progress bar: + +**1. Ignore a specific request**: +Use the `HttpHeaders` to add the `ignoreProgressBar` header to the request, and the progress bar will ignore that request. + +```typescript +const headers = new HttpHeaders({ ignoreProgressBar: '' }); +this.http.get('/api/tasks', { headers }).subscribe(...); +``` + +**2. Ignore requests to a specific API**: +You can configure the `NgProgressHttp` provider to ignore all requests to a specific API. + +**Example:** Ignore all requests to `https://api.domain.com` + +```typescript +import { provideNgProgressHttp, progressInterceptor } from 'ngx-progressbar/http'; + +bootstrapApplication(AppComponent, { + providers: [ + provideHttpClient(withInterceptors([progressInterceptor])), + provideNgProgressHttp({ + silentApis: ['https://api.domain.com'] + }) + ] +}); +``` + +**Example:** Ignore all requests that contain `users` in the API path + +```typescript +import { provideNgProgressHttp, progressInterceptor } from 'ngx-progressbar/http'; + +bootstrapApplication(AppComponent, { + providers: [ + provideHttpClient(withInterceptors([progressInterceptor])), + provideNgProgressHttp({ + silentApis: ['users'] + }) + ] +}); +``` + +**Result:** + +> https://prod.domain.com/users: Ignored +> https://example.com/users: Ignored +> https://domain.com/reviews: Not ignored + + +**3. Ignore requests using a regular expression**: +You can use a regular expression to specify which requests should be ignored by the progress bar. + +```typescript +import { provideNgProgressHttp, progressInterceptor } from 'ngx-progressbar/http'; + +bootstrapApplication(AppComponent, { + providers: [ + provideHttpClient(withInterceptors([progressInterceptor])), + provideNgProgressHttp({ + matcher: `https?:\\/\\/(\\S*\\.)?domain\\.com` + }) + ] +}); +``` + +**Result:** + +> https://api.domain.com/places: Ignored +> https://prod.domain.com/users: Ignored +> https://domain.com/reviews/v1/test: Ignored + +You can also use the `matcher` option in combination with the `silentApis` option to create more complex rules for ignoring requests. + +```typescript +import { provideNgProgressHttp, progressInterceptor } from 'ngx-progressbar/http'; + +bootstrapApplication(AppComponent, { + providers: [ + provideHttpClient(withInterceptors([progressInterceptor])), + provideNgProgressHttp({ + silentApis: ['v1', 'users'], + matcher: `https?:\\/\\/(\\S*\\.)?domain\\.com` + }) + ] +}); +``` + +**Result:** + +> https://api.domain.com/places: Not ignored +> https://prod.domain.com/users: Ignored +> https://domain.com/reviews/v1/test: Ignored + +### NgProgressHttp API + +| Name | Default | Description | +| ------------------ | :---------: | ---------------------------------------------------------- | +| **silentApis** | [ ] | *Array of silent APIs which will be ignored.* | +| **matcher** | undefined | *More flexible/permissive. subdomain.* | diff --git a/projects/ngx-progressbar/docs/Integration.md b/projects/ngx-progressbar/docs/Integration.md new file mode 100644 index 0000000..346543f --- /dev/null +++ b/projects/ngx-progressbar/docs/Integration.md @@ -0,0 +1,78 @@ +The `ngProgressRef` directive provides a way to integrate the progress bar with other UI components, such as material progress bars. + +### Examples + +#### Integrating with `` + +```html + + @if (progressRef.active()) { + + } + +``` + +This example shows the material progress bar only when the progress is active, and updates the value based on the progress. + +#### Integrating with `` with animation + +```html + +``` + +This example uses the `[@fadeInOut]` animation to show and hide the progress bar based on the active state. + +### `NgProgressRef` Directive API + +The `NgProgressRef` directive provides the following properties and methods: + +| Name | Default | Description | +|-----------------------|:--------:|------------------------------------------------------------| +| **[direction]** | ltr+ | *Progress bar direction (`ltr+`, `ltr-`, `rtl+`, `rtl-`).* | +| **[trickleSpeed]** | 300 | *Progress trickling speed in ms.* | +| **[fadeOutSpeed]** | 50 | *Progress fade out speed in ms.* | +| **[trickleFunc]** | Function | *A **function** that returns the trickling amount.* | +| **[debounceTime]** | 0 | *Debounce time before starting the progress bar in ms.* | +| **[speed]** | 200 | *Transition speed in ms.* | +| **[min]** | 8 | *Progress initial starting value.* | +| **[max]** | 100 | *Progress maximum value.* | +| **[spinner]** | false | *Display spinner.* | +| **[spinnerPosition]** | right | *Spinner position. (`right`, `left`).* | +| **[relative]** | false | *Position the progress bar relative to parent.* | +| **[flat]** | false | *Flat style (disables meteor style).* | +| **(started)** | - | *Stream that emits when the progress bar has started.* | +| **(completed)** | - | *Stream that emits when the progress bar has completed.* | +| **active** | - | *Signal that emits the active state.* | +| **progress** | - | *Signal that emits the progress.* | +| **start()** | - | *Starts the progress.* | +| **set(n)** | - | *Sets a percentage n (where n is between 0-100).* | +| **inc(n)** | - | *Increments by n (where n is between 0-100).* | +| **complete()** | - | *Completes the progress.* | + +### Automagic features + +The library provides two additional directives that can automatically integrate the progress bar with common use cases: + +1. `ngProgressHttp`: Starts and completes the progress bar when HTTP requests are made. + +```html + +``` + +2. `ngProgressRouter`: Starts and completes the progress bar when the router navigates. + +```html + + +``` + +These directives automatically handle the progress bar lifecycle, making it easy to integrate with common use cases. diff --git a/projects/ngx-progressbar/docs/Router-events.md b/projects/ngx-progressbar/docs/Router-events.md new file mode 100644 index 0000000..9928187 --- /dev/null +++ b/projects/ngx-progressbar/docs/Router-events.md @@ -0,0 +1,54 @@ +### Usage + +Use the directive `ngProgressRouter` to start and complete the progress bar with your router navigation. + +**Example:** + +```ts +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; +import { NgProgressbar } from 'ngx-progressbar'; +import { NgProgressRouter } from 'ngx-progressbar/router'; + +@Component({ + standalone: true, + selector: 'app-root', + imports: [NgProgressbar, NgProgressRouter, RouterOutlet], + template: ` + + + ` +}) +export class AppComponent { +} +``` + +### Custom router events + +```ts +import { GuardsCheckEnd, NavigationEnd } from '@angular/router'; +import { provideNgProgressRouter } from '@ngx-progressbar/router'; + +bootstrapApplication(AppComponent, { + providers: [ + provideNgProgressRouter({ + startEvents: [GuardsCheckEnd], + completeEvents: [NavigationEnd], + minDuration: 1000 + }) + ] +}) +``` + +> If Typescript complained about `startEvents` or `completeEvents` values with red underlines, don't worry it will compile just fine. optionally, you can use type assertion e.g. `completeEvents: [NavigationEnd] as Type[]`. + +### NgProgressRouter API + +| Name | Default | Description | +| ------------------ | :------------------------------------------------: |-------------------------------------------------------------------------------| +| **minDuration** | 0 | *The minimum duration (in ms) the progress bar should run before completing.* | +| **startEvents** | [NavigationStart] | *Router events that starts the progressbar.* | +| **completeEvents** | [NavigationEnd, NavigationCancel, NavigationError] | *Router events that completes the progressbar.* | + + +A list of available router events can be found [https://angular.dev/guide/routing/router-reference#router-events](https://angular.dev/guide/routing/router-reference#router-events) diff --git a/projects/ngx-progressbar/docs/Styling.md b/projects/ngx-progressbar/docs/Styling.md new file mode 100644 index 0000000..9c50dc1 --- /dev/null +++ b/projects/ngx-progressbar/docs/Styling.md @@ -0,0 +1,28 @@ +To customize the appearance of the progress bar, you can use the following CSS variables / classes + +### CSS variables + +| Variable name | Default value | +|-----------------------------------|:--------------| +| `--ng-progress-thickness` | 2 | +| `--ng-progress-color` | #1B95E0 | +| `--ng-progress-holder-color` | transparent | +| `--ng-progress-ease` | linear | +| `--ng-progress-spinner-thickness` | 2 | +| `--ng-progress-spinner-spacing` | 15 | +| `--ng-progress-spinner-size` | 18 | +| `--ng-progress-spinner-speed` | 250ms | + + +### CSS classes + +| Class name | Description | +|------------------------------|:----------------------------------------------------------------------------------------------| +| **.ng-progress-bar** | This class is applied to the host element of the progress bar. | +| **.ng-progress-bar-active** | This class is applied to the host element when the progress bar is running. | +| **.ng-progress-bar-wrapper** | This class is applied to the overall wrapper element that wraps the bar and the spinner. | +| **.ng-bar-placeholder** | This class is applied to the direct wrapper of the progress bar. | +| **.ng-bar** | This class is applied to the actual bar element that translates when the progress increments. | +| **.ng-spinner** | This class is applied to the spinner wrapper element. | +| **.ng-spinner-icon** | This class is applied to the spinner icon element. | + diff --git a/projects/ngx-progressbar/docs/Usage.md b/projects/ngx-progressbar/docs/Usage.md new file mode 100644 index 0000000..fed2387 --- /dev/null +++ b/projects/ngx-progressbar/docs/Usage.md @@ -0,0 +1,95 @@ +## Overview + +The progress bar component library provides a simple and customizable way to add progress bars to your application. The library includes the `NgProgressbar` component, which can be used to display a progress bar in your application. + +## Installation + +To use the progress bar component library, you will need to install the `ngx-progressbar` package. You can do this using npm or yarn: + +``` +npm install ngx-progressbar +``` + +## Usage + +### Accessing the Progress Bar Directly from the Template + +To add a progress bar to your template and access it directly, use the `` component and a template reference variable: + +```html + + + + +``` + +### Accessing the Progress Bar from the Component Code + +Alternatively, you can add the progress bar and access the instance using the `@ViewChild` decorator: + +```typescript +import { NgProgressbar } from 'ngx-progressbar'; + +@Component({ + standalone: true, + selector: 'app-home', + imports: [NgProgressbar], + template: ` + + ` +}) +export class HomeComponent { + progressBar: Signal = viewChild(NgProgressRef); + + start() { + this.progressBar().start(); + } +} +``` + +### NgProgress Component API + +| Name | Default | Description | +|-----------------------|:--------:|------------------------------------------------------------| +| **[direction]** | ltr+ | *Progress bar direction (`ltr+`, `ltr-`, `rtl+`, `rtl-`).* | +| **[trickleSpeed]** | 300 | *Progress trickling speed in ms.* | +| **[fadeOutSpeed]** | 50 | *Progress fade out speed in ms.* | +| **[trickleFunc]** | Function | *A **function** that returns the trickling amount.* | +| **[debounceTime]** | 0 | *Debounce time before starting the progress bar in ms.* | +| **[speed]** | 200 | *Transition speed in ms.* | +| **[min]** | 8 | *Progress initial starting value.* | +| **[max]** | 100 | *Progress maximum value.* | +| **[spinner]** | false | *Display spinner.* | +| **[spinnerPosition]** | right | *Spinner position. (`right`, `left`).* | +| **[relative]** | false | *Position the progress bar relative to parent.* | +| **[flat]** | false | *Flat style (disables meteor style).* | +| **(started)** | - | *Stream that emits when the progress bar has started.* | +| **(completed)** | - | *Stream that emits when the progress bar has completed.* | +| **progressRef** | - | *`NgProgressRef` instance of the progress bar.* | + + +Here is an example of how to use the `` component with some of the available options: + +```html + +``` + +## Automagic features + +#### Use `ngProgressHttp` directive to start/complete the progress bar with http requests. + +```html + +``` + +> More info on customizing `ngProgressHttp` can be found in [http requests guide](./HttpClient-requests.md). + +#### Use `ngProgressRouter` to start/complete the progress bar with router events. + +```html + +``` + +> More info on customizing `ngProgressRouter` can be found in [router events guide](./Router-events.md). diff --git a/projects/ngx-progressbar/http/src/ng-progress-http.directive.ts b/projects/ngx-progressbar/http/src/ng-progress-http.directive.ts index a86c99a..f799d69 100644 --- a/projects/ngx-progressbar/http/src/ng-progress-http.directive.ts +++ b/projects/ngx-progressbar/http/src/ng-progress-http.directive.ts @@ -10,8 +10,15 @@ class NgProgressHttpBase { private readonly progressRef: NgProgressRef = inject(NgProgressRef, { host: true, self: true }); constructor() { + let initial: boolean = true; effect(() => { const requestLoading: boolean = this.manager.requestsLoading(); + // Ignore the initial execution if loading state is false + if (initial) { + initial = false; + if (!requestLoading) return; + } + untracked(() => { if (requestLoading) { this.progressRef.start(); diff --git a/projects/ngx-progressbar/ng-package.json b/projects/ngx-progressbar/ng-package.json index 3bc8379..b81bbc9 100644 --- a/projects/ngx-progressbar/ng-package.json +++ b/projects/ngx-progressbar/ng-package.json @@ -1,7 +1,10 @@ { "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", "dest": "../../dist/ngx-progressbar", + "assets": [ + "docs/*.md" + ], "lib": { "entryFile": "src/public-api.ts" } -} \ No newline at end of file +} diff --git a/projects/ngx-progressbar/package.json b/projects/ngx-progressbar/package.json index 7cdaf7b..65bed7b 100644 --- a/projects/ngx-progressbar/package.json +++ b/projects/ngx-progressbar/package.json @@ -1,6 +1,6 @@ { "name": "ngx-progressbar", - "version": "12.0.2", + "version": "13.0.0", "author": { "name": "Murhaf Sousli", "url": "https://github.com/MurhafSousli", diff --git a/projects/ngx-progressbar/router/src/ng-progress-router.directive.ts b/projects/ngx-progressbar/router/src/ng-progress-router.directive.ts index 1ad5f41..5472aa2 100644 --- a/projects/ngx-progressbar/router/src/ng-progress-router.directive.ts +++ b/projects/ngx-progressbar/router/src/ng-progress-router.directive.ts @@ -1,6 +1,7 @@ -import { Directive, inject, Type, OnInit, OnDestroy } from '@angular/core'; +import { Directive, inject, Type, effect, untracked, Signal, EffectCleanupRegisterFn } from '@angular/core'; import { Event, Router } from '@angular/router'; -import { Observable, Subscription, of, delay, filter, switchMap, tap } from 'rxjs'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { filter, map } from 'rxjs'; import { NgProgressRef } from 'ngx-progressbar'; import { NG_PROGRESS_ROUTER_OPTIONS, NgProgressRouterOptions } from './ng-progress-router.model'; @@ -12,36 +13,38 @@ function eventExists(routerEvent: Event, events: Type[]): boolean { } @Directive() -class NgProgressRouterBase implements OnInit, OnDestroy { - - private subscription: Subscription; +class NgProgressRouterBase { private readonly router: Router = inject(Router); - readonly progressRef: NgProgressRef = inject(NgProgressRef, { host: true, self: true }); - private readonly config: NgProgressRouterOptions = inject(NG_PROGRESS_ROUTER_OPTIONS); - ngOnInit(): void { - const startProgress: Observable = of({}).pipe( - tap(() => this.progressRef.start()) - ); + readonly progressRef: NgProgressRef = inject(NgProgressRef, { host: true, self: true }); - const completeProgress: Observable = of({}).pipe( - delay(this.config.minDuration), - tap(() => this.progressRef.complete()) - ); + private readonly routerToggleEvent: Signal = toSignal( + this.router.events.pipe( + filter((event: Event) => eventExists(event, [...this.config.startEvents, ...this.config.completeEvents])), + map((event: Event) => eventExists(event, this.config.startEvents)) + ) + ); - const filterEvents: Type[] = [...this.config.startEvents, ...this.config.completeEvents]; + constructor() { + effect((onCleanup: EffectCleanupRegisterFn) => { + const toggle: boolean = this.routerToggleEvent(); + let completeTimeout: ReturnType; - this.subscription = this.router.events.pipe( - filter((event: Event) => eventExists(event, filterEvents)), - switchMap((event: Event) => eventExists(event, this.config.startEvents) ? startProgress : completeProgress) - ).subscribe(); - } + untracked(() => { + if (toggle) { + this.progressRef.start(); + } else { + completeTimeout = setTimeout(() => { + this.progressRef.complete(); + }, this.config.minDuration); + } - ngOnDestroy(): void { - this.subscription?.unsubscribe(); + onCleanup(() => clearTimeout(completeTimeout)); + }); + }); } } diff --git a/projects/ngx-progressbar/src/lib/ng-progress-default.ts b/projects/ngx-progressbar/src/lib/ng-progress-default.ts index 9cc5237..d55391f 100644 --- a/projects/ngx-progressbar/src/lib/ng-progress-default.ts +++ b/projects/ngx-progressbar/src/lib/ng-progress-default.ts @@ -6,6 +6,7 @@ export const defaultOptions: NgProgressOptions = { speed: 200, debounceTime: 0, trickleSpeed: 300, + fadeOutSpeed: 50, relative: false, flat: false, spinner: false, diff --git a/projects/ngx-progressbar/src/lib/ng-progress-ref.ts b/projects/ngx-progressbar/src/lib/ng-progress-ref.ts index f6cf91f..303e4b3 100644 --- a/projects/ngx-progressbar/src/lib/ng-progress-ref.ts +++ b/projects/ngx-progressbar/src/lib/ng-progress-ref.ts @@ -3,33 +3,50 @@ import { inject, signal, effect, + output, computed, untracked, + numberAttribute, + input, Signal, + InputSignal, WritableSignal, - EffectCleanupRegisterFn + OutputEmitterRef, + EffectCleanupRegisterFn, + InputSignalWithTransform } from '@angular/core'; +import { outputToObservable } from '@angular/core/rxjs-interop'; import { Observable, - Subject, Subscription, BehaviorSubject, of, tap, delay, timer, - switchMap, + filter, finalize, + switchMap, takeUntil, EMPTY } from 'rxjs'; -import { NgProgressOptions, NG_PROGRESS_OPTIONS } from './ng-progress.model'; +import { NgProgressOptions, NG_PROGRESS_OPTIONS, NgProgressRefOptions } from './ng-progress.model'; enum TriggerType { START = 'START', COMPLETE = 'COMPLETE' } +function minAttribute(value: string | number): number { + const min: number = numberAttribute(value) || 0; + return (min < 100 && min >= 0) ? min : 0; +} + +function maxAttribute(value: string | number): number { + const max: number = numberAttribute(value) || 100; + return (max > 0 && max <= 100) ? max : 100; +} + @Directive({ standalone: true, selector: '[ngProgressRef]', @@ -37,7 +54,27 @@ enum TriggerType { }) export class NgProgressRef { - private readonly _config: WritableSignal = signal(inject(NG_PROGRESS_OPTIONS)); + private readonly defaultOptions: NgProgressOptions = inject(NG_PROGRESS_OPTIONS); + + min: InputSignalWithTransform = input(this.defaultOptions.min, { transform: minAttribute }); + max: InputSignalWithTransform = input(this.defaultOptions.max, { transform: maxAttribute }); + speed: InputSignalWithTransform = input(this.defaultOptions.speed, { transform: numberAttribute }); + trickleSpeed: InputSignalWithTransform = input(this.defaultOptions.trickleSpeed, { transform: numberAttribute }); + fadeOutSpeed: InputSignalWithTransform = input(this.defaultOptions.fadeOutSpeed, { transform: numberAttribute }); + debounceTime: InputSignalWithTransform = input(this.defaultOptions.debounceTime, { transform: numberAttribute }); + trickleFunc: InputSignal<(n: number) => number> = input(this.defaultOptions.trickleFunc); + + config: Signal = computed(() => { + return { + max: this.max(), + min: this.min(), + speed: this.speed(), + trickleSpeed: this.trickleSpeed(), + fadeOutSpeed: this.fadeOutSpeed(), + trickleFunc: this.trickleFunc(), + debounceTime: this.debounceTime() + } + }); private _progress: WritableSignal = signal(0); @@ -47,17 +84,13 @@ export class NgProgressRef { progress: Signal = computed(() => this._progress()); - config: Signal = computed(() => this._config()); - - private _trigger: BehaviorSubject = new BehaviorSubject(null); - // Progress start source event (used to cancel onComplete delays) - private readonly _started: Subject = new Subject(); - readonly started: Observable = this._started.asObservable(); + started: OutputEmitterRef = output(); // Progress ended source event - private readonly _completed: Subject = new Subject(); - readonly completed: Observable = this._completed.asObservable(); + completed: OutputEmitterRef = output(); + + private _trigger: BehaviorSubject = new BehaviorSubject(null); constructor() { let sub$: Subscription; @@ -65,23 +98,20 @@ export class NgProgressRef { const config: NgProgressOptions = this.config(); untracked(() => { - sub$?.unsubscribe(); - sub$ = this._trigger.pipe( + filter((trigger: TriggerType) => !!trigger), switchMap((trigger: TriggerType) => { if (trigger === TriggerType.START) { return timer(config.debounceTime).pipe( switchMap(() => this.onTrickling(config)) ); - } else if (trigger === TriggerType.COMPLETE) { - return this.onComplete(config); } - return EMPTY; + return this.onComplete(config); }) ).subscribe(); - }) - onCleanup(() => sub$?.unsubscribe()); + onCleanup(() => sub$?.unsubscribe()); + }); }); } @@ -89,7 +119,7 @@ export class NgProgressRef { * Start the progress */ start(): void { - this._started.next(); + this.started.emit(); this._trigger.next(TriggerType.START); this._active.set(true); } @@ -124,13 +154,6 @@ export class NgProgressRef { this._progress.set(this.clamp(n)); } - /** - * Set config - */ - setConfig(config: NgProgressOptions): void { - this._config.set({ ...this.config(), ...config }); - } - /** * Clamps a value to be between min and max */ @@ -152,27 +175,27 @@ export class NgProgressRef { * Completes then resets the progress */ private onComplete(config: NgProgressOptions): Observable { + // If it's not active no need to complete if (!this.active()) { return EMPTY; } // Emit completed - this._completed.next(); + this.completed.emit(); return of({}).pipe( // Complete the progress tap(() => this._progress.set(100)), - // Deactivate the progress after a tiny delay - delay(config.speed * 1.7), + delay(config.speed + 140), tap(() => this._active.set(false)), // Use a tiny delay before resetting - delay(config.speed), + delay(config.fadeOutSpeed), // Force the progress to reset even it got cancelled finalize(() => this._progress.set(0)), // Cancel any of the finalizing delays if the progress has started again - takeUntil(this._started) + takeUntil(outputToObservable(this.started)) ); } } diff --git a/projects/ngx-progressbar/src/lib/ng-progress.component.scss b/projects/ngx-progressbar/src/lib/ng-progress.component.scss index 4b2dd3c..5b32477 100644 --- a/projects/ngx-progressbar/src/lib/ng-progress.component.scss +++ b/projects/ngx-progressbar/src/lib/ng-progress.component.scss @@ -18,6 +18,8 @@ --_ng-progress-spinner-size: var(--ng-progress-spinner-size, 18); --_ng-progress-spinner-size-px: calc(var(--_ng-progress-spinner-size) * 1px); + --_ng-progress-spinner-speed: var(--ng-progress-spinner-speed, 250ms); + z-index: 999999; pointer-events: none; @@ -104,7 +106,7 @@ transform: scale(1); filter: alpha(opacity=0); opacity: 0; - transition: opacity var(--_ng-progress-speed) var(--_ng-progress-ease); + transition: opacity var(--_ng-progress-fade-out-speed) linear; } .ng-bar-placeholder { @@ -118,7 +120,6 @@ height: 100%; transform: translate(-100%, 0, 0); background: var(--_ng-progress-color); - transition: all var(--_ng-progress-speed) var(--_ng-progress-ease); } .ng-meteor { @@ -139,7 +140,7 @@ .ng-spinner-icon { box-sizing: border-box; - animation: spinner-animation 250ms linear infinite; + animation: spinner-animation var(--_ng-progress-spinner-speed) linear infinite; border-style: solid; border-color: transparent; border-radius: 50%; diff --git a/projects/ngx-progressbar/src/lib/ng-progress.component.ts b/projects/ngx-progressbar/src/lib/ng-progress.component.ts index b8370ab..84e2351 100644 --- a/projects/ngx-progressbar/src/lib/ng-progress.component.ts +++ b/projects/ngx-progressbar/src/lib/ng-progress.component.ts @@ -1,19 +1,14 @@ import { Component, inject, - effect, computed, - untracked, - numberAttribute, booleanAttribute, input, Signal, InputSignal, - OutputRef, ChangeDetectionStrategy, InputSignalWithTransform } from '@angular/core'; -import { outputFromObservable } from '@angular/core/rxjs-interop'; import { NgProgressRef } from './ng-progress-ref'; import { NG_PROGRESS_OPTIONS, NgProgressOptions } from './ng-progress.model'; @@ -28,8 +23,14 @@ import { NG_PROGRESS_OPTIONS, NgProgressOptions } from './ng-progress.model'; '[class.ng-progress-bar-relative]': 'relative()', '[attr.spinnerPosition]': 'spinnerPosition()', '[attr.direction]': 'direction()', - '[style.--_ng-progress-speed]': 'this.speed() + "ms"' + '[style.--_ng-progress-speed]': 'progressRef.speed() + "ms"', + '[style.--_ng-progress-fade-out-speed]': 'progressRef.fadeOutSpeed() + "ms"' }, + hostDirectives: [{ + directive: NgProgressRef, + inputs: ['min', 'max', 'speed', 'trickleSpeed', 'fadeOutSpeed', 'debounceTime'], + outputs: ['started', 'completed'] + }], template: `
@@ -46,7 +47,6 @@ import { NG_PROGRESS_OPTIONS, NgProgressOptions } from './ng-progress.model'; }
`, - providers: [NgProgressRef], styleUrl: './ng-progress.component.scss', changeDetection: ChangeDetectionStrategy.OnPush }) @@ -57,57 +57,13 @@ export class NgProgressbar { /** Progress bar worker */ progressRef: NgProgressRef = inject(NgProgressRef, { host: true, self: true }); - /** Initializes inputs from the global config */ - min: InputSignalWithTransform = input(this.config.min, { transform: numberAttribute }); - max: InputSignalWithTransform = input(this.config.max, { transform: numberAttribute }); - speed: InputSignalWithTransform = input(this.config.speed, { transform: numberAttribute }); - trickleSpeed: InputSignalWithTransform = input(this.config.trickleSpeed, { transform: numberAttribute }); - debounceTime: InputSignalWithTransform = input(this.config.debounceTime, { transform: numberAttribute }); - flat: InputSignalWithTransform = input(this.config.flat, { transform: booleanAttribute }); spinner: InputSignalWithTransform = input(this.config.spinner, { transform: booleanAttribute }); relative: InputSignalWithTransform = input(this.config.relative, { transform: booleanAttribute }); - - trickleFunc: InputSignal<(n: number) => number> = input(this.config.trickleFunc); - spinnerPosition: InputSignal<'left' | 'right'> = input(this.config.spinnerPosition); - direction: InputSignal<'ltr+' | 'ltr-' | 'rtl+' | 'rtl-'> = input(this.config.direction); + spinnerPosition: InputSignal<'left' | 'right'> = input<'left' | 'right'>(this.config.spinnerPosition); + direction: InputSignal<'ltr+' | 'ltr-' | 'rtl+' | 'rtl-'> = input<'ltr+' | 'ltr-' | 'rtl+' | 'rtl-'>(this.config.direction); progressTransform: Signal = computed(() => { return `translate3d(${ this.progressRef.progress() }%,0,0)`; }); - - started: OutputRef = outputFromObservable(this.progressRef.started); - - completed: OutputRef = outputFromObservable(this.progressRef.completed); - - constructor() { - effect(() => { - const config: NgProgressOptions = { - max: (this.max() > 0 && this.max() <= 100) ? this.max() : 100, - min: (this.min() < 100 && this.min() >= 0) ? this.min() : 0, - speed: this.speed(), - trickleSpeed: this.trickleSpeed(), - trickleFunc: this.trickleFunc(), - debounceTime: this.debounceTime() - }; - // Update progress bar config when inputs change - untracked(() => this.progressRef.setConfig(config)); - }); - } - - start(): void { - this.progressRef.start(); - } - - complete(): void { - this.progressRef.complete(); - } - - inc(n?: number): void { - this.progressRef.inc(n); - } - - set(n: number): void { - this.progressRef.set(n); - } } diff --git a/projects/ngx-progressbar/src/lib/ng-progress.model.ts b/projects/ngx-progressbar/src/lib/ng-progress.model.ts index 02c490d..665f134 100644 --- a/projects/ngx-progressbar/src/lib/ng-progress.model.ts +++ b/projects/ngx-progressbar/src/lib/ng-progress.model.ts @@ -1,20 +1,24 @@ import { InjectionToken, Provider } from '@angular/core'; import { defaultOptions } from './ng-progress-default'; -export interface NgProgressOptions { - spinnerPosition?: 'left' | 'right'; - direction?: 'ltr+' | 'ltr-' | 'rtl+' | 'rtl-'; - relative?: boolean; - flat?: boolean; - spinner?: boolean; +export interface NgProgressRefOptions { max?: number; min?: number; speed?: number; trickleSpeed?: number; + fadeOutSpeed?: number; trickleFunc?: (n: number) => number; debounceTime?: number; } +export type NgProgressOptions = NgProgressRefOptions & { + spinnerPosition?: 'left' | 'right'; + direction?: 'ltr+' | 'ltr-' | 'rtl+' | 'rtl-'; + relative?: boolean; + flat?: boolean; + spinner?: boolean; +} + export const NG_PROGRESS_OPTIONS: InjectionToken = new InjectionToken('NG_PROGRESS_OPTIONS', { providedIn: 'root', factory: () => defaultOptions diff --git a/projects/ngx-progressbar/src/lib/tests/ng-progress-ref.spec.ts b/projects/ngx-progressbar/src/lib/tests/ng-progress-ref.spec.ts index b6df79d..a2103ac 100644 --- a/projects/ngx-progressbar/src/lib/tests/ng-progress-ref.spec.ts +++ b/projects/ngx-progressbar/src/lib/tests/ng-progress-ref.spec.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { By } from '@angular/platform-browser'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { NgProgressOptions, NgProgressRef } from 'ngx-progressbar'; +import { NgProgressRef } from 'ngx-progressbar'; import { defaultOptions } from '../ng-progress-default'; export async function afterTimeout(timeout: number): Promise { @@ -14,7 +14,7 @@ describe('NgProgressRef', () => { let fixture: ComponentFixture; beforeEach(async () => { - await TestBed.configureTestingModule({ + TestBed.configureTestingModule({ imports: [TestComponent] }); @@ -23,7 +23,15 @@ describe('NgProgressRef', () => { }); it('should initialize with the default config', () => { - expect(directive.config()).toEqual(defaultOptions); + expect(directive.config()).toEqual({ + max: defaultOptions.max, + min: defaultOptions.min, + speed: defaultOptions.speed, + trickleSpeed: defaultOptions.trickleSpeed, + fadeOutSpeed: defaultOptions.fadeOutSpeed, + trickleFunc: defaultOptions.trickleFunc, + debounceTime: defaultOptions.debounceTime + }); }); it('should start and complete the progress', async () => { @@ -101,26 +109,73 @@ describe('NgProgressRef', () => { expect(completedEmitted).toBeTrue(); }); - it('should update the config', () => { - const newConfig: NgProgressOptions = { ...defaultOptions, min: 20, max: 80 }; - directive.setConfig(newConfig); - expect(directive.config()).toEqual(newConfig); - }); - it('should not do anything if complete() is called when progress has not started', () => { const completeSpy: jasmine.Spy = spyOn(directive, 'complete').and.callThrough(); directive.complete(); fixture.detectChanges(); expect(completeSpy).toHaveBeenCalled(); }); + + it('should set minimum value to 0 when given a value smaller than 0', async () => { + fixture.componentInstance.min = -10; + fixture.detectChanges(); + await afterTimeout(20); + expect(directive.min()).toBe(0); + }); + + it('should set maximum value to 100 when given a value greater than 100', async () => { + fixture.componentInstance.max = 200; + fixture.detectChanges(); + await afterTimeout(20); + expect(directive.max()).toBe(100); + }); + + it('should start/complete the progress using the start/complete functions', (done: DoneFn) => { + const startSpy: jasmine.Spy = spyOn(directive, 'start'); + const completeSpy: jasmine.Spy = spyOn(directive, 'complete'); + + directive.start(); + expect(startSpy).toHaveBeenCalled(); + + setTimeout(() => { + directive.complete(); + expect(completeSpy).toHaveBeenCalled(); + done(); + }, 200); + }); + + it('should active signal when progress is started', (done: DoneFn) => { + directive.start(); + + setTimeout(() => { + expect(directive.active()).toBeTrue(); + done(); + }, 50); + }); + + it('should increment the progress using inc function', () => { + const incSpy: jasmine.Spy = spyOn(directive, 'inc'); + + directive.inc(20); + expect(incSpy).toHaveBeenCalledWith(20); + }); + + it('should increment the progress using set function', () => { + const setSpy: jasmine.Spy = spyOn(directive, 'set'); + + directive.set(50); + expect(setSpy).toHaveBeenCalledWith(50); + }); }); @Component({ standalone: true, imports: [NgProgressRef], template: ` -
+
` }) class TestComponent { + min: number; + max: number; } diff --git a/projects/ngx-progressbar/src/lib/tests/ng-progress-router.spec.ts b/projects/ngx-progressbar/src/lib/tests/ng-progress-router.spec.ts index fb3ef17..3542f5c 100644 --- a/projects/ngx-progressbar/src/lib/tests/ng-progress-router.spec.ts +++ b/projects/ngx-progressbar/src/lib/tests/ng-progress-router.spec.ts @@ -67,7 +67,7 @@ describe(`NgProgressRouter`, () => { const startSpy: jasmine.Spy = spyOn(progressRef, 'start'); const completeSpy: jasmine.Spy = spyOn(progressRef, 'complete'); - progressRouter.ngOnInit(); + fixture.detectChanges(); router.navigate(['page2']).then(() => { fixture.detectChanges(); @@ -77,6 +77,9 @@ describe(`NgProgressRouter`, () => { }, CUSTOM_PROGRESS_DELAY); }); - expect(startSpy).toHaveBeenCalled(); + // Need a tiny delay to catch the start call + setTimeout(() => { + expect(startSpy).toHaveBeenCalled(); + }); }); }); diff --git a/projects/ngx-progressbar/src/lib/tests/ng-progress.component.spec.ts b/projects/ngx-progressbar/src/lib/tests/ng-progress.component.spec.ts index a461043..14c7375 100644 --- a/projects/ngx-progressbar/src/lib/tests/ng-progress.component.spec.ts +++ b/projects/ngx-progressbar/src/lib/tests/ng-progress.component.spec.ts @@ -1,14 +1,13 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NgProgressbar, NgProgressRef } from 'ngx-progressbar'; -import { afterTimeout } from './ng-progress-ref.spec'; describe('NgProgress Component', () => { let fixture: ComponentFixture; let component: NgProgressbar; let progressRef: NgProgressRef; - beforeEach(async () => { - await TestBed.configureTestingModule({ + beforeEach(() => { + TestBed.configureTestingModule({ imports: [NgProgressbar] }); @@ -19,56 +18,6 @@ describe('NgProgress Component', () => { it('should create a progress bar', () => { expect(component).toBeDefined(); - }); - - it('should set minimum value to 0 when given a value smaller than 0', async () => { - fixture.componentRef.setInput('min', -10); - fixture.detectChanges(); - await afterTimeout(20); - expect(component.progressRef.config().min).toBe(0); - }); - - it('should set maximum value to 100 when given a value greater than 100', async () => { - fixture.componentRef.setInput('max', 200); - fixture.detectChanges(); - await afterTimeout(20); - expect(component.progressRef.config().max).toBe(100); - }); - - it('should start/complete the progress using the start/complete functions', (done: DoneFn) => { - const startSpy: jasmine.Spy = spyOn(progressRef, 'start'); - const completeSpy: jasmine.Spy = spyOn(progressRef, 'complete'); - - component.start(); - expect(startSpy).toHaveBeenCalled(); - - setTimeout(() => { - component.complete(); - expect(completeSpy).toHaveBeenCalled(); - done(); - }, 200); - }); - - it('should active signal when progress is started', (done: DoneFn) => { - component.start(); - - setTimeout(() => { - expect(progressRef.active()).toBeTrue(); - done(); - }, 50); - }); - - it('should increment the progress using inc function', () => { - const incSpy: jasmine.Spy = spyOn(progressRef, 'inc'); - - component.inc(20); - expect(incSpy).toHaveBeenCalledWith(20); - }); - - it('should increment the progress using set function', () => { - const setSpy: jasmine.Spy = spyOn(progressRef, 'set'); - - component.set(50); - expect(setSpy).toHaveBeenCalledWith(50); + expect(progressRef).toBeDefined(); }); });