diff --git a/.storybook/msw/handlers.ts b/.storybook/msw/handlers.ts index 59b1ff4934..5ce2275d5a 100644 --- a/.storybook/msw/handlers.ts +++ b/.storybook/msw/handlers.ts @@ -7,12 +7,12 @@ const usersSearchHandler = genericHandler( // Get and parse params from query params { paging: (p) => p, - search: (search) => search.toLowerCase(), + clue: (clue) => clue.toLowerCase(), id: (ids) => ids.split(',').map((id) => parseInt(id)), }, { // Apply filters to items - search: applyFilter((user, { search }) => `${user.firstName} ${user.lastName}`.includes(search)), + clue: applyFilter((user, { clue }) => `${user.firstName.toLowerCase()} ${user.lastName.toLowerCase()}`.includes(clue)), id: applyFilter((user, { id }) => id.includes(user.id)), // Then paging/limiting paging: applyV3Paging, diff --git a/.vscode/settings.json b/.vscode/settings.json index db5719c6a7..d8642b0e73 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -41,4 +41,4 @@ "source.fixAll.markdownlint": "explicit" } } -} +} \ No newline at end of file diff --git a/README.md b/README.md index db0328cbca..b86b251384 100644 --- a/README.md +++ b/README.md @@ -97,9 +97,9 @@ To import all components, replace the previous code by the 3 following lines (no ``` // Import styles -@forward '@lucca-front/icons/src/main’; -@forward '@lucca-front/scss/src/main-all’; -@forward '@lucca-front/ng/src/main’; +@forward '@lucca-front/icons/src/main'; +@forward '@lucca-front/scss/src/main-all'; +@forward '@lucca-front/ng/src/main'; ``` For custom imports, check our [advanced usage documentation](https://prisme.lucca.io/94310e217/p/950783-chargement-des-composants). @@ -113,9 +113,9 @@ In angular.json, we suggest to add a couple of entries to your paths: "build": { "options": { "stylePreprocessorOptions": { - “includePaths": [ + "includePaths": [ "src/scss", - "node_modules", + "node_modules" ] }, }, diff --git a/docs/dialog.md b/docs/dialog.md index 07a1fe28cd..af1ab70376 100644 --- a/docs/dialog.md +++ b/docs/dialog.md @@ -181,25 +181,25 @@ Dans le cas où vous souhaitez utiliser un formulaire au sein d’une dialog box ```html - -
- Header with Form inside - - - - - - - - - - - -
-
-``` \ No newline at end of file + +
+ Header with Form inside + + + + + + + + + + + +
+ +``` diff --git a/docs/popover2.md b/docs/popover2.md new file mode 100644 index 0000000000..f8be223136 --- /dev/null +++ b/docs/popover2.md @@ -0,0 +1,63 @@ +# Popover2 + +Popover2 est la nouvelle version de LuPopover, il a été choisi de partir sur une implémentation différente et donc, afin d'éviter les impacts d'un breaking change, +une nouvelle directive a vu le jour `luPopover2`, dans un nouveau point d'entrée, `@lucca-front/ng/popover2`. + +## Mise en place + +Popover2 est fait pour être simple à utiliser, il suffit de l'importer dans votre environement avec `configureLuPopover()` (à placer dans les providers de votre `AppModule` ou lors du bootstrap de `AppComponent` si vous êtes en full standalone). + +## Utilisation + +Pour utiliser `Popover2` dans un template, il suffit d'appliquer la directive `[luPopover2]` en renseignant en input une référence à un `ng-template`, exemple: + +```angular2html + + + + Je suis le contenu du popover ! + + +``` + +## Paramètres et position + +Seule la référence au `ng-template` est obligatoire, mais la directive propose des paramètres pour divers usages: + +- `luPopoverPosition` par défaut à `above`, permet de régler la position voulue du popover, en cas d'espace manquant dans le rendu, le composant tentera de se positionner d'abord à l'opposé de la position demandée, puis les deux autres à tour de rôle. +- `luPopoverDisabled` permet de désactiver totalement le popover. +- `customPositions` à utiliser avec précaution, permet de renseigner des `ConnectionPositionPair` pour totalement remplacer la logique de positionnement, très utile pour les menus qui doivent être `below` mais alignés sur un côté plutôt que l'autre. + +Les positions custom doivent être déclarées dans le `component.ts` sous forme d'un tableau et passés dans le template en input, exemple pour un menu qui s'ouvre en dessous à gauche (ou au dessus à gauche si pas de place): + +component.ts: + +```typescript +import { ConnectionPositionPair } from "@angular/cdk/overlay"; + +export class ExampleComponent { + protected positions: ConnectionPositionPair[] = [ + // En dessous, aligné à gauche + new ConnectionPositionPair( + { originX: "left", originY: "bottom" }, + { overlayX: "left", overlayY: "top" } + ), + // Au dessus, aligné à gauche + new ConnectionPositionPair( + { originX: "left", originY: "top" }, + { overlayX: "left", overlayY: "bottom" } + ) + ] +} +``` + +component.html: + +```angular2html + + + + Je suis le contenu du popover ! + + +``` diff --git a/package-lock.json b/package-lock.json index ca9655b22e..995949a4bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,7 +45,7 @@ "@storybook/addon-essentials": "^8.1.2", "@storybook/addon-interactions": "^8.1.2", "@storybook/addon-mdx-gfm": "^8.1.2", - "@storybook/angular": "^8.1.4", + "@storybook/angular": "^8.1.6", "@storybook/test-runner": "^0.18.1", "@testing-library/angular": "^16.0.0", "@testing-library/jest-dom": "^6.4.5", @@ -75,7 +75,7 @@ "postcss-value-parser": "^4.2.0", "prettier": "^3.2.5", "sass": "^1.62.1", - "storybook": "^8.0.6", + "storybook": "^8.1.6", "stylelint": "^14.15.0", "stylelint-config-prettier": "^9.0.4", "stylelint-prettier": "^2.0.0", @@ -794,12 +794,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz", - "integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.24.6", + "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" }, "engines": { @@ -925,19 +925,19 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.6.tgz", - "integrity": "sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-function-name": "^7.24.6", - "@babel/helper-member-expression-to-functions": "^7.24.6", - "@babel/helper-optimise-call-expression": "^7.24.6", - "@babel/helper-replace-supers": "^7.24.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", - "@babel/helper-split-export-declaration": "^7.24.6", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.7.tgz", + "integrity": "sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", "semver": "^6.3.1" }, "engines": { @@ -948,24 +948,24 @@ } }, "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", - "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", - "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1035,74 +1035,79 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", - "integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz", - "integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", "dev": true, "dependencies": { - "@babel/template": "^7.24.6", - "@babel/types": "^7.24.6" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.6.tgz", - "integrity": "sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.6.tgz", - "integrity": "sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz", + "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz", - "integrity": "sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.6.tgz", - "integrity": "sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", + "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-module-imports": "^7.24.6", - "@babel/helper-simple-access": "^7.24.6", - "@babel/helper-split-export-declaration": "^7.24.6", - "@babel/helper-validator-identifier": "^7.24.6" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1112,33 +1117,33 @@ } }, "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", - "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.6.tgz", - "integrity": "sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", - "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", + "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", "dev": true, "engines": { "node": ">=6.9.0" @@ -1174,14 +1179,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.6.tgz", - "integrity": "sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", + "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-member-expression-to-functions": "^7.24.6", - "@babel/helper-optimise-call-expression": "^7.24.6" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1191,24 +1196,26 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz", - "integrity": "sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.6.tgz", - "integrity": "sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1227,27 +1234,27 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz", - "integrity": "sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", + "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz", - "integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.6.tgz", - "integrity": "sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", + "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", "dev": true, "engines": { "node": ">=6.9.0" @@ -1281,12 +1288,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz", - "integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -1296,9 +1303,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", - "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1459,12 +1466,12 @@ } }, "node_modules/@babel/plugin-syntax-flow": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.6.tgz", - "integrity": "sha512-gNkksSdV8RbsCoHF9sjVYrHfYACMl/8U32UfUhJ9+84/ASXw8dlx+eHyyF0m6ncQJ9IBSxfuCkB36GJqYdXTOA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.7.tgz", + "integrity": "sha512-9G8GYT/dxn/D1IIKOUBmGX0mnmj46mGH9NnZyJLwtCpgh5f7D2VbuKodb+2s9m1Yavh1s7ASQN8lf0eqrb1LTw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1528,12 +1535,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.6.tgz", - "integrity": "sha512-lWfvAIFNWMlCsU0DRUun2GpFwZdGTukLaHJqRh1JRb80NdAP5Sb1HDHB5X9P9OtgZHQl089UzQkpYlBq2VTPRw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1645,12 +1652,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.6.tgz", - "integrity": "sha512-TzCtxGgVTEJWWwcYwQhCIQ6WaKlo80/B+Onsk4RRCcYqpYGFcG9etPW94VToGte5AAcxRrhjPUFvUS3Y2qKi4A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1945,13 +1952,13 @@ } }, "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.6.tgz", - "integrity": "sha512-1l8b24NoCpaQ13Vi6FtLG1nv6kNoi8PWvQb1AYO7GHZDpFfBYc3lbXArx1lP2KRt8b4pej1eWc/zrRmsQTfOdQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.7.tgz", + "integrity": "sha512-cjRKJ7FobOH2eakx7Ja+KpJRj8+y+/SiB3ooYm/n2UJfxu0oEaOoxOinitkJcPqv9KxS0kxTGPUaR7L2XcXDXA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/plugin-syntax-flow": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-flow": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2072,14 +2079,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.6.tgz", - "integrity": "sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.7.tgz", + "integrity": "sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-simple-access": "^7.24.6" + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2465,15 +2472,15 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.6.tgz", - "integrity": "sha512-H0i+hDLmaYYSt6KU9cZE0gb3Cbssa/oxWis7PX4ofQzbvsfix9Lbh8SRk7LCPDlLWJHUiFeHU0qRRpF/4Zv7mQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.7.tgz", + "integrity": "sha512-iLD3UNkgx2n/HrjBesVbYX6j0yqn/sJktvbtKKgcaLIQ4bTTQ8obAypc1VpyHPD2y4Phh9zHOaAt8e/L14wCpw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", - "@babel/helper-create-class-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/plugin-syntax-typescript": "^7.24.6" + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-typescript": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2483,12 +2490,12 @@ } }, "node_modules/@babel/plugin-transform-typescript/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", - "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2662,14 +2669,14 @@ } }, "node_modules/@babel/preset-flow": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.6.tgz", - "integrity": "sha512-huoe0T1Qs9fQhMWbmqE/NHUeZbqmHDsN6n/jYvPcUUHfuKiPV32C9i8tDhMbQ1DEKTjbBP7Rjm3nSLwlB2X05g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.7.tgz", + "integrity": "sha512-NL3Lo0NorCU607zU3NwRyJbpaB6E3t0xtd3LfAQKDfkeX4/ggcDXvkmkW42QWT5owUeW/jAe4hn+2qvkV1IbfQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-validator-option": "^7.24.6", - "@babel/plugin-transform-flow-strip-types": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-transform-flow-strip-types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2693,16 +2700,16 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.6.tgz", - "integrity": "sha512-U10aHPDnokCFRXgyT/MaIRTivUu2K/mu0vJlwRS9LxJmJet+PFQNKpggPyFCUtC6zWSBPjvxjnpNkAn3Uw2m5w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", + "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-validator-option": "^7.24.6", - "@babel/plugin-syntax-jsx": "^7.24.6", - "@babel/plugin-transform-modules-commonjs": "^7.24.6", - "@babel/plugin-transform-typescript": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2858,33 +2865,33 @@ } }, "node_modules/@babel/template": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz", - "integrity": "sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.24.6", - "@babel/parser": "^7.24.6", - "@babel/types": "^7.24.6" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.6.tgz", - "integrity": "sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.6", - "@babel/generator": "^7.24.6", - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-function-name": "^7.24.6", - "@babel/helper-hoist-variables": "^7.24.6", - "@babel/helper-split-export-declaration": "^7.24.6", - "@babel/parser": "^7.24.6", - "@babel/types": "^7.24.6", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", + "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2893,12 +2900,12 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.6.tgz", - "integrity": "sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", + "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6", + "@babel/types": "^7.24.7", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -2908,25 +2915,25 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", - "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", - "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.24.6", - "@babel/helper-validator-identifier": "^7.24.6", + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -7107,23 +7114,23 @@ } }, "node_modules/@storybook/angular": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/angular/-/angular-8.1.5.tgz", - "integrity": "sha512-yluF7t8728O1RA5Lj2v/KqIf8qjrfLRJThGHDTmkoQD0PmWvroD3jbnADIJVQ4bu7b2PM+z9OweqLaDkdq2mTA==", - "dev": true, - "dependencies": { - "@storybook/builder-webpack5": "8.1.5", - "@storybook/client-logger": "8.1.5", - "@storybook/core-common": "8.1.5", - "@storybook/core-events": "8.1.5", - "@storybook/core-server": "8.1.5", - "@storybook/core-webpack": "8.1.5", - "@storybook/docs-tools": "8.1.5", + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/angular/-/angular-8.1.6.tgz", + "integrity": "sha512-RDKAJphZRdM1KJtlf4bv0f/NlQm2aLc2Dfr5B4bU1q0I4WoxsmhxC5BFlCFOxwVX0K4d6FuXrZSySd4pFZN8Fg==", + "dev": true, + "dependencies": { + "@storybook/builder-webpack5": "8.1.6", + "@storybook/client-logger": "8.1.6", + "@storybook/core-common": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/core-server": "8.1.6", + "@storybook/core-webpack": "8.1.6", + "@storybook/docs-tools": "8.1.6", "@storybook/global": "^5.0.0", - "@storybook/node-logger": "8.1.5", - "@storybook/preview-api": "8.1.5", - "@storybook/telemetry": "8.1.5", - "@storybook/types": "8.1.5", + "@storybook/node-logger": "8.1.6", + "@storybook/preview-api": "8.1.6", + "@storybook/telemetry": "8.1.6", + "@storybook/types": "8.1.6", "@types/node": "^18.0.0", "@types/react": "^18.0.37", "@types/react-dom": "^18.0.11", @@ -7167,81 +7174,7 @@ } } }, - "node_modules/@storybook/blocks": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.1.5.tgz", - "integrity": "sha512-rq8Ej5feS2BlfXOpNLDwdASkIIZJtKzLy9cUpuGftTiu06HiWAk3wpNpnn/kuunDYlZUa+qHEOSiIkTrdduwYw==", - "dev": true, - "dependencies": { - "@storybook/channels": "8.1.5", - "@storybook/client-logger": "8.1.5", - "@storybook/components": "8.1.5", - "@storybook/core-events": "8.1.5", - "@storybook/csf": "^0.1.7", - "@storybook/docs-tools": "8.1.5", - "@storybook/global": "^5.0.0", - "@storybook/icons": "^1.2.5", - "@storybook/manager-api": "8.1.5", - "@storybook/preview-api": "8.1.5", - "@storybook/theming": "8.1.5", - "@storybook/types": "8.1.5", - "@types/lodash": "^4.14.167", - "color-convert": "^2.0.1", - "dequal": "^2.0.2", - "lodash": "^4.17.21", - "markdown-to-jsx": "7.3.2", - "memoizerific": "^1.11.3", - "polished": "^4.2.2", - "react-colorful": "^5.1.2", - "telejson": "^7.2.0", - "tocbot": "^4.20.1", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/@storybook/builder-manager": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/builder-manager/-/builder-manager-8.1.5.tgz", - "integrity": "sha512-wDiHLV+UPaUN+765WwXkocVRB2QnJ61CjLHbpWaLiJvryFJt+JQ6nAvgSalCRnZxI046ztbS9T6okhpFI011IA==", - "dev": true, - "dependencies": { - "@fal-works/esbuild-plugin-global-externals": "^2.1.2", - "@storybook/core-common": "8.1.5", - "@storybook/manager": "8.1.5", - "@storybook/node-logger": "8.1.5", - "@types/ejs": "^3.1.1", - "@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.10", - "browser-assert": "^1.2.1", - "ejs": "^3.1.10", - "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0", - "esbuild-plugin-alias": "^0.2.1", - "express": "^4.17.3", - "fs-extra": "^11.1.0", - "process": "^0.11.10", - "util": "^0.12.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - } - }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/aix-ppc64": { + "node_modules/@storybook/angular/node_modules/@esbuild/aix-ppc64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", @@ -7257,7 +7190,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/android-arm": { + "node_modules/@storybook/angular/node_modules/@esbuild/android-arm": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", @@ -7273,7 +7206,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/android-arm64": { + "node_modules/@storybook/angular/node_modules/@esbuild/android-arm64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", @@ -7289,7 +7222,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/android-x64": { + "node_modules/@storybook/angular/node_modules/@esbuild/android-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", @@ -7305,7 +7238,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/darwin-arm64": { + "node_modules/@storybook/angular/node_modules/@esbuild/darwin-arm64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", @@ -7321,7 +7254,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/darwin-x64": { + "node_modules/@storybook/angular/node_modules/@esbuild/darwin-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", @@ -7337,7 +7270,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/freebsd-arm64": { + "node_modules/@storybook/angular/node_modules/@esbuild/freebsd-arm64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", @@ -7353,7 +7286,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/freebsd-x64": { + "node_modules/@storybook/angular/node_modules/@esbuild/freebsd-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", @@ -7369,7 +7302,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-arm": { + "node_modules/@storybook/angular/node_modules/@esbuild/linux-arm": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", @@ -7385,7 +7318,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-arm64": { + "node_modules/@storybook/angular/node_modules/@esbuild/linux-arm64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", @@ -7401,7 +7334,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-ia32": { + "node_modules/@storybook/angular/node_modules/@esbuild/linux-ia32": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", @@ -7417,7 +7350,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-loong64": { + "node_modules/@storybook/angular/node_modules/@esbuild/linux-loong64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", @@ -7433,7 +7366,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-mips64el": { + "node_modules/@storybook/angular/node_modules/@esbuild/linux-mips64el": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", @@ -7449,7 +7382,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-ppc64": { + "node_modules/@storybook/angular/node_modules/@esbuild/linux-ppc64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", @@ -7465,7 +7398,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-riscv64": { + "node_modules/@storybook/angular/node_modules/@esbuild/linux-riscv64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", @@ -7481,7 +7414,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-s390x": { + "node_modules/@storybook/angular/node_modules/@esbuild/linux-s390x": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", @@ -7497,7 +7430,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-x64": { + "node_modules/@storybook/angular/node_modules/@esbuild/linux-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", @@ -7513,7 +7446,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/netbsd-x64": { + "node_modules/@storybook/angular/node_modules/@esbuild/netbsd-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", @@ -7529,7 +7462,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/openbsd-x64": { + "node_modules/@storybook/angular/node_modules/@esbuild/openbsd-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", @@ -7545,7 +7478,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/sunos-x64": { + "node_modules/@storybook/angular/node_modules/@esbuild/sunos-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", @@ -7561,7 +7494,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/win32-arm64": { + "node_modules/@storybook/angular/node_modules/@esbuild/win32-arm64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", @@ -7577,7 +7510,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/win32-ia32": { + "node_modules/@storybook/angular/node_modules/@esbuild/win32-ia32": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", @@ -7593,7 +7526,7 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/@esbuild/win32-x64": { + "node_modules/@storybook/angular/node_modules/@esbuild/win32-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", @@ -7609,228 +7542,192 @@ "node": ">=12" } }, - "node_modules/@storybook/builder-manager/node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "node_modules/@storybook/angular/node_modules/@storybook/channels": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-8.1.6.tgz", + "integrity": "sha512-CzDnP6qfI8OC8pGUk+wPUzLPYcKhX8XbriF2gBtwl6qVM8YfkHP2mLTiDYDwBIi0rLuUbSm/SpILXQ/ouOHOGw==", "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" + "dependencies": { + "@storybook/client-logger": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/global": "^5.0.0", + "telejson": "^7.2.0", + "tiny-invariant": "^1.3.1" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/builder-webpack5": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-8.1.5.tgz", - "integrity": "sha512-gGVlApa0JVu0q7Ws37Kubh9e8wDKoJh23DXGIeK3EHVloL2XU9+wgP2NcUoiySvTIKPtDB7Zljg1/BXgqeOJ4w==", + "node_modules/@storybook/angular/node_modules/@storybook/client-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-8.1.6.tgz", + "integrity": "sha512-QfSoUxS1rmrBzO7o99og9g+Gkm7sTmU5ZOpTkjszjlRqfV6/77eUnUOzUikej4LqPLmlJV5fqGuvoP0aNVksDw==", "dev": true, "dependencies": { - "@storybook/channels": "8.1.5", - "@storybook/client-logger": "8.1.5", - "@storybook/core-common": "8.1.5", - "@storybook/core-events": "8.1.5", - "@storybook/core-webpack": "8.1.5", - "@storybook/node-logger": "8.1.5", - "@storybook/preview": "8.1.5", - "@storybook/preview-api": "8.1.5", - "@types/node": "^18.0.0", - "@types/semver": "^7.3.4", - "browser-assert": "^1.2.1", - "case-sensitive-paths-webpack-plugin": "^2.4.0", - "cjs-module-lexer": "^1.2.3", - "constants-browserify": "^1.0.0", - "css-loader": "^6.7.1", - "es-module-lexer": "^1.5.0", - "express": "^4.17.3", - "fork-ts-checker-webpack-plugin": "^8.0.0", - "fs-extra": "^11.1.0", - "html-webpack-plugin": "^5.5.0", - "magic-string": "^0.30.5", - "path-browserify": "^1.0.1", - "process": "^0.11.10", - "semver": "^7.3.7", - "style-loader": "^3.3.1", - "terser-webpack-plugin": "^5.3.1", - "ts-dedent": "^2.0.0", - "url": "^0.11.0", - "util": "^0.12.4", - "util-deprecate": "^1.0.2", - "webpack": "5", - "webpack-dev-middleware": "^6.1.2", - "webpack-hot-middleware": "^2.25.1", - "webpack-virtual-modules": "^0.5.0" + "@storybook/global": "^5.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } } }, - "node_modules/@storybook/builder-webpack5/node_modules/css-loader": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", - "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "node_modules/@storybook/angular/node_modules/@storybook/core-common": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-8.1.6.tgz", + "integrity": "sha512-OTlfJFaTOB588ibXrrFm0TAXam6E5xV1VXSjNXL+fIifx8Kjln2HNSy1JKjvcblQneYiV4J1xPCVnAIe0EGHDg==", "dev": true, "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.1.0", - "postcss-modules-local-by-default": "^4.0.5", - "postcss-modules-scope": "^3.2.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">= 12.13.0" + "@storybook/core-events": "8.1.6", + "@storybook/csf-tools": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@storybook/types": "8.1.6", + "@yarnpkg/fslib": "2.10.3", + "@yarnpkg/libzip": "2.3.0", + "chalk": "^4.1.0", + "cross-spawn": "^7.0.3", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0", + "esbuild-register": "^3.5.0", + "execa": "^5.0.0", + "file-system-cache": "2.3.0", + "find-cache-dir": "^3.0.0", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "glob": "^10.0.0", + "handlebars": "^4.7.7", + "lazy-universal-dotenv": "^4.0.0", + "node-fetch": "^2.0.0", + "picomatch": "^2.3.0", + "pkg-dir": "^5.0.0", + "prettier-fallback": "npm:prettier@^3", + "pretty-hrtime": "^1.0.3", + "resolve-from": "^5.0.0", + "semver": "^7.3.7", + "tempy": "^3.1.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0", + "util": "^0.12.4" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.0.0" + "prettier": "^2 || ^3" }, "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { + "prettier": { "optional": true } } }, - "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.3.tgz", - "integrity": "sha512-A4ChP0Qj8oGociTs6UdlRUGANIGrCDL3y+pmQMc+dSsraXHCatFpmMey4mYELA+juqwUqwQsUgJJISXl1KWmiw==", + "node_modules/@storybook/angular/node_modules/@storybook/core-events": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-8.1.6.tgz", + "integrity": "sha512-DaIVe4TUp/7uQdSJYGmJv9S/S364tSgZ3S3dZ1vsf1rgoUbCp5kTBtcd/fcqgukMPREgCgO9oDhmemI3SLAqzw==", "dev": true, "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.12", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 14.15.0" + "@storybook/csf": "^0.1.7", + "ts-dedent": "^2.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/angular/node_modules/@storybook/csf-tools": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-8.1.6.tgz", + "integrity": "sha512-jrKfHFNhiLBhWWW4/fm2wgKEVg55e6QuYUHY16KGd7PdPuzm+2Pt7jIl5V9yIj6a59YbjeMpT6jWPKbFx2TuCw==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "@storybook/csf": "^0.1.7", + "@storybook/types": "8.1.6", + "fs-extra": "^11.1.0", + "recast": "^0.23.5", + "ts-dedent": "^2.0.0" }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/channels": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-8.1.5.tgz", - "integrity": "sha512-R+puP4tWYzQUbpIp8sX6U5oI+ZUevVOaFxXGaAN3PRXjIRC38oKTVWzj/G6GdziVFzN6rDn+JsYPmiRMYo1sYg==", + "node_modules/@storybook/angular/node_modules/@storybook/docs-tools": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/docs-tools/-/docs-tools-8.1.6.tgz", + "integrity": "sha512-IhqQHSJ5nEBEJ162P/6/6c45toLinWpAkB7pwbAoP00djZSzfHNdQ4HfpZSGfD4GUJIvzsqMzUlyqCKLAoRPPA==", "dev": true, "dependencies": { - "@storybook/client-logger": "8.1.5", - "@storybook/core-events": "8.1.5", - "@storybook/global": "^5.0.0", - "telejson": "^7.2.0", - "tiny-invariant": "^1.3.1" + "@storybook/core-common": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/preview-api": "8.1.6", + "@storybook/types": "8.1.6", + "@types/doctrine": "^0.0.3", + "assert": "^2.1.0", + "doctrine": "^3.0.0", + "lodash": "^4.17.21" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/cli": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/cli/-/cli-8.1.5.tgz", - "integrity": "sha512-VEYluZEMleNEnD5wTD90KTh03pwjvQwEEmzHAJQJdLbWTAcgBxZ3Gb45nbUPauSqBL+HdJx0QXF8Ielk+iBttw==", + "node_modules/@storybook/angular/node_modules/@storybook/node-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-8.1.6.tgz", + "integrity": "sha512-IZEiTLFHu8Oom/vdEGpisSw5CfU+cw6/fTaX1P3EVClFOWVuy8/3X5MPu4wJH3jPym6E2DBduIUFeRsiuq61gA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/angular/node_modules/@storybook/preview-api": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.1.6.tgz", + "integrity": "sha512-g9EvVg/DYqmjMh1uivJBJnSIvURyuK4LLabYicQNmYdQJscAeXX2bpMcA4aeci9BBm9B2RP7JbSnq7DbXZaJYA==", "dev": true, "dependencies": { - "@babel/core": "^7.24.4", - "@babel/types": "^7.24.0", - "@ndelangen/get-tarball": "^3.0.7", - "@storybook/codemod": "8.1.5", - "@storybook/core-common": "8.1.5", - "@storybook/core-events": "8.1.5", - "@storybook/core-server": "8.1.5", - "@storybook/csf-tools": "8.1.5", - "@storybook/node-logger": "8.1.5", - "@storybook/telemetry": "8.1.5", - "@storybook/types": "8.1.5", - "@types/semver": "^7.3.4", - "@yarnpkg/fslib": "2.10.3", - "@yarnpkg/libzip": "2.3.0", - "chalk": "^4.1.0", - "commander": "^6.2.1", - "cross-spawn": "^7.0.3", - "detect-indent": "^6.1.0", - "envinfo": "^7.7.3", - "execa": "^5.0.0", - "find-up": "^5.0.0", - "fs-extra": "^11.1.0", - "get-npm-tarball-url": "^2.0.3", - "giget": "^1.0.0", - "globby": "^14.0.1", - "jscodeshift": "^0.15.1", - "leven": "^3.1.0", - "ora": "^5.4.1", - "prettier": "^3.1.1", - "prompts": "^2.4.0", - "read-pkg-up": "^7.0.1", - "semver": "^7.3.7", - "strip-json-comments": "^3.0.1", - "tempy": "^3.1.0", + "@storybook/channels": "8.1.6", + "@storybook/client-logger": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/csf": "^0.1.7", + "@storybook/global": "^5.0.0", + "@storybook/types": "8.1.6", + "@types/qs": "^6.9.5", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", "tiny-invariant": "^1.3.1", - "ts-dedent": "^2.0.0" + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" }, - "bin": { - "getstorybook": "bin/index.js", - "sb": "bin/index.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/angular/node_modules/@storybook/types": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/types/-/types-8.1.6.tgz", + "integrity": "sha512-cWpS9+x1pxCO39spR8QmumMK2ub2p5cvMtrRvWaIjBFPbCwm2CvjBXFWIra2veBCZTxUKJ9VWxvi7pzRHjN/nw==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.6", + "@types/express": "^4.7.0", + "file-system-cache": "2.3.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/cli/node_modules/ansi-styles": { + "node_modules/@storybook/angular/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -7845,7 +7742,7 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@storybook/cli/node_modules/chalk": { + "node_modules/@storybook/angular/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -7861,16 +7758,45 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@storybook/cli/node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "node_modules/@storybook/angular/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { - "node": ">= 6" + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" } }, - "node_modules/@storybook/cli/node_modules/has-flag": { + "node_modules/@storybook/angular/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", @@ -7879,7 +7805,19 @@ "node": ">=8" } }, - "node_modules/@storybook/cli/node_modules/supports-color": { + "node_modules/@storybook/angular/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@storybook/angular/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", @@ -7891,61 +7829,35 @@ "node": ">=8" } }, - "node_modules/@storybook/client-logger": { + "node_modules/@storybook/blocks": { "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-8.1.5.tgz", - "integrity": "sha512-zd+aENXnOHsxBATppELmhw/UywLzCxQjz/8i/xkUjeTRB4Ggp0hJlOUdJUEdIJz631ydyytfvM70ktBj9gMl1w==", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.1.5.tgz", + "integrity": "sha512-rq8Ej5feS2BlfXOpNLDwdASkIIZJtKzLy9cUpuGftTiu06HiWAk3wpNpnn/kuunDYlZUa+qHEOSiIkTrdduwYw==", "dev": true, "dependencies": { - "@storybook/global": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - } - }, - "node_modules/@storybook/codemod": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-8.1.5.tgz", - "integrity": "sha512-eGoYozT2XPfsIFrzm4cJo9tRTX0yuK1y4uTYmKvnomezHu5kiY8qo2fUzQa5DHxiAzRDTpGlQTzb0PsxHOxYoA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.24.4", - "@babel/preset-env": "^7.24.4", - "@babel/types": "^7.24.0", - "@storybook/csf": "^0.1.7", - "@storybook/csf-tools": "8.1.5", - "@storybook/node-logger": "8.1.5", - "@storybook/types": "8.1.5", - "@types/cross-spawn": "^6.0.2", - "cross-spawn": "^7.0.3", - "globby": "^14.0.1", - "jscodeshift": "^0.15.1", - "lodash": "^4.17.21", - "prettier": "^3.1.1", - "recast": "^0.23.5", - "tiny-invariant": "^1.3.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - } - }, - "node_modules/@storybook/components": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.1.5.tgz", - "integrity": "sha512-IxoT2pH7V98gF0zDAMUuq9sUZPg0vvQ9Y+A13HeYHvaY25XdesXVMbdzEd6SpeLYmfPykMPIAEcADfqeM6eXfA==", - "dev": true, - "dependencies": { - "@radix-ui/react-dialog": "^1.0.5", - "@radix-ui/react-slot": "^1.0.2", + "@storybook/channels": "8.1.5", "@storybook/client-logger": "8.1.5", + "@storybook/components": "8.1.5", + "@storybook/core-events": "8.1.5", "@storybook/csf": "^0.1.7", + "@storybook/docs-tools": "8.1.5", "@storybook/global": "^5.0.0", "@storybook/icons": "^1.2.5", + "@storybook/manager-api": "8.1.5", + "@storybook/preview-api": "8.1.5", "@storybook/theming": "8.1.5", "@storybook/types": "8.1.5", + "@types/lodash": "^4.14.167", + "color-convert": "^2.0.1", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "markdown-to-jsx": "7.3.2", "memoizerific": "^1.11.3", + "polished": "^4.2.2", + "react-colorful": "^5.1.2", + "telejson": "^7.2.0", + "tocbot": "^4.20.1", + "ts-dedent": "^2.0.0", "util-deprecate": "^1.0.2" }, "funding": { @@ -7955,58 +7867,43 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } } }, - "node_modules/@storybook/core-common": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-8.1.5.tgz", - "integrity": "sha512-1QDOT6KPZ9KV7Gs1yyqzvSwGBmNSUB33gckUldSBF4aqP+tZ7W5JIQ6/YTtp3V02sEokZGdL9Ud4LczQxTgy3A==", + "node_modules/@storybook/builder-manager": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/builder-manager/-/builder-manager-8.1.6.tgz", + "integrity": "sha512-Y5d+dikKnUuCYyh4VLEF6A+AbWughEgtipVkDKOddSTzn04trClIOKqfhQqEUObydCpgvvfdjGXJa/zDRV/UQA==", "dev": true, "dependencies": { - "@storybook/core-events": "8.1.5", - "@storybook/csf-tools": "8.1.5", - "@storybook/node-logger": "8.1.5", - "@storybook/types": "8.1.5", - "@yarnpkg/fslib": "2.10.3", - "@yarnpkg/libzip": "2.3.0", - "chalk": "^4.1.0", - "cross-spawn": "^7.0.3", + "@fal-works/esbuild-plugin-global-externals": "^2.1.2", + "@storybook/core-common": "8.1.6", + "@storybook/manager": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@types/ejs": "^3.1.1", + "@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.10", + "browser-assert": "^1.2.1", + "ejs": "^3.1.10", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0", - "esbuild-register": "^3.5.0", - "execa": "^5.0.0", - "file-system-cache": "2.3.0", - "find-cache-dir": "^3.0.0", - "find-up": "^5.0.0", + "esbuild-plugin-alias": "^0.2.1", + "express": "^4.17.3", "fs-extra": "^11.1.0", - "glob": "^10.0.0", - "handlebars": "^4.7.7", - "lazy-universal-dotenv": "^4.0.0", - "node-fetch": "^2.0.0", - "picomatch": "^2.3.0", - "pkg-dir": "^5.0.0", - "prettier-fallback": "npm:prettier@^3", - "pretty-hrtime": "^1.0.3", - "resolve-from": "^5.0.0", - "semver": "^7.3.7", - "tempy": "^3.1.0", - "tiny-invariant": "^1.3.1", - "ts-dedent": "^2.0.0", + "process": "^0.11.10", "util": "^0.12.4" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "prettier": "^2 || ^3" - }, - "peerDependenciesMeta": { - "prettier": { - "optional": true - } } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/aix-ppc64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/aix-ppc64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", @@ -8022,7 +7919,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/android-arm": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/android-arm": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", @@ -8038,7 +7935,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/android-arm64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/android-arm64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", @@ -8054,7 +7951,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/android-x64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/android-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", @@ -8070,7 +7967,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/darwin-arm64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/darwin-arm64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", @@ -8086,7 +7983,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/darwin-x64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/darwin-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", @@ -8102,7 +7999,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/freebsd-arm64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/freebsd-arm64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", @@ -8118,7 +8015,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/freebsd-x64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/freebsd-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", @@ -8134,7 +8031,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/linux-arm": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-arm": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", @@ -8150,7 +8047,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/linux-arm64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-arm64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", @@ -8166,7 +8063,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/linux-ia32": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-ia32": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", @@ -8182,7 +8079,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/linux-loong64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-loong64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", @@ -8198,7 +8095,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/linux-mips64el": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-mips64el": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", @@ -8214,7 +8111,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/linux-ppc64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-ppc64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", @@ -8230,7 +8127,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/linux-riscv64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-riscv64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", @@ -8246,7 +8143,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/linux-s390x": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-s390x": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", @@ -8262,7 +8159,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/linux-x64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/linux-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", @@ -8278,7 +8175,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/netbsd-x64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/netbsd-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", @@ -8294,7 +8191,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/openbsd-x64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/openbsd-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", @@ -8310,7 +8207,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/sunos-x64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/sunos-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", @@ -8326,7 +8223,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/win32-arm64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/win32-arm64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", @@ -8342,7 +8239,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/win32-ia32": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/win32-ia32": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", @@ -8358,7 +8255,7 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/@esbuild/win32-x64": { + "node_modules/@storybook/builder-manager/node_modules/@esbuild/win32-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", @@ -8374,181 +8271,146 @@ "node": ">=12" } }, - "node_modules/@storybook/core-common/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@storybook/builder-manager/node_modules/@storybook/channels": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-8.1.6.tgz", + "integrity": "sha512-CzDnP6qfI8OC8pGUk+wPUzLPYcKhX8XbriF2gBtwl6qVM8YfkHP2mLTiDYDwBIi0rLuUbSm/SpILXQ/ouOHOGw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "@storybook/client-logger": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/global": "^5.0.0", + "telejson": "^7.2.0", + "tiny-invariant": "^1.3.1" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/core-common/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@storybook/builder-manager/node_modules/@storybook/client-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-8.1.6.tgz", + "integrity": "sha512-QfSoUxS1rmrBzO7o99og9g+Gkm7sTmU5ZOpTkjszjlRqfV6/77eUnUOzUikej4LqPLmlJV5fqGuvoP0aNVksDw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "@storybook/global": "^5.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/core-common/node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "node_modules/@storybook/builder-manager/node_modules/@storybook/core-common": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-8.1.6.tgz", + "integrity": "sha512-OTlfJFaTOB588ibXrrFm0TAXam6E5xV1VXSjNXL+fIifx8Kjln2HNSy1JKjvcblQneYiV4J1xPCVnAIe0EGHDg==", "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" + "dependencies": { + "@storybook/core-events": "8.1.6", + "@storybook/csf-tools": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@storybook/types": "8.1.6", + "@yarnpkg/fslib": "2.10.3", + "@yarnpkg/libzip": "2.3.0", + "chalk": "^4.1.0", + "cross-spawn": "^7.0.3", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0", + "esbuild-register": "^3.5.0", + "execa": "^5.0.0", + "file-system-cache": "2.3.0", + "find-cache-dir": "^3.0.0", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "glob": "^10.0.0", + "handlebars": "^4.7.7", + "lazy-universal-dotenv": "^4.0.0", + "node-fetch": "^2.0.0", + "picomatch": "^2.3.0", + "pkg-dir": "^5.0.0", + "prettier-fallback": "npm:prettier@^3", + "pretty-hrtime": "^1.0.3", + "resolve-from": "^5.0.0", + "semver": "^7.3.7", + "tempy": "^3.1.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0", + "util": "^0.12.4" }, - "engines": { - "node": ">=12" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } } }, - "node_modules/@storybook/core-common/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@storybook/builder-manager/node_modules/@storybook/core-events": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-8.1.6.tgz", + "integrity": "sha512-DaIVe4TUp/7uQdSJYGmJv9S/S364tSgZ3S3dZ1vsf1rgoUbCp5kTBtcd/fcqgukMPREgCgO9oDhmemI3SLAqzw==", "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@storybook/core-common/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" + "dependencies": { + "@storybook/csf": "^0.1.7", + "ts-dedent": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "opencollective", + "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/core-common/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@storybook/builder-manager/node_modules/@storybook/csf-tools": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-8.1.6.tgz", + "integrity": "sha512-jrKfHFNhiLBhWWW4/fm2wgKEVg55e6QuYUHY16KGd7PdPuzm+2Pt7jIl5V9yIj6a59YbjeMpT6jWPKbFx2TuCw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@babel/generator": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "@storybook/csf": "^0.1.7", + "@storybook/types": "8.1.6", + "fs-extra": "^11.1.0", + "recast": "^0.23.5", + "ts-dedent": "^2.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/core-events": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-8.1.5.tgz", - "integrity": "sha512-fgwbrHoLtSX6kfmamTGJqD+KfuEgun8cc4mWKZK094ByaqbSjhnOyeYO1sfVk8qst7QTFlOfhLAUe4cz1z149A==", + "node_modules/@storybook/builder-manager/node_modules/@storybook/node-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-8.1.6.tgz", + "integrity": "sha512-IZEiTLFHu8Oom/vdEGpisSw5CfU+cw6/fTaX1P3EVClFOWVuy8/3X5MPu4wJH3jPym6E2DBduIUFeRsiuq61gA==", "dev": true, - "dependencies": { - "@storybook/csf": "^0.1.7", - "ts-dedent": "^2.0.0" - }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/core-server": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/core-server/-/core-server-8.1.5.tgz", - "integrity": "sha512-y16W2sg5KIHG6qgbd+a0nBUYHAgiUpPDFF7cdcIpbeOIoqFn+6ECp93MVefukumiSj3sQiJFU/tSm2A8apGltw==", + "node_modules/@storybook/builder-manager/node_modules/@storybook/types": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/types/-/types-8.1.6.tgz", + "integrity": "sha512-cWpS9+x1pxCO39spR8QmumMK2ub2p5cvMtrRvWaIjBFPbCwm2CvjBXFWIra2veBCZTxUKJ9VWxvi7pzRHjN/nw==", "dev": true, "dependencies": { - "@aw-web-design/x-default-browser": "1.4.126", - "@babel/core": "^7.24.4", - "@babel/parser": "^7.24.4", - "@discoveryjs/json-ext": "^0.5.3", - "@storybook/builder-manager": "8.1.5", - "@storybook/channels": "8.1.5", - "@storybook/core-common": "8.1.5", - "@storybook/core-events": "8.1.5", - "@storybook/csf": "^0.1.7", - "@storybook/csf-tools": "8.1.5", - "@storybook/docs-mdx": "3.1.0-next.0", - "@storybook/global": "^5.0.0", - "@storybook/manager": "8.1.5", - "@storybook/manager-api": "8.1.5", - "@storybook/node-logger": "8.1.5", - "@storybook/preview-api": "8.1.5", - "@storybook/telemetry": "8.1.5", - "@storybook/types": "8.1.5", - "@types/detect-port": "^1.3.0", - "@types/diff": "^5.0.9", - "@types/node": "^18.0.0", - "@types/pretty-hrtime": "^1.0.0", - "@types/semver": "^7.3.4", - "better-opn": "^3.0.2", - "chalk": "^4.1.0", - "cli-table3": "^0.6.1", - "compression": "^1.7.4", - "detect-port": "^1.3.0", - "diff": "^5.2.0", - "express": "^4.17.3", - "fs-extra": "^11.1.0", - "globby": "^14.0.1", - "ip": "^2.0.1", - "lodash": "^4.17.21", - "open": "^8.4.0", - "pretty-hrtime": "^1.0.3", - "prompts": "^2.4.0", - "read-pkg-up": "^7.0.1", - "semver": "^7.3.7", - "telejson": "^7.2.0", - "tiny-invariant": "^1.3.1", - "ts-dedent": "^2.0.0", - "util": "^0.12.4", - "util-deprecate": "^1.0.2", - "watchpack": "^2.2.0", - "ws": "^8.2.3" + "@storybook/channels": "8.1.6", + "@types/express": "^4.7.0", + "file-system-cache": "2.3.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/core-server/node_modules/ansi-styles": { + "node_modules/@storybook/builder-manager/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -8563,7 +8425,7 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@storybook/core-server/node_modules/chalk": { + "node_modules/@storybook/builder-manager/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -8579,7 +8441,45 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@storybook/core-server/node_modules/has-flag": { + "node_modules/@storybook/builder-manager/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/@storybook/builder-manager/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", @@ -8588,7 +8488,19 @@ "node": ">=8" } }, - "node_modules/@storybook/core-server/node_modules/supports-color": { + "node_modules/@storybook/builder-manager/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@storybook/builder-manager/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", @@ -8600,257 +8512,4260 @@ "node": ">=8" } }, - "node_modules/@storybook/core-webpack": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-8.1.5.tgz", - "integrity": "sha512-yXixldqg6gGT0OGWuWd52YZycgTrqiPlVHsi91SPtQJSaj3YRS2cM/Giq+gPTE0Zb9+Izq8QEnkyr8B4MfvGbQ==", - "dev": true, - "dependencies": { - "@storybook/core-common": "8.1.5", - "@storybook/node-logger": "8.1.5", - "@storybook/types": "8.1.5", + "node_modules/@storybook/builder-webpack5": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-8.1.6.tgz", + "integrity": "sha512-FP/vEUSM+/x+6Pof4d3EBaLH4dlzpH97Pzc3RsVD1qvEqVRHUyfbROh5Ud7/+X0m75M2kkpFtmlH/W9fVWzWGw==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.6", + "@storybook/client-logger": "8.1.6", + "@storybook/core-common": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/core-webpack": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@storybook/preview": "8.1.6", + "@storybook/preview-api": "8.1.6", "@types/node": "^18.0.0", - "ts-dedent": "^2.0.0" + "@types/semver": "^7.3.4", + "browser-assert": "^1.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "cjs-module-lexer": "^1.2.3", + "constants-browserify": "^1.0.0", + "css-loader": "^6.7.1", + "es-module-lexer": "^1.5.0", + "express": "^4.17.3", + "fork-ts-checker-webpack-plugin": "^8.0.0", + "fs-extra": "^11.1.0", + "html-webpack-plugin": "^5.5.0", + "magic-string": "^0.30.5", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "semver": "^7.3.7", + "style-loader": "^3.3.1", + "terser-webpack-plugin": "^5.3.1", + "ts-dedent": "^2.0.0", + "url": "^0.11.0", + "util": "^0.12.4", + "util-deprecate": "^1.0.2", + "webpack": "5", + "webpack-dev-middleware": "^6.1.2", + "webpack-hot-middleware": "^2.25.1", + "webpack-virtual-modules": "^0.5.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@storybook/csf": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.7.tgz", - "integrity": "sha512-53JeLZBibjQxi0Ep+/AJTfxlofJlxy1jXcSKENlnKxHjWEYyHQCumMP5yTFjf7vhNnMjEpV3zx6t23ssFiGRyw==", + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "type-fest": "^2.19.0" + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@storybook/csf-plugin": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.1.5.tgz", - "integrity": "sha512-p6imdhlcm2iEeCU+3BDDR1fuw+u9sOQDlQQbTLYhBDvjy3lydp3W0erWo5aUANhQRU2uobZf4wZ52MLrENt+dQ==", + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "@storybook/csf-tools": "8.1.5", - "unplugin": "^1.3.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@storybook/csf-tools": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-8.1.5.tgz", - "integrity": "sha512-jOfUo0arlaG4LlsdWaRfZCS0I1FhUnkf06ThzRBrrp8mFAPtOpf9iW16J3fYMS5vAdE/v+Z1RxuTRich4/JGdQ==", + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@babel/generator": "^7.24.4", - "@babel/parser": "^7.24.4", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0", - "@storybook/csf": "^0.1.7", - "@storybook/types": "8.1.5", - "fs-extra": "^11.1.0", - "recast": "^0.23.5", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@storybook/docs-mdx": { - "version": "3.1.0-next.0", - "resolved": "https://registry.npmjs.org/@storybook/docs-mdx/-/docs-mdx-3.1.0-next.0.tgz", - "integrity": "sha512-t4syFIeSyufieNovZbLruPt2DmRKpbwL4fERCZ1MifWDRIORCKLc4NCEHy+IqvIqd71/SJV2k4B51nF7vlJfmQ==", - "dev": true - }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@storybook/channels": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-8.1.6.tgz", + "integrity": "sha512-CzDnP6qfI8OC8pGUk+wPUzLPYcKhX8XbriF2gBtwl6qVM8YfkHP2mLTiDYDwBIi0rLuUbSm/SpILXQ/ouOHOGw==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/global": "^5.0.0", + "telejson": "^7.2.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@storybook/client-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-8.1.6.tgz", + "integrity": "sha512-QfSoUxS1rmrBzO7o99og9g+Gkm7sTmU5ZOpTkjszjlRqfV6/77eUnUOzUikej4LqPLmlJV5fqGuvoP0aNVksDw==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@storybook/core-common": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-8.1.6.tgz", + "integrity": "sha512-OTlfJFaTOB588ibXrrFm0TAXam6E5xV1VXSjNXL+fIifx8Kjln2HNSy1JKjvcblQneYiV4J1xPCVnAIe0EGHDg==", + "dev": true, + "dependencies": { + "@storybook/core-events": "8.1.6", + "@storybook/csf-tools": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@storybook/types": "8.1.6", + "@yarnpkg/fslib": "2.10.3", + "@yarnpkg/libzip": "2.3.0", + "chalk": "^4.1.0", + "cross-spawn": "^7.0.3", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0", + "esbuild-register": "^3.5.0", + "execa": "^5.0.0", + "file-system-cache": "2.3.0", + "find-cache-dir": "^3.0.0", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "glob": "^10.0.0", + "handlebars": "^4.7.7", + "lazy-universal-dotenv": "^4.0.0", + "node-fetch": "^2.0.0", + "picomatch": "^2.3.0", + "pkg-dir": "^5.0.0", + "prettier-fallback": "npm:prettier@^3", + "pretty-hrtime": "^1.0.3", + "resolve-from": "^5.0.0", + "semver": "^7.3.7", + "tempy": "^3.1.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@storybook/core-events": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-8.1.6.tgz", + "integrity": "sha512-DaIVe4TUp/7uQdSJYGmJv9S/S364tSgZ3S3dZ1vsf1rgoUbCp5kTBtcd/fcqgukMPREgCgO9oDhmemI3SLAqzw==", + "dev": true, + "dependencies": { + "@storybook/csf": "^0.1.7", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@storybook/csf-tools": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-8.1.6.tgz", + "integrity": "sha512-jrKfHFNhiLBhWWW4/fm2wgKEVg55e6QuYUHY16KGd7PdPuzm+2Pt7jIl5V9yIj6a59YbjeMpT6jWPKbFx2TuCw==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "@storybook/csf": "^0.1.7", + "@storybook/types": "8.1.6", + "fs-extra": "^11.1.0", + "recast": "^0.23.5", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@storybook/node-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-8.1.6.tgz", + "integrity": "sha512-IZEiTLFHu8Oom/vdEGpisSw5CfU+cw6/fTaX1P3EVClFOWVuy8/3X5MPu4wJH3jPym6E2DBduIUFeRsiuq61gA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@storybook/preview-api": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.1.6.tgz", + "integrity": "sha512-g9EvVg/DYqmjMh1uivJBJnSIvURyuK4LLabYicQNmYdQJscAeXX2bpMcA4aeci9BBm9B2RP7JbSnq7DbXZaJYA==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.6", + "@storybook/client-logger": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/csf": "^0.1.7", + "@storybook/global": "^5.0.0", + "@storybook/types": "8.1.6", + "@types/qs": "^6.9.5", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@storybook/types": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/types/-/types-8.1.6.tgz", + "integrity": "sha512-cWpS9+x1pxCO39spR8QmumMK2ub2p5cvMtrRvWaIjBFPbCwm2CvjBXFWIra2veBCZTxUKJ9VWxvi7pzRHjN/nw==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.6", + "@types/express": "^4.7.0", + "file-system-cache": "2.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.3.tgz", + "integrity": "sha512-A4ChP0Qj8oGociTs6UdlRUGANIGrCDL3y+pmQMc+dSsraXHCatFpmMey4mYELA+juqwUqwQsUgJJISXl1KWmiw==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/@storybook/channels": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-8.1.5.tgz", + "integrity": "sha512-R+puP4tWYzQUbpIp8sX6U5oI+ZUevVOaFxXGaAN3PRXjIRC38oKTVWzj/G6GdziVFzN6rDn+JsYPmiRMYo1sYg==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "8.1.5", + "@storybook/core-events": "8.1.5", + "@storybook/global": "^5.0.0", + "telejson": "^7.2.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/cli": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/cli/-/cli-8.1.6.tgz", + "integrity": "sha512-xsFdBoAbo+2h/UCWuVXiH4Tu49iQ6d+3R1J8F2n4N6rAKxMqAb6fzYnH1GeRYeZk0HGqb2iNc4kBkxj0jW0rKw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/types": "^7.24.0", + "@ndelangen/get-tarball": "^3.0.7", + "@storybook/codemod": "8.1.6", + "@storybook/core-common": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/core-server": "8.1.6", + "@storybook/csf-tools": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@storybook/telemetry": "8.1.6", + "@storybook/types": "8.1.6", + "@types/semver": "^7.3.4", + "@yarnpkg/fslib": "2.10.3", + "@yarnpkg/libzip": "2.3.0", + "chalk": "^4.1.0", + "commander": "^6.2.1", + "cross-spawn": "^7.0.3", + "detect-indent": "^6.1.0", + "envinfo": "^7.7.3", + "execa": "^5.0.0", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "get-npm-tarball-url": "^2.0.3", + "giget": "^1.0.0", + "globby": "^14.0.1", + "jscodeshift": "^0.15.1", + "leven": "^3.1.0", + "ora": "^5.4.1", + "prettier": "^3.1.1", + "prompts": "^2.4.0", + "read-pkg-up": "^7.0.1", + "semver": "^7.3.7", + "strip-json-comments": "^3.0.1", + "tempy": "^3.1.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0" + }, + "bin": { + "getstorybook": "bin/index.js", + "sb": "bin/index.js" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/cli/node_modules/@storybook/channels": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-8.1.6.tgz", + "integrity": "sha512-CzDnP6qfI8OC8pGUk+wPUzLPYcKhX8XbriF2gBtwl6qVM8YfkHP2mLTiDYDwBIi0rLuUbSm/SpILXQ/ouOHOGw==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/global": "^5.0.0", + "telejson": "^7.2.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/cli/node_modules/@storybook/client-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-8.1.6.tgz", + "integrity": "sha512-QfSoUxS1rmrBzO7o99og9g+Gkm7sTmU5ZOpTkjszjlRqfV6/77eUnUOzUikej4LqPLmlJV5fqGuvoP0aNVksDw==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/cli/node_modules/@storybook/core-common": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-8.1.6.tgz", + "integrity": "sha512-OTlfJFaTOB588ibXrrFm0TAXam6E5xV1VXSjNXL+fIifx8Kjln2HNSy1JKjvcblQneYiV4J1xPCVnAIe0EGHDg==", + "dev": true, + "dependencies": { + "@storybook/core-events": "8.1.6", + "@storybook/csf-tools": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@storybook/types": "8.1.6", + "@yarnpkg/fslib": "2.10.3", + "@yarnpkg/libzip": "2.3.0", + "chalk": "^4.1.0", + "cross-spawn": "^7.0.3", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0", + "esbuild-register": "^3.5.0", + "execa": "^5.0.0", + "file-system-cache": "2.3.0", + "find-cache-dir": "^3.0.0", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "glob": "^10.0.0", + "handlebars": "^4.7.7", + "lazy-universal-dotenv": "^4.0.0", + "node-fetch": "^2.0.0", + "picomatch": "^2.3.0", + "pkg-dir": "^5.0.0", + "prettier-fallback": "npm:prettier@^3", + "pretty-hrtime": "^1.0.3", + "resolve-from": "^5.0.0", + "semver": "^7.3.7", + "tempy": "^3.1.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/@storybook/cli/node_modules/@storybook/core-events": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-8.1.6.tgz", + "integrity": "sha512-DaIVe4TUp/7uQdSJYGmJv9S/S364tSgZ3S3dZ1vsf1rgoUbCp5kTBtcd/fcqgukMPREgCgO9oDhmemI3SLAqzw==", + "dev": true, + "dependencies": { + "@storybook/csf": "^0.1.7", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/cli/node_modules/@storybook/csf-tools": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-8.1.6.tgz", + "integrity": "sha512-jrKfHFNhiLBhWWW4/fm2wgKEVg55e6QuYUHY16KGd7PdPuzm+2Pt7jIl5V9yIj6a59YbjeMpT6jWPKbFx2TuCw==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "@storybook/csf": "^0.1.7", + "@storybook/types": "8.1.6", + "fs-extra": "^11.1.0", + "recast": "^0.23.5", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/cli/node_modules/@storybook/node-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-8.1.6.tgz", + "integrity": "sha512-IZEiTLFHu8Oom/vdEGpisSw5CfU+cw6/fTaX1P3EVClFOWVuy8/3X5MPu4wJH3jPym6E2DBduIUFeRsiuq61gA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/cli/node_modules/@storybook/types": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/types/-/types-8.1.6.tgz", + "integrity": "sha512-cWpS9+x1pxCO39spR8QmumMK2ub2p5cvMtrRvWaIjBFPbCwm2CvjBXFWIra2veBCZTxUKJ9VWxvi7pzRHjN/nw==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.6", + "@types/express": "^4.7.0", + "file-system-cache": "2.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/cli/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@storybook/cli/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/@storybook/cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/cli/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@storybook/cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/client-logger": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-8.1.5.tgz", + "integrity": "sha512-zd+aENXnOHsxBATppELmhw/UywLzCxQjz/8i/xkUjeTRB4Ggp0hJlOUdJUEdIJz631ydyytfvM70ktBj9gMl1w==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/codemod": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-8.1.6.tgz", + "integrity": "sha512-N5JeimfscAOcME7FIrTCmxcsXxow11vtmPTjYWoeLYokBodaH5RyWcyyQ5KS1ACtt+dHYoX8lepSZA5SBEzYog==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/preset-env": "^7.24.4", + "@babel/types": "^7.24.0", + "@storybook/csf": "^0.1.7", + "@storybook/csf-tools": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@storybook/types": "8.1.6", + "@types/cross-spawn": "^6.0.2", + "cross-spawn": "^7.0.3", + "globby": "^14.0.1", + "jscodeshift": "^0.15.1", + "lodash": "^4.17.21", + "prettier": "^3.1.1", + "recast": "^0.23.5", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/codemod/node_modules/@storybook/channels": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-8.1.6.tgz", + "integrity": "sha512-CzDnP6qfI8OC8pGUk+wPUzLPYcKhX8XbriF2gBtwl6qVM8YfkHP2mLTiDYDwBIi0rLuUbSm/SpILXQ/ouOHOGw==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/global": "^5.0.0", + "telejson": "^7.2.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/codemod/node_modules/@storybook/client-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-8.1.6.tgz", + "integrity": "sha512-QfSoUxS1rmrBzO7o99og9g+Gkm7sTmU5ZOpTkjszjlRqfV6/77eUnUOzUikej4LqPLmlJV5fqGuvoP0aNVksDw==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/codemod/node_modules/@storybook/core-events": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-8.1.6.tgz", + "integrity": "sha512-DaIVe4TUp/7uQdSJYGmJv9S/S364tSgZ3S3dZ1vsf1rgoUbCp5kTBtcd/fcqgukMPREgCgO9oDhmemI3SLAqzw==", + "dev": true, + "dependencies": { + "@storybook/csf": "^0.1.7", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/codemod/node_modules/@storybook/csf-tools": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-8.1.6.tgz", + "integrity": "sha512-jrKfHFNhiLBhWWW4/fm2wgKEVg55e6QuYUHY16KGd7PdPuzm+2Pt7jIl5V9yIj6a59YbjeMpT6jWPKbFx2TuCw==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "@storybook/csf": "^0.1.7", + "@storybook/types": "8.1.6", + "fs-extra": "^11.1.0", + "recast": "^0.23.5", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/codemod/node_modules/@storybook/node-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-8.1.6.tgz", + "integrity": "sha512-IZEiTLFHu8Oom/vdEGpisSw5CfU+cw6/fTaX1P3EVClFOWVuy8/3X5MPu4wJH3jPym6E2DBduIUFeRsiuq61gA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/codemod/node_modules/@storybook/types": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/types/-/types-8.1.6.tgz", + "integrity": "sha512-cWpS9+x1pxCO39spR8QmumMK2ub2p5cvMtrRvWaIjBFPbCwm2CvjBXFWIra2veBCZTxUKJ9VWxvi7pzRHjN/nw==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.6", + "@types/express": "^4.7.0", + "file-system-cache": "2.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/components": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.1.5.tgz", + "integrity": "sha512-IxoT2pH7V98gF0zDAMUuq9sUZPg0vvQ9Y+A13HeYHvaY25XdesXVMbdzEd6SpeLYmfPykMPIAEcADfqeM6eXfA==", + "dev": true, + "dependencies": { + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-slot": "^1.0.2", + "@storybook/client-logger": "8.1.5", + "@storybook/csf": "^0.1.7", + "@storybook/global": "^5.0.0", + "@storybook/icons": "^1.2.5", + "@storybook/theming": "8.1.5", + "@storybook/types": "8.1.5", + "memoizerific": "^1.11.3", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" + } + }, + "node_modules/@storybook/core-common": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-8.1.5.tgz", + "integrity": "sha512-1QDOT6KPZ9KV7Gs1yyqzvSwGBmNSUB33gckUldSBF4aqP+tZ7W5JIQ6/YTtp3V02sEokZGdL9Ud4LczQxTgy3A==", + "dev": true, + "dependencies": { + "@storybook/core-events": "8.1.5", + "@storybook/csf-tools": "8.1.5", + "@storybook/node-logger": "8.1.5", + "@storybook/types": "8.1.5", + "@yarnpkg/fslib": "2.10.3", + "@yarnpkg/libzip": "2.3.0", + "chalk": "^4.1.0", + "cross-spawn": "^7.0.3", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0", + "esbuild-register": "^3.5.0", + "execa": "^5.0.0", + "file-system-cache": "2.3.0", + "find-cache-dir": "^3.0.0", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "glob": "^10.0.0", + "handlebars": "^4.7.7", + "lazy-universal-dotenv": "^4.0.0", + "node-fetch": "^2.0.0", + "picomatch": "^2.3.0", + "pkg-dir": "^5.0.0", + "prettier-fallback": "npm:prettier@^3", + "pretty-hrtime": "^1.0.3", + "resolve-from": "^5.0.0", + "semver": "^7.3.7", + "tempy": "^3.1.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-common/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/core-common/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/core-common/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/@storybook/core-common/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/core-common/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@storybook/core-common/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/core-events": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-8.1.5.tgz", + "integrity": "sha512-fgwbrHoLtSX6kfmamTGJqD+KfuEgun8cc4mWKZK094ByaqbSjhnOyeYO1sfVk8qst7QTFlOfhLAUe4cz1z149A==", + "dev": true, + "dependencies": { + "@storybook/csf": "^0.1.7", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-server/-/core-server-8.1.6.tgz", + "integrity": "sha512-rgkeTG8V4emzhPqjlhchsjLay0WtgK7SrXNf1X40oTJIwmbgbReLJ5EmOXBe9rhWSXJ13aKL3l6JuTLAoptSkg==", + "dev": true, + "dependencies": { + "@aw-web-design/x-default-browser": "1.4.126", + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "@discoveryjs/json-ext": "^0.5.3", + "@storybook/builder-manager": "8.1.6", + "@storybook/channels": "8.1.6", + "@storybook/core-common": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/csf": "^0.1.7", + "@storybook/csf-tools": "8.1.6", + "@storybook/docs-mdx": "3.1.0-next.0", + "@storybook/global": "^5.0.0", + "@storybook/manager": "8.1.6", + "@storybook/manager-api": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@storybook/preview-api": "8.1.6", + "@storybook/telemetry": "8.1.6", + "@storybook/types": "8.1.6", + "@types/detect-port": "^1.3.0", + "@types/diff": "^5.0.9", + "@types/node": "^18.0.0", + "@types/pretty-hrtime": "^1.0.0", + "@types/semver": "^7.3.4", + "better-opn": "^3.0.2", + "chalk": "^4.1.0", + "cli-table3": "^0.6.1", + "compression": "^1.7.4", + "detect-port": "^1.3.0", + "diff": "^5.2.0", + "express": "^4.17.3", + "fs-extra": "^11.1.0", + "globby": "^14.0.1", + "lodash": "^4.17.21", + "open": "^8.4.0", + "pretty-hrtime": "^1.0.3", + "prompts": "^2.4.0", + "read-pkg-up": "^7.0.1", + "semver": "^7.3.7", + "telejson": "^7.2.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0", + "util": "^0.12.4", + "util-deprecate": "^1.0.2", + "watchpack": "^2.2.0", + "ws": "^8.2.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-server/node_modules/@storybook/channels": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-8.1.6.tgz", + "integrity": "sha512-CzDnP6qfI8OC8pGUk+wPUzLPYcKhX8XbriF2gBtwl6qVM8YfkHP2mLTiDYDwBIi0rLuUbSm/SpILXQ/ouOHOGw==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/global": "^5.0.0", + "telejson": "^7.2.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server/node_modules/@storybook/client-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-8.1.6.tgz", + "integrity": "sha512-QfSoUxS1rmrBzO7o99og9g+Gkm7sTmU5ZOpTkjszjlRqfV6/77eUnUOzUikej4LqPLmlJV5fqGuvoP0aNVksDw==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server/node_modules/@storybook/core-common": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-8.1.6.tgz", + "integrity": "sha512-OTlfJFaTOB588ibXrrFm0TAXam6E5xV1VXSjNXL+fIifx8Kjln2HNSy1JKjvcblQneYiV4J1xPCVnAIe0EGHDg==", + "dev": true, + "dependencies": { + "@storybook/core-events": "8.1.6", + "@storybook/csf-tools": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@storybook/types": "8.1.6", + "@yarnpkg/fslib": "2.10.3", + "@yarnpkg/libzip": "2.3.0", + "chalk": "^4.1.0", + "cross-spawn": "^7.0.3", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0", + "esbuild-register": "^3.5.0", + "execa": "^5.0.0", + "file-system-cache": "2.3.0", + "find-cache-dir": "^3.0.0", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "glob": "^10.0.0", + "handlebars": "^4.7.7", + "lazy-universal-dotenv": "^4.0.0", + "node-fetch": "^2.0.0", + "picomatch": "^2.3.0", + "pkg-dir": "^5.0.0", + "prettier-fallback": "npm:prettier@^3", + "pretty-hrtime": "^1.0.3", + "resolve-from": "^5.0.0", + "semver": "^7.3.7", + "tempy": "^3.1.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/@storybook/core-server/node_modules/@storybook/core-events": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-8.1.6.tgz", + "integrity": "sha512-DaIVe4TUp/7uQdSJYGmJv9S/S364tSgZ3S3dZ1vsf1rgoUbCp5kTBtcd/fcqgukMPREgCgO9oDhmemI3SLAqzw==", + "dev": true, + "dependencies": { + "@storybook/csf": "^0.1.7", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server/node_modules/@storybook/csf-tools": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-8.1.6.tgz", + "integrity": "sha512-jrKfHFNhiLBhWWW4/fm2wgKEVg55e6QuYUHY16KGd7PdPuzm+2Pt7jIl5V9yIj6a59YbjeMpT6jWPKbFx2TuCw==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "@storybook/csf": "^0.1.7", + "@storybook/types": "8.1.6", + "fs-extra": "^11.1.0", + "recast": "^0.23.5", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server/node_modules/@storybook/manager-api": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.1.6.tgz", + "integrity": "sha512-L/s1FdFh/P+eFmQwLtFtJHwFJrGD9H7nauaQlKJOrU3GeXfjBjtlAZQF0Q6B4ZTGxwZjQrzShpt/0yKc6gymtw==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.6", + "@storybook/client-logger": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/csf": "^0.1.7", + "@storybook/global": "^5.0.0", + "@storybook/icons": "^1.2.5", + "@storybook/router": "8.1.6", + "@storybook/theming": "8.1.6", + "@storybook/types": "8.1.6", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "store2": "^2.14.2", + "telejson": "^7.2.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server/node_modules/@storybook/node-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-8.1.6.tgz", + "integrity": "sha512-IZEiTLFHu8Oom/vdEGpisSw5CfU+cw6/fTaX1P3EVClFOWVuy8/3X5MPu4wJH3jPym6E2DBduIUFeRsiuq61gA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server/node_modules/@storybook/preview-api": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.1.6.tgz", + "integrity": "sha512-g9EvVg/DYqmjMh1uivJBJnSIvURyuK4LLabYicQNmYdQJscAeXX2bpMcA4aeci9BBm9B2RP7JbSnq7DbXZaJYA==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.6", + "@storybook/client-logger": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/csf": "^0.1.7", + "@storybook/global": "^5.0.0", + "@storybook/types": "8.1.6", + "@types/qs": "^6.9.5", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server/node_modules/@storybook/router": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-8.1.6.tgz", + "integrity": "sha512-tvuhB2uXHEKK640Epm1SqVzPhQ9lXYfF7FX6FleJgVYEvZpJpNTD4RojedQoLI6SUUSXNy1Vs2QV26VM0XIPHQ==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "8.1.6", + "memoizerific": "^1.11.3", + "qs": "^6.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server/node_modules/@storybook/theming": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.1.6.tgz", + "integrity": "sha512-0Cl/7/0z2WSfXhZ9XSw6rgEjb0fXac7jfktieX0vYo1YckrNpWFRQP9NCpVPAcYZaFLlRSOqYark6CLoutEsIg==", + "dev": true, + "dependencies": { + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@storybook/client-logger": "8.1.6", + "@storybook/global": "^5.0.0", + "memoizerific": "^1.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/core-server/node_modules/@storybook/types": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/types/-/types-8.1.6.tgz", + "integrity": "sha512-cWpS9+x1pxCO39spR8QmumMK2ub2p5cvMtrRvWaIjBFPbCwm2CvjBXFWIra2veBCZTxUKJ9VWxvi7pzRHjN/nw==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.6", + "@types/express": "^4.7.0", + "file-system-cache": "2.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/core-server/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/core-server/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/@storybook/core-server/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/core-server/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@storybook/core-server/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/core-webpack": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-8.1.6.tgz", + "integrity": "sha512-KjcAEDpHnX0M/7/hUckmZghvb+8FwrShQ2On92jkeL1HgKwzk9HUxFowMJAn1arYfkUT45q9g7HfqSmon36f5Q==", + "dev": true, + "dependencies": { + "@storybook/core-common": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@storybook/types": "8.1.6", + "@types/node": "^18.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@storybook/channels": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-8.1.6.tgz", + "integrity": "sha512-CzDnP6qfI8OC8pGUk+wPUzLPYcKhX8XbriF2gBtwl6qVM8YfkHP2mLTiDYDwBIi0rLuUbSm/SpILXQ/ouOHOGw==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "8.1.6", + "@storybook/core-events": "8.1.6", + "@storybook/global": "^5.0.0", + "telejson": "^7.2.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@storybook/client-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-8.1.6.tgz", + "integrity": "sha512-QfSoUxS1rmrBzO7o99og9g+Gkm7sTmU5ZOpTkjszjlRqfV6/77eUnUOzUikej4LqPLmlJV5fqGuvoP0aNVksDw==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@storybook/core-common": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-8.1.6.tgz", + "integrity": "sha512-OTlfJFaTOB588ibXrrFm0TAXam6E5xV1VXSjNXL+fIifx8Kjln2HNSy1JKjvcblQneYiV4J1xPCVnAIe0EGHDg==", + "dev": true, + "dependencies": { + "@storybook/core-events": "8.1.6", + "@storybook/csf-tools": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@storybook/types": "8.1.6", + "@yarnpkg/fslib": "2.10.3", + "@yarnpkg/libzip": "2.3.0", + "chalk": "^4.1.0", + "cross-spawn": "^7.0.3", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0", + "esbuild-register": "^3.5.0", + "execa": "^5.0.0", + "file-system-cache": "2.3.0", + "find-cache-dir": "^3.0.0", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "glob": "^10.0.0", + "handlebars": "^4.7.7", + "lazy-universal-dotenv": "^4.0.0", + "node-fetch": "^2.0.0", + "picomatch": "^2.3.0", + "pkg-dir": "^5.0.0", + "prettier-fallback": "npm:prettier@^3", + "pretty-hrtime": "^1.0.3", + "resolve-from": "^5.0.0", + "semver": "^7.3.7", + "tempy": "^3.1.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/@storybook/core-webpack/node_modules/@storybook/core-events": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-8.1.6.tgz", + "integrity": "sha512-DaIVe4TUp/7uQdSJYGmJv9S/S364tSgZ3S3dZ1vsf1rgoUbCp5kTBtcd/fcqgukMPREgCgO9oDhmemI3SLAqzw==", + "dev": true, + "dependencies": { + "@storybook/csf": "^0.1.7", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@storybook/csf-tools": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-8.1.6.tgz", + "integrity": "sha512-jrKfHFNhiLBhWWW4/fm2wgKEVg55e6QuYUHY16KGd7PdPuzm+2Pt7jIl5V9yIj6a59YbjeMpT6jWPKbFx2TuCw==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "@storybook/csf": "^0.1.7", + "@storybook/types": "8.1.6", + "fs-extra": "^11.1.0", + "recast": "^0.23.5", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@storybook/node-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-8.1.6.tgz", + "integrity": "sha512-IZEiTLFHu8Oom/vdEGpisSw5CfU+cw6/fTaX1P3EVClFOWVuy8/3X5MPu4wJH3jPym6E2DBduIUFeRsiuq61gA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@storybook/types": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/types/-/types-8.1.6.tgz", + "integrity": "sha512-cWpS9+x1pxCO39spR8QmumMK2ub2p5cvMtrRvWaIjBFPbCwm2CvjBXFWIra2veBCZTxUKJ9VWxvi7pzRHjN/nw==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.6", + "@types/express": "^4.7.0", + "file-system-cache": "2.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-webpack/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/core-webpack/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/core-webpack/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/@storybook/core-webpack/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/core-webpack/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@storybook/core-webpack/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/csf": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.7.tgz", + "integrity": "sha512-53JeLZBibjQxi0Ep+/AJTfxlofJlxy1jXcSKENlnKxHjWEYyHQCumMP5yTFjf7vhNnMjEpV3zx6t23ssFiGRyw==", + "dev": true, + "dependencies": { + "type-fest": "^2.19.0" + } + }, + "node_modules/@storybook/csf-plugin": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.1.5.tgz", + "integrity": "sha512-p6imdhlcm2iEeCU+3BDDR1fuw+u9sOQDlQQbTLYhBDvjy3lydp3W0erWo5aUANhQRU2uobZf4wZ52MLrENt+dQ==", + "dev": true, + "dependencies": { + "@storybook/csf-tools": "8.1.5", + "unplugin": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/csf-tools": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-8.1.5.tgz", + "integrity": "sha512-jOfUo0arlaG4LlsdWaRfZCS0I1FhUnkf06ThzRBrrp8mFAPtOpf9iW16J3fYMS5vAdE/v+Z1RxuTRich4/JGdQ==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "@storybook/csf": "^0.1.7", + "@storybook/types": "8.1.5", + "fs-extra": "^11.1.0", + "recast": "^0.23.5", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/docs-mdx": { + "version": "3.1.0-next.0", + "resolved": "https://registry.npmjs.org/@storybook/docs-mdx/-/docs-mdx-3.1.0-next.0.tgz", + "integrity": "sha512-t4syFIeSyufieNovZbLruPt2DmRKpbwL4fERCZ1MifWDRIORCKLc4NCEHy+IqvIqd71/SJV2k4B51nF7vlJfmQ==", + "dev": true + }, "node_modules/@storybook/docs-tools": { "version": "8.1.5", "resolved": "https://registry.npmjs.org/@storybook/docs-tools/-/docs-tools-8.1.5.tgz", "integrity": "sha512-zlHv8fi1Bw8RbjkGGBJoO/RbM41bwxU1kV76TPQUyqQmzqPRsHi3zt+8bdddQLNrC6rhTF+Cj3yEdPfTZrB0aA==", "dev": true, - "dependencies": { - "@storybook/core-common": "8.1.5", - "@storybook/core-events": "8.1.5", - "@storybook/preview-api": "8.1.5", - "@storybook/types": "8.1.5", - "@types/doctrine": "^0.0.3", - "assert": "^2.1.0", - "doctrine": "^3.0.0", - "lodash": "^4.17.21" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" + "dependencies": { + "@storybook/core-common": "8.1.5", + "@storybook/core-events": "8.1.5", + "@storybook/preview-api": "8.1.5", + "@storybook/types": "8.1.5", + "@types/doctrine": "^0.0.3", + "assert": "^2.1.0", + "doctrine": "^3.0.0", + "lodash": "^4.17.21" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true + }, + "node_modules/@storybook/icons": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.2.9.tgz", + "integrity": "sha512-cOmylsz25SYXaJL/gvTk/dl3pyk7yBFRfeXTsHvTA3dfhoU/LWSq0NKL9nM7WBasJyn6XPSGnLS4RtKXLw5EUg==", + "dev": true, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/instrumenter": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.1.5.tgz", + "integrity": "sha512-pyOg0YeL06bIFw8J3y0E1xyaJEVX5dtyvFZ31xi7jcElhsO/uPTbrJzSfMFtv3kDXU3hKDpeI2pbxpkFUVSvsQ==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.5", + "@storybook/client-logger": "8.1.5", + "@storybook/core-events": "8.1.5", + "@storybook/global": "^5.0.0", + "@storybook/preview-api": "8.1.5", + "@vitest/utils": "^1.3.1", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/manager": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-8.1.6.tgz", + "integrity": "sha512-B7xc09FYHqC1sknJoWkGHBBCMQlfg7hF+4x42cGhAyYed4TeYAf7b1PDniq8L/PLbUgzTw+A62UC1fMurCcVDQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/manager-api": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.1.5.tgz", + "integrity": "sha512-iVP7FOKDf9L7zWCb8C2XeZjWSILS3hHeNwILvd9YSX9dg9du41kJYahsAHxDCR/jp/gv0ZM/V0vuHzi+naVPkQ==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.5", + "@storybook/client-logger": "8.1.5", + "@storybook/core-events": "8.1.5", + "@storybook/csf": "^0.1.7", + "@storybook/global": "^5.0.0", + "@storybook/icons": "^1.2.5", + "@storybook/router": "8.1.5", + "@storybook/theming": "8.1.5", + "@storybook/types": "8.1.5", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "store2": "^2.14.2", + "telejson": "^7.2.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/node-logger": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-8.1.5.tgz", + "integrity": "sha512-9qwPX/uGhdHaVjeVUSwJUSbKX7g9goyhGYdKVuCEyl7vHR9Kp7Zkag2sEHmVdd9ixTea3jk2GZQEbnBDNQNGnw==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/preview": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/preview/-/preview-8.1.6.tgz", + "integrity": "sha512-o9OgOmO10GyX1ZC7WiapYqGdst4TOCPLqWSu3H2nL4ZT7BQLUQfCy30kyoMO7KyxCgc5K5rcqG7qZ/N0tfUgRg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/preview-api": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.1.5.tgz", + "integrity": "sha512-pv0aT5WbnSYR7KWQgy3jLfuBM0ocYG6GTcmZLREW5554oiBPHhzNFv+ZrBI47RzbrbFxq1h5dj4v8lkEcKIrbA==", + "dev": true, + "dependencies": { + "@storybook/channels": "8.1.5", + "@storybook/client-logger": "8.1.5", + "@storybook/core-events": "8.1.5", + "@storybook/csf": "^0.1.7", + "@storybook/global": "^5.0.0", + "@storybook/types": "8.1.5", + "@types/qs": "^6.9.5", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/react-dom-shim": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.1.5.tgz", + "integrity": "sha512-eyHSngIBHeFT4vVkQTN2+c/mSKCPrb8uPpWbrc3ihGBKvL/656erWNmiUVnY3zuQvCBPz2q2Vy3v2Pr+nvfOTw==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" + } + }, + "node_modules/@storybook/router": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-8.1.5.tgz", + "integrity": "sha512-DCwvAswlbLhQu6REPV04XNRhtPvsrRqHjMHKzjlfs+qYJWY7Egkofy05qlegqjkMDve33czfnRGBm0C16IydkA==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "8.1.5", + "memoizerific": "^1.11.3", + "qs": "^6.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/telemetry": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-8.1.6.tgz", + "integrity": "sha512-qNWjQPF6ufRvLCAavulhNYoqldDIeBvioFuCjLlwbw3BZw3ck7pwh1vZg4AJ0SAfzbnpnXPGrHe31gnxV0D6tw==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "8.1.6", + "@storybook/core-common": "8.1.6", + "@storybook/csf-tools": "8.1.6", + "chalk": "^4.1.0", + "detect-package-manager": "^2.0.1", + "fetch-retry": "^5.0.2", + "fs-extra": "^11.1.0", + "read-pkg-up": "^7.0.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/telemetry/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@storybook/global": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", - "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", - "dev": true + "node_modules/@storybook/telemetry/node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@storybook/icons": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.2.9.tgz", - "integrity": "sha512-cOmylsz25SYXaJL/gvTk/dl3pyk7yBFRfeXTsHvTA3dfhoU/LWSq0NKL9nM7WBasJyn6XPSGnLS4RtKXLw5EUg==", + "node_modules/@storybook/telemetry/node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], "dev": true, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + "node": ">=12" } }, - "node_modules/@storybook/instrumenter": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.1.5.tgz", - "integrity": "sha512-pyOg0YeL06bIFw8J3y0E1xyaJEVX5dtyvFZ31xi7jcElhsO/uPTbrJzSfMFtv3kDXU3hKDpeI2pbxpkFUVSvsQ==", + "node_modules/@storybook/telemetry/node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], "dev": true, - "dependencies": { - "@storybook/channels": "8.1.5", - "@storybook/client-logger": "8.1.5", - "@storybook/core-events": "8.1.5", - "@storybook/global": "^5.0.0", - "@storybook/preview-api": "8.1.5", - "@vitest/utils": "^1.3.1", - "util": "^0.12.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@storybook/manager": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-8.1.5.tgz", - "integrity": "sha512-qMYwD1cXW0hJ3pMmdMlbsqktVBlsjsqwMH5PBzAN4FoWiCQ/yHeAnDXRUgFFaLcORS72h9H/cQuJ+p//RdeURg==", + "node_modules/@storybook/telemetry/node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@storybook/manager-api": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.1.5.tgz", - "integrity": "sha512-iVP7FOKDf9L7zWCb8C2XeZjWSILS3hHeNwILvd9YSX9dg9du41kJYahsAHxDCR/jp/gv0ZM/V0vuHzi+naVPkQ==", + "node_modules/@storybook/telemetry/node_modules/@storybook/channels": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-8.1.6.tgz", + "integrity": "sha512-CzDnP6qfI8OC8pGUk+wPUzLPYcKhX8XbriF2gBtwl6qVM8YfkHP2mLTiDYDwBIi0rLuUbSm/SpILXQ/ouOHOGw==", "dev": true, "dependencies": { - "@storybook/channels": "8.1.5", - "@storybook/client-logger": "8.1.5", - "@storybook/core-events": "8.1.5", - "@storybook/csf": "^0.1.7", + "@storybook/client-logger": "8.1.6", + "@storybook/core-events": "8.1.6", "@storybook/global": "^5.0.0", - "@storybook/icons": "^1.2.5", - "@storybook/router": "8.1.5", - "@storybook/theming": "8.1.5", - "@storybook/types": "8.1.5", - "dequal": "^2.0.2", - "lodash": "^4.17.21", - "memoizerific": "^1.11.3", - "store2": "^2.14.2", "telejson": "^7.2.0", - "ts-dedent": "^2.0.0" + "tiny-invariant": "^1.3.1" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/node-logger": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-8.1.5.tgz", - "integrity": "sha512-9qwPX/uGhdHaVjeVUSwJUSbKX7g9goyhGYdKVuCEyl7vHR9Kp7Zkag2sEHmVdd9ixTea3jk2GZQEbnBDNQNGnw==", + "node_modules/@storybook/telemetry/node_modules/@storybook/client-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-8.1.6.tgz", + "integrity": "sha512-QfSoUxS1rmrBzO7o99og9g+Gkm7sTmU5ZOpTkjszjlRqfV6/77eUnUOzUikej4LqPLmlJV5fqGuvoP0aNVksDw==", "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/preview": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/preview/-/preview-8.1.5.tgz", - "integrity": "sha512-8qNzK/5fCjfWcup5w3UxJXMAUp4+iOdh+vO+vDIJWSbPXRPtuarSM/tv/12N7hz/zvCpGLGBql0BE+oyC0bmhw==", + "node_modules/@storybook/telemetry/node_modules/@storybook/core-common": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-8.1.6.tgz", + "integrity": "sha512-OTlfJFaTOB588ibXrrFm0TAXam6E5xV1VXSjNXL+fIifx8Kjln2HNSy1JKjvcblQneYiV4J1xPCVnAIe0EGHDg==", "dev": true, + "dependencies": { + "@storybook/core-events": "8.1.6", + "@storybook/csf-tools": "8.1.6", + "@storybook/node-logger": "8.1.6", + "@storybook/types": "8.1.6", + "@yarnpkg/fslib": "2.10.3", + "@yarnpkg/libzip": "2.3.0", + "chalk": "^4.1.0", + "cross-spawn": "^7.0.3", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0", + "esbuild-register": "^3.5.0", + "execa": "^5.0.0", + "file-system-cache": "2.3.0", + "find-cache-dir": "^3.0.0", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "glob": "^10.0.0", + "handlebars": "^4.7.7", + "lazy-universal-dotenv": "^4.0.0", + "node-fetch": "^2.0.0", + "picomatch": "^2.3.0", + "pkg-dir": "^5.0.0", + "prettier-fallback": "npm:prettier@^3", + "pretty-hrtime": "^1.0.3", + "resolve-from": "^5.0.0", + "semver": "^7.3.7", + "tempy": "^3.1.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0", + "util": "^0.12.4" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } } }, - "node_modules/@storybook/preview-api": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.1.5.tgz", - "integrity": "sha512-pv0aT5WbnSYR7KWQgy3jLfuBM0ocYG6GTcmZLREW5554oiBPHhzNFv+ZrBI47RzbrbFxq1h5dj4v8lkEcKIrbA==", + "node_modules/@storybook/telemetry/node_modules/@storybook/core-events": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-8.1.6.tgz", + "integrity": "sha512-DaIVe4TUp/7uQdSJYGmJv9S/S364tSgZ3S3dZ1vsf1rgoUbCp5kTBtcd/fcqgukMPREgCgO9oDhmemI3SLAqzw==", "dev": true, "dependencies": { - "@storybook/channels": "8.1.5", - "@storybook/client-logger": "8.1.5", - "@storybook/core-events": "8.1.5", "@storybook/csf": "^0.1.7", - "@storybook/global": "^5.0.0", - "@storybook/types": "8.1.5", - "@types/qs": "^6.9.5", - "dequal": "^2.0.2", - "lodash": "^4.17.21", - "memoizerific": "^1.11.3", - "qs": "^6.10.0", - "tiny-invariant": "^1.3.1", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2" + "ts-dedent": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/react-dom-shim": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.1.5.tgz", - "integrity": "sha512-eyHSngIBHeFT4vVkQTN2+c/mSKCPrb8uPpWbrc3ihGBKvL/656erWNmiUVnY3zuQvCBPz2q2Vy3v2Pr+nvfOTw==", + "node_modules/@storybook/telemetry/node_modules/@storybook/csf-tools": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-8.1.6.tgz", + "integrity": "sha512-jrKfHFNhiLBhWWW4/fm2wgKEVg55e6QuYUHY16KGd7PdPuzm+2Pt7jIl5V9yIj6a59YbjeMpT6jWPKbFx2TuCw==", "dev": true, + "dependencies": { + "@babel/generator": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "@storybook/csf": "^0.1.7", + "@storybook/types": "8.1.6", + "fs-extra": "^11.1.0", + "recast": "^0.23.5", + "ts-dedent": "^2.0.0" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" } }, - "node_modules/@storybook/router": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/router/-/router-8.1.5.tgz", - "integrity": "sha512-DCwvAswlbLhQu6REPV04XNRhtPvsrRqHjMHKzjlfs+qYJWY7Egkofy05qlegqjkMDve33czfnRGBm0C16IydkA==", + "node_modules/@storybook/telemetry/node_modules/@storybook/node-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-8.1.6.tgz", + "integrity": "sha512-IZEiTLFHu8Oom/vdEGpisSw5CfU+cw6/fTaX1P3EVClFOWVuy8/3X5MPu4wJH3jPym6E2DBduIUFeRsiuq61gA==", "dev": true, - "dependencies": { - "@storybook/client-logger": "8.1.5", - "memoizerific": "^1.11.3", - "qs": "^6.10.0" - }, "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/telemetry": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-8.1.5.tgz", - "integrity": "sha512-QbB1Ox7oBaCvIF2TacFjPLi1XYeHxSPeZUuFXeE+tSMdvvWZzYLnXfj/oISmV6Q+X5VZfyJVMrZ2LfeW9CuFNg==", + "node_modules/@storybook/telemetry/node_modules/@storybook/types": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/types/-/types-8.1.6.tgz", + "integrity": "sha512-cWpS9+x1pxCO39spR8QmumMK2ub2p5cvMtrRvWaIjBFPbCwm2CvjBXFWIra2veBCZTxUKJ9VWxvi7pzRHjN/nw==", "dev": true, "dependencies": { - "@storybook/client-logger": "8.1.5", - "@storybook/core-common": "8.1.5", - "@storybook/csf-tools": "8.1.5", - "chalk": "^4.1.0", - "detect-package-manager": "^2.0.1", - "fetch-retry": "^5.0.2", - "fs-extra": "^11.1.0", - "read-pkg-up": "^7.0.1" + "@storybook/channels": "8.1.6", + "@types/express": "^4.7.0", + "file-system-cache": "2.3.0" }, "funding": { "type": "opencollective", @@ -8888,6 +12803,44 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@storybook/telemetry/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, "node_modules/@storybook/telemetry/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -8897,6 +12850,18 @@ "node": ">=8" } }, + "node_modules/@storybook/telemetry/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@storybook/telemetry/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -16178,9 +20143,9 @@ "dev": true }, "node_modules/flow-parser": { - "version": "0.237.1", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.237.1.tgz", - "integrity": "sha512-PUeG8GQLmrv49vEcFcag7mriJvVs7Yyegnv1DGskvcokhP8UyqWsLV0KoTQ1iAW3ePVUIGUc3MFfBaXwz9MmIg==", + "version": "0.237.2", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.237.2.tgz", + "integrity": "sha512-mvI/kdfr3l1waaPbThPA8dJa77nHXrfZIun+SWvFwSwDjmeByU7mGJGRmv1+7guU6ccyLV8e1lqZA1lD4iMGnQ==", "dev": true, "engines": { "node": ">=0.4.0" @@ -17828,12 +21793,6 @@ "loose-envify": "^1.0.0" } }, - "node_modules/ip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", - "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", - "dev": true - }, "node_modules/ip-address": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", @@ -28099,12 +32058,12 @@ "dev": true }, "node_modules/storybook": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.1.5.tgz", - "integrity": "sha512-v4o8AfTvxWpdGa9Pa9x8EAmqbN5yJc+2fW8b6ZaCsDOTh2t5Y3EUHbIzdtvX+1Gb6ALsOs5e2Q9GlCAzjz+WNQ==", + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.1.6.tgz", + "integrity": "sha512-qouQEB+sSb9ktE6fGVoBy6CLEUq4NOqDUpt/EhnITaWqzUeAZSQXTcoHg9DXhTMiynnbfqsUcZuK9PZOjgt7/w==", "dev": true, "dependencies": { - "@storybook/cli": "8.1.5" + "@storybook/cli": "8.1.6" }, "bin": { "sb": "index.js", diff --git a/package.json b/package.json index bbbe27f45d..dcb534f3b8 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "@storybook/addon-essentials": "^8.1.2", "@storybook/addon-interactions": "^8.1.2", "@storybook/addon-mdx-gfm": "^8.1.2", - "@storybook/angular": "^8.1.4", + "@storybook/angular": "^8.1.6", "@storybook/test-runner": "^0.18.1", "@testing-library/angular": "^16.0.0", "@testing-library/jest-dom": "^6.4.5", @@ -99,7 +99,7 @@ "postcss-value-parser": "^4.2.0", "prettier": "^3.2.5", "sass": "^1.62.1", - "storybook": "^8.0.6", + "storybook": "^8.1.6", "stylelint": "^14.15.0", "stylelint-config-prettier": "^9.0.4", "stylelint-prettier": "^2.0.0", diff --git a/packages/ng/button/button.component.ts b/packages/ng/button/button.component.ts index 95e3f6c112..f20a62650c 100644 --- a/packages/ng/button/button.component.ts +++ b/packages/ng/button/button.component.ts @@ -1,4 +1,4 @@ -import { booleanAttribute, ChangeDetectionStrategy, Component, ContentChild, ElementRef, inject, Input, OnChanges, ViewEncapsulation } from '@angular/core'; +import { booleanAttribute, ChangeDetectionStrategy, Component, ContentChild, ElementRef, inject, Input, OnChanges, OnInit, Renderer2, ViewEncapsulation } from '@angular/core'; import { LuClass, Palette } from '@lucca-front/ng/core'; import { IconComponent } from '@lucca-front/ng/icon'; @@ -15,9 +15,10 @@ import { IconComponent } from '@lucca-front/ng/icon'; class: 'button', }, }) -export class ButtonComponent implements OnChanges { +export class ButtonComponent implements OnChanges, OnInit { #luClass = inject(LuClass); #elementRef = inject>(ElementRef); + #renderer = inject(Renderer2); @Input() size: 'M' | 'S' | 'XS'; @@ -27,6 +28,11 @@ export class ButtonComponent implements OnChanges { }) block = false; + @Input({ + transform: booleanAttribute, + }) + delete = false; + @Input() palette: Palette = 'none'; @@ -63,6 +69,12 @@ export class ButtonComponent implements OnChanges { this.updateClasses(); } + ngOnInit(): void { + if (this.#elementRef.nativeElement.tagName.toLowerCase() === 'button' && this.#elementRef.nativeElement.getAttribute('type') === null) { + this.#renderer.setAttribute(this.#elementRef.nativeElement, 'type', 'button'); + } + } + updateClasses(): void { const ngClassConfig = { [`mod-${this.size}`]: true, @@ -71,6 +83,7 @@ export class ButtonComponent implements OnChanges { [`is-${this.state}`]: true, ['mod-onlyIcon']: this.iconOnly, ['mod-withIcon']: this.#iconComponentRef !== undefined, + ['mod-delete']: this.delete, }; if (this.luButton !== '') { diff --git a/packages/ng/core-select/option/option-outlet.directive.ts b/packages/ng/core-select/option/option-outlet.directive.ts index c4132f74f3..bbbe06b7e5 100644 --- a/packages/ng/core-select/option/option-outlet.directive.ts +++ b/packages/ng/core-select/option/option-outlet.directive.ts @@ -62,7 +62,7 @@ export class LuOptionOutletDirective implements OnChanges, OnDestroy { private updateRefValue(): void { if (this.embeddedViewRef) { - this.embeddedViewRef.context = { $implicit: this.luOptionOutletValue }; + this.embeddedViewRef.context.$implicit = this.luOptionOutletValue; } else if (this.componentRef) { this.optionContext.option$.next(this.luOptionOutletValue); } diff --git a/packages/ng/core/date/date-adapter.class.ts b/packages/ng/core/date/date-adapter.class.ts index 400e79ec9a..70c1a5bbf1 100644 --- a/packages/ng/core/date/date-adapter.class.ts +++ b/packages/ng/core/date/date-adapter.class.ts @@ -1,12 +1,12 @@ import { ILuDateAdapter } from './date-adapter.interface'; -import { ELuDateGranularity } from './date-granularity.enum'; +import { ELuDateGranularity, LuDateGranularity } from './date-granularity.enum'; export abstract class ALuDateAdapter implements ILuDateAdapter { abstract forge(year: number, month: number, date: number): D; abstract forgeToday(): D; abstract forgeInvalid(): D; abstract isValid(d: D): boolean; - compare(a: D, b: D, granularity: ELuDateGranularity): number { + compare(a: D, b: D, granularity: LuDateGranularity): number { if (!a || !b || !this.isValid(a) || !this.isValid(b)) { throw new Error('you must provide valid and not null dates to be compared'); } @@ -60,8 +60,8 @@ export abstract class ALuDateAdapter implements ILuDateAdapter { return 0; } - abstract isParsable(text: string, granularity?: ELuDateGranularity): boolean; - abstract parse(text: string, granularity?: ELuDateGranularity): D; + abstract isParsable(text: string, granularity?: LuDateGranularity): boolean; + abstract parse(text: string, granularity?: LuDateGranularity): D; abstract format(d: D, format: string): string; abstract clone(d: D): D; @@ -70,5 +70,5 @@ export abstract class ALuDateAdapter implements ILuDateAdapter { abstract getDate(d: D): number; abstract getDay(d: D): number; - abstract add(d: D, count: number, granularity: ELuDateGranularity): D; + abstract add(d: D, count: number, granularity: LuDateGranularity): D; } diff --git a/packages/ng/core/date/date-adapter.interface.ts b/packages/ng/core/date/date-adapter.interface.ts index b1eb32174d..0e85a8087b 100644 --- a/packages/ng/core/date/date-adapter.interface.ts +++ b/packages/ng/core/date/date-adapter.interface.ts @@ -1,13 +1,13 @@ -import { ELuDateGranularity } from './date-granularity.enum'; +import { LuDateGranularity } from './date-granularity.enum'; export interface ILuDateAdapter { forge(year: number, month: number, date: number): D; forgeToday(): D; forgeInvalid(): D; isValid(d: D): boolean; - compare(a: D, b: D, granularity: ELuDateGranularity): number; - isParsable(text: string, granularity?: ELuDateGranularity): boolean; - parse(text: string, granularity?: ELuDateGranularity): D; + compare(a: D, b: D, granularity: LuDateGranularity): number; + isParsable(text: string, granularity?: LuDateGranularity): boolean; + parse(text: string, granularity?: LuDateGranularity): D; format(d: D, format: string): string; clone(d: D): D; @@ -16,5 +16,5 @@ export interface ILuDateAdapter { getDate(d: D): number; getDay(d: D): number; - add(d: D, count: number, granularity: ELuDateGranularity): D; + add(d: D, count: number, granularity: LuDateGranularity): D; } diff --git a/packages/ng/core/date/date-granularity.enum.ts b/packages/ng/core/date/date-granularity.enum.ts index 7684e37faa..cf7dfec124 100644 --- a/packages/ng/core/date/date-granularity.enum.ts +++ b/packages/ng/core/date/date-granularity.enum.ts @@ -1,6 +1,10 @@ +import { EnumValue } from '../type'; + export enum ELuDateGranularity { day = 'day', month = 'month', year = 'year', decade = 'decade', } + +export type LuDateGranularity = EnumValue; diff --git a/packages/ng/core/date/native/native-date.adapter.ts b/packages/ng/core/date/native/native-date.adapter.ts index 781a792b4d..7e5e1503a7 100644 --- a/packages/ng/core/date/native/native-date.adapter.ts +++ b/packages/ng/core/date/native/native-date.adapter.ts @@ -2,8 +2,8 @@ import { formatDate, FormatWidth, getLocaleDateFormat } from '@angular/common'; import { Inject, Injectable, LOCALE_ID, Optional } from '@angular/core'; import { ALuDateAdapter } from '../date-adapter.class'; import { ILuDateAdapter } from '../date-adapter.interface'; -import { ELuDateGranularity } from '../date-granularity.enum'; -import { ILuNativeDateAdapterOptions, luDefaultNativeDateAdapterOptions, LU_NATIVE_DATE_ADAPTER_OPTIONS } from './native-date.option'; +import { ELuDateGranularity, LuDateGranularity } from '../date-granularity.enum'; +import { ILuNativeDateAdapterOptions, LU_NATIVE_DATE_ADAPTER_OPTIONS, luDefaultNativeDateAdapterOptions } from './native-date.option'; @Injectable() export class LuNativeDateAdapter extends ALuDateAdapter implements ILuDateAdapter { @@ -38,7 +38,7 @@ export class LuNativeDateAdapter extends ALuDateAdapter implements ILuDate } }); } - private extract(text: string, granularity: ELuDateGranularity = ELuDateGranularity.day): { date: number; month: number; year: number } { + private extract(text: string, granularity: LuDateGranularity = ELuDateGranularity.day): { date: number; month: number; year: number } { const groups = text.split(this._regex); let date = 1, month = 1, @@ -59,7 +59,7 @@ export class LuNativeDateAdapter extends ALuDateAdapter implements ILuDate } return { date, month, year }; } - isParsable(text: string, granularity = ELuDateGranularity.day): boolean { + isParsable(text: string, granularity: LuDateGranularity = ELuDateGranularity.day): boolean { if (!text) { return false; } @@ -123,7 +123,7 @@ export class LuNativeDateAdapter extends ALuDateAdapter implements ILuDate return false; } } - parse(text: string, granularity = ELuDateGranularity.day): Date { + parse(text: string, granularity: LuDateGranularity = ELuDateGranularity.day): Date { if (!text) { return undefined; } @@ -205,7 +205,7 @@ export class LuNativeDateAdapter extends ALuDateAdapter implements ILuDate } } - add(d: Date, count: number, granularity: ELuDateGranularity): Date { + add(d: Date, count: number, granularity: LuDateGranularity): Date { let year = this.getYear(d); let month = this.getMonth(d); let date = this.getDate(d); diff --git a/packages/ng/core/date/string/string-date.adapter.ts b/packages/ng/core/date/string/string-date.adapter.ts index 71c75600ac..e421e6d68a 100644 --- a/packages/ng/core/date/string/string-date.adapter.ts +++ b/packages/ng/core/date/string/string-date.adapter.ts @@ -1,8 +1,8 @@ -import { Injectable, Inject, LOCALE_ID } from '@angular/core'; -import { LuNativeDateAdapter } from '../native/index'; +import { Inject, Injectable, LOCALE_ID } from '@angular/core'; import { ALuDateAdapter } from '../date-adapter.class'; -import { ELuDateGranularity } from '../date-granularity.enum'; import { ILuDateAdapter } from '../date-adapter.interface'; +import { LuDateGranularity } from '../date-granularity.enum'; +import { LuNativeDateAdapter } from '../native/index'; /** bind to a string with iso 26001 format YYYY-MM-DD */ @Injectable() @@ -35,7 +35,7 @@ export class LuStringDateAdapter extends ALuDateAdapter implements ILuDa return this._nativeAdapter.isValid(this.stringToDate(d)); } - override compare(a: string, b: string, granularity: ELuDateGranularity): number { + override compare(a: string, b: string, granularity: LuDateGranularity): number { const da = this.stringToDate(a); const db = this.stringToDate(b); @@ -46,7 +46,7 @@ export class LuStringDateAdapter extends ALuDateAdapter implements ILuDa return this._nativeAdapter.isParsable(text); } - parse(text: string, granularity: ELuDateGranularity): string { + parse(text: string, granularity: LuDateGranularity): string { return this.dateToString(this._nativeAdapter.parse(text, granularity)); } @@ -74,7 +74,7 @@ export class LuStringDateAdapter extends ALuDateAdapter implements ILuDa return this._nativeAdapter.getDay(this.stringToDate(d)); } - add(d: string, count: number, granularity: ELuDateGranularity): string { + add(d: string, count: number, granularity: LuDateGranularity): string { return this.dateToString(this._nativeAdapter.add(this.stringToDate(d), count, granularity)); } diff --git a/packages/ng/core/portal/portal.directive.spec.ts b/packages/ng/core/portal/portal.directive.spec.ts index 297264551b..155a1f0b0e 100644 --- a/packages/ng/core/portal/portal.directive.spec.ts +++ b/packages/ng/core/portal/portal.directive.spec.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, TemplateRef, viewChild } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PortalDirective } from './portal.directive'; @@ -10,12 +10,15 @@ import { PortalDirective } from './portal.directive'; @if (displayed) {
} + {{ value }} `, }) class PortalTestComponent { content: PortalDirective['luPortal'] | null = null; context: PortalDirective['luPortalContext'] | null = null; displayed = true; + + contentTpl = viewChild.required>('tpl'); } @Component({ @@ -75,4 +78,20 @@ describe('PortalDirective', () => { fixture.detectChanges(); expect(hostContent.textContent).toBe('Component content'); }); + + it('should work with templateRef with context updates', () => { + // Arrange + host.content = host.contentTpl(); + host.context = { $implicit: 'test' }; + fixture.detectChanges(); + + // Act + const firstText = hostContent.textContent; + host.context = { $implicit: 'test2' }; + fixture.detectChanges(); + + // Assert + expect(firstText).toBe('test'); + expect(hostContent.textContent).toBe('test2'); + }); }); diff --git a/packages/ng/core/portal/portal.directive.ts b/packages/ng/core/portal/portal.directive.ts index cd0921abfd..9e57668736 100644 --- a/packages/ng/core/portal/portal.directive.ts +++ b/packages/ng/core/portal/portal.directive.ts @@ -1,4 +1,4 @@ -import { Directive, inject, Injector, Input, OnChanges, OnDestroy, Renderer2, SimpleChanges, TemplateRef, ViewContainerRef } from '@angular/core'; +import { ComponentRef, Directive, EmbeddedViewRef, inject, Injector, Input, OnChanges, OnDestroy, Renderer2, SimpleChanges, TemplateRef, ViewContainerRef } from '@angular/core'; import { PORTAL_CONTEXT, PortalContent } from './portal-content'; @Directive({ @@ -18,16 +18,21 @@ export class PortalDirective implements OnChanges, OnDestroy { public luPortalContext: T | null = null; private createdTextElement: Text | null = null; + private embeddedViewRef?: EmbeddedViewRef; + private componentRef?: ComponentRef; private render(): void { this.viewContainerRef.clear(); + this.embeddedViewRef = undefined; + this.componentRef = undefined; if (typeof this.luPortal !== 'string') { this.destroyRenderedText(); } if (this.luPortal instanceof TemplateRef) { - this.viewContainerRef.createEmbeddedView(this.luPortal, this.luPortalContext); + const context = Object.assign({}, this.luPortalContext); + this.embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.luPortal, context); } else if (typeof this.luPortal === 'string') { this.renderText(this.luPortal); } else { @@ -35,8 +40,8 @@ export class PortalDirective implements OnChanges, OnDestroy { parent: this.injector, providers: [{ provide: PORTAL_CONTEXT, useValue: this.luPortalContext }], }); - const ref = this.viewContainerRef.createComponent(this.luPortal, { injector }); - ref.changeDetectorRef.detectChanges(); + this.componentRef = this.viewContainerRef.createComponent(this.luPortal, { injector }); + this.componentRef.changeDetectorRef.detectChanges(); } } @@ -45,11 +50,15 @@ export class PortalDirective implements OnChanges, OnDestroy { // If we're here, it means that either the template ref changed or the string changed, // meaning that we need to render again this.render(); + } else if (changes['luPortalContext'] && this.embeddedViewRef) { + this.updateEmbeddedViewContext(this.luPortalContext); } } ngOnDestroy(): void { this.destroyRenderedText(); + this.embeddedViewRef?.destroy(); + this.componentRef?.destroy(); } private renderText(text: string): void { @@ -70,4 +79,21 @@ export class PortalDirective implements OnChanges, OnDestroy { this.createdTextElement = null; } } + + /** + * Embeded view context should not be overwritten, but updated. + * @see https://github.com/angular/angular/pull/51887 + */ + private updateEmbeddedViewContext(context: T): void { + if (this.embeddedViewRef) { + const props = Object.keys(context); + + for (const prop of props) { + delete this.embeddedViewRef.context[prop]; + } + + Object.assign(this.embeddedViewRef.context, context); + this.embeddedViewRef.detectChanges(); + } + } } diff --git a/packages/ng/core/translate/translation.model.ts b/packages/ng/core/translate/translation.model.ts index 2c684354d6..30c6026caf 100644 --- a/packages/ng/core/translate/translation.model.ts +++ b/packages/ng/core/translate/translation.model.ts @@ -1,9 +1,9 @@ export interface ILuTranslation { en: T; + fr: T; 'en-GB'?: T; 'en-US'?: T; es?: T; de?: T; - fr?: T; pt?: T; } diff --git a/packages/ng/core/type/enum.ts b/packages/ng/core/type/enum.ts new file mode 100644 index 0000000000..20c0c4fd50 --- /dev/null +++ b/packages/ng/core/type/enum.ts @@ -0,0 +1,14 @@ +/** + * Extracts the values of an enum as a union type. + * + * @example + * ```ts + * enum ExampleEnum { + * A = 'a', + * B = 'b', + * } + * + * type ExampleEnumValue = EnumValue; // Same as 'a' | 'b' + * ``` + */ +export type EnumValue = `${T[keyof T] & string}`; diff --git a/packages/ng/core/type/index.ts b/packages/ng/core/type/index.ts index 54fcd8052f..d1a7421170 100644 --- a/packages/ng/core/type/index.ts +++ b/packages/ng/core/type/index.ts @@ -1 +1,2 @@ +export * from './enum'; export * from './style'; diff --git a/packages/ng/date/calendar/calendar-input.component.ts b/packages/ng/date/calendar/calendar-input.component.ts index 57e1e47cec..bad71e2901 100644 --- a/packages/ng/date/calendar/calendar-input.component.ts +++ b/packages/ng/date/calendar/calendar-input.component.ts @@ -1,7 +1,7 @@ import { CommonModule, FormStyle, getLocaleDayNames, getLocaleFirstDayOfWeek, TranslationWidth } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, Inject, Input, LOCALE_ID, OnInit, Renderer2 } from '@angular/core'; import { AbstractControl, ControlValueAccessor, FormsModule, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validator } from '@angular/forms'; -import { ALuDateAdapter, ELuDateGranularity } from '@lucca-front/ng/core'; +import { ALuDateAdapter, ELuDateGranularity, LuDateGranularity } from '@lucca-front/ng/core'; import { ALuInput } from '@lucca-front/ng/input'; import { LuCalendarItemFactory } from './calendar-item.factory'; import { ICalendarItem } from './calendar-item.interface'; @@ -30,10 +30,10 @@ import { ICalendarItem } from './calendar-item.interface'; export class LuCalendarInputComponent extends ALuInput implements ControlValueAccessor, OnInit, Validator { @Input() min?: D; @Input() max?: D; - @Input() granularity: ELuDateGranularity = ELuDateGranularity.day; + @Input() granularity: LuDateGranularity = ELuDateGranularity.day; @Input() startOn: D = this._adapter.forgeToday(); - viewGranularity: ELuDateGranularity; + viewGranularity: LuDateGranularity; header: ICalendarItem; items: ICalendarItem[] = []; get mod() { diff --git a/packages/ng/date/calendar/calendar-item.class.ts b/packages/ng/date/calendar/calendar-item.class.ts index 6e0359f7bd..f3bde03dd8 100644 --- a/packages/ng/date/calendar/calendar-item.class.ts +++ b/packages/ng/date/calendar/calendar-item.class.ts @@ -1,4 +1,4 @@ -import { ELuDateGranularity } from '@lucca-front/ng/core'; +import { ELuDateGranularity, LuDateGranularity } from '@lucca-front/ng/core'; import { ICalendarItem } from './calendar-item.interface'; export abstract class ACalendarItem implements ICalendarItem { @@ -9,7 +9,7 @@ export abstract class ACalendarItem implements ICalendarItem { mods: string[] = []; isDisabled = false; label: string; - readonly granularity: ELuDateGranularity; + readonly granularity: LuDateGranularity; } export class DayItem extends ACalendarItem implements ICalendarItem { override readonly granularity = ELuDateGranularity.day; diff --git a/packages/ng/date/calendar/calendar-item.interface.ts b/packages/ng/date/calendar/calendar-item.interface.ts index 8cbae0b679..2616a67898 100644 --- a/packages/ng/date/calendar/calendar-item.interface.ts +++ b/packages/ng/date/calendar/calendar-item.interface.ts @@ -1,4 +1,4 @@ -import { ELuDateGranularity } from '@lucca-front/ng/core'; +import { LuDateGranularity } from '@lucca-front/ng/core'; export interface ICalendarItem { id: string; @@ -6,5 +6,5 @@ export interface ICalendarItem { mods: string[]; label: string; isDisabled: boolean; - granularity: ELuDateGranularity; + granularity: LuDateGranularity; } diff --git a/packages/ng/date/humanize/humanize.formatter.ts b/packages/ng/date/humanize/humanize.formatter.ts new file mode 100644 index 0000000000..4baac06049 --- /dev/null +++ b/packages/ng/date/humanize/humanize.formatter.ts @@ -0,0 +1,11 @@ +import { Injectable, LOCALE_ID, inject } from '@angular/core'; +import { LuRelativeTime } from './humanize.model'; + +@Injectable() +export class LuHumanizeDateFormatter { + #intlRelativeTimeFormat = new Intl.RelativeTimeFormat(inject(LOCALE_ID)); + + format(relativeTime: LuRelativeTime): string { + return this.#intlRelativeTimeFormat.format(relativeTime.value, relativeTime.unit); + } +} diff --git a/packages/ng/date/humanize/humanize.model.ts b/packages/ng/date/humanize/humanize.model.ts new file mode 100644 index 0000000000..ba07ba962e --- /dev/null +++ b/packages/ng/date/humanize/humanize.model.ts @@ -0,0 +1,14 @@ +export const luRelativeTimeFormatUnit = ['second', 'minute', 'hour', 'day', 'week', 'month', 'year'] as const; +export type LuRelativeTimeFormatUnit = (typeof luRelativeTimeFormatUnit)[number]; + +export interface LuRelativeTime { + /** + * The relevant unit for the relative time. + */ + unit: LuRelativeTimeFormatUnit; + /** + * The integer value of the relative time. + * Negative values are used for past dates. + */ + value: number; +} diff --git a/packages/ng/date/humanize/humanize.pipe.ts b/packages/ng/date/humanize/humanize.pipe.ts new file mode 100644 index 0000000000..c013bb75f0 --- /dev/null +++ b/packages/ng/date/humanize/humanize.pipe.ts @@ -0,0 +1,17 @@ +import { Pipe, PipeTransform, inject } from '@angular/core'; +import { Observable, map } from 'rxjs'; +import { LuHumanizeDateFormatter } from './humanize.formatter'; +import { LuRelativeTimeFormatUnit } from './humanize.model'; +import { relativeTimeTimer } from './humanize.utils'; + +@Pipe({ + name: 'luHumanizeDate', + standalone: true, +}) +export class LuHumanizeDatePipe implements PipeTransform { + #formatter = inject(LuHumanizeDateFormatter, { optional: true }) ?? new LuHumanizeDateFormatter(); + + transform(value: Date | string | number, allowedUnits?: readonly LuRelativeTimeFormatUnit[]): Observable { + return relativeTimeTimer(new Date(value), allowedUnits).pipe(map((relativeTime) => this.#formatter.format(relativeTime))); + } +} diff --git a/packages/ng/date/humanize/humanize.utils.spec.ts b/packages/ng/date/humanize/humanize.utils.spec.ts new file mode 100644 index 0000000000..25d3e4b358 --- /dev/null +++ b/packages/ng/date/humanize/humanize.utils.spec.ts @@ -0,0 +1,260 @@ +import { fakeAsync, tick } from '@angular/core/testing'; +import { LuRelativeTime, LuRelativeTimeFormatUnit } from './humanize.model'; +import { getRelativeTime, relativeTimeTimer } from './humanize.utils'; + +describe('HumanizeUtils', () => { + describe('getRelativeTime', () => { + interface TestCase { + durationInMs: number; + expectedUnit: LuRelativeTimeFormatUnit; + expectedValue: number; + } + + const minute = 60_000; + const hour = 60 * minute; + const day = 24 * hour; + const week = 7 * day; + + describe('with all units', () => { + const testCases: TestCase[] = [ + { expectedUnit: 'second', expectedValue: 0, durationInMs: 0 }, + { expectedUnit: 'second', expectedValue: 59, durationInMs: minute - 1 }, + { expectedUnit: 'minute', expectedValue: 1, durationInMs: minute }, + { expectedUnit: 'minute', expectedValue: 59, durationInMs: hour - 1 }, + { expectedUnit: 'hour', expectedValue: 1, durationInMs: hour }, + { expectedUnit: 'hour', expectedValue: 23, durationInMs: day - 1 }, + { expectedUnit: 'day', expectedValue: 1, durationInMs: day }, + { expectedUnit: 'day', expectedValue: 6, durationInMs: week - 1 }, + { expectedUnit: 'week', expectedValue: 1, durationInMs: week }, + { expectedUnit: 'week', expectedValue: 4, durationInMs: week * 4 }, + { expectedUnit: 'month', expectedValue: 1, durationInMs: week * 5 }, + { expectedUnit: 'month', expectedValue: 2, durationInMs: week * 10 }, + ]; + + // Positive times + for (const { expectedUnit, expectedValue, durationInMs } of testCases) { + it(`should return ${expectedValue} ${expectedUnit} when duration is ${durationInMs}`, () => { + // Act + const reference = new Date(2024, 0, 1).getTime(); + const { unit, value } = getRelativeTime(reference + durationInMs, reference); + + // Assert + expect(unit).toBe(expectedUnit); + expect(value).toBe(expectedValue); + }); + } + + // Negative times (slice first element because +/-0 is the same value) + for (const { expectedUnit, expectedValue, durationInMs } of testCases.slice(1)) { + it(`should return ${-expectedValue} ${expectedUnit} when duration is ${-durationInMs}`, () => { + // Act + const reference = new Date(2024, 0, 1).getTime(); + const { unit, value } = getRelativeTime(reference - durationInMs, reference); + + // Assert + expect(unit).toBe(expectedUnit); + expect(value).toBe(-expectedValue); + }); + } + }); + + describe('with only some units', () => { + it('should return 0 with the nearest greater unit when no lower unit is allowed', () => { + // Arrange + const reference = new Date(2024, 0, 1).getTime(); + const durationInMs = 20 * hour; + + // Act + const { unit, value } = getRelativeTime(reference + durationInMs, reference, ['day', 'month', 'year']); + + // Assert + expect(unit).toBe('day'); + expect(value).toBe(0); + }); + + it('should return value with the nearest lower unit when one lower unit', () => { + // Arrange + const reference = new Date(2024, 0, 1).getTime(); + const durationInMs = 20 * hour; + + // Act + const { unit, value } = getRelativeTime(reference + durationInMs, reference, ['minute', 'day', 'month', 'year']); + + // Assert + expect(unit).toBe('minute'); + expect(value).toBe(20 * 60); + }); + + it('should return value the last unit when difference is greater than the last unit', () => { + // Arrange + const reference = new Date(2024, 0, 1).getTime(); + const durationInMs = 20 * hour; + + // Act + const { unit, value } = getRelativeTime(reference + durationInMs, reference, ['second', 'minute']); + + // Assert + expect(unit).toBe('minute'); + expect(value).toBe(20 * 60); + }); + }); + }); + + describe('relativeTimeTimer', () => { + describe('past date', () => { + it('should emit immedialty', () => { + // Arrange + const date = Date.now() - 55_000; + const relativeTime$ = relativeTimeTimer(date); + const emittedValues: LuRelativeTime[] = []; + + // Act + const sub = relativeTime$.subscribe((relativeTime) => emittedValues.push(relativeTime)); + + // Assert + expect(emittedValues).toEqual([{ unit: 'second', value: -55 }]); + sub.unsubscribe(); + }); + + it('should emit each second until one minute', fakeAsync(() => { + // Arrange + const date = Date.now() - 55_000; + const relativeTime$ = relativeTimeTimer(date); + const emittedValues: LuRelativeTime[] = []; + const lastValue = () => emittedValues[emittedValues.length - 1]; + + // Act + const sub = relativeTime$.subscribe((relativeTime) => emittedValues.push(relativeTime)); + + // Assert + expect(emittedValues).toEqual([{ unit: 'second', value: -55 }]); + + tick(1000); + expect(emittedValues.length).toBe(2); + expect(lastValue()).toEqual({ unit: 'second', value: -56 }); + + tick(1000); + expect(emittedValues.length).toBe(3); + expect(lastValue()).toEqual({ unit: 'second', value: -57 }); + + tick(1000); + expect(emittedValues.length).toBe(4); + expect(lastValue()).toEqual({ unit: 'second', value: -58 }); + + tick(1000); + expect(emittedValues.length).toBe(5); + expect(lastValue()).toEqual({ unit: 'second', value: -59 }); + + tick(1000); + expect(emittedValues.length).toBe(6); + expect(lastValue()).toEqual({ unit: 'minute', value: -1 }); + + sub.unsubscribe(); + })); + + it('should emit each minute until one hour', fakeAsync(() => { + // Arrange + const date = Date.now() - 60_000; + const relativeTime$ = relativeTimeTimer(date); + const emittedValues: LuRelativeTime[] = []; + const lastValue = () => emittedValues[emittedValues.length - 1]; + + // Act + const sub = relativeTime$.subscribe((relativeTime) => emittedValues.push(relativeTime)); + + // Assert + for (let i = 1; i <= 58; i++) { + tick(60_000); + expect(emittedValues.length).toBe(i + 1); + expect(lastValue()).toEqual({ unit: 'minute', value: -i - 1 }); + } + + tick(60_000); + expect(emittedValues.length).toBe(60); + expect(lastValue()).toEqual({ unit: 'hour', value: -1 }); + + sub.unsubscribe(); + })); + }); + + describe('future date', () => { + it('should emit immedialty', () => { + // Arrange + const date = Date.now() + 55_000; + const relativeTime$ = relativeTimeTimer(date); + const emittedValues: LuRelativeTime[] = []; + + // Act + const sub = relativeTime$.subscribe((relativeTime) => emittedValues.push(relativeTime)); + + // Assert + expect(emittedValues).toEqual([{ unit: 'second', value: 55 }]); + sub.unsubscribe(); + }); + + it('should emit each minute then each seconds', fakeAsync(() => { + // Arrange + const date = Date.now() + 120_000; + const relativeTime$ = relativeTimeTimer(date); + const emittedValues: LuRelativeTime[] = []; + const lastValue = () => emittedValues[emittedValues.length - 1]; + + // Act + const sub = relativeTime$.subscribe((relativeTime) => emittedValues.push(relativeTime)); + + // Assert + expect(emittedValues.length).toBe(1); + expect(lastValue()).toEqual({ unit: 'minute', value: 2 }); + + tick(60_000); + expect(emittedValues.length).toBe(2); + expect(lastValue()).toEqual({ unit: 'minute', value: 1 }); + + tick(1_000); + expect(emittedValues.length).toBe(3); + expect(lastValue()).toEqual({ unit: 'second', value: 59 }); + + tick(1_000); + expect(emittedValues.length).toBe(4); + expect(lastValue()).toEqual({ unit: 'second', value: 58 }); + + sub.unsubscribe(); + })); + }); + + describe('from future to past', () => { + it('should emit each secondes', fakeAsync(() => { + // Arrange + const date = Date.now() + 2_000; + const relativeTime$ = relativeTimeTimer(date); + const emittedValues: LuRelativeTime[] = []; + const lastValue = () => emittedValues[emittedValues.length - 1]; + + // Act + const sub = relativeTime$.subscribe((relativeTime) => emittedValues.push(relativeTime)); + + // Assert + expect(emittedValues.length).toBe(1); + expect(lastValue()).toEqual({ unit: 'second', value: 2 }); + + tick(1_000); + expect(emittedValues.length).toBe(2); + expect(lastValue()).toEqual({ unit: 'second', value: 1 }); + + tick(1_000); + expect(emittedValues.length).toBe(3); + expect(lastValue()).toEqual({ unit: 'second', value: 0 }); + + tick(1_000); + expect(emittedValues.length).toBe(4); + expect(lastValue()).toEqual({ unit: 'second', value: -1 }); + + tick(1_000); + expect(emittedValues.length).toBe(5); + expect(lastValue()).toEqual({ unit: 'second', value: -2 }); + + sub.unsubscribe(); + })); + }); + }); +}); diff --git a/packages/ng/date/humanize/humanize.utils.ts b/packages/ng/date/humanize/humanize.utils.ts new file mode 100644 index 0000000000..a531fa6126 --- /dev/null +++ b/packages/ng/date/humanize/humanize.utils.ts @@ -0,0 +1,96 @@ +import { differenceInDays, differenceInHours, differenceInMinutes, differenceInMonths, differenceInSeconds, differenceInWeeks, differenceInYears } from 'date-fns'; +import { Observable } from 'rxjs'; +import { LuRelativeTime, LuRelativeTimeFormatUnit, luRelativeTimeFormatUnit } from './humanize.model'; + +const getDifferenceByUnit: Record number> = { + second: differenceInSeconds, + minute: differenceInMinutes, + hour: differenceInHours, + day: differenceInDays, + week: differenceInWeeks, + month: differenceInMonths, + year: differenceInYears, +}; + +export function getRelativeTime(date: number | Date, reference: number | Date, allowedUnits: readonly LuRelativeTimeFormatUnit[] = luRelativeTimeFormatUnit): LuRelativeTime { + if (!allowedUnits.length) { + throw new Error('[getRelativeTime] Pass at least one unit'); + } + + for (let i = 0; i < allowedUnits.length; i++) { + const unit = allowedUnits[i]; + const isLastUnit = i === allowedUnits.length - 1; + + if (isLastUnit) { + return { unit, value: getDifferenceByUnit[unit](date, reference) }; + } + + const nextUnit = allowedUnits[i + 1]; + const diff = getDifferenceByUnit[nextUnit](date, reference); + + if (Math.abs(diff) < 1) { + return { unit, value: getDifferenceByUnit[unit](date, reference) }; + } + } + + // Should never happen as the for loop should always return + throw new Error('[getRelativeTime] No unit found for the given date'); +} + +const nextRelativeTimeTickInMsByUnit: Record = { + second: 1_000, + minute: 60_000, + hour: 60 * 60_000, + day: 24 * 60 * 60_000, + week: 24 * 60 * 60_000, + month: 24 * 60 * 60_000, + year: 24 * 60 * 60_000, +}; + +const previousRelativeTimeUnitByUnit: Record = { + second: null, + minute: 'second', + hour: 'minute', + day: 'hour', + week: 'day', + month: 'week', + year: 'month', +}; + +export function relativeTimeTimer(date: Date | number, allowedUnits?: readonly LuRelativeTimeFormatUnit[]): Observable { + return new Observable((subscriber) => { + let timeoutId: ReturnType | null = null; + const dateAsNumber = typeof date === 'number' ? date : date.getTime(); + + function next() { + const now = Date.now(); + const relativeTime = getRelativeTime(date, now, allowedUnits); + subscriber.next(relativeTime); + + const unit = + relativeTime.value === 1 && relativeTime.unit !== 'second' + ? // We a future date come closer, we need to switch to the previous unit + // For example, if we are at 1 minutes, we should switch to second to avoid displaying '1 minute' during '1 minute' (we want to wait one second to display '59 seconds') + previousRelativeTimeUnitByUnit[relativeTime.unit] + : relativeTime.unit; + + const delta = now - dateAsNumber; + const nextTick = nextRelativeTimeTickInMsByUnit[unit]; + + // setTimeout is not an exact science, so we need to adjust the next tick to avoid drift over time + const shift = Math.abs(delta) % nextTick; + const nextWait = relativeTime.value !== 1 ? nextTick - shift : 1000; + + timeoutId = setTimeout(next, nextWait); + } + + // Trigger the recursive loop + next(); + + return () => { + if (timeoutId) { + clearTimeout(timeoutId); + } + }; + }); +} diff --git a/packages/ng/date/humanize/index.ts b/packages/ng/date/humanize/index.ts new file mode 100644 index 0000000000..0f8cf8d80a --- /dev/null +++ b/packages/ng/date/humanize/index.ts @@ -0,0 +1,4 @@ +export * from './humanize.formatter'; +export * from './humanize.model'; +export * from './humanize.pipe'; +export * from './humanize.utils'; diff --git a/packages/ng/date/input/date-input.directive.ts b/packages/ng/date/input/date-input.directive.ts index 1dd8c759d0..f3f8c80c45 100644 --- a/packages/ng/date/input/date-input.directive.ts +++ b/packages/ng/date/input/date-input.directive.ts @@ -1,6 +1,6 @@ import { ChangeDetectorRef, Directive, ElementRef, forwardRef, HostListener, Input, OnInit, Renderer2 } from '@angular/core'; import { AbstractControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validator } from '@angular/forms'; -import { ALuDateAdapter, ELuDateGranularity, getIntl } from '@lucca-front/ng/core'; +import { ALuDateAdapter, ELuDateGranularity, getIntl, LuDateGranularity } from '@lucca-front/ng/core'; import { ALuInput } from '@lucca-front/ng/input'; import { LU_DATE_INPUT_TRANSLATIONS } from './date-input.translate'; @@ -24,7 +24,7 @@ export class LuDateInputDirective extends ALuInput imple private _focused = false; @Input() min?: D; @Input() max?: D; - @Input() granularity: ELuDateGranularity = ELuDateGranularity.day; + @Input() granularity: LuDateGranularity = ELuDateGranularity.day; @Input() override set placeholder(p: string) { this._elementRef.nativeElement.placeholder = p; diff --git a/packages/ng/date/picker/date-picker.component.ts b/packages/ng/date/picker/date-picker.component.ts index 6093ded288..767253d0cc 100644 --- a/packages/ng/date/picker/date-picker.component.ts +++ b/packages/ng/date/picker/date-picker.component.ts @@ -5,7 +5,7 @@ import { A11yModule } from '@angular/cdk/a11y'; import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, EventEmitter, forwardRef, Input, Output, TemplateRef, ViewChild } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { ALuDateAdapter, ELuDateGranularity } from '@lucca-front/ng/core'; +import { ALuDateAdapter, ELuDateGranularity, LuDateGranularity } from '@lucca-front/ng/core'; import { ALuPickerPanel } from '@lucca-front/ng/picker'; import { luTransformPopover } from '@lucca-front/ng/popover'; import { LuCalendarInputComponent } from '../calendar'; @@ -31,7 +31,7 @@ export class LuDatePickerComponent extends ALuPickerPanel { @Input() min?: D; @Input() max?: D; - @Input() granularity: ELuDateGranularity = ELuDateGranularity.day; + @Input() granularity: LuDateGranularity = ELuDateGranularity.day; @Input() startOn: D = this._adapter.forgeToday(); @Output() override close = new EventEmitter(); diff --git a/packages/ng/date/public-api.ts b/packages/ng/date/public-api.ts index 3e5eba08d7..327078c029 100644 --- a/packages/ng/date/public-api.ts +++ b/packages/ng/date/public-api.ts @@ -1,6 +1,7 @@ -export * from './date.module'; +export * from './adapter/index'; export * from './calendar/index'; +export * from './date.module'; +export * from './humanize/index'; export * from './input/index'; export * from './picker/index'; -export * from './adapter/index'; export * from './select/index'; diff --git a/packages/ng/date/select/date-select-input.component.ts b/packages/ng/date/select/date-select-input.component.ts index e7ec0205ff..15061be5c7 100644 --- a/packages/ng/date/select/date-select-input.component.ts +++ b/packages/ng/date/select/date-select-input.component.ts @@ -1,7 +1,7 @@ import { Overlay, OverlayModule } from '@angular/cdk/overlay'; import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, Input, Renderer2, ViewContainerRef } from '@angular/core'; import { AbstractControl, ControlValueAccessor, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validator } from '@angular/forms'; -import { ALuDateAdapter, ELuDateGranularity, getIntl } from '@lucca-front/ng/core'; +import { ALuDateAdapter, ELuDateGranularity, LuDateGranularity, getIntl } from '@lucca-front/ng/core'; import { LuInputClearerComponent, LuInputDirective, LuInputDisplayerDirective } from '@lucca-front/ng/input'; import { ILuInputWithPicker } from '@lucca-front/ng/picker'; import { ALuSelectInputComponent } from '@lucca-front/ng/select'; @@ -32,7 +32,7 @@ import { LU_DATE_SELECT_INPUT_TRANSLATIONS } from './date-select-input.translate export class LuDateSelectInputComponent extends ALuSelectInputComponent implements ControlValueAccessor, ILuInputWithPicker, AfterViewInit, Validator { @Input() min?: D; @Input() max?: D; - @Input() granularity: ELuDateGranularity = ELuDateGranularity.day; + @Input() granularity: LuDateGranularity = ELuDateGranularity.day; @Input('placeholder') override set inputPlaceholder(p: string) { this._placeholder = p; } diff --git a/packages/ng/dialog/dialog.service.ts b/packages/ng/dialog/dialog.service.ts index 43722bb54d..62f2ef33e9 100644 --- a/packages/ng/dialog/dialog.service.ts +++ b/packages/ng/dialog/dialog.service.ts @@ -26,7 +26,7 @@ export class LuDialogService { ariaModal: config.modal ?? true, hasBackdrop: config.modal ?? true, data: 'data' in config ? config.data : null, - disableClose: true, + disableClose: false, closeOnDestroy: true, role: config.alert ? 'alertdialog' : 'dialog', restoreFocus: true, @@ -57,7 +57,7 @@ export class LuDialogService { if (!config.alert) { // Setup close listeners on backdrop click and escape key by ourselves so we can hook the `canClose` method to it. - merge(cdkRef.backdropClick, cdkRef.keydownEvents.pipe(filter((e) => e.key === 'Escape' && !e.defaultPrevented))) + merge(cdkRef.backdropClick.pipe(filter(() => !config.cdkConfigOverride.disableClose)), cdkRef.keydownEvents.pipe(filter((e) => e.key === 'Escape' && !e.defaultPrevented))) .pipe( switchMap(() => { const canClose = config.canClose?.(cdkRef.componentInstance) ?? true; diff --git a/packages/ng/dialog/dialog/dialog.component.ts b/packages/ng/dialog/dialog/dialog.component.ts index 4792210569..04eaebecf6 100644 --- a/packages/ng/dialog/dialog/dialog.component.ts +++ b/packages/ng/dialog/dialog/dialog.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, ElementRef, inject, OnInit, ViewEncapsulation } from '@angular/core'; +import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, inject, ViewEncapsulation } from '@angular/core'; import { LuDialogRef } from '../model'; @Component({ @@ -12,7 +12,7 @@ import { LuDialogRef } from '../model'; class: 'dialog-inside', }, }) -export class DialogComponent implements OnInit { +export class DialogComponent implements AfterViewInit { public readonly dialogRef = inject(LuDialogRef); #htmlElement = inject>(ElementRef).nativeElement; @@ -25,7 +25,7 @@ export class DialogComponent implements OnInit { this.dialogRef.dismiss(); } - ngOnInit(): void { + ngAfterViewInit(): void { if (this.dialogRef.config.autoFocus === 'first-input' && !this.dialogRef.config.cdkConfigOverride?.autoFocus) { const focusable: HTMLElement = this.#htmlElement.querySelector('.luDialog-autofocus .luNativeInput') || this.#htmlElement.querySelector('.luDialog-autofocus') || this.#htmlElement.querySelector('.luNativeInput'); diff --git a/packages/ng/dialog/model/dialog-config.ts b/packages/ng/dialog/model/dialog-config.ts index 33ca9cb969..6a79c63a40 100644 --- a/packages/ng/dialog/model/dialog-config.ts +++ b/packages/ng/dialog/model/dialog-config.ts @@ -33,9 +33,9 @@ interface BaseLuDialogConfig { modal?: boolean; /** - * Can this dialog box be dismissed by clicking on the backdrop or pressing escape? + * Is this dialog a blocking popup that cannot be dismissed ? * - * Defaults to true, setting this to false will also remove the close button in the header + * Defaults to false, setting this to true will also remove the close button in the header * if you're using `lu-dialog-header`. */ alert?: boolean; diff --git a/packages/ng/empty-state/empty-state-page/empty-state-page.component.html b/packages/ng/empty-state/empty-state-page/empty-state-page.component.html index 974349026e..3936097919 100644 --- a/packages/ng/empty-state/empty-state-page/empty-state-page.component.html +++ b/packages/ng/empty-state/empty-state-page/empty-state-page.component.html @@ -1,5 +1,6 @@
-

{{ title }}

-

+

{{ title }}
+

diff --git a/packages/ng/empty-state/empty-state-page/empty-state-page.component.ts b/packages/ng/empty-state/empty-state-page/empty-state-page.component.ts index 7d4d8e8f3b..eeba3ad253 100644 --- a/packages/ng/empty-state/empty-state-page/empty-state-page.component.ts +++ b/packages/ng/empty-state/empty-state-page/empty-state-page.component.ts @@ -53,13 +53,12 @@ export class EmptyStatePageComponent { @Input() contentBackgroundColor = 'var(--pr-t-elevation-surface-default)'; - @Input({ - required: true, - }) + @Input() title: string; - @Input({ - required: true, - }) + @Input() description: PortalContent; + + @Input() + hx: 1 | 2 | 3 | 4 | 5 | 6 = 1; } diff --git a/packages/ng/empty-state/empty-state-section/empty-state-section.component.html b/packages/ng/empty-state/empty-state-section/empty-state-section.component.html index 9ef48826cc..0ce77d8145 100644 --- a/packages/ng/empty-state/empty-state-section/empty-state-section.component.html +++ b/packages/ng/empty-state/empty-state-section/empty-state-section.component.html @@ -1,10 +1,10 @@ -
+
-

{{ title }}

-

+

{{ title }}
+

diff --git a/packages/ng/empty-state/empty-state-section/empty-state-section.component.ts b/packages/ng/empty-state/empty-state-section/empty-state-section.component.ts index e85bb12a16..c8af0810d7 100644 --- a/packages/ng/empty-state/empty-state-section/empty-state-section.component.ts +++ b/packages/ng/empty-state/empty-state-section/empty-state-section.component.ts @@ -1,7 +1,7 @@ +import { NgIf } from '@angular/common'; import { booleanAttribute, ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core'; import { Palette, PortalContent, PortalDirective } from '@lucca-front/ng/core'; import { LuSafeExternalSvgPipe } from '@lucca-front/ng/safe-content'; -import { NgIf } from '@angular/common'; @Component({ selector: 'lu-empty-state-section', @@ -27,13 +27,12 @@ export class EmptyStateSectionComponent { }) center = false; - @Input({ - required: true, - }) + @Input() title: string; - @Input({ - required: true, - }) + @Input() description: PortalContent; + + @Input() + hx: 1 | 2 | 3 | 4 | 5 | 6 = 3; } diff --git a/packages/ng/form-field/form-field.component.html b/packages/ng/form-field/form-field.component.html index cb1ec241e8..f6ab29d4ad 100644 --- a/packages/ng/form-field/form-field.component.html +++ b/packages/ng/form-field/form-field.component.html @@ -3,7 +3,14 @@ - + - + +
{{ addon.content }} diff --git a/packages/ng/forms/text-input/text-input.component.ts b/packages/ng/forms/text-input/text-input.component.ts index 03cc3c5945..3eaa76fa0e 100644 --- a/packages/ng/forms/text-input/text-input.component.ts +++ b/packages/ng/forms/text-input/text-input.component.ts @@ -32,6 +32,9 @@ export class TextInputComponent { @Input({ transform: booleanAttribute }) hasSearchIcon = false; + @Input({ transform: booleanAttribute }) + valueAlignRight = false; + @ViewChild('inputElement', { static: true }) inputElementRef: ElementRef; diff --git a/packages/ng/forms/textarea-input/textarea-input.component.html b/packages/ng/forms/textarea-input/textarea-input.component.html index d68cb8c7ae..bf1d83b363 100644 --- a/packages/ng/forms/textarea-input/textarea-input.component.html +++ b/packages/ng/forms/textarea-input/textarea-input.component.html @@ -1,5 +1,11 @@
- +
diff --git a/packages/ng/forms/textarea-input/textarea-input.component.ts b/packages/ng/forms/textarea-input/textarea-input.component.ts index 7584971555..562061b9b9 100644 --- a/packages/ng/forms/textarea-input/textarea-input.component.ts +++ b/packages/ng/forms/textarea-input/textarea-input.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core'; -import { InputDirective } from '@lucca-front/ng/form-field'; import { ReactiveFormsModule } from '@angular/forms'; +import { InputDirective } from '@lucca-front/ng/form-field'; import { injectNgControl } from '../inject-ng-control'; import { NoopValueAccessorDirective } from '../noop-value-accessor.directive'; @@ -18,4 +18,7 @@ export class TextareaInputComponent { @Input() placeholder: string = ''; + + @Input() + rows?: number; } diff --git a/packages/ng/material/style/_components.scss b/packages/ng/material/style/_components.scss deleted file mode 100644 index 037b4e9606..0000000000 --- a/packages/ng/material/style/_components.scss +++ /dev/null @@ -1,13 +0,0 @@ -// deprecated - -@import - 'components/mixins', - 'components/buttons', - 'components/datepicker', - 'components/dialog', - 'components/input', - 'components/select', - 'components/autocomplete', - 'components/menu', - 'components/options', - 'components/tooltip'; diff --git a/packages/ng/material/style/components/_autocomplete.scss b/packages/ng/material/style/components/_autocomplete.scss deleted file mode 100644 index 1708bf0ca4..0000000000 --- a/packages/ng/material/style/components/_autocomplete.scss +++ /dev/null @@ -1,15 +0,0 @@ -// deprecated - -.mat-autocomplete-panel { - @extend .textfield-options; - - background: white; - position: relative; - top: auto; - - &.mat-autocomplete-visible { - opacity: 1; - overflow-x: hidden; - transform: scaleY(1); - } -} diff --git a/packages/ng/material/style/components/_buttons.scss b/packages/ng/material/style/components/_buttons.scss deleted file mode 100644 index a3e6c5e999..0000000000 --- a/packages/ng/material/style/components/_buttons.scss +++ /dev/null @@ -1,5 +0,0 @@ -// deprecated - -.mat-button-focus-overlay { - display: none; -} diff --git a/packages/ng/material/style/components/_datepicker.scss b/packages/ng/material/style/components/_datepicker.scss deleted file mode 100644 index 2df553195d..0000000000 --- a/packages/ng/material/style/components/_datepicker.scss +++ /dev/null @@ -1,124 +0,0 @@ -// deprecated - -@use '@lucca-front/icons/src/commons/utils/icon'; -@use '@lucca-front/scss/src/commons/utils/form'; - -.mat-datepicker-content { - @include box-shadow-override(); - @extend .card; - display: block; - margin-top: 2px; -} - -.mat-datepicker-toggle { - @extend .textfield-suffix; - pointer-events: auto; - - button { - background: none !important; - border-radius: 0; - height: auto; - line-height: 1; - width: auto; - - &::after { - @include icon.generate('calendar_date'); - } - - mat-icon { - display: none; - } - } -} - -// CALENDAR -.mat-calendar { - width: 296px; - - .mat-button { - @extend .button, .mod-text; - font-size: 1em; - text-decoration: none; - } - - .mat-calendar-arrow { - display: none; - } - - .mat-calendar-arrow { - display: none; - } - - .mat-icon-button { - @extend .button, .mod-text; - border-radius: 3px; - } - - .mat-calendar-content { - padding: 0 0.5em 0.5em 0.5em; - } -} - -// CALENDAR HEADER -.mat-calendar-controls { - margin-top: 0 !important; - .mat-icon-button[disabled] { - opacity: 0.4; - } - .mat-calendar-period-button { - flex: 1; - order: 1; - } - - .mat-calendar-next-button { - order: 2; - } - - .mat-calendar-spacer { - display: none; - } -} - -// TABLE -.mat-calendar-body-cell { - .mat-calendar-body-cell-content { - box-shadow: form.fakeBorderOverlay(var(--commons-divider-color)); - border: none; - border-radius: 0; - color: var(--palettes-neutral-600); - height: 100%; - left: 0; - top: 0; - width: 100%; - - &:hover, - &.mat-calendar-body-selected { - background-color: var(--palettes-product-700); - color: var(--palettes-product-text); - } - } - - &.mat-calendar-body-disabled { - opacity: 0.5; - pointer-events: none; - } -} - -// SPECIFIC MONTH-VIEW -md-month-view, -mat-month-view { - .mat-calendar-table-header th { - color: var(--palettes-neutral-600); - font-size: 0.9em; - padding-bottom: 0.4em; - } - - .mat-calendar-body-label { - overflow: hidden; - text-indent: -9999px; - - &[colspan='7'] { - display: none; // REMOVE MONTH LABEL ABOVE NUMBERS IF FULL WIDTH - } - } -} diff --git a/packages/ng/material/style/components/_dialog.scss b/packages/ng/material/style/components/_dialog.scss deleted file mode 100644 index 30f8438a54..0000000000 --- a/packages/ng/material/style/components/_dialog.scss +++ /dev/null @@ -1,34 +0,0 @@ -// deprecated - -@use '@lucca-front/scss/src/commons/utils/media'; -@use '@lucca-front/icons/src/commons/utils/icon'; - -.mat-dialog-container { - @extend .card; - - background: white; - max-width: 80vw; // MIGHT BE CHANGED INTO A THEME VARIABLE - overflow: visible !important; - padding: 0 !important; -} - -.cdk-overlay-pane { - &.mod-sidePanel { - position: fixed !important; - top: var(--commons-banner-height); - right: 0; - bottom: 0; - width: 60%; - max-width: 800px; - @include media.max('S') { - width: 80%; - } - @include media.max('XS') { - width: 100%; - } - - .mat-dialog-container { - max-width: 100%; - } - } -} diff --git a/packages/ng/material/style/components/_input.scss b/packages/ng/material/style/components/_input.scss deleted file mode 100644 index fb1cf3ebee..0000000000 --- a/packages/ng/material/style/components/_input.scss +++ /dev/null @@ -1,5 +0,0 @@ -// deprecated - -input.mat-input-element { - margin-top: 0 !important; -} diff --git a/packages/ng/material/style/components/_menu.scss b/packages/ng/material/style/components/_menu.scss deleted file mode 100644 index 0a3cebd444..0000000000 --- a/packages/ng/material/style/components/_menu.scss +++ /dev/null @@ -1,23 +0,0 @@ -// deprecated - -.mat-menu-item { - @extend .textfield-options-entry; - background-color: transparent; - &.mat-selected, - &.mat-active { - @extend .is-focus; - } -} - -.mat-menu-panel { - @extend .textfield-options; - position: relative; - top: auto; - opacity: 1; - transform: none; -} - -.mat-menu-content { - padding-top: 0 !important; - padding-bottom: 0 !important; -} diff --git a/packages/ng/material/style/components/_mixins.scss b/packages/ng/material/style/components/_mixins.scss deleted file mode 100644 index acdc3de641..0000000000 --- a/packages/ng/material/style/components/_mixins.scss +++ /dev/null @@ -1,10 +0,0 @@ -// deprecated - -@mixin box-shadow-override($hasHover: false) { - box-shadow: var(--commons-boxShadow-XS) !important; - @if $hasHover { - &:hover { - box-shadow: var(--commons-boxShadow-M) !important; - } - } -} diff --git a/packages/ng/material/style/components/_options.scss b/packages/ng/material/style/components/_options.scss deleted file mode 100644 index 9aa56e2b46..0000000000 --- a/packages/ng/material/style/components/_options.scss +++ /dev/null @@ -1,26 +0,0 @@ -// deprecated - -.mat-option { - @extend .textfield-options-entry; - - display: block; - line-height: unset !important; - outline: none; - &.mat-selected, - &.mat-active { - @extend .textfield-options-entry, .is-focus; - } - - .mat-option-ripple { - bottom: 0; - left: 0; - pointer-events: none; - position: absolute; - right: 0; - top: 0; - } - - .mat-ripple { - overflow: hidden; - } -} diff --git a/packages/ng/material/style/components/_select.scss b/packages/ng/material/style/components/_select.scss deleted file mode 100644 index 1a7edf1b4f..0000000000 --- a/packages/ng/material/style/components/_select.scss +++ /dev/null @@ -1,46 +0,0 @@ -// deprecated - -mat-select { - @extend .textfield; -} - -.textfield.mod-framed mat-select { - padding: 0 !important; - - .mat-select-trigger { - font-size: var(--sizes-M-fontSize); - margin: 2.2rem var(--pr-t-spacings-200) 0.7rem; - &::after { - bottom: -0.7rem; - content: ''; - display: block; - left: calc(var(--pr-t-spacings-200) * -1); - position: absolute; - right: calc(var(--pr-t-spacings-200) * -1); - top: -2.2rem; - } - } -} - -.textfield:not(.mod-compact) mat-select { - padding-top: 0 !important; -} - -.mat-select-trigger { - height: 1.1rem !important; - min-width: 0 !important; - text-overflow: ellipsis; -} - -.mat-select-placeholder { - width: auto !important; -} - -.mat-select-panel { - @extend .textfield-options; - - position: relative; - top: auto; - transform: none; - opacity: 1; -} diff --git a/packages/ng/material/style/components/_tooltip.scss b/packages/ng/material/style/components/_tooltip.scss deleted file mode 100644 index cdd036b7fa..0000000000 --- a/packages/ng/material/style/components/_tooltip.scss +++ /dev/null @@ -1,11 +0,0 @@ -// deprecated - -.mat-tooltip { - border-radius: var(--commons-borderRadius-M); - background: var(--components-tooltip-background-color); - color: var(--components-tooltip-color); - font-size: var(--sizes-XS-lineHeight) !important; - margin: var(--pr-t-spacings-100) !important; - padding: var(--pr-t-spacings-50) var(--pr-t-spacings-100) !important; - line-height: var(--sizes-XS-lineHeight); -} diff --git a/packages/ng/material/style/main.scss b/packages/ng/material/style/main.scss deleted file mode 100644 index 84a43efca9..0000000000 --- a/packages/ng/material/style/main.scss +++ /dev/null @@ -1,12 +0,0 @@ -// deprecated - -@use '@angular/material' as mat; - -@import 'components'; - -// CHANGE DEFAULT FONTS TO LUCCA-FRONT FONTS -$lucca-front-mat-typography: mat.define-typography-config( - $font-family: var(--commons-font-family), -); - -@include mat.all-component-typographies($lucca-front-mat-typography); diff --git a/packages/ng/multi-select/displayer/counter-displayer/counter-displayer.component.scss b/packages/ng/multi-select/displayer/counter-displayer/counter-displayer.component.scss new file mode 100644 index 0000000000..2486878d86 --- /dev/null +++ b/packages/ng/multi-select/displayer/counter-displayer/counter-displayer.component.scss @@ -0,0 +1,4 @@ +:host { + display: block; + width: 100%; +} diff --git a/packages/ng/multi-select/displayer/counter-displayer/counter-displayer.component.ts b/packages/ng/multi-select/displayer/counter-displayer/counter-displayer.component.ts new file mode 100644 index 0000000000..5f9126653d --- /dev/null +++ b/packages/ng/multi-select/displayer/counter-displayer/counter-displayer.component.ts @@ -0,0 +1,99 @@ +import { AsyncPipe, NgFor, NgIf, NgPlural, NgPluralCase } from '@angular/common'; +import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, inject, Input, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { FormsModule } from '@angular/forms'; +import { ILuOptionContext, LU_OPTION_CONTEXT, ɵLuOptionOutletDirective } from '@lucca-front/ng/core-select'; +import { InputDirective } from '@lucca-front/ng/form-field'; +import { LuTooltipModule } from '@lucca-front/ng/tooltip'; +import { switchMap } from 'rxjs/operators'; +import { BehaviorSubject, of } from 'rxjs'; +import { LuMultiSelectInputComponent } from '../../input'; + +@Component({ + selector: 'lu-multi-select-counter-displayer', + standalone: true, + imports: [AsyncPipe, LuTooltipModule, NgIf, NgFor, NgPlural, NgPluralCase, ɵLuOptionOutletDirective, FormsModule, InputDirective], + template: ` +
+ +
+
+ +
+ {{ selectedOptions?.length }}{{ label }} +
+
+ `, + styleUrls: ['./counter-displayer.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class LuMultiSelectCounterDisplayerComponent implements OnInit { + select = inject>(LuMultiSelectInputComponent); + + protected destroyRef = inject(DestroyRef); + + @ViewChild('inputElement') + inputElementRef: ElementRef; + + get value(): T[] { + return this.select.value || []; + } + + get ariaControls() { + return this.select.ariaControls; + } + + context = inject>(LU_OPTION_CONTEXT); + + selectedOptions$ = new BehaviorSubject([]); + + @Input() + set selected(options: T[]) { + this.selectedOptions$.next(options); + } + + placeholder$ = this.context.option$.pipe( + switchMap((options) => { + if ((options || []).length > 0) { + return of(''); + } + return this.select.placeholder$; + }), + ); + + @Input({ required: true }) + label: string; + + ngOnInit(): void { + this.select.focusInput$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data?: { keepClue: true }) => { + // Everytime we want to focus, we need to reset the input + // This is done when a value is selected and when panel is opened. + if (!data?.keepClue) { + this.inputElementRef.nativeElement.value = ''; + this.select.clueChanged(''); + } + this.inputElementRef.nativeElement.focus(); + }); + this.select.emptyClue$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => { + this.inputElementRef.nativeElement.value = ''; + }); + } +} diff --git a/packages/ng/multi-select/displayer/default-displayer.component.ts b/packages/ng/multi-select/displayer/default-displayer.component.ts index c0e3d48d36..2a3612b967 100644 --- a/packages/ng/multi-select/displayer/default-displayer.component.ts +++ b/packages/ng/multi-select/displayer/default-displayer.component.ts @@ -1,5 +1,5 @@ import { AsyncPipe, NgFor, NgIf, NgPlural, NgPluralCase } from '@angular/common'; -import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, OnInit, ViewChild, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, inject, OnInit, ViewChild } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormsModule } from '@angular/forms'; import { getIntl } from '@lucca-front/ng/core'; @@ -40,7 +40,7 @@ import { of } from 'rxjs'; {{ intl.removeOption }}
-
+ {{ overflow }}
+
+ {{ overflow }}
`, styleUrls: ['./default-displayer.component.scss'], diff --git a/packages/ng/multi-select/displayer/index.ts b/packages/ng/multi-select/displayer/index.ts index 75776a1405..73776ea3d9 100644 --- a/packages/ng/multi-select/displayer/index.ts +++ b/packages/ng/multi-select/displayer/index.ts @@ -1,3 +1,4 @@ +export * from './counter-displayer/counter-displayer.component'; export * from './default-displayer.component'; export * from './displayer.directive'; export * from './displayer-input.directive'; diff --git a/packages/ng/popover2/content/popover-content/popover-content.component.html b/packages/ng/popover2/content/popover-content/popover-content.component.html new file mode 100644 index 0000000000..5a84ab536d --- /dev/null +++ b/packages/ng/popover2/content/popover-content/popover-content.component.html @@ -0,0 +1,10 @@ +
+
+ +
+ + +
diff --git a/packages/ng/popover2/content/popover-content/popover-content.component.scss b/packages/ng/popover2/content/popover-content/popover-content.component.scss new file mode 100644 index 0000000000..ce6df49f6f --- /dev/null +++ b/packages/ng/popover2/content/popover-content/popover-content.component.scss @@ -0,0 +1,2 @@ +@use '@lucca-front/scss/src/components/button'; +@use '@lucca-front/scss/src/components/popover'; diff --git a/packages/ng/popover2/content/popover-content/popover-content.component.ts b/packages/ng/popover2/content/popover-content/popover-content.component.ts new file mode 100644 index 0000000000..a90a8e4c7b --- /dev/null +++ b/packages/ng/popover2/content/popover-content/popover-content.component.ts @@ -0,0 +1,80 @@ +import { AfterViewInit, ChangeDetectionStrategy, Component, DestroyRef, ElementRef, HostBinding, HostListener, inject, TemplateRef, ViewEncapsulation } from '@angular/core'; +import { NgTemplateOutlet } from '@angular/common'; +import { ButtonComponent } from '@lucca-front/ng/button'; +import { IconComponent } from '@lucca-front/ng/icon'; +import { PopoverFocusTrap } from '../../popover-focus-trap'; +import { Subject } from 'rxjs'; +import { POPOVER_CONFIG } from '../../popover-tokens'; +import { LU_POPOVER2_TRANSLATIONS } from '../../popover.translate'; +import { getIntl } from '@lucca-front/ng/core'; + +@Component({ + selector: 'lu-popover-content', + standalone: true, + imports: [NgTemplateOutlet, ButtonComponent, IconComponent], + templateUrl: './popover-content.component.html', + styleUrl: './popover-content.component.scss', + + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class PopoverContentComponent implements AfterViewInit { + intl = getIntl(LU_POPOVER2_TRANSLATIONS); + + #elementRef = inject>(ElementRef); + + #config = inject(POPOVER_CONFIG); + + destroyRef = inject(DestroyRef); + + @HostBinding('attr.id') + contentId = this.#config.contentId; + + content: TemplateRef = this.#config.content; + + #focusManager = new PopoverFocusTrap(this.#elementRef.nativeElement, this.#config.triggerElement); + + closed$ = new Subject(); + + mouseEnter$ = new Subject(); + + @HostListener('mouseenter') + mouseEnter(): void { + this.mouseEnter$.next(); + } + + mouseLeave$ = new Subject(); + + @HostListener('mouseleave') + mouseLeave(): void { + this.mouseLeave$.next(); + } + + ngAfterViewInit(): void { + this.#focusManager.attachAnchors(); + if (!this.#config.disableFocusManipulation) { + void this.#focusManager.focusInitialElementWhenReady(); + } + } + + grabFocus(): void { + if (!this.#config.disableFocusManipulation) { + this.#focusManager.focusInitialElement(); + } + } + + @HostListener('window:keydown.escape') + close(): void { + if (!this.#config.disableFocusManipulation) { + // Focus initial trigger element + this.#config.triggerElement.focus(); + } + // Tell the directive we're closed now + this.closed$.next(); + this.closed$.complete(); + this.mouseEnter$.complete(); + this.mouseLeave$.complete(); + // Detach overlay + this.#config.ref.detach(); + } +} diff --git a/packages/ng/popover2/ng-package.json b/packages/ng/popover2/ng-package.json new file mode 100644 index 0000000000..35e7407829 --- /dev/null +++ b/packages/ng/popover2/ng-package.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public-api.ts" + } +} diff --git a/packages/ng/popover2/popover-focus-trap.ts b/packages/ng/popover2/popover-focus-trap.ts new file mode 100644 index 0000000000..a58daff9f5 --- /dev/null +++ b/packages/ng/popover2/popover-focus-trap.ts @@ -0,0 +1,23 @@ +import { FocusTrap, InteractivityChecker } from '@angular/cdk/a11y'; +import { inject, Injectable, NgZone } from '@angular/core'; +import { DOCUMENT } from '@angular/common'; + +@Injectable() +export class PopoverFocusTrap extends FocusTrap { + override startAnchorListener = () => { + this.triggerElement.focus(); + return true; + }; + + override endAnchorListener = () => { + this.triggerElement.focus(); + return true; + }; + + constructor( + element: HTMLElement, + private triggerElement: HTMLElement, + ) { + super(element, inject(InteractivityChecker), inject(NgZone), inject(DOCUMENT), true); + } +} diff --git a/packages/ng/popover2/popover-tokens.ts b/packages/ng/popover2/popover-tokens.ts new file mode 100644 index 0000000000..5586e4276c --- /dev/null +++ b/packages/ng/popover2/popover-tokens.ts @@ -0,0 +1,12 @@ +import { InjectionToken, TemplateRef } from '@angular/core'; +import { OverlayRef } from '@angular/cdk/overlay'; + +export interface PopoverConfig { + triggerElement: HTMLElement; + content: TemplateRef; + ref: OverlayRef; + contentId: string; + disableFocusManipulation: boolean; +} + +export const POPOVER_CONFIG = new InjectionToken('Popover:Config'); diff --git a/packages/ng/popover2/popover.directive.ts b/packages/ng/popover2/popover.directive.ts new file mode 100644 index 0000000000..1ce8c05a2a --- /dev/null +++ b/packages/ng/popover2/popover.directive.ts @@ -0,0 +1,207 @@ +import { booleanAttribute, DestroyRef, Directive, ElementRef, HostBinding, HostListener, inject, Injector, input, Input, InputSignal, signal, TemplateRef, ViewContainerRef } from '@angular/core'; +import { ConnectedPosition, ConnectionPositionPair, Overlay, OverlayRef } from '@angular/cdk/overlay'; +import { ComponentPortal } from '@angular/cdk/portal'; +import { PopoverContentComponent } from './content/popover-content/popover-content.component'; +import { POPOVER_CONFIG, PopoverConfig } from './popover-tokens'; +import { combineLatest, debounce, filter, map, merge, Subject, switchMap, timer } from 'rxjs'; +import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop'; + +export type PopoverPosition = 'above' | 'below' | 'before' | 'after'; + +let nextId = 0; + +const defaultPositionPairs: Record = { + above: new ConnectionPositionPair( + { originX: 'center', originY: 'top' }, + { + overlayX: 'center', + overlayY: 'bottom', + }, + ), + below: new ConnectionPositionPair( + { originX: 'center', originY: 'bottom' }, + { + overlayX: 'center', + overlayY: 'top', + }, + ), + before: new ConnectionPositionPair( + { originX: 'start', originY: 'center' }, + { + overlayX: 'end', + overlayY: 'center', + }, + ), + after: new ConnectionPositionPair( + { originX: 'end', originY: 'center' }, + { + overlayX: 'start', + overlayY: 'center', + }, + ), +}; + +@Directive({ + selector: '[luPopover2]', + host: { + '[attr.aria-expanded]': 'opened()', + }, + standalone: true, +}) +export class PopoverDirective { + #overlay = inject(Overlay); + + #elementRef = inject>(ElementRef); + + #vcr = inject(ViewContainerRef); + + #destroyRef = inject(DestroyRef); + + @Input({ + alias: 'luPopover2', + }) + content: TemplateRef; + + @Input() + luPopoverPosition: PopoverPosition = 'above'; + + @Input({ + transform: booleanAttribute, + }) + luPopoverDisabled = false; + + luPopoverTrigger = input<'click' | 'click+hover'>('click'); + + @Input() + customPositions?: ConnectionPositionPair[]; + + // We have to type these two for Compodoc to find the right type and tell Storybook these aren't strings + luPopoverOpenDelay: InputSignal = input(300); + + luPopoverCloseDelay: InputSignal = input(100); + + open$ = new Subject(); + + close$ = new Subject(); + + #overlayRef: OverlayRef; + + #componentRef?: PopoverContentComponent; + + positionPairs: Record = defaultPositionPairs; + + opened = signal(false); + + @HostBinding('attr.aria-controls') + ariaControls = `popover-content-${nextId++}`; + + constructor() { + combineLatest([toObservable(this.luPopoverOpenDelay), toObservable(this.luPopoverCloseDelay), toObservable(this.luPopoverTrigger)]) + .pipe( + filter(([, , trigger]) => { + return trigger.includes('hover'); + }), + switchMap(([openDelay, closeDelay]) => { + return merge(this.open$.pipe(map(() => 'open')), this.close$.pipe(map(() => 'close'))).pipe( + debounce((event) => { + return timer(event === 'open' ? openDelay : closeDelay); + }), + ); + }), + takeUntilDestroyed(this.#destroyRef), + ) + .subscribe((event) => { + if (event === 'open') { + this.openPopover(true); + } else { + this.#componentRef?.close(); + } + }); + } + + @HostListener('mouseenter') + onMouseEnter() { + this.open$.next(); + } + + @HostListener('mouseleave') + onMouseLeave() { + this.close$.next(); + } + + @HostListener('click') + click(): void { + if (this.opened()) { + this.#componentRef?.close(); + } else { + this.openPopover(); + } + } + + openPopover(disableFocusHandler = false): void { + if (!this.opened() && !this.luPopoverDisabled) { + this.opened.set(true); + this.#overlayRef = this.#overlay.create({ + positionStrategy: this.#overlay + .position() + .flexibleConnectedTo(this.#elementRef) + .withPositions(this.customPositions || this.#buildPositions()), + scrollStrategy: this.#overlay.scrollStrategies.block(), + hasBackdrop: this.luPopoverTrigger() === 'click', + backdropClass: '', + disposeOnNavigation: true, + }); + // Close on backdrop click even if backdrop is invisible + this.#overlayRef + .backdropClick() + .pipe(takeUntilDestroyed(this.#destroyRef)) + .subscribe(() => this.#componentRef.close()); + const config: PopoverConfig = { + content: this.content, + ref: this.#overlayRef, + contentId: this.ariaControls, + triggerElement: this.#elementRef.nativeElement, + disableFocusManipulation: disableFocusHandler, + }; + this.#componentRef = this.#overlayRef.attach( + new ComponentPortal( + PopoverContentComponent, + this.#vcr, + Injector.create({ + providers: [{ provide: POPOVER_CONFIG, useValue: config }], + }), + ), + ).instance; + // On tooltip leave => trigger close + this.#componentRef.mouseLeave$.pipe(takeUntilDestroyed(this.#componentRef.destroyRef), takeUntilDestroyed(this.#destroyRef)).subscribe(() => this.close$.next()); + // On tooltip enter => trigger open to keep it opened + this.#componentRef.mouseEnter$.pipe(takeUntilDestroyed(this.#componentRef.destroyRef), takeUntilDestroyed(this.#destroyRef)).subscribe(() => this.open$.next()); + this.#componentRef.closed$.pipe(takeUntilDestroyed(this.#componentRef.destroyRef), takeUntilDestroyed(this.#destroyRef)).subscribe(() => this.opened.set(false)); + } + } + + @HostListener('keydown.Tab', ['$event']) + focusBackToContent(event: KeyboardEvent): void { + if (this.opened()) { + event.preventDefault(); + this.#componentRef.grabFocus(); + } + } + + #buildPositions(): ConnectedPosition[] { + const opposite: Record = { + before: 'after', + after: 'before', + above: 'below', + below: 'above', + }; + // Once we have opposite, what's remaining? + const remaining: Record = { + before: ['above', 'below'], + after: ['above', 'below'], + above: ['before', 'after'], + below: ['before', 'after'], + }; + return [this.positionPairs[this.luPopoverPosition], this.positionPairs[opposite[this.luPopoverPosition]], ...remaining[this.luPopoverPosition].map((r) => this.positionPairs[r])]; + } +} diff --git a/packages/ng/popover2/popover.providers.ts b/packages/ng/popover2/popover.providers.ts new file mode 100644 index 0000000000..7e1969e101 --- /dev/null +++ b/packages/ng/popover2/popover.providers.ts @@ -0,0 +1,6 @@ +import { EnvironmentProviders, importProvidersFrom, makeEnvironmentProviders } from '@angular/core'; +import { OverlayModule } from '@angular/cdk/overlay'; + +export function configureLuPopover(): EnvironmentProviders { + return makeEnvironmentProviders([importProvidersFrom(OverlayModule)]); +} diff --git a/packages/ng/popover2/popover.translate.ts b/packages/ng/popover2/popover.translate.ts new file mode 100644 index 0000000000..c5af414760 --- /dev/null +++ b/packages/ng/popover2/popover.translate.ts @@ -0,0 +1,28 @@ +import { InjectionToken } from '@angular/core'; +import { ILuTranslation } from '@lucca-front/ng/core'; + +export const LU_POPOVER2_TRANSLATIONS = new InjectionToken('LuPopover2Translations', { + factory: () => luPopoverTranslations, +}); + +export interface ILuPopover2Label { + close: string; +} + +export const luPopoverTranslations: ILuTranslation = { + en: { + close: 'Close', + }, + fr: { + close: 'Fermer', + }, + de: { + close: 'Schließen', + }, + es: { + close: 'Cerrar', + }, + pt: { + close: 'Fechar', + }, +}; diff --git a/packages/ng/popover2/public-api.ts b/packages/ng/popover2/public-api.ts new file mode 100644 index 0000000000..6221fd2290 --- /dev/null +++ b/packages/ng/popover2/public-api.ts @@ -0,0 +1,2 @@ +export * from './popover.directive'; +export * from './popover.providers'; diff --git a/packages/ng/popup-employee/card/panel/user-popover-panel.component.html b/packages/ng/popup-employee/card/panel/user-popover-panel.component.html index e23fcd60c3..530249ed67 100644 --- a/packages/ng/popup-employee/card/panel/user-popover-panel.component.html +++ b/packages/ng/popup-employee/card/panel/user-popover-panel.component.html @@ -10,7 +10,7 @@ (mousedown)="onMouseDown()" >
-
+
@@ -22,27 +22,26 @@
-

-
+

+ -

-

+ + - + {{employee.firstName}} {{employee.lastName}} +

{{employee.jobTitle}}

+

{{employee.userDepartment?.name}}

-

{{employee.jobTitle}}

-

{{employee.userDepartment?.name}}

- -

- +

+ - {{intl.EMPLOYEE_CARD_PANEL_COMING_ON_LABEL | injectParameter : (employee.dtContractStart | date: 'longDate') }} + {{intl.EMPLOYEE_CARD_PANEL_COMING_ON_LABEL | injectParameter : (employee.dtContractStart | date: 'shortDate') }} {{intl.EMPLOYEE_CARD_PANEL_EMPLOYEE_HAS_LEAVED_LABEL }} - + {{ employee.currentWorkLocation?.name }} - - - - {{employee.currentWorkLocation?.area?.name}} +  – {{employee.currentWorkLocation?.area?.name}} - {{intl.EMPLOYEE_CARD_PANEL_PRESENT_LABEL }} + {{intl.EMPLOYEE_CARD_PANEL_PRESENT_LABEL }} {{ intl.EMPLOYEE_CARD_PANEL_ABSENCE_LABEL }} - - - {{ employee.leaveEndsOn | leaveEndsDisplay: employee.leaveEndIsFirstHalfDay }} +  – {{ employee.leaveEndsOn | leaveEndsDisplay: employee.leaveEndIsFirstHalfDay }} @@ -88,6 +86,6 @@

-
+
diff --git a/packages/ng/skeleton/ng-package.json b/packages/ng/skeleton/ng-package.json new file mode 100644 index 0000000000..68facef35b --- /dev/null +++ b/packages/ng/skeleton/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public-api.ts", + "styleIncludePaths": ["../styles"] + } +} diff --git a/packages/ng/skeleton/public-api.ts b/packages/ng/skeleton/public-api.ts new file mode 100644 index 0000000000..95380e3e8e --- /dev/null +++ b/packages/ng/skeleton/public-api.ts @@ -0,0 +1,3 @@ +export * from './skeleton-button/skeleton-button.component'; +export * from './skeleton-header/skeleton-header.component'; +export * from './skeleton-field/skeleton-field.component'; diff --git a/packages/ng/skeleton/skeleton-button/skeleton-button.component.html b/packages/ng/skeleton/skeleton-button/skeleton-button.component.html new file mode 100644 index 0000000000..5158168cd3 --- /dev/null +++ b/packages/ng/skeleton/skeleton-button/skeleton-button.component.html @@ -0,0 +1,5 @@ +
+
+ +
+
diff --git a/packages/ng/skeleton/skeleton-button/skeleton-button.component.scss b/packages/ng/skeleton/skeleton-button/skeleton-button.component.scss new file mode 100644 index 0000000000..1df0f0cb39 --- /dev/null +++ b/packages/ng/skeleton/skeleton-button/skeleton-button.component.scss @@ -0,0 +1,12 @@ +@use '@lucca-front/scss/src/components/button'; +@use '@lucca-front/scss/src/components/skeleton'; + +.skeleton.is-loading { + .button { + background-color: transparent; + + .skeleton-item { + width: 4rem; + } + } +} diff --git a/packages/ng/skeleton/skeleton-button/skeleton-button.component.ts b/packages/ng/skeleton/skeleton-button/skeleton-button.component.ts new file mode 100644 index 0000000000..83517763db --- /dev/null +++ b/packages/ng/skeleton/skeleton-button/skeleton-button.component.ts @@ -0,0 +1,13 @@ +import { booleanAttribute, ChangeDetectionStrategy, Component, Input } from '@angular/core'; + +@Component({ + selector: 'lu-skeleton-button', + standalone: true, + templateUrl: './skeleton-button.component.html', + styleUrl: './skeleton-button.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SkeletonButtonComponent { + @Input({ transform: booleanAttribute }) + dark = false; +} diff --git a/packages/ng/skeleton/skeleton-field/skeleton-field.component.html b/packages/ng/skeleton/skeleton-field/skeleton-field.component.html new file mode 100644 index 0000000000..2a26f2ba00 --- /dev/null +++ b/packages/ng/skeleton/skeleton-field/skeleton-field.component.html @@ -0,0 +1,10 @@ +
+ +
+
+ + + +
+
+
diff --git a/packages/ng/skeleton/skeleton-field/skeleton-field.component.scss b/packages/ng/skeleton/skeleton-field/skeleton-field.component.scss new file mode 100644 index 0000000000..f00a69f5a7 --- /dev/null +++ b/packages/ng/skeleton/skeleton-field/skeleton-field.component.scss @@ -0,0 +1,2 @@ +@use '@lucca-front/scss/src/components/textField'; +@use '@lucca-front/scss/src/components/skeleton'; diff --git a/packages/ng/skeleton/skeleton-field/skeleton-field.component.ts b/packages/ng/skeleton/skeleton-field/skeleton-field.component.ts new file mode 100644 index 0000000000..99b9cf8af6 --- /dev/null +++ b/packages/ng/skeleton/skeleton-field/skeleton-field.component.ts @@ -0,0 +1,13 @@ +import { booleanAttribute, ChangeDetectionStrategy, Component, Input } from '@angular/core'; + +@Component({ + selector: 'lu-skeleton-field', + standalone: true, + templateUrl: './skeleton-field.component.html', + styleUrl: './skeleton-field.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SkeletonFieldComponent { + @Input({ transform: booleanAttribute }) + dark = false; +} diff --git a/packages/ng/skeleton/skeleton-header/skeleton-header.component.html b/packages/ng/skeleton/skeleton-header/skeleton-header.component.html new file mode 100644 index 0000000000..39efc05ce8 --- /dev/null +++ b/packages/ng/skeleton/skeleton-header/skeleton-header.component.html @@ -0,0 +1,14 @@ + diff --git a/packages/ng/skeleton/skeleton-header/skeleton-header.component.scss b/packages/ng/skeleton/skeleton-header/skeleton-header.component.scss new file mode 100644 index 0000000000..df10d29a8b --- /dev/null +++ b/packages/ng/skeleton/skeleton-header/skeleton-header.component.scss @@ -0,0 +1,12 @@ +@use '@lucca-front/scss/src/components/pageHeader'; +@use '@lucca-front/scss/src/components/skeleton'; +@use '@lucca-front/scss/src/commons/utils/media'; + +.pageHeader.skeleton.is-loading { + .pageHeader-content-actions { + width: 100px; + @include media.max('XS') { + display: none; + } + } +} diff --git a/packages/ng/skeleton/skeleton-header/skeleton-header.component.ts b/packages/ng/skeleton/skeleton-header/skeleton-header.component.ts new file mode 100644 index 0000000000..710a9388fe --- /dev/null +++ b/packages/ng/skeleton/skeleton-header/skeleton-header.component.ts @@ -0,0 +1,13 @@ +import { booleanAttribute, ChangeDetectionStrategy, Component, Input } from '@angular/core'; + +@Component({ + selector: 'lu-skeleton-header', + standalone: true, + templateUrl: './skeleton-header.component.html', + styleUrl: './skeleton-header.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SkeletonHeaderComponent { + @Input({ transform: booleanAttribute }) + dark = false; +} diff --git a/packages/ng/styles/_definitions.scss b/packages/ng/styles/_definitions.scss index 5ef8287ebd..f4c7498df7 100644 --- a/packages/ng/styles/_definitions.scss +++ b/packages/ng/styles/_definitions.scss @@ -6,4 +6,3 @@ @import 'definitions/option/option-searcher'; @import 'definitions/option/option-selector'; @import 'definitions/option/option-placeholder'; -@import 'definitions/tooltip/tooltip'; diff --git a/packages/ng/styles/definitions/option/_option-item.scss b/packages/ng/styles/definitions/option/_option-item.scss index 3c01b20bb0..9bf8c6eea7 100644 --- a/packages/ng/styles/definitions/option/_option-item.scss +++ b/packages/ng/styles/definitions/option/_option-item.scss @@ -6,8 +6,6 @@ --components-options-item-padding-horizontal: var(--pr-t-spacings-100); --components-options-item-multiple-padding: 2.25rem; --components-options-item-icon-color: var(--palettes-neutral-800); - - --components-options-checkbox-left: 0.5rem; --components-options-checkbox-size: 1.25rem; --components-options-checkbox-color: var(--palettes-product-700); --components-options-checkbox-border-radius: 6px; @@ -116,9 +114,8 @@ &::before { display: block; position: absolute; - left: var(--components-options-checkbox-left); - top: 50%; - transform: translateY(-50%); + left: var(--pr-t-spacings-100); + top: var(--pr-t-spacings-75); } &::before { @@ -140,7 +137,7 @@ line-height: var(--components-options-checkbox-size); position: absolute; text-align: center; - transform: translateY(-50%) scale(0); + transform: scale(0); transition: all 100ms; width: var(--components-options-checkbox-size); } @@ -153,7 +150,7 @@ &::after { color: var(--colors-white-color); - transform: translateY(-50%) scale(1); + transform: scale(1); } } diff --git a/packages/ng/styles/definitions/select/_select-input.scss b/packages/ng/styles/definitions/select/_select-input.scss index 414860597d..60963bcdff 100644 --- a/packages/ng/styles/definitions/select/_select-input.scss +++ b/packages/ng/styles/definitions/select/_select-input.scss @@ -82,11 +82,6 @@ } ::ng-deep .lu-select-value { - .label { - padding: var(--pr-t-spacings-50) var(--pr-t-spacings-100); - margin-left: 0; - } - .chip { vertical-align: baseline; max-width: 100%; @@ -127,16 +122,6 @@ } ::ng-deep .lu-select-value { - .label { - // deprecated - font-size: var(--sizes-S-fontSize); - line-height: var(--sizes-S-lineHeight); - font-weight: 600; - margin: 0; - padding: 0; - background-color: transparent; - } - .chip { height: var(--sizes-XS-lineHeight); line-height: var(--sizes-XS-lineHeight); diff --git a/packages/ng/styles/definitions/tooltip/_tooltip.scss b/packages/ng/styles/definitions/tooltip/_tooltip.scss deleted file mode 100644 index 0251f02751..0000000000 --- a/packages/ng/styles/definitions/tooltip/_tooltip.scss +++ /dev/null @@ -1,36 +0,0 @@ -@mixin tooltipStyle { - .lu-tooltip-panel { - --components-tooltip-background-color: var(--palettes-neutral-900); - --components-tooltip-color: var(--colors-white-color); - --components-tooltip-max-width: 15rem; - - background: var(--components-tooltip-background-color); - color: var(--components-tooltip-color); - padding: var(--pr-t-spacings-50) var(--pr-t-spacings-100); - max-width: var(--components-tooltip-max-width); - border-radius: var(--commons-borderRadius-M); - font-size: var(--sizes-XS-fontSize); - line-height: var(--sizes-XS-lineHeight); - display: block; - text-align: center; - - &.is-above { - transform-origin: bottom center; - } - - &.is-below { - transform-origin: top center; - margin-top: 2px; - } - - &.is-before { - transform-origin: center right; - margin-right: 5px; - } - - &.is-after { - transform-origin: center left; - margin-left: 5px; - } - } -} diff --git a/packages/ng/styles/definitions/user/user-picture.scss b/packages/ng/styles/definitions/user/user-picture.scss index 79b974b47e..0d7d880556 100644 --- a/packages/ng/styles/definitions/user/user-picture.scss +++ b/packages/ng/styles/definitions/user/user-picture.scss @@ -4,25 +4,30 @@ @mixin userPictureVars { --components-userPicture-XS-image: 1.5rem; - --components-userPicture-XS-fontSize: var(--sizes-XS-fontSize); + --components-userPicture-XS-fontSize: 0.75rem; --components-userPicture-XS-placeholder: 0.75rem; --components-userPicture-S-image: 2rem; - --components-userPicture-S-fontSize: var(--sizes-S-fontSize); - --components-userPicture-S-placeholder: var(--sizes-XS-lineHeight); + --components-userPicture-S-fontSize: 0.875rem; + --components-userPicture-S-placeholder: 1rem; --components-userPicture-M-image: 2.5rem; - --components-userPicture-M-fontSize: var(--sizes-M-fontSize); - --components-userPicture-M-placeholder: var(--sizes-S-lineHeight); + --components-userPicture-M-fontSize: 1rem; + --components-userPicture-M-placeholder: 1.25rem; --components-userPicture-L-image: 3rem; - --components-userPicture-L-fontSize: var(--sizes-L-fontSize); - --components-userPicture-L-placeholder: var(--sizes-M-lineHeight); + --components-userPicture-L-fontSize: 1.125rem; + --components-userPicture-L-placeholder: 1.5rem; + --components-userPicture-XL-image: 4rem; + --components-userPicture-XL-fontSize: 1.25rem; + --components-userPicture-XL-placeholder: 2rem; + --components-userPicture-XXL-image: 5rem; + --components-userPicture-XXL-fontSize: 1.5rem; + --components-userPicture-XXL-placeholder: 2.25rem; + --components-userPicture-XXXL-image: 6rem; + --components-userPicture-XXXL-fontSize: 1.75rem; + --components-userPicture-XXXL-placeholder: 2.5rem; // deprecated --components-userPicture-XXS-image: 1rem; --components-userPicture-XXS-fontSize: 0.5625rem; - --components-userPicture-XL-image: 4.5rem; - --components-userPicture-XL-fontSize: 1.8rem; - --components-userPicture-XXL-image: 7.5rem; - --components-userPicture-XXL-fontSize: 3rem; } @mixin userPictureStyle { @@ -74,11 +79,19 @@ &.mod-XL { --components-user-picture-image-size: var(--components-userPicture-XL-image); --components-user-picture-font-size: var(--components-userPicture-XL-fontSize); + --components-user-picture-placeholder: var(--components-userPicture-XL-placeholder); } &.mod-XXL { --components-user-picture-image-size: var(--components-userPicture-XXL-image); --components-user-picture-font-size: var(--components-userPicture-XXL-fontSize); + --components-user-picture-placeholder: var(--components-userPicture-XXL-placeholder); + } + + &.mod-XXXL { + --components-user-picture-image-size: var(--components-userPicture-XXXL-image); + --components-user-picture-font-size: var(--components-userPicture-XXXL-fontSize); + --components-user-picture-placeholder: var(--components-userPicture-XXXL-placeholder); } &.mod-border { diff --git a/packages/ng/styles/definitions/user/user-tile.scss b/packages/ng/styles/definitions/user/user-tile.scss index 335c0c6c42..3db60c11b2 100644 --- a/packages/ng/styles/definitions/user/user-tile.scss +++ b/packages/ng/styles/definitions/user/user-tile.scss @@ -79,4 +79,9 @@ --components-user-picture-image-size: var(--components-userPicture-XXL-image); --components-user-picture-font-size: var(--components-userPicture-XXL-fontSize); } + + &.mod-XXXL { + --components-user-picture-image-size: var(--components-userPicture-XXXL-image); + --components-user-picture-font-size: var(--components-userPicture-XXXL-fontSize); + } } diff --git a/packages/ng/tag/ng-package.json b/packages/ng/tag/ng-package.json new file mode 100644 index 0000000000..35e7407829 --- /dev/null +++ b/packages/ng/tag/ng-package.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public-api.ts" + } +} diff --git a/packages/ng/tag/public-api.ts b/packages/ng/tag/public-api.ts new file mode 100644 index 0000000000..060ebad79d --- /dev/null +++ b/packages/ng/tag/public-api.ts @@ -0,0 +1 @@ +export * from './tag.component'; diff --git a/packages/ng/tag/tag.component.html b/packages/ng/tag/tag.component.html new file mode 100644 index 0000000000..027e4f5009 --- /dev/null +++ b/packages/ng/tag/tag.component.html @@ -0,0 +1,11 @@ +@if (link) { + + @if (icon) { + {{ label }} } @else { {{ label }} } +} @else { + + @if (icon) { + {{ label }} } @else { {{ label }} } +} diff --git a/packages/ng/tag/tag.component.scss b/packages/ng/tag/tag.component.scss new file mode 100644 index 0000000000..e0d6d6c260 --- /dev/null +++ b/packages/ng/tag/tag.component.scss @@ -0,0 +1 @@ +@use '@lucca-front/scss/src/components/tag'; diff --git a/packages/ng/tag/tag.component.ts b/packages/ng/tag/tag.component.ts new file mode 100644 index 0000000000..af185efda7 --- /dev/null +++ b/packages/ng/tag/tag.component.ts @@ -0,0 +1,51 @@ +import { booleanAttribute, ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { LuccaIcon } from '@lucca-front/icons'; +import { Palette } from '@lucca-front/ng/core'; +import { IconComponent } from '@lucca-front/ng/icon'; + +@Component({ + selector: 'lu-tag', + standalone: true, + templateUrl: './tag.component.html', + styleUrls: ['./tag.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + imports: [IconComponent, RouterLink], +}) +export class TagComponent { + @Input({ required: true }) + label: string; + + @Input() + /** + * Which size should the callout be? Defaults to medium + */ + size: 'M' | 'S' = 'M'; + + @Input() + /** + * Which palette should be used for the entire callout. + * Defaults to none (inherits parent palette) + */ + palette: Palette = 'none'; + + @Input({ transform: booleanAttribute }) + /** + * Should display be outlined? + */ + outlined = false; + + @Input() + /** + * For routerLink usage + */ + link: string; + + @Input() + /** + * Which icon should we display in the callout if any? + * Defaults to no icon. + */ + icon: LuccaIcon; +} diff --git a/packages/ng/time/core/base-picker.component.ts b/packages/ng/time/core/base-picker.component.ts new file mode 100644 index 0000000000..4398c6af23 --- /dev/null +++ b/packages/ng/time/core/base-picker.component.ts @@ -0,0 +1,59 @@ +import { ISO8601Duration, ISO8601Time } from './date-primitives'; +import { Component, computed, input, model, ViewChild } from '@angular/core'; +import { TimePickerPartComponent } from './time-picker-part.component'; +import { ControlValueAccessor } from '@angular/forms'; + +@Component({ + template: '', +}) +export abstract class BasePickerComponent implements ControlValueAccessor { + onChange: (value: ISO8601Time | ISO8601Duration) => void; + onTouched: () => void; + + step = input(null); + + disabled = model(false); + + size = input<'S' | 'M'>(); + + @ViewChild('hoursPart') + hoursPart?: TimePickerPartComponent; + + @ViewChild('minutesPart') + minutesPart?: TimePickerPartComponent; + + protected hoursIncrement = computed(() => this.getHoursIncrement()); + protected minutesIncrement = computed(() => this.getMinutesIncrement()); + + registerOnChange(fn: () => void): void { + this.onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + abstract writeValue(value: ISO8601Time | ISO8601Duration): void; + + abstract getHoursIncrement(): number; + + abstract getMinutesIncrement(): number; + + protected focusPart(type: 'hours' | 'minutes') { + this.onTouched?.(); + if (type === 'hours') { + if (this.hoursIncrement() === 0) { + return; + } + + this.hoursPart?.focus(); + } + if (type === 'minutes') { + if (this.minutesIncrement() === 0) { + return; + } + + this.minutesPart?.focus(); + } + } +} diff --git a/packages/ng/time/core/date-primitives.ts b/packages/ng/time/core/date-primitives.ts new file mode 100644 index 0000000000..22a91b5ecc --- /dev/null +++ b/packages/ng/time/core/date-primitives.ts @@ -0,0 +1,2 @@ +export type ISO8601Duration = `${string}P${string}`; // Looks like P1DT2H30M +export type ISO8601Time = `${string}:${string}:${string}`; // Looks like 00:30:00 diff --git a/packages/ng/time/core/date.utils.ts b/packages/ng/time/core/date.utils.ts new file mode 100644 index 0000000000..2e68e89d9f --- /dev/null +++ b/packages/ng/time/core/date.utils.ts @@ -0,0 +1,52 @@ +import { ISO8601Time } from './date-primitives'; + +export const castToIsoTime = (str: string) => str as ISO8601Time; + +export const convertStringToIsoTime = (time: string): ISO8601Time => { + if (/^\d{1,2}:\d{2}:\d{2}$/.test(time)) { + return castToIsoTime(time); + } + + if (/^\d{1,2}:\d{2}$/.test(time)) { + return castToIsoTime(`${time}:00`); + } + + if (/^\d{1,2}h\d{2}$/.test(time)) { + return convertStringToIsoTime(time.replace('h', ':')); + } + + throw new Error(`Invalid time format: ${time}`); +}; + +export const createIsoTimeFromHoursAndMinutes = (hours: number, minutes: number, seconds: number = 0): ISO8601Time => { + const hoursStr = hours.toString().padStart(2, '0'); + const minutesStr = minutes.toString().padStart(2, '0'); + const secondsStr = seconds.toString().padStart(2, '0'); + + return `${hoursStr}:${minutesStr}:${secondsStr}`; +}; + +export const isoTimeToSeconds = (time: ISO8601Time): number => { + return getHoursPartFromIsoTime(time) * 3600 + getMinutesPartFromIsoTime(time) * 60 + getSecondsPartFromIsoTime(time); +}; + +export const getHoursPartFromIsoTime = (time: ISO8601Time): number => Number(time.split(':')[0]) || 0; + +export const getMinutesPartFromIsoTime = (time: ISO8601Time): number => Number(time.split(':')[1]) || 0; +export const getSecondsPartFromIsoTime = (time: ISO8601Time): number => Number(time.split(':')[2]) || 0; + +export const getHoursDisplayPartFromIsoTime = (time: ISO8601Time): number | '--' => { + const hours = time.split(':')[0]; + if (hours === '--') { + return hours; + } + return Number(hours); +}; + +export const getMinutesDisplayPartFromIsoTime = (time: ISO8601Time): number | '--' => { + const minutes = time.split(':')[1]; + if (minutes === '--') { + return minutes; + } + return Number(minutes); +}; diff --git a/packages/ng/time/core/duration.utils.ts b/packages/ng/time/core/duration.utils.ts new file mode 100644 index 0000000000..2b210b2292 --- /dev/null +++ b/packages/ng/time/core/duration.utils.ts @@ -0,0 +1,86 @@ +import { Duration } from 'date-fns'; +import { ISO8601Duration } from './date-primitives'; +import { isNotNil } from './misc.utils'; + +export type NonNullableDateFnsDuration = { + years: number; + months: number; + days: number; + hours: number; + minutes: number; + seconds: number; +}; + +type DateFnsDuration = Duration; + +const ISO8601DurationRegExp = + /^(?-)?P(?:(?-?\d+)Y)?(?:(?-?\d+)M)?(?:(?-?\d+)W)?(?:(?-?\d+)D)?(?:T(?:(?-?\d+)H)?(?:(?-?\d+)M)?(?:(?-?\d+(?:\.\d+)?)S)?)?$/; + +// TODO memoize +export const isoDurationToDateFnsDuration = (isoDuration: ISO8601Duration): NonNullableDateFnsDuration => { + const matches = ISO8601DurationRegExp.exec(isoDuration); + + const groups = matches?.groups; + + if (!groups) { + throw new Error(`Invalid ISO 8601 duration: ${isoDuration}`); + } + + const withSign = groups['sign'] === '-' ? -1 : 1; + + const result: NonNullableDateFnsDuration = { + years: groups['years'] ? Number(groups['years']) : 0, + months: groups['months'] ? Number(groups['months']) : 0, + days: groups['days'] ? Number(groups['days']) : 0, + hours: groups['hours'] ? Number(groups['hours']) : 0, + minutes: groups['minutes'] ? Number(groups['minutes']) : 0, + seconds: groups['seconds'] ? Number(groups['seconds']) : 0, + }; + + result.years *= withSign; + result.months *= withSign; + result.days *= withSign; + result.hours *= withSign; + result.minutes *= withSign; + result.seconds *= withSign; + + return result; +}; + +export function isISO8601Duration(value: string): value is ISO8601Duration { + return ISO8601DurationRegExp.test(value); +} + +export const dateFnsDurationToSeconds = (durationFns: DateFnsDuration): number => { + const { years, months } = durationFns; + let { days, hours, minutes, seconds } = durationFns; + + if ((isNotNil(years) && years !== 0) || (isNotNil(months) && months !== 0)) { + throw new Error('years and months are not supported'); + } + + days = days || 0; + hours = hours || 0; + minutes = minutes || 0; + seconds = seconds || 0; + + return days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60 + seconds; +}; + +export const isoDurationToSeconds = (duration: ISO8601Duration): number => { + const durationFns = isoDurationToDateFnsDuration(duration); + + return dateFnsDurationToSeconds(durationFns); +}; + +export const getHoursPartFromDuration = (duration: ISO8601Duration): number => { + return Math.floor(isoDurationToSeconds(duration) / 3600); +}; + +export const getMinutesPartFromDuration = (duration: ISO8601Duration): number => { + return Math.floor((isoDurationToSeconds(duration) % 3600) / 60); +}; + +export const createDurationFromHoursAndMinutes = (hours: number, minutes: number): ISO8601Duration => { + return `PT${hours}H${minutes}M`; +}; diff --git a/packages/ng/time/core/math.utils.ts b/packages/ng/time/core/math.utils.ts new file mode 100644 index 0000000000..c5388c2f85 --- /dev/null +++ b/packages/ng/time/core/math.utils.ts @@ -0,0 +1,19 @@ +export const roundToNearest = (value: number, step: number) => Math.round(value / step) * step; + +export const floorToNearest = (value: number, step: number) => Math.floor(value / step) * step; + +export const ceilToNearest = (value: number, step: number) => Math.ceil(value / step) * step; + +/** + * Returns the value of n circularized between 0 and max. + * Given n = 0 and max = 10, returns 0. + * Given n = 10 and max = 10, returns 10. + * Given n = 11 and max = 10, returns 1. + * Given n = -1 and max = 10, returns 9. + */ +export const circularize = (n: number, max: number) => { + if (n % max === 0) { + return n === 0 ? 0 : max; + } + return ((n % max) + max) % max; +}; diff --git a/packages/ng/time/core/misc.utils.ts b/packages/ng/time/core/misc.utils.ts new file mode 100644 index 0000000000..9a9a7b586b --- /dev/null +++ b/packages/ng/time/core/misc.utils.ts @@ -0,0 +1,5 @@ +export const isNil = (value: T | null | undefined): value is null | undefined => typeof value === 'undefined' || value === null; + +export const isNotNil = (value: T): value is NonNullable => !isNil(value); + +export type PickerControlDirection = 'up' | 'down'; diff --git a/packages/ng/time/core/repeat-on-hold.directive.ts b/packages/ng/time/core/repeat-on-hold.directive.ts new file mode 100644 index 0000000000..ec531ca7d9 --- /dev/null +++ b/packages/ng/time/core/repeat-on-hold.directive.ts @@ -0,0 +1,79 @@ +import { Directive, ElementRef, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; + +const INITIAL_INTERVAL = 500; + +@Directive({ + selector: '[luRepeatOnHold]', + standalone: true, +}) +export class RepeatOnHoldDirective implements OnDestroy, OnInit { + @Output() hold = new EventEmitter(); + + onMouseDown = () => { + if (this.startTime !== undefined) { + return; + } + + this.hold.emit(); + this.animationFrameId = window.requestAnimationFrame(this.animationFrameHandler); + + window.removeEventListener('mouseup', this.onWindowMouseUp); + window.addEventListener('mouseup', this.onWindowMouseUp); + }; + + onWindowMouseUp = () => { + this.cancelAnimationFrame(); + }; + + constructor(private elementRef: ElementRef) {} + + ngOnInit(): void { + this.elementRef.nativeElement.addEventListener('mousedown', this.onMouseDown); + } + + interval = INITIAL_INTERVAL; + startTime: number | undefined = undefined; + previousTime: number | undefined = undefined; + animationFrameId: number | undefined = undefined; + + private cancelAnimationFrame(): void { + if (this.animationFrameId) { + this.previousTime = undefined; + this.interval = INITIAL_INTERVAL; + this.startTime = undefined; + window.cancelAnimationFrame(this.animationFrameId); + this.animationFrameId = undefined; + } + } + + private animationFrameHandler = (time: number): void => { + if (this.startTime === undefined) { + this.startTime = time; + } + + if (this.previousTime === undefined) { + this.previousTime = time; + } + + if (time - this.previousTime > this.interval) { + this.hold.emit(); + this.previousTime = time; + } + + if (time - this.startTime > 1000) { + this.interval = 200; + } + + if (time - this.startTime > 2000) { + this.interval = 50; + } + + this.animationFrameId = window.requestAnimationFrame(this.animationFrameHandler); + }; + + ngOnDestroy(): void { + this.elementRef.nativeElement.removeEventListener('mousedown', this.onMouseDown); + window.removeEventListener('mouseup', this.onWindowMouseUp); + this.cancelAnimationFrame(); + } +} diff --git a/packages/ng/time/core/time-picker-part.component.html b/packages/ng/time/core/time-picker-part.component.html new file mode 100644 index 0000000000..61172f7260 --- /dev/null +++ b/packages/ng/time/core/time-picker-part.component.html @@ -0,0 +1,30 @@ +
+ +
+ + +
+ @if (displayArrows()) { + + + } +
diff --git a/packages/ng/time/core/time-picker-part.component.ts b/packages/ng/time/core/time-picker-part.component.ts new file mode 100644 index 0000000000..04b0b19de2 --- /dev/null +++ b/packages/ng/time/core/time-picker-part.component.ts @@ -0,0 +1,176 @@ +import { DecimalPipe, formatNumber } from '@angular/common'; +import { + booleanAttribute, + ChangeDetectionStrategy, + Component, + computed, + ElementRef, + EventEmitter, + Inject, + input, + LOCALE_ID, + model, + ModelSignal, + numberAttribute, + Output, + ViewChild, +} from '@angular/core'; +import { RepeatOnHoldDirective } from './repeat-on-hold.directive'; +import { PickerControlDirection } from './misc.utils'; +import { InputDirective } from '@lucca-front/ng/form-field'; + +let nextId = 0; + +@Component({ + selector: 'lu-time-picker-part', + standalone: true, + imports: [RepeatOnHoldDirective, DecimalPipe, InputDirective], + templateUrl: './time-picker-part.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TimePickerPartComponent { + label = input(''); + + decimalConf = input('2.0-0'); + + value: ModelSignal = model('--'); + + max = input(0, { + transform: numberAttribute, + }); + + displayArrows = input(false, { + transform: booleanAttribute, + }); + + isReadonly = input(false, { + transform: booleanAttribute, + }); + + hideValue = input(false, { + transform: booleanAttribute, + }); + + disabled = input(false, { + transform: booleanAttribute, + }); + + focused = input(false, { + transform: booleanAttribute, + }); + + @Output() prevRequest = new EventEmitter(); + @Output() nextRequest = new EventEmitter(); + @Output() inputControlClick = new EventEmitter(); + @Output() touched = new EventEmitter(); + + @ViewChild('timePickerInput') timePickerInput?: ElementRef; + + valueLabel = computed(() => { + if (this.hideValue()) { + return ' '; + } + const value = this.value(); + if (value === '--') { + return value; + } + return formatNumber(value, this.locale, this.decimalConf()); + }); + + protected inputId = `time-picker-part-${nextId++}`; + + constructor(@Inject(LOCALE_ID) private locale: string) {} + + arrowKeyPressed(event: KeyboardEvent, isUpArrow: boolean): void { + event.preventDefault(); + this.inputControlClick.emit(isUpArrow ? 'up' : 'down'); + } + + keysInputHandler(event: Event): void { + event.preventDefault(); + + if (!(event.target instanceof HTMLInputElement) || !(event instanceof InputEvent)) { + return; + } + + if (event.data && /\D+/.test(event.data)) { + event.target.value = String(this.value()); + return; + } + + const value = event.target.value; + + let val = value.slice(-2) || '00'; + + if (this.max() && Number(val) * 10 > this.max()) { + this.moveRequest(event, 'next'); + } + + if (this.max() && Number(val) > this.max()) { + val = value.slice(-1); + } + + event.target.value = val; + this.value.set(Number(val)); + } + + clearField(event: Event): void { + if (event instanceof KeyboardEvent) { + event.preventDefault(); + } + + this.value.set(0); + } + + clickHandler(event: MouseEvent) { + event.preventDefault(); + } + + up(): void { + this.inputControlClick.emit('up'); + } + + down(): void { + this.inputControlClick.emit('down'); + } + + keydownHandler(event: KeyboardEvent): void { + switch (event.key) { + case 'ArrowLeft': + this.moveRequest(event, 'prev'); + break; + case 'H': + case 'h': + case ':': + case 'ArrowRight': + this.moveRequest(event, 'next'); + break; + case 'Delete': + case 'Backspace': + this.clearField(event); + break; + case 'ArrowUp': + this.arrowKeyPressed(event, true); + break; + case 'ArrowDown': + this.arrowKeyPressed(event, false); + break; + } + } + + moveRequest(event: Event, direction: 'prev' | 'next'): void { + event.preventDefault(); + + if (direction === 'prev') { + this.prevRequest.emit(); + } else { + this.nextRequest.emit(); + } + } + + focus(): void { + if (this.timePickerInput) { + this.timePickerInput.nativeElement.focus(); + } + } +} diff --git a/packages/ng/time/duration-picker/duration-picker.component.html b/packages/ng/time/duration-picker/duration-picker.component.html new file mode 100644 index 0000000000..22a9c333ef --- /dev/null +++ b/packages/ng/time/duration-picker/duration-picker.component.html @@ -0,0 +1,32 @@ +
+
+ {{ label }} + + + +
+
diff --git a/packages/ng/time/duration-picker/duration-picker.component.ts b/packages/ng/time/duration-picker/duration-picker.component.ts new file mode 100644 index 0000000000..b75d7cc566 --- /dev/null +++ b/packages/ng/time/duration-picker/duration-picker.component.ts @@ -0,0 +1,224 @@ +import { NgClass } from '@angular/common'; +import { booleanAttribute, ChangeDetectionStrategy, Component, computed, forwardRef, Input, input, model, output } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { getIntl } from '@lucca-front/ng/core'; +import { BasePickerComponent } from '../core/base-picker.component'; +import { ISO8601Duration } from '../core/date-primitives'; +import { createDurationFromHoursAndMinutes, getHoursPartFromDuration, getMinutesPartFromDuration, isISO8601Duration, isoDurationToDateFnsDuration, isoDurationToSeconds } from '../core/duration.utils'; +import { ceilToNearest, circularize, floorToNearest, roundToNearest } from '../core/math.utils'; +import { isNil, isNotNil, PickerControlDirection } from '../core/misc.utils'; +import { TimePickerPartComponent } from '../core/time-picker-part.component'; +import { DEFAULT_TIME_DECIMAL_PIPE_FORMAT, DurationChangeEvent } from './duration-picker.model'; +import { LU_DURATION_PICKER_TRANSLATIONS } from './duration-picker.translate'; + +@Component({ + selector: 'lu-duration-picker', + standalone: true, + imports: [TimePickerPartComponent, NgClass], + templateUrl: './duration-picker.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => DurationPickerComponent), + multi: true, + }, + ], +}) +export class DurationPickerComponent extends BasePickerComponent { + protected intl = getIntl(LU_DURATION_PICKER_TRANSLATIONS); + + value = model('PT0S'); + max = input('PT99H'); + + displayArrows = input(false, { transform: booleanAttribute }); + + @Input() label: string; + + hideZeroValue = input(false, { transform: booleanAttribute }); + + durationChange = output(); + + protected hours = computed(() => getHoursPartFromDuration(this.value())); + protected minutes = computed(() => getMinutesPartFromDuration(this.value())); + protected shouldHideValue = computed(() => this.hideZeroValue() && this.hours() === 0 && this.minutes() === 0); + + protected pickerClasses = computed(() => { + return { + timePicker: true, + 'mod-stepper': this.displayArrows(), + 'mod-stepperHover': this.displayArrows(), + [`mod-${this.size()}`]: Boolean(this.size()), + }; + }); + protected fieldsetSuffixClasses = computed(() => { + return { + 'timePicker-fieldset-groupSeparator': true, + 'u-visibilityHidden': this.shouldHideValue(), + }; + }); + protected separator = this.intl.timePickerTimeSeparator; + + protected hoursDecimalConf = DEFAULT_TIME_DECIMAL_PIPE_FORMAT; + + writeValue(value: ISO8601Duration): void { + this.value.set(value || 'PT0S'); + } + + setDisabledState?(isDisabled: boolean): void { + this.disabled.set(isDisabled); + } + + protected hoursInputHandler(value: number): void { + this.setTime({ + previousValue: this.value(), + value: createDurationFromHoursAndMinutes(value, this.minutes()), + source: 'input', + }); + } + + protected minutesInputHandler(value: number): void { + this.setTime({ + previousValue: this.value(), + value: createDurationFromHoursAndMinutes(this.hours(), value), + source: 'input', + }); + } + + protected copyHandler(event: ClipboardEvent): void { + event.preventDefault(); + // write value to clipboard + const value = this.value(); + if (isNotNil(value)) { + event.clipboardData?.setData('text/plain', value); + } + } + + protected pasteHandler(event: ClipboardEvent): void { + event.preventDefault(); + const pastedValue = event.clipboardData?.getData('text/plain'); + if (isNotNil(pastedValue)) { + let value: ISO8601Duration; + // If it's an iso duration, handle as-is + if (isISO8601Duration(pastedValue)) { + value = pastedValue; + } + if (/\d?\dh\d\d/.test(pastedValue)) { + const split = pastedValue.split('h'); + value = createDurationFromHoursAndMinutes(+split[0], +split[1]); + } + if (/\d?\d:\d\d/.test(pastedValue)) { + const split = pastedValue.split(':'); + value = createDurationFromHoursAndMinutes(+split[0], +split[1]); + } + if (value) { + this.durationChange.emit({ + previousValue: this.value(), + source: 'paste', + value, + }); + this.value.set(value); + this.onChange?.(value); + } + } + } + + override getHoursIncrement(): number { + const step = this.step(); + if (isNil(step)) { + return 1; + } + + const { hours } = isoDurationToDateFnsDuration(step); + + if (hours === 0) { + return 1; + } + + return 24 % hours === 0 ? hours : 1; + } + + override getMinutesIncrement(): number | null { + const step = this.step(); + if (isNil(step)) { + return 1; + } + + const { minutes } = isoDurationToDateFnsDuration(step); + + if (minutes === 0) { + return null; + } + + return 60 % minutes === 0 ? minutes : 1; + } + + private setTime(protoEvent: DurationChangeEvent): void { + let hoursPart = getHoursPartFromDuration(protoEvent.value); + const minutesPart = getMinutesPartFromDuration(protoEvent.value); + + if (hoursPart < 0) { + hoursPart = getHoursPartFromDuration(this.max()); + if (isoDurationToSeconds(createDurationFromHoursAndMinutes(hoursPart, minutesPart)) > isoDurationToSeconds(this.max())) { + // If current value with minutes is > max, decrement hours again + hoursPart--; + } + } else if (hoursPart > getHoursPartFromDuration(this.max())) { + hoursPart = 0; + } + + const max = isoDurationToSeconds(this.max()); + + const candidateTimeAsSeconds = hoursPart * 3600 + minutesPart * 60; + + const seconds = roundToNearest(circularize(candidateTimeAsSeconds, max), 60); + + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + + const result = createDurationFromHoursAndMinutes(hours, minutes); + + this.value.set(result); + this.onChange?.(result); + this.durationChange.emit({ + ...protoEvent, + value: result, + }); + } + + protected inputControlClickHandler(part: 'hours' | 'minutes', direction: PickerControlDirection): void { + const val = this.value() ?? 'PT0S'; + const hoursPart = getHoursPartFromDuration(val); + const minutesPart = getMinutesPartFromDuration(val); + + const selectedPart = part === 'hours' ? hoursPart : minutesPart; + const selectedIncrement = part === 'hours' ? this.hoursIncrement() : this.minutesIncrement(); + let modifiedVal: number; + + if (selectedIncrement === null) { + return; + } + + if (direction === 'up') { + modifiedVal = floorToNearest(selectedPart + selectedIncrement, selectedIncrement); + } else { + modifiedVal = ceilToNearest(selectedPart - selectedIncrement, selectedIncrement); + } + + const newTime = part === 'hours' ? createDurationFromHoursAndMinutes(modifiedVal, minutesPart) : createDurationFromHoursAndMinutes(hoursPart, modifiedVal); + + this.setTime({ + source: 'control', + previousValue: this.value(), + value: newTime, + part, + direction, + }); + } + + public focus() { + if (isNotNil(this.hoursPart)) { + this.focusPart('hours'); + } + } +} diff --git a/packages/ng/time/duration-picker/duration-picker.model.ts b/packages/ng/time/duration-picker/duration-picker.model.ts new file mode 100644 index 0000000000..b214e75d69 --- /dev/null +++ b/packages/ng/time/duration-picker/duration-picker.model.ts @@ -0,0 +1,13 @@ +import { ISO8601Duration } from '../core/date-primitives'; + +export type DurationChangeEvent = { + previousValue: ISO8601Duration | null; + value: ISO8601Duration; +} & ( + | { + source: 'input' | 'paste'; + } + | { source: 'control'; part: 'minutes' | 'hours'; direction: 'up' | 'down' } +); + +export const DEFAULT_TIME_DECIMAL_PIPE_FORMAT = '2.0-0'; diff --git a/packages/ng/time/duration-picker/duration-picker.translate.ts b/packages/ng/time/duration-picker/duration-picker.translate.ts new file mode 100644 index 0000000000..3d3107041c --- /dev/null +++ b/packages/ng/time/duration-picker/duration-picker.translate.ts @@ -0,0 +1,25 @@ +import { InjectionToken } from '@angular/core'; +import { ILuTranslation } from '../../core/translate'; + +export const LU_DURATION_PICKER_TRANSLATIONS = new InjectionToken('LuDurationPickerTranslations', { + factory: () => luDurationPickerTranslations, +}); + +export type DurationPickerTranslations = { + timePickerHours: string; + timePickerTimeSeparator: string; + timePickerMinutes: string; +}; + +export const luDurationPickerTranslations: ILuTranslation = { + en: { + timePickerHours: 'hours', + timePickerTimeSeparator: 'h', + timePickerMinutes: 'minutes', + }, + fr: { + timePickerHours: 'heures', + timePickerTimeSeparator: 'h', + timePickerMinutes: 'minutes', + }, +}; diff --git a/packages/ng/time/ng-package.json b/packages/ng/time/ng-package.json new file mode 100644 index 0000000000..68facef35b --- /dev/null +++ b/packages/ng/time/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public-api.ts", + "styleIncludePaths": ["../styles"] + } +} diff --git a/packages/ng/time/public-api.ts b/packages/ng/time/public-api.ts new file mode 100644 index 0000000000..9471acc98e --- /dev/null +++ b/packages/ng/time/public-api.ts @@ -0,0 +1 @@ +export * from './time-picker/time-picker.component'; diff --git a/packages/ng/time/time-picker/time-picker.component.html b/packages/ng/time/time-picker/time-picker.component.html new file mode 100644 index 0000000000..1578d09064 --- /dev/null +++ b/packages/ng/time/time-picker/time-picker.component.html @@ -0,0 +1,33 @@ +
+
+ {{ label }} + + + +
+
diff --git a/packages/ng/time/time-picker/time-picker.component.ts b/packages/ng/time/time-picker/time-picker.component.ts new file mode 100644 index 0000000000..b28e704f29 --- /dev/null +++ b/packages/ng/time/time-picker/time-picker.component.ts @@ -0,0 +1,212 @@ +import { NgClass } from '@angular/common'; +import { booleanAttribute, ChangeDetectionStrategy, Component, computed, forwardRef, Input, input, model, output } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { getIntl } from '@lucca-front/ng/core'; +import { BasePickerComponent } from '../core/base-picker.component'; +import { ISO8601Time } from '../core/date-primitives'; +import { + convertStringToIsoTime, + createIsoTimeFromHoursAndMinutes, + getHoursDisplayPartFromIsoTime, + getHoursPartFromIsoTime, + getMinutesDisplayPartFromIsoTime, + getMinutesPartFromIsoTime, + isoTimeToSeconds, +} from '../core/date.utils'; +import { isoDurationToDateFnsDuration } from '../core/duration.utils'; +import { ceilToNearest, circularize, floorToNearest, roundToNearest } from '../core/math.utils'; +import { isNil, isNotNil, PickerControlDirection } from '../core/misc.utils'; +import { TimePickerPartComponent } from '../core/time-picker-part.component'; +import { DEFAULT_MIN_TIME, DEFAULT_TIME_DECIMAL_PIPE_FORMAT, TimeChangeEvent } from './time-picker.model'; +import { LU_TIME_PICKER_TRANSLATIONS } from './time-picker.translate'; + +@Component({ + selector: 'lu-time-picker', + standalone: true, + imports: [TimePickerPartComponent, NgClass], + templateUrl: './time-picker.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => TimePickerComponent), + multi: true, + }, + ], +}) +export class TimePickerComponent extends BasePickerComponent { + protected intl = getIntl(LU_TIME_PICKER_TRANSLATIONS); + + value = model('--:--:--'); + max = input(null); + + displayArrows = input(false, { transform: booleanAttribute }); + + @Input() label: string; + + timeChange = output(); + + protected hoursDisplay = computed(() => getHoursDisplayPartFromIsoTime(this.value())); + protected minutesDisplay = computed(() => getMinutesDisplayPartFromIsoTime(this.value())); + + protected hours = computed(() => getHoursPartFromIsoTime(this.value())); + protected minutes = computed(() => getMinutesPartFromIsoTime(this.value())); + protected pickerClasses = computed(() => { + return { + timePicker: true, + 'mod-stepper': this.displayArrows(), + 'mod-stepperHover': this.displayArrows(), + [`mod-${this.size()}`]: Boolean(this.size()), + }; + }); + protected separator = this.intl.timePickerTimeSeparator; + + protected hoursDecimalConf = DEFAULT_TIME_DECIMAL_PIPE_FORMAT; + + protected maxHours = computed(() => { + return getHoursPartFromIsoTime(this.max() ?? '23:59:59'); + }); + + writeValue(value: ISO8601Time): void { + this.value.set(value || '--:--:--'); + } + + setDisabledState?(isDisabled: boolean): void { + this.disabled.set(isDisabled); + } + + protected hoursInputHandler(value: number | '--'): void { + this.setTime({ + previousValue: this.value(), + // Mostly for compiler because we never set the time to -- with input handler + value: createIsoTimeFromHoursAndMinutes(+value, this.minutes()), + source: 'input', + }); + } + + protected minutesInputHandler(value: number | '--'): void { + this.setTime({ + previousValue: this.value(), + // Mostly for compiler because we never set the time to -- with input handler + value: createIsoTimeFromHoursAndMinutes(this.hours(), +value), + source: 'input', + }); + } + + protected copyHandler(event: ClipboardEvent): void { + event.preventDefault(); + // write value to clipboard + const value = this.value(); + if (isNotNil(value)) { + event.clipboardData?.setData('text/plain', value); + } + } + + protected pasteHandler(event: ClipboardEvent): void { + event.preventDefault(); + const pastedValue = event.clipboardData?.getData('text/plain'); + if (isNotNil(pastedValue)) { + try { + const value = convertStringToIsoTime(pastedValue); + this.timeChange.emit({ + previousValue: this.value(), + source: 'paste', + value, + }); + this.value.set(value); + this.onChange?.(value); + } catch (e) { + // do nothing + } + } + } + + override getHoursIncrement(): number { + const step = this.step(); + if (isNil(step)) { + return 1; + } + + const { hours } = isoDurationToDateFnsDuration(step); + + if (hours === 0) { + return 1; + } + + return 24 % hours === 0 ? hours : 1; + } + + override getMinutesIncrement(): number | null { + const step = this.step(); + if (isNil(step)) { + return 1; + } + + const { minutes } = isoDurationToDateFnsDuration(step); + + if (minutes === 0) { + return null; + } + + return 60 % minutes === 0 ? minutes : 1; + } + + private setTime(protoEvent: TimeChangeEvent): void { + const hoursPart = getHoursPartFromIsoTime(protoEvent.value); + const minutesPart = getMinutesPartFromIsoTime(protoEvent.value); + + const max = isoTimeToSeconds(this.max()); + + const candidateTimeAsSeconds = hoursPart * 3600 + minutesPart * 60; + + const seconds = roundToNearest(circularize(candidateTimeAsSeconds, max), 60); + + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + + const result = createIsoTimeFromHoursAndMinutes(hours, minutes); + + this.value.set(result); + this.onChange?.(result); + this.timeChange.emit({ + ...protoEvent, + value: result, + }); + } + + protected inputControlClickHandler(part: 'hours' | 'minutes', direction: PickerControlDirection): void { + const val = this.value() ?? DEFAULT_MIN_TIME; + const hoursPart = getHoursPartFromIsoTime(val); + const minutesPart = getMinutesPartFromIsoTime(val); + + const selectedPart = part === 'hours' ? hoursPart : minutesPart; + const selectedIncrement = part === 'hours' ? this.hoursIncrement() : this.minutesIncrement(); + let modifiedVal: number; + + if (selectedIncrement === null) { + return; + } + + if (direction === 'up') { + modifiedVal = floorToNearest(selectedPart + selectedIncrement, selectedIncrement); + } else { + modifiedVal = ceilToNearest(selectedPart - selectedIncrement, selectedIncrement); + } + + const newTime = part === 'hours' ? createIsoTimeFromHoursAndMinutes(modifiedVal, minutesPart) : createIsoTimeFromHoursAndMinutes(hoursPart, modifiedVal); + + this.setTime({ + source: 'control', + previousValue: this.value(), + value: newTime, + part, + direction, + }); + } + + public focus() { + if (isNotNil(this.hoursPart)) { + this.focusPart('hours'); + } + } +} diff --git a/packages/ng/time/time-picker/time-picker.model.ts b/packages/ng/time/time-picker/time-picker.model.ts new file mode 100644 index 0000000000..4f554d792a --- /dev/null +++ b/packages/ng/time/time-picker/time-picker.model.ts @@ -0,0 +1,14 @@ +import { ISO8601Time } from '../core/date-primitives'; + +export type TimeChangeEvent = { + previousValue: ISO8601Time | null; + value: ISO8601Time; +} & ( + | { + source: 'input' | 'paste'; + } + | { source: 'control'; part: 'minutes' | 'hours'; direction: 'up' | 'down' } +); +export const DEFAULT_MIN_TIME: ISO8601Time = '--:--:--'; + +export const DEFAULT_TIME_DECIMAL_PIPE_FORMAT = '2.0-0'; diff --git a/packages/ng/time/time-picker/time-picker.translate.ts b/packages/ng/time/time-picker/time-picker.translate.ts new file mode 100644 index 0000000000..4572696202 --- /dev/null +++ b/packages/ng/time/time-picker/time-picker.translate.ts @@ -0,0 +1,25 @@ +import { InjectionToken } from '@angular/core'; +import { ILuTranslation } from '@lucca-front/ng/core'; + +export const LU_TIME_PICKER_TRANSLATIONS = new InjectionToken('LuTimePickerTranslations', { + factory: () => luTimePickerTranslations, +}); + +export type TimePickerTranslations = { + timePickerHours: string; + timePickerTimeSeparator: string; + timePickerMinutes: string; +}; + +export const luTimePickerTranslations: ILuTranslation = { + en: { + timePickerHours: 'hours', + timePickerTimeSeparator: ':', + timePickerMinutes: 'minutes', + }, + fr: { + timePickerHours: 'heures', + timePickerTimeSeparator: ':', + timePickerMinutes: 'minutes', + }, +}; diff --git a/packages/ng/toast/toasts.component.html b/packages/ng/toast/toasts.component.html index 875fb7d366..79a3fc260c 100644 --- a/packages/ng/toast/toasts.component.html +++ b/packages/ng/toast/toasts.component.html @@ -1,17 +1,22 @@ -
+
{{ toast.title }}
+ @if (isStringPortalContent(toast.message)) {
+ } @else { + + }
-
diff --git a/packages/ng/toast/toasts.component.ts b/packages/ng/toast/toasts.component.ts index 4baab85f52..7b7dbf559d 100644 --- a/packages/ng/toast/toasts.component.ts +++ b/packages/ng/toast/toasts.component.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, Input, OnDestroy } from '@angular/core'; -import { getIntl } from '@lucca-front/ng/core'; +import { getIntl, PortalContent, PortalDirective } from '@lucca-front/ng/core'; import { merge, Observable, Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { LuToast, LuToastInput, LuToastType } from './toasts.model'; @@ -12,7 +12,7 @@ import { LU_TOAST_TRANSLATIONS } from './toasts.translate'; templateUrl: './toasts.component.html', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [CommonModule], + imports: [CommonModule, PortalDirective], }) export class LuToastsComponent implements OnDestroy { @Input() public bottom = false; @@ -49,6 +49,10 @@ export class LuToastsComponent implements OnDestroy { Warning: 'palette-warning', }; + public isStringPortalContent(message: PortalContent): message is string { + return typeof message === 'string'; + } + public removeToast(toast: LuToast): void { this.toastsService.removeToast(toast); } diff --git a/packages/ng/toast/toasts.model.ts b/packages/ng/toast/toasts.model.ts index 237c7dd098..c39b7cc108 100644 --- a/packages/ng/toast/toasts.model.ts +++ b/packages/ng/toast/toasts.model.ts @@ -1,3 +1,5 @@ +import { PortalContent } from '@lucca-front/ng/core'; + export type LuToastType = 'Info' | 'Error' | 'Success' | 'Warning'; export const defaultToastDuration = 5000; @@ -6,7 +8,7 @@ export interface LuToastInput { /** * InnerHTML supported. */ - message: string; + message: PortalContent; /** * Bold title. * InnerHTML not supported. diff --git a/packages/ng/tooltip/panel/tooltip-panel.component.html b/packages/ng/tooltip/panel/tooltip-panel.component.html index cb157bfdf5..fd3c3570e2 100644 --- a/packages/ng/tooltip/panel/tooltip-panel.component.html +++ b/packages/ng/tooltip/panel/tooltip-panel.component.html @@ -1,11 +1 @@ - +
diff --git a/packages/ng/tooltip/panel/tooltip-panel.component.scss b/packages/ng/tooltip/panel/tooltip-panel.component.scss index e232ed1c40..ded932376d 100644 --- a/packages/ng/tooltip/panel/tooltip-panel.component.scss +++ b/packages/ng/tooltip/panel/tooltip-panel.component.scss @@ -1,2 +1 @@ -@import '_definitions'; -@include tooltipStyle; +@use '@lucca-front/scss/src/components/tooltip'; diff --git a/packages/ng/tooltip/panel/tooltip-panel.component.ts b/packages/ng/tooltip/panel/tooltip-panel.component.ts index 5897215097..9a79226022 100644 --- a/packages/ng/tooltip/panel/tooltip-panel.component.ts +++ b/packages/ng/tooltip/panel/tooltip-panel.component.ts @@ -1,54 +1,50 @@ -import { OverlayModule } from '@angular/cdk/overlay'; -import { CommonModule } from '@angular/common'; -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostBinding, Output, TemplateRef, ViewChild } from '@angular/core'; +import { HorizontalConnectionPos, VerticalConnectionPos } from '@angular/cdk/overlay'; +import { ChangeDetectionStrategy, Component, DestroyRef, HostBinding, HostListener, inject } from '@angular/core'; import { SafeHtml } from '@angular/platform-browser'; -import { ALuPopoverPanel, ILuPopoverPanel } from '@lucca-front/ng/popover'; -import { luTransformTooltip } from '../animation/index'; +import { Subject } from 'rxjs'; +import { NgClass } from '@angular/common'; @Component({ selector: 'lu-tooltip-panel', templateUrl: './tooltip-panel.component.html', styleUrls: ['./tooltip-panel.component.scss'], - animations: [luTransformTooltip], standalone: true, - imports: [CommonModule, OverlayModule], + host: { + role: 'tooltip', + }, changeDetection: ChangeDetectionStrategy.OnPush, + imports: [NgClass], }) -export class LuTooltipPanelComponent extends ALuPopoverPanel implements ILuPopoverPanel { - @HostBinding('@transformTooltip') animationState = 'enter'; +export class LuTooltipPanelComponent { + destroyRef = inject(DestroyRef); - private _content: string | SafeHtml; - get content() { - return this._content; - } - set content(c) { - this._content = c; - this._changeDetectorRef.markForCheck(); - } + mouseEnter$ = new Subject(); - //FIXME output event - // eslint-disable-next-line @angular-eslint/no-output-native - @Output() override close = new EventEmitter(); - // eslint-disable-next-line @angular-eslint/no-output-native - @Output() override open = new EventEmitter(); - @Output() override hovered = new EventEmitter(); - @ViewChild(TemplateRef, { static: true }) - set vcTemplateRef(tr: TemplateRef) { - this.templateRef = tr; - } - constructor(private _changeDetectorRef: ChangeDetectorRef) { - super(); - this.scrollStrategy = 'close'; + @HostListener('mouseenter') + mouseEnter(): void { + this.mouseEnter$.next(); } - _emitCloseEvent(): void { - this.close.emit(); - } + mouseLeave$ = new Subject(); - _emitOpenEvent(): void { - this.open.emit(); + @HostListener('mouseleave') + mouseLeave(): void { + this.mouseLeave$.next(); } - _emitHoveredEvent(hovered: boolean): void { - this.hovered.emit(hovered); + + content: string | SafeHtml; + + @HostBinding('attr.id') + id: string; + + contentPositionClasses: Record = {}; + + setPanelPosition(posX: HorizontalConnectionPos, posY: VerticalConnectionPos): void { + this.contentPositionClasses = { + 'is-before': posX === 'end', + 'is-after': posX === 'start', + 'is-above': posY === 'bottom', + 'is-below': posY === 'top', + }; } } diff --git a/packages/ng/tooltip/trigger/tooltip-trigger.directive.spec.ts b/packages/ng/tooltip/trigger/tooltip-trigger.directive.spec.ts deleted file mode 100644 index b28a646881..0000000000 --- a/packages/ng/tooltip/trigger/tooltip-trigger.directive.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component } from '@angular/core'; -import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { By, DomSanitizer, SafeHtml } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { LuTooltipModule } from '../tooltip.module'; -import { LuTooltipTriggerDirective } from './tooltip-trigger.directive'; - -@Component({ - standalone: true, - imports: [LuTooltipModule], - selector: 'lu-test', - template: `
`, -}) -export class LuTestComponent { - content: string | SafeHtml = ''; -} - -describe('LuTooltipTriggerDirective', () => { - let component: LuTestComponent; - let fixture: ComponentFixture; - let tooltipTrigger: LuTooltipTriggerDirective; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [LuTestComponent, NoopAnimationsModule], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(LuTestComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - - tooltipTrigger = fixture.debugElement.query(By.directive(LuTooltipTriggerDirective)).injector.get(LuTooltipTriggerDirective); - }); - - it('should not append unsafe html in dom', fakeAsync(() => { - // Arrange - component.content = ''; - - // Act - tooltipTrigger.onMouseEnter(); - tick(tooltipTrigger.enterDelay); - fixture.detectChanges(); - - // Assert - const images = fixture.debugElement.queryAll(By.css('img')).map((el) => (el.nativeElement instanceof HTMLElement ? el.nativeElement : null)); - - expect(images.length).toBe(1); - expect(images[0].getAttribute('onerror')).toBe(null); - })); - - it('should allow trusted html', fakeAsync(() => { - // Arrange - const sanitizer = TestBed.inject(DomSanitizer); - component.content = sanitizer.bypassSecurityTrustHtml(''); - - // Act - tooltipTrigger.onMouseEnter(); - tick(tooltipTrigger.enterDelay); - fixture.detectChanges(); - - // Assert - const images = fixture.debugElement.queryAll(By.css('img')).map((el) => (el.nativeElement instanceof HTMLElement ? el.nativeElement : null)); - - expect(images.length).toBe(1); - expect(images[0].getAttribute('onerror')).toBe('hack()'); - })); -}); diff --git a/packages/ng/tooltip/trigger/tooltip-trigger.directive.ts b/packages/ng/tooltip/trigger/tooltip-trigger.directive.ts index bfad9d1b5d..2c6e53f890 100644 --- a/packages/ng/tooltip/trigger/tooltip-trigger.directive.ts +++ b/packages/ng/tooltip/trigger/tooltip-trigger.directive.ts @@ -1,160 +1,350 @@ -import { FlexibleConnectedPositionStrategy, Overlay, OverlayRef } from '@angular/cdk/overlay'; +import { FlexibleConnectedPositionStrategy, HorizontalConnectionPos, OriginConnectionPosition, Overlay, OverlayConnectionPosition, OverlayRef, VerticalConnectionPos } from '@angular/cdk/overlay'; import { ComponentPortal } from '@angular/cdk/portal'; -import { AfterViewInit, Directive, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnDestroy, Output, ViewContainerRef } from '@angular/core'; +import { AfterContentInit, ChangeDetectorRef, DestroyRef, Directive, ElementRef, HostBinding, HostListener, Input, Renderer2, booleanAttribute, inject, numberAttribute } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { SafeHtml } from '@angular/platform-browser'; -import { ALuPopoverTrigger, LuPopoverPosition, LuPopoverScrollStrategy, LuPopoverTarget } from '@lucca-front/ng/popover'; -import { LuTooltipPanelComponent } from '../panel/tooltip-panel.component'; +import { LuPopoverPosition } from '@lucca-front/ng/popover'; +import { BehaviorSubject, Observable, Subject, combineLatest, merge, startWith, switchMap, timer } from 'rxjs'; +import { debounce, debounceTime, filter, map } from 'rxjs/operators'; +import { LuTooltipPanelComponent } from '../panel'; + +let nextId = 0; @Directive({ selector: '[luTooltip]', standalone: true, }) -export class LuTooltipTriggerDirective extends ALuPopoverTrigger implements AfterViewInit, OnDestroy { - @Input('luTooltip') set tooltipContent(c: string | SafeHtml) { - if (this.panel) { - this.panel.content = c; - } +export class LuTooltipTriggerDirective implements AfterContentInit { + #overlay = inject(Overlay); - this._tooltipContent = c; - } - /** when trigger = hover, delay before the popover panel appears, default 300ms */ - @Input('luTooltipEnterDelay') set inputEnterDelay(d: number) { - this.enterDelay = d; + #host = inject>(ElementRef); + + #renderer = inject(Renderer2); + + #destroyRef = inject(DestroyRef); + + #cdr = inject(ChangeDetectorRef); + + @Input() + luTooltip: string | SafeHtml; + + #openDelay$ = new BehaviorSubject(300); + + @Input({ transform: numberAttribute }) + set luTooltipEnterDelay(delay: number) { + this.#openDelay$.next(delay); } - /** when trigger = hover, delay before the popover panel disappears, default 100ms */ - @Input('luTooltipLeaveDelay') set inputLeaveDelay(d: number) { - this.leaveDelay = d; + + #closeDelay$ = new BehaviorSubject(100); + + @Input({ transform: numberAttribute }) + set luTooltipLeaveDelay(delay: number) { + this.#closeDelay$.next(delay); } - /** disable popover apparition */ - @Input('luTooltipDisabled') set inputDisabled(d: boolean) { - this.disabled = d; - if (this._handleTabindex) { - this._setTabindex(d ? null : 0); + + #disabled = false; + + @Input({ transform: booleanAttribute }) + set luTooltipDisabled(disabled: boolean) { + this.#disabled = disabled; + if (disabled) { + this.setAccessibilityProperties(null); } } - @Input('luTooltipPosition') set inputPosition(pos: LuPopoverPosition) { - this.target.position = pos; - } + @Input() + luTooltipPosition: LuPopoverPosition = 'above'; - @Input('luTooltipWhenEllipsis') public set inputWhenEllipsis(we: boolean) { - this.whenEllipsis = we; - } + @Input({ transform: booleanAttribute }) + luTooltipWhenEllipsis = false; + + resize$ = new Observable((observer) => { + const resizeObserver = new ResizeObserver(() => { + observer.next(); + }); + resizeObserver.observe(this.#host.nativeElement); + return () => { + resizeObserver.disconnect(); + }; + }); - // FIXME output native - /** Event emitted when the associated popover is opened. */ - // eslint-disable-next-line @angular-eslint/no-output-on-prefix - @Output('luTooltipOnOpen') onOpen = new EventEmitter(); - /** Event emitted when the associated popover is closed. */ - // eslint-disable-next-line @angular-eslint/no-output-on-prefix - @Output('luTooltipOnClose') onClose = new EventEmitter(); + open$ = new Subject(); + + close$ = new Subject(); @HostListener('mouseenter') - override onMouseEnter() { - super.onMouseEnter(); + onMouseEnter() { + this.open$.next(); } + @HostListener('mouseleave') - override onMouseLeave() { - super.onMouseLeave(); + onMouseLeave() { + this.close$.next(); } + @HostListener('focus') - override onFocus() { - super.onFocus(); + onFocus() { + this.open$.next(); } + @HostListener('blur') - override onBlur() { - super.onBlur(); + onBlur() { + this.close$.next(); } - private _handleTabindex = false; - // @HostBinding('attr.tabindex') tabindex; - // private set tabindex(i: number = null) { - // } + #generatedId = `${this.#host.nativeElement.tagName.toLowerCase()}-tooltip-${nextId++}`; - /** accessibility attribute - dont override */ - @HostBinding('attr.id') get _attrId() { - return this._triggerId; - } - /** accessibility attribute - dont override */ - @HostBinding('attr.aria-describedby') get _attrAriaDescribedBy() { - return this._panelId; + @HostBinding('attr.id') + _id: string; + + @HostBinding('attr.aria-describedby') + get ariaDescribedBy() { + if (this.#disabled || this.luTooltipWhenEllipsis) { + return null; + } + return `${this.#generatedId}-panel`; } - protected override _portal: ComponentPortal; - protected _tooltipContent: string | SafeHtml = ''; + overlayRef?: OverlayRef; - constructor( - protected override _overlay: Overlay, - protected override _elementRef: ElementRef, - protected override _viewContainerRef: ViewContainerRef, - ) { - super(_overlay, _elementRef, _viewContainerRef); - this.target = new LuPopoverTarget(); - this.target.elementRef = this._elementRef; - this._triggerId = this._elementRef.nativeElement.getAttribute('id') || this._triggerId; - this.triggerEvent = 'hover'; - this.target.position = 'above'; - this.enterDelay = 300; - this.leaveDelay = 100; + constructor() { + combineLatest([this.#openDelay$, this.#closeDelay$]) + .pipe( + switchMap(([openDelay, closeDelay]) => { + // We only filter open events because even if it's disabled while opened, + // we want the tooltip to be able to close itself no matter what + const openEvents$ = this.open$.pipe( + filter(() => { + if (this.#disabled) { + return false; + } + // If not disabled, let's check for ellipsis if needed + if (this.luTooltipWhenEllipsis) { + return this.hasEllipsis(); + } + // If it's not disabled and is not triggered based on ellipsis, just return true + return true; + }), + map(() => 'open'), + ); + return merge(openEvents$, this.close$.pipe(map(() => 'close'))).pipe( + debounce((event) => { + return timer(event === 'open' ? openDelay : closeDelay); + }), + ); + }), + takeUntilDestroyed(this.#destroyRef), + ) + .subscribe((event) => { + if (event === 'open') { + this.openTooltip(); + } else { + this.closeTooltip(); + } + }); - this._handleTabindex = this._shouldHandleTabindex(); + this.resize$.pipe(takeUntilDestroyed(this.#destroyRef), debounceTime(150)).subscribe(() => { + this.setAccessibilityProperties(0); + this.#cdr.markForCheck(); + }); + } - if (this._handleTabindex) { - this._setTabindex(0); + private openTooltip(): void { + // If tooltip is already opened, don't do anything + if (this.overlayRef) { + return; } + const position = this.legacyPositionBuilder(); + this.overlayRef = this.#overlay.create({ + positionStrategy: position, + scrollStrategy: this.#overlay.scrollStrategies.close(), + disposeOnNavigation: true, + }); + const portal = new ComponentPortal(LuTooltipPanelComponent); + const ref = this.overlayRef.attach(portal); + position.positionChanges + .pipe( + takeUntilDestroyed(this.#destroyRef), + map(({ connectionPair }) => connectionPair), + startWith(position.positions[0]), + ) + .subscribe(({ overlayX, overlayY }) => { + ref.instance.setPanelPosition(overlayX, overlayY); + }); + if (this.luTooltip) { + ref.instance.content = this.luTooltip; + } else if (this.luTooltipWhenEllipsis) { + ref.instance.content = this.#host.nativeElement.innerText; + } + ref.instance.id = this.ariaDescribedBy; + // On tooltip leave => trigger close + ref.instance.mouseLeave$.pipe(takeUntilDestroyed(ref.instance.destroyRef)).subscribe(() => this.close$.next()); + // On tooltip enter => trigger open to keep it opened + ref.instance.mouseEnter$.pipe(takeUntilDestroyed(ref.instance.destroyRef)).subscribe(() => this.open$.next()); } - ngAfterViewInit() { - this._checkTarget(); - } - ngOnDestroy() { - this._cleanUpSubscriptions(); - if (this._popoverOpen) { - this.closePopover(); + private closeTooltip(): void { + if (this.overlayRef) { + this.overlayRef.detach(); + delete this.overlayRef; } - this.destroyPopover(); - } - protected _emitOpen(): void { - this.onOpen.emit(); - } - protected _emitClose(): void { - this.onClose.emit(); } - protected override _createOverlay(): OverlayRef { - if (!this._overlayRef) { - this._portal = new ComponentPortal(LuTooltipPanelComponent, this._viewContainerRef); - const config = this._getOverlayConfig(); - this._subscribeToPositions(config.positionStrategy as FlexibleConnectedPositionStrategy); - this._overlayRef = this._overlay.create(config); + private setAccessibilityProperties(tabindex: number | null): void { + if (this.#disabled || (this.luTooltipWhenEllipsis && !this.hasEllipsis())) { + this.#renderer.removeAttribute(this.#host.nativeElement, 'tabindex'); + return; } - return this._overlayRef; + const tag = this.#host.nativeElement.tagName.toLowerCase(); + const nativelyFocusableTags = ['a', 'button', 'input', 'select', 'textarea']; + const isNatevelyFocusableTag = nativelyFocusableTags.includes(tag); + + const hasATabIndex = this.#host.nativeElement.getAttribute('tabindex') !== null; + + if (!isNatevelyFocusableTag && !hasATabIndex) { + this.#renderer.setAttribute(this.#host.nativeElement, 'tabindex', tabindex.toString()); + } } - protected override _attachPortalToOverlay(): void { - const componentRef = this._overlayRef.attach(this._portal); - this._panel = componentRef.instance; - this._panel.content = this._tooltipContent; + /** + * Hacky af but let's explain everything + * This method checks for ellipsis by cloning the node and checking its width against original element. + * + * We used to do this using scrollWidth but the thing is, it's a rounded value. Sometimes, + * you'd get true while it should be false and vice-versa, because of rounding. + * + * We could also use getBoundingClientRect() but it only considers text content, meaning that if ellipsis is caused by + * any margin or padding, it won't be detected + * + * @private + */ + private hasEllipsis(): boolean { + if (window.getComputedStyle(this.#host.nativeElement).textOverflow !== 'ellipsis') { + return false; + } + + const mask = this.#renderer.createElement('div') as HTMLDivElement; + const clone = this.#host.nativeElement.cloneNode(true) as HTMLElement; + + this.#renderer.setStyle(clone, 'position', 'fixed'); + this.#renderer.setStyle(clone, 'overflow', 'visible'); + this.#renderer.setStyle(clone, 'white-space', 'nowrap'); + this.#renderer.setStyle(clone, 'visibility', 'hidden'); + this.#renderer.setStyle(clone, 'width', 'fit-content'); + + this.#renderer.addClass(mask, 'u-mask'); + this.#renderer.setAttribute(mask, 'aria-hidden', 'true'); + this.#renderer.appendChild(mask, clone); + + this.#renderer.appendChild(this.#host.nativeElement.parentElement, mask); + try { + const fullWidth = clone.getBoundingClientRect().width; + const displayWidth = this.#host.nativeElement.getBoundingClientRect().width; + + return fullWidth > displayWidth; + } catch (e) { + return false; + } finally { + mask.remove(); + } } - protected override _getPanelScrollStrategy(): LuPopoverScrollStrategy { - return 'close'; + ngAfterContentInit(): void { + this.setAccessibilityProperties(0); + this._id = this.#host.nativeElement.id || this.#generatedId; } - private _shouldHandleTabindex(): boolean { - const tag = this._elementRef.nativeElement.tagName?.toLowerCase(); - // https://allyjs.io/data-tables/focusable.html - // i'm choosing to not support area and iframe, dont @ me - const nativelyFocusableTags = ['a', 'button', 'input', 'select', 'textarea']; - const isNatevelyFocusableTag = nativelyFocusableTags.includes(tag); + /********************** + * + * LEGACY STUFF TO HANDLE EXISTING POSITIONS + * + ***********************/ + + private legacyPositionBuilder(): FlexibleConnectedPositionStrategy { + const connectionPosition: OriginConnectionPosition = { + originX: 'start', + originY: 'top', + }; + + // Position + const position = this.luTooltipPosition; + if (position === 'above') { + connectionPosition.originY = 'top'; + } else if (position === 'below') { + connectionPosition.originY = 'bottom'; + } else if (position === 'before') { + connectionPosition.originX = 'start'; + } else if (position === 'after') { + connectionPosition.originX = 'end'; + } + + // Alignment + if (position === 'above' || position === 'below') { + connectionPosition.originX = 'center'; + } else { + connectionPosition.originY = 'center'; + } - const hasATabIndex = this._elementRef.nativeElement.getAttribute('tabindex') !== null; + const overlayPosition: OverlayConnectionPosition = { + overlayX: 'start', + overlayY: 'top', + }; - return !isNatevelyFocusableTag && !hasATabIndex; + if (position === 'above' || position === 'below') { + overlayPosition.overlayX = connectionPosition.originX; + overlayPosition.overlayY = position === 'above' ? 'bottom' : 'top'; + } else { + overlayPosition.overlayX = position === 'before' ? 'end' : 'start'; + overlayPosition.overlayY = connectionPosition.originY; + } + + return this.#overlay + .position() + .flexibleConnectedTo(this.#host) + .withPositions([ + { + originX: connectionPosition.originX, + originY: connectionPosition.originY, + overlayX: overlayPosition.overlayX, + overlayY: overlayPosition.overlayY, + }, + { + originX: connectionPosition.originX, + originY: this.invertVerticalPos(connectionPosition.originY), + overlayX: overlayPosition.overlayX, + overlayY: this.invertVerticalPos(overlayPosition.overlayY), + }, + { + originX: this.invertHorizontalPos(connectionPosition.originX), + originY: connectionPosition.originY, + overlayX: this.invertHorizontalPos(overlayPosition.overlayX), + overlayY: overlayPosition.overlayY, + }, + { + originX: this.invertHorizontalPos(connectionPosition.originX), + originY: this.invertVerticalPos(connectionPosition.originY), + overlayX: this.invertHorizontalPos(overlayPosition.overlayX), + overlayY: this.invertVerticalPos(overlayPosition.overlayY), + }, + ]); + } + + private invertVerticalPos(y: VerticalConnectionPos): VerticalConnectionPos { + if (y === 'top') { + return 'bottom'; + } else if (y === 'bottom') { + return 'top'; + } + return y; } - private _setTabindex(i: number = null): void { - this._elementRef.nativeElement.setAttribute('tabindex', `${i}`); + private invertHorizontalPos(x: HorizontalConnectionPos): HorizontalConnectionPos { + if (x === 'end') { + return 'start'; + } else if (x === 'start') { + return 'end'; + } + return x; } } diff --git a/packages/ng/user/display/display-format.model.ts b/packages/ng/user/display/display-format.model.ts index 39cac4d499..786c185983 100644 --- a/packages/ng/user/display/display-format.model.ts +++ b/packages/ng/user/display/display-format.model.ts @@ -1,4 +1,5 @@ import { InjectionToken } from '@angular/core'; +import { EnumValue } from '@lucca-front/ng/core'; export enum LuDisplayFullname { firstlast = 'fl', @@ -21,7 +22,7 @@ export enum LuDisplayHybrid { lastFullfirstI = 'lF', } -export type LuDisplayFormat = LuDisplayFullname | LuDisplayInitials | LuDisplayHybrid; +export type LuDisplayFormat = EnumValue | EnumValue | EnumValue; /** Injection token that can be used to change the default displayed user format. */ export const LU_DEFAULT_DISPLAY_POLICY = new InjectionToken('LuDisplayFormat', { factory: () => LuDisplayFullname.lastfirst }); diff --git a/packages/ng/user/display/user-display.pipe.spec.ts b/packages/ng/user/display/user-display.pipe.spec.ts index 4f022d36c6..213fe88c2d 100644 --- a/packages/ng/user/display/user-display.pipe.spec.ts +++ b/packages/ng/user/display/user-display.pipe.spec.ts @@ -1,17 +1,16 @@ import { createPipeFactory, SpectatorPipe } from '@ngneat/spectator/jest'; -import { ILuUser } from '../user.model'; -import { LuDisplayFullname, LuDisplayHybrid, LuDisplayInitials, LU_DEFAULT_DISPLAY_POLICY } from './display-format.model'; +import { LU_DEFAULT_DISPLAY_POLICY, LuDisplayFullname, LuDisplayHybrid, LuDisplayInitials } from './display-format.model'; import { luUserDisplay, LuUserDisplayPipe } from './user-display.pipe'; -describe('UserNamePipe', () => { - let user: ILuUser; - let userFirst: ILuUser; - let userLast: ILuUser; - beforeEach(() => { - user = { firstName: 'John', lastName: 'Doe' }; - userFirst = { firstName: 'John', lastName: '' }; - userLast = { firstName: '', lastName: 'Doe' }; - }); +describe(LuUserDisplayPipe.name, () => { + const users = [ + { firstName: 'John', lastName: 'Doe' }, + { firstName: 'Michael', lastName: 'Scott' }, + { firstName: 'Dwight', lastName: 'Schrute' }, + ]; + const user = users[0]; + const userFirst = { firstName: user.firstName, lastName: '' }; + const userLast = { firstName: '', lastName: user.lastName }; describe('luUserDisplay()', () => { it("should return the right value with 'lf' format", () => { @@ -91,7 +90,7 @@ describe('UserNamePipe', () => { let spectator: SpectatorPipe; const createPipe = createPipeFactory(LuUserDisplayPipe); - it(`should return the right value with 'lf' format`, () => { + it(`should return the right single value with default 'lf' format`, () => { spectator = createPipe(`{{ user | luUserDisplay }}`, { hostProps: { user, @@ -100,7 +99,7 @@ describe('UserNamePipe', () => { expect(spectator.element).toHaveText('Doe John'); }); - it(`should return the right value with 'fl' format`, () => { + it(`should return the right single value with provide 'fl' format`, () => { const provider = { provide: LU_DEFAULT_DISPLAY_POLICY, useValue: LuDisplayFullname.firstlast }; spectator = createPipe(`{{ user | luUserDisplay }}`, { hostProps: { @@ -110,5 +109,61 @@ describe('UserNamePipe', () => { }); expect(spectator.element).toHaveText('John Doe'); }); + + it(`should return the right single value with specify 'FL' format`, () => { + spectator = createPipe(`{{ user | luUserDisplay:'FL' }}`, { + hostProps: { + user, + }, + }); + expect(spectator.element).toHaveText('JD'); + }); + + it(`should return the right multiple value with default 'lf' format and default ', ' separator`, () => { + spectator = createPipe(`{{ users | luUserDisplay }}`, { + hostProps: { + users, + }, + }); + expect(spectator.element).toHaveText('Doe John, Scott Michael, Schrute Dwight'); + }); + + it(`should return the right multiple value with default 'lf' format and '; ' separator`, () => { + spectator = createPipe(`{{ users | luUserDisplay:{ separator: '; ' } }}`, { + hostProps: { + users, + }, + }); + expect(spectator.element).toHaveText('Doe John; Scott Michael; Schrute Dwight'); + }); + + it(`should return the right multiple value with default 'Lf' format and default ', ' separator`, () => { + spectator = createPipe(`{{ users | luUserDisplay:{ format: 'Lf' } }}`, { + hostProps: { + users, + }, + }); + expect(spectator.element).toHaveText('D. John, S. Michael, S. Dwight'); + }); + + it(`should return the right multiple value with specify 'Fl' format and ' ' separator`, () => { + spectator = createPipe(`{{ users | luUserDisplay:{ format: 'Fl', separator: ' ' } }}`, { + hostProps: { + users, + }, + }); + expect(spectator.element).toHaveText('J. Doe M. Scott D. Schrute'); + }); + + it(`should return the right multiple value with specify 'fL' format and formatter`, () => { + const formatter = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' }); + spectator = createPipe(`{{ users | luUserDisplay:{ format: 'fL', formatter } }}`, { + hostProps: { + users, + formatter, + }, + }); + expect(spectator.element).toHaveText('John D., Michael S., and Dwight S.'); + }); }); }); diff --git a/packages/ng/user/display/user-display.pipe.ts b/packages/ng/user/display/user-display.pipe.ts index 689964ecc7..8c59695ef4 100644 --- a/packages/ng/user/display/user-display.pipe.ts +++ b/packages/ng/user/display/user-display.pipe.ts @@ -1,62 +1,58 @@ import { inject, Pipe, PipeTransform } from '@angular/core'; import { LU_DEFAULT_DISPLAY_POLICY, LuDisplayFormat, LuDisplayFullname, LuDisplayHybrid, LuDisplayInitials } from './display-format.model'; +function getFirstCharacter([firstCharacter]: string): string { + return firstCharacter ?? ''; +} + +function isNotEmptyString(value: string): boolean { + return value.length > 0; +} + export interface LuUserDisplayInput { firstName: string; lastName: string; } +const formatUser: Record string> = { + [LuDisplayFullname.lastfirst]: ({ firstName, lastName }) => [lastName, firstName].filter(isNotEmptyString).join(' '), + [LuDisplayFullname.firstlast]: ({ firstName, lastName }) => [firstName, lastName].filter(isNotEmptyString).join(' '), + [LuDisplayFullname.first]: ({ firstName }) => firstName, + [LuDisplayFullname.last]: ({ lastName }) => lastName, + [LuDisplayInitials.lastfirst]: ({ firstName, lastName }) => [getFirstCharacter(lastName), getFirstCharacter(firstName)].filter(isNotEmptyString).join(''), + [LuDisplayInitials.firstlast]: ({ firstName, lastName }) => [getFirstCharacter(firstName), getFirstCharacter(lastName)].filter(isNotEmptyString).join(''), + [LuDisplayInitials.first]: ({ firstName }) => getFirstCharacter(firstName), + [LuDisplayInitials.last]: ({ lastName }) => getFirstCharacter(lastName), + [LuDisplayHybrid.lastIfirstFull]: ({ firstName, lastName }) => [isNotEmptyString(lastName) ? getFirstCharacter(lastName) + '.' : '', firstName].filter(isNotEmptyString).join(' '), + [LuDisplayHybrid.firstIlastFull]: ({ firstName, lastName }) => [isNotEmptyString(firstName) ? getFirstCharacter(firstName) + '.' : '', lastName].filter(isNotEmptyString).join(' '), + [LuDisplayHybrid.lastFullfirstI]: ({ firstName, lastName }) => [lastName, firstName ? getFirstCharacter(firstName) + '.' : ''].filter(isNotEmptyString).join(' '), + [LuDisplayHybrid.firstFulllastI]: ({ firstName, lastName }) => [firstName, lastName ? getFirstCharacter(lastName) + '.' : ''].filter(isNotEmptyString).join(' '), +}; + /** * Displays a user name according to specified format. Supported formats: f for first name, * F for first initial, l for last name, L for last initial. */ export function luUserDisplay(user: LuUserDisplayInput, format: LuDisplayFormat = LuDisplayFullname.lastfirst): string { - let result = ''; - if (user) { - switch (format) { - case LuDisplayFullname.lastfirst: - result = [user.lastName, user.firstName].filter((v) => !!v).join(' '); - break; - case LuDisplayFullname.firstlast: - result = [user.firstName, user.lastName].filter((v) => !!v).join(' '); - break; - case LuDisplayFullname.first: - result = user.firstName; - break; - case LuDisplayFullname.last: - result = user.lastName; - break; - case LuDisplayInitials.lastfirst: - result = [user.lastName?.charAt(0), user.firstName?.charAt(0)].filter((v) => !!v).join(''); - break; - case LuDisplayInitials.firstlast: - result = [user.firstName?.charAt(0), user.lastName?.charAt(0)].filter((v) => !!v).join(''); - break; - case LuDisplayInitials.first: - result = user.firstName?.charAt(0) ?? ''; - break; - case LuDisplayInitials.last: - result = user.lastName?.charAt(0) ?? ''; - break; - case LuDisplayHybrid.firstIlastFull: - result = [user.firstName ? user.firstName.charAt(0) + '.' : '', user.lastName].filter((v) => !!v).join(' '); - break; - case LuDisplayHybrid.lastIfirstFull: - result = [user.lastName ? user.lastName.charAt(0) + '.' : '', user.firstName].filter((v) => !!v).join(' '); - break; - case LuDisplayHybrid.lastFullfirstI: - result = [user.lastName, user.firstName ? user.firstName.charAt(0) + '.' : ''].filter((v) => !!v).join(' '); - break; - case LuDisplayHybrid.firstFulllastI: - result = [user.firstName, user.lastName ? user.lastName.charAt(0) + '.' : ''].filter((v) => !!v).join(' '); - break; - default: - break; - } + return formatUser[format](user); +} + +/** + * Displays a user name according to specified format. Supported formats: f for first name, + * F for first initial, l for last name, L for last initial. + */ +export function luUsersDisplay(users: LuUserDisplayInput[], options: LuUserDisplayMultipleOptions): string { + const usersStringified = users.map((u) => luUserDisplay(u, options.format)); + if ('separator' in options) { + return usersStringified.join(options.separator); } - return result; + return options.formatter.format(usersStringified); } +export type LuUserDisplaySingleOptions = LuDisplayFormat | { format: LuDisplayFormat }; + +export type LuUserDisplayMultipleOptions = { format: LuDisplayFormat; separator: string } | { format: LuDisplayFormat; formatter: Intl.ListFormat }; + /** * Displays a user name according to specified format. Supported formats: f for first name, * F for first initial, l for last name, L for last initial. @@ -65,7 +61,25 @@ export function luUserDisplay(user: LuUserDisplayInput, format: LuDisplayFormat export class LuUserDisplayPipe implements PipeTransform { private readonly defaultFormat = inject(LU_DEFAULT_DISPLAY_POLICY); - public transform(user: LuUserDisplayInput, format: LuDisplayFormat = this.defaultFormat): string { - return luUserDisplay(user, format); + public transform(user: T, options?: Partial): string; + public transform(users: T[], options?: Partial): string; + public transform(userOrUsers: T | T[], options?: Partial | Partial): string { + if (userOrUsers == null) { + throw new Error("Parameter 'userOrUsers' must be a user or a user array"); + } + + options = typeof options === 'string' ? { format: options } : options || {}; + + const format = options.format ?? this.defaultFormat; + + if (Array.isArray(userOrUsers)) { + if ('formatter' in options) { + return luUsersDisplay(userOrUsers, { format, formatter: options.formatter }); + } + const separator = ('separator' in options ? options.separator : undefined) ?? ', '; + return luUsersDisplay(userOrUsers, { format, separator }); + } + + return luUserDisplay(userOrUsers, format); } } diff --git a/packages/ng/user/select/input/user-select-input.translate.ts b/packages/ng/user/select/input/user-select-input.translate.ts index 7df9069988..a59da20d28 100644 --- a/packages/ng/user/select/input/user-select-input.translate.ts +++ b/packages/ng/user/select/input/user-select-input.translate.ts @@ -23,4 +23,8 @@ export const luUserSelectInputTranslations: ILuTranslation = es: { includeFormerEmployees: 'Incluir a los antiguos empleados', }, + de: { + includeFormerEmployees: 'Ehemalige Mitarbeiter einbeziehen', + }, }; diff --git a/packages/scss/src/commons/base.scss b/packages/scss/src/commons/base.scss index a95ed99795..aa3db5e7f9 100644 --- a/packages/scss/src/commons/base.scss +++ b/packages/scss/src/commons/base.scss @@ -6,40 +6,78 @@ @mixin base($atRoot: 'without: rule') { @at-root ($atRoot) { - @font-face { - font-family: 'Source Sans Pro'; - src: url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-regular.woff2') format('woff2'), - url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-regular.woff') format('woff'); - font-weight: 400; - font-style: normal; - font-display: swap; - } + @if config.$fontFamily != 'Source Sans Pro' { + @font-face { + font-family: '#{config.$fontFamily}'; + src: url('//cdn.lucca.fr/fonts/#{config.$fontFamily}/regular.woff2') format('woff2'), + url('//cdn.lucca.fr/fonts/#{config.$fontFamily}/regular.woff') format('woff'); + font-weight: 400; + font-style: normal; + font-display: swap; + } - @font-face { - font-family: 'Source Sans Pro'; - src: url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-semibold.woff2') format('woff2'), - url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-semibold.woff') format('woff'); - font-weight: 600; - font-style: normal; - font-display: swap; - } + @font-face { + font-family: '#{config.$fontFamily}'; + src: url('//cdn.lucca.fr/fonts/#{config.$fontFamily}/semibold.woff2') format('woff2'), + url('//cdn.lucca.fr/fonts/#{config.$fontFamily}/semibold.woff') format('woff'); + font-weight: 600; + font-style: normal; + font-display: swap; + } - @font-face { - font-family: 'Source Sans Pro'; - src: url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-bold.woff2') format('woff2'), - url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-bold.woff') format('woff'); - font-weight: 700; - font-style: normal; - font-display: swap; - } + @font-face { + font-family: '#{config.$fontFamily}'; + src: url('//cdn.lucca.fr/fonts/#{config.$fontFamily}/bold.woff2') format('woff2'), + url('//cdn.lucca.fr/fonts/#{config.$fontFamily}/bold.woff') format('woff'); + font-weight: 700; + font-style: normal; + font-display: swap; + } - @font-face { - font-family: 'Source Sans Pro'; - src: url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-black.woff2') format('woff2'), - url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-black.woff') format('woff'); - font-weight: 900; - font-style: normal; - font-display: swap; + @font-face { + font-family: '#{config.$fontFamily}'; + src: url('//cdn.lucca.fr/fonts/#{config.$fontFamily}/black.woff2') format('woff2'), + url('//cdn.lucca.fr/fonts/#{config.$fontFamily}/black.woff') format('woff'); + font-weight: 900; + font-style: normal; + font-display: swap; + } + } @else { + @font-face { + font-family: 'Source Sans Pro'; + src: url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-regular.woff2') format('woff2'), + url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-regular.woff') format('woff'); + font-weight: 400; + font-style: normal; + font-display: swap; + } + + @font-face { + font-family: 'Source Sans Pro'; + src: url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-semibold.woff2') format('woff2'), + url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-semibold.woff') format('woff'); + font-weight: 600; + font-style: normal; + font-display: swap; + } + + @font-face { + font-family: 'Source Sans Pro'; + src: url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-bold.woff2') format('woff2'), + url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-bold.woff') format('woff'); + font-weight: 700; + font-style: normal; + font-display: swap; + } + + @font-face { + font-family: 'Source Sans Pro'; + src: url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-black.woff2') format('woff2'), + url('//cdn.lucca.fr/fonts/SourceSans/sourcesanspro-black.woff') format('woff'); + font-weight: 900; + font-style: normal; + font-display: swap; + } } *, diff --git a/packages/scss/src/commons/config.scss b/packages/scss/src/commons/config.scss index 0b315bf55c..ec7fdaf0dd 100644 --- a/packages/scss/src/commons/config.scss +++ b/packages/scss/src/commons/config.scss @@ -3,6 +3,7 @@ $importDeprecatedSpacings: true !default; +$fontFamily: 'Source Sans Pro' !default; $product: 'brand' !default; $palettesShades: text, 25, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900; $palettesStates: 'critical', 'error', 'warning', 'success'; @@ -469,6 +470,7 @@ $sizes: ( $borderRadius: ( 'M': 4px, 'L': 8px, + 'XL': 12px, 'full': 9999px, ) !default; diff --git a/packages/scss/src/commons/core.scss b/packages/scss/src/commons/core.scss index fedbf8517a..1c8e206545 100644 --- a/packages/scss/src/commons/core.scss +++ b/packages/scss/src/commons/core.scss @@ -120,3 +120,20 @@ $overflow: 'hidden', 'auto', 'visible', 'scroll'; } } } + +@mixin rosetta($before, $after, $iterations) { + @if type-of($iterations) == map { + @each $iterationBefore, $iterationAfter in $iterations { + @if type-of($iterationAfter) == string { + #{$before}-#{$iterationBefore}: var(#{$after}-#{$iterationAfter}); + } @else { + #{$before}-#{$iterationBefore}: #{$iterationAfter}; + } + } + } + @else { + @each $iteration in $iterations { + #{$before}-#{$iteration}: var(#{$after}-#{$iteration}); + } + } +} diff --git a/packages/scss/src/commons/utils/index.scss b/packages/scss/src/commons/utils/index.scss index 693fd717c6..648a793455 100644 --- a/packages/scss/src/commons/utils/index.scss +++ b/packages/scss/src/commons/utils/index.scss @@ -323,12 +323,20 @@ .u-insetReset { inset: 0 !important; } - } @else { + } @else if $direction != 'block' and $direction != 'inline' { // .u-#{$direction}Reset is deprecated .u-#{$direction}0, .u-#{$direction}Reset { #{$direction}: 0 !important; } + } @else { + @each $boxModel in core.$boxModel { + @if $boxModel != 'border' { + .u-#{$boxModel}#{transform.capitalize($direction)}0 { + #{$boxModel}-#{$direction}: 0 !important; + } + } + } } } diff --git a/packages/scss/src/commons/utils/media.scss b/packages/scss/src/commons/utils/media.scss index 489f228b98..6b10811235 100644 --- a/packages/scss/src/commons/utils/media.scss +++ b/packages/scss/src/commons/utils/media.scss @@ -18,6 +18,10 @@ @if $max { $reversed: 'not all and'; + + @if $at == 'container' { + $reversed: 'not'; + } } @if map.get(config.$breakpoints, $breakpoint) { @@ -32,6 +36,10 @@ @mixin queries($breakpoint1, $breakpoint2, $property: 'width', $at: 'media', $name: '') { $reversed: 'not all and'; + @if $at == 'container' { + $reversed: 'not'; + } + @if map.get(config.$breakpoints, $breakpoint1) { $breakpoint1: pxToEm(map.get(config.$breakpoints, $breakpoint1)); } diff --git a/packages/scss/src/commons/vars.scss b/packages/scss/src/commons/vars.scss index 3c5a00ccf1..224e308738 100644 --- a/packages/scss/src/commons/vars.scss +++ b/packages/scss/src/commons/vars.scss @@ -5,7 +5,6 @@ @use '@lucca-front/scss/src/commons/core'; @mixin vars { - // TOKENS @each $key, $map in config.$elevation { @@ -44,9 +43,8 @@ @include core.cssvars('colors', config.$colors, '-color'); @include core.cssvars('colors', config.$colorsRgb, '-rgb'); - --commons-banner-height: 50px; - --commons-font-family: 'Source Sans Pro', Tahoma, sans-serif; + --commons-font-family: '#{config.$fontFamily}', Tahoma, sans-serif; --commons-divider-width: 1px; --commons-divider-style: solid; --commons-divider-border: var(--commons-divider-width) var(--commons-divider-style) var(--commons-divider-color); diff --git a/packages/scss/src/components/avatar/mods.scss b/packages/scss/src/components/avatar/mods.scss index 71a4541759..6cc81fd2e7 100644 --- a/packages/scss/src/components/avatar/mods.scss +++ b/packages/scss/src/components/avatar/mods.scss @@ -1,7 +1,6 @@ @mixin XL { - --components-avatar-size: 4.5rem; + --components-avatar-size: 4rem; --components-avatar-fontSize: var(--sizes-XL-fontSize); - --components-avatar-border: 4px; } @mixin L { diff --git a/packages/scss/src/components/breadcrumbs/component.scss b/packages/scss/src/components/breadcrumbs/component.scss index 4e8048b15f..a01ff3a870 100644 --- a/packages/scss/src/components/breadcrumbs/component.scss +++ b/packages/scss/src/components/breadcrumbs/component.scss @@ -21,7 +21,7 @@ &::before { @include icon.generate('arrow_chevron_right'); - color: var(--palettes-neutral-600); + color: var(--palettes-neutral-700); font-size: var(--sizes-XS-lineHeight); padding: 0 var(--pr-t-spacings-50); } @@ -29,7 +29,7 @@ } .breadcrumbs-list-item-action { - color: var(--palettes-neutral-600); + color: var(--palettes-neutral-700); transition-duration: var(--commons-animations-durations-fast); transition-property: color; text-decoration: none; @@ -40,7 +40,7 @@ cursor: pointer; &:hover { - color: var(--palettes-neutral-600); + color: var(--palettes-neutral-700); text-decoration: underline; } diff --git a/packages/scss/src/components/breadcrumbs/mods.scss b/packages/scss/src/components/breadcrumbs/mods.scss index b3c187d5b5..b437163a94 100644 --- a/packages/scss/src/components/breadcrumbs/mods.scss +++ b/packages/scss/src/components/breadcrumbs/mods.scss @@ -12,7 +12,7 @@ &:first-child { .breadcrumbs-list-item-action { &::before { - @include icon.generate('format_corner_up_left'); + @include icon.generate('arrow_left'); padding-right: var(--pr-t-spacings-50); font-size: var(--sizes-XS-lineHeight); diff --git a/packages/scss/src/components/breadcrumbs/states.scss b/packages/scss/src/components/breadcrumbs/states.scss index e019538036..7cc6d0c19e 100644 --- a/packages/scss/src/components/breadcrumbs/states.scss +++ b/packages/scss/src/components/breadcrumbs/states.scss @@ -11,6 +11,6 @@ &:hover, &:focus-visible { outline: none; - color: var(--palettes-neutral-600); + color: var(--palettes-neutral-700); } } diff --git a/packages/scss/src/components/button/index.scss b/packages/scss/src/components/button/index.scss index 527f623d6d..4f0620927d 100644 --- a/packages/scss/src/components/button/index.scss +++ b/packages/scss/src/components/button/index.scss @@ -44,19 +44,6 @@ } } - // .mod-counter deprecated - &.mod-counter { - @include counter; - - &.mod-S { - @include counterS; - } - - &.mod-XS { - @include counterXS; - } - } - // .mod-icon is deprecated &.mod-withIcon, &.mod-icon { diff --git a/packages/scss/src/components/button/mods.scss b/packages/scss/src/components/button/mods.scss index 2ddbdff345..9ee3122d5d 100644 --- a/packages/scss/src/components/button/mods.scss +++ b/packages/scss/src/components/button/mods.scss @@ -92,12 +92,6 @@ --components-button-color: var(--palettes-700, var(--palettes-neutral-700)); --components-button-boxShadow: 0 0 0 var(--commons-divider-width) var(--palettes-400, var(--palettes-neutral-400)); - // deprecated - .button-counter { - color: var(--palettes-800, var(--palettes-neutral-800)); - background-color: var(--palettes-300, var(--palettes-neutral-300)); - } - &:hover { --components-button-color: var(--palettes-700, var(--palettes-neutral-700)); --components-button-backgroundColor: var(--palettes-100, var(--palettes-neutral-100)); @@ -122,11 +116,11 @@ &:hover, &:focus-visible { --components-button-color: var(--colors-white-color); - --components-button-backgroundColor: var(--palettes-800, var(--palettes-neutral-800)); + --components-button-backgroundColor: var(--palettes-neutral-900); } &:active { - --components-button-backgroundColor: var(--palettes-700, var(--palettes-neutral-700)); + --components-button-backgroundColor: var(--palettes-neutral-700); } } @@ -192,46 +186,3 @@ --components-button-backgroundColor: var(--palettes-error-200); } } - -// deprecated -@mixin counter { - --components-button-padding: var(--pr-t-spacings-100) var(--pr-t-spacings-150) var(--pr-t-spacings-100) var(--pr-t-spacings-200); - - .button-counter { - background-color: var(--palettes-600, var(--palettes-product-600)); - border-radius: 1rem; - display: flex; - font-size: var(--sizes-XS-fontSize); - height: 1.5rem; - min-width: 1.5rem; - align-items: center; - justify-content: center; - transition: background-color var(--commons-animations-durations-fast) ease; - } - - &:hover { - .button-counter { - --components-button-backgroundColor: var(--palettes-500, var(--palettes-product-500)); - } - } -} - -// deprecated -@mixin counterS { - --components-button-padding: var(--pr-t-spacings-75) var(--pr-t-spacings-150) var(--pr-t-spacings-75) var(--pr-t-spacings-200); - - .button-counter { - height: 1.25rem; - min-width: 1.25rem; - } -} - -// deprecated -@mixin counterXS { - --components-button-padding: var(--pr-t-spacings-50) var(--pr-t-spacings-100) var(--pr-t-spacings-50) var(--pr-t-spacings-150); - - .button-counter { - height: 1rem; - min-width: 1rem; - } -} diff --git a/packages/scss/src/components/callout/component.scss b/packages/scss/src/components/callout/component.scss index b1dd08e8c9..5385a47e86 100644 --- a/packages/scss/src/components/callout/component.scss +++ b/packages/scss/src/components/callout/component.scss @@ -1,6 +1,7 @@ @use '@lucca-front/icons/src/commons/utils/icon'; @use '@lucca-front/scss/src/commons/utils/reset'; @use '@lucca-front/scss/src/commons/utils/a11y'; +@use '@lucca-front/scss/src/components/button/exports' as button; @mixin component($atRoot: 'without: rule') { align-items: flex-start; @@ -36,6 +37,17 @@ font-weight: 600; } + .callout-content-description-actions { + display: flex; + gap: var(--pr-t-spacings-75); + margin-top: var(--pr-t-spacings-50); + padding: var(--pr-t-spacings-50) 0; + + .button { + @include button.S; + } + } + .callout-icon { display: inline-flex; color: var(--palettes-700, var(--palettes-neutral-700)); diff --git a/packages/scss/src/components/callout/index.scss b/packages/scss/src/components/callout/index.scss index 4860ffea58..7801796ee8 100644 --- a/packages/scss/src/components/callout/index.scss +++ b/packages/scss/src/components/callout/index.scss @@ -7,8 +7,4 @@ &.mod-S { @include S; } - - &.mod-tiny { - @include tiny; - } } diff --git a/packages/scss/src/components/callout/mods.scss b/packages/scss/src/components/callout/mods.scss index 7f2aeec639..b92c99e4b4 100644 --- a/packages/scss/src/components/callout/mods.scss +++ b/packages/scss/src/components/callout/mods.scss @@ -1,4 +1,5 @@ @use '@lucca-front/icons/src/icon/exports' as icon; +@use '@lucca-front/scss/src/components/button/exports' as button; @mixin S { --components-callout-gap: var(--pr-t-spacings-100); @@ -8,6 +9,12 @@ .callout-icon { @include icon.S; } + + .callout-content-description-actions { + .button { + @include button.XS; + } + } } @mixin tiny { diff --git a/packages/scss/src/components/comment/component.scss b/packages/scss/src/components/comment/component.scss new file mode 100644 index 0000000000..0fc246305c --- /dev/null +++ b/packages/scss/src/components/comment/component.scss @@ -0,0 +1,90 @@ +@mixin component($atRoot: 'without: rule') { + container: comment / inline-size; + display: flex; + flex-direction: column; + gap: var(--pr-t-spacings-100); + max-width: 40rem; + + @at-root ($atRoot) { + .comment-infos { + display: flex; + font-style: normal; + gap: var(--pr-t-spacings-100); + justify-content: flex-start; + align-items: flex-start; + } + + .comment-infos-content { + flex-direction: column; + display: var(--components-comment-info-content-display); + font-size: var(--components-comment-info-fontSize); + line-height: var(--components-comment-info-lineHeight); + margin-top: var(--components-comment-info-content-marginTop); + } + + .comment-infos-name { + & + .comment-infos-date { + &::before { + content: var(--components-comment-info-separator); + color: var(--palettes-grey-400); + padding-inline: 1ch; + + @supports (content: '*' / '') { + content: var(--components-comment-info-separator) / ''; + } + } + } + } + + .comment-content { + background: var(--palettes-grey-50); + border-radius: var(--commons-borderRadius-M) var(--commons-borderRadius-L) var(--commons-borderRadius-L); + display: flex; + flex-direction: column; + gap: var(--pr-t-spacings-150); + margin: 0 0 0 var(--components-comment-content-margin); + max-width: fit-content; + padding: var(--pr-t-spacings-100) var(--pr-t-spacings-150); + } + + .comment-content-text { + margin-bottom: 0; + } + + .comment-content-textContainer { + display: flex; + flex-direction: column; + gap: var(--pr-t-spacings-100); + + > * { + margin: 0; + } + } + + .comment-content-text { + font-size: var(--components-comment-text-fontSize); + line-height: var(--components-comment-text-lineHeight); + } + + .comment-content-textContainer { + font-size: var(--components-comment-text-fontSize); + line-height: var(--components-comment-text-lineHeight); + } + + .commentWrapper { + display: flex; + flex-direction: column; + gap: var(--pr-t-spacings-100); + margin: 0; + padding: 0; + } + + .commentWrapper-item { + list-style: none; + + &.mod-WrapperAvatar ~ &:not(.mod-WrapperAvatar) { + padding-left: var(--components-comment-content-margin); + } + } + } +} diff --git a/packages/scss/src/components/status/exports.scss b/packages/scss/src/components/comment/exports.scss similarity index 100% rename from packages/scss/src/components/status/exports.scss rename to packages/scss/src/components/comment/exports.scss diff --git a/packages/scss/src/components/comment/index.scss b/packages/scss/src/components/comment/index.scss new file mode 100644 index 0000000000..cfafb3758f --- /dev/null +++ b/packages/scss/src/components/comment/index.scss @@ -0,0 +1,28 @@ +@use '@lucca-front/scss/src/commons/utils/container'; + +@use 'exports' as *; + +.comment { + @include vars; + @include component; + + &.mod-S { + @include S; + } + + &.mod-noAvatar { + @include noAvatar; + } + + @include container.max(25rem, $name: 'comment') { + @include narrow; + } +} + +.commentWrapper { + @include vars; + + &.mod-compact { + @include wrapperCompact; + } +} diff --git a/packages/scss/src/components/comment/mods.scss b/packages/scss/src/components/comment/mods.scss new file mode 100644 index 0000000000..20f328e606 --- /dev/null +++ b/packages/scss/src/components/comment/mods.scss @@ -0,0 +1,37 @@ +@use '@lucca-front/scss/src/commons/utils/a11y'; + +@mixin S { + --components-comment-text-fontSize: var(--sizes-S-fontSize); + --components-comment-text-lineHeight: var(--sizes-S-lineHeight); + --components-comment-info-fontSize: var(--sizes-XS-fontSize); + --components-comment-info-lineHeight: var(--sizes-XS-lineHeight); + --components-comment-info-content-marginTop: var(--pr-t-spacings-50); +} + +@mixin noAvatar { + --components-comment-content-margin: 0; +} + +@mixin narrow { + @at-root { + .comment-infos-content { + --components-comment-info-content-display: flex; + } + + .comment-infos-name + .comment-infos-date { + &::before { + --components-comment-info-separator: none; + } + } + } +} + +@mixin wrapperCompact { + .commentWrapper-item { + &:not(:first-child) { + .comment-infos { + @include a11y.mask; + } + } + } +} diff --git a/packages/scss/src/components/status/mods.scss b/packages/scss/src/components/comment/states.scss similarity index 100% rename from packages/scss/src/components/status/mods.scss rename to packages/scss/src/components/comment/states.scss diff --git a/packages/scss/src/components/comment/vars.scss b/packages/scss/src/components/comment/vars.scss new file mode 100644 index 0000000000..0330c5ac4d --- /dev/null +++ b/packages/scss/src/components/comment/vars.scss @@ -0,0 +1,10 @@ +@mixin vars { + --components-comment-text-fontSize: var(--sizes-M-fontSize); + --components-comment-text-lineHeight: var(--sizes-M-lineHeight); + --components-comment-info-fontSize: var(--sizes-S-fontSize); + --components-comment-info-lineHeight: var(--sizes-S-lineHeight); + --components-comment-content-margin: calc(1.5rem + var(--pr-t-spacings-100)); // 1.5rem for the width of the avatar and 0.5rem for the gap + --components-comment-info-separator: '•'; + --components-comment-info-content-display: block; + --components-comment-info-content-marginTop: var(--pr-t-spacings-25); +} diff --git a/packages/scss/src/components/dialog/component.scss b/packages/scss/src/components/dialog/component.scss index cb3e79ab18..00568752a5 100644 --- a/packages/scss/src/components/dialog/component.scss +++ b/packages/scss/src/components/dialog/component.scss @@ -6,6 +6,10 @@ @mixin component($atRoot: 'without: rule') { @include keyframe.scaleIn; + @supports not (height: 1dvh) { + --components-dialog-maxHeight: var(--components-dialog-maxHeightFallback); + } + animation-name: var(--components-dialog-animationOpening); animation-duration: var(--commons-animations-durations-standard); inset: var(--components-dialog-inset); diff --git a/packages/scss/src/components/dialog/mods.scss b/packages/scss/src/components/dialog/mods.scss index 4d0b967381..4f5b3e8bfe 100644 --- a/packages/scss/src/components/dialog/mods.scss +++ b/packages/scss/src/components/dialog/mods.scss @@ -27,6 +27,7 @@ --components-dialog-animationOpening: slideFromRight; --components-dialog-maxHeight: none; + --components-dialog-maxHeightFallback: var(--components-dialog-maxHeight); --components-dialog-height: 100%; --components-dialog-maxWidth: calc(100vw - var(--pr-t-spacings-200)); --components-dialog-borderRadius: var(--commons-borderRadius-L) 0 0 var(--commons-borderRadius-L); @@ -38,6 +39,7 @@ --components-dialog-animationOpening: slideFromBottom; --components-dialog-maxHeight: calc(100dvh - var(--pr-t-spacings-200)); + --components-dialog-maxHeightFallback: calc(100vh - var(--pr-t-spacings-200)); --components-dialog-maxWidth: none; --components-dialog-inset: auto 0 0 0; --components-dialog-borderRadius: var(--commons-borderRadius-L) var(--commons-borderRadius-L) 0 0; @@ -56,5 +58,6 @@ --components-dialog-size: 100%; --components-dialog-maxWidth: none; --components-dialog-maxHeight: none; + --components-dialog-maxHeightFallback: var(--components-dialog-maxHeight); --components-dialog-borderRadius: 0; } diff --git a/packages/scss/src/components/dialog/vars.scss b/packages/scss/src/components/dialog/vars.scss index f9375a4931..e8c57f29e1 100644 --- a/packages/scss/src/components/dialog/vars.scss +++ b/packages/scss/src/components/dialog/vars.scss @@ -4,6 +4,7 @@ --components-dialog-height: fit-content; --components-dialog-maxWidth: calc(100vw - (var(--pr-t-spacings-200) * 2)); --components-dialog-maxHeight: calc(100dvh - (var(--pr-t-spacings-200) * 2)); + --components-dialog-maxHeightFallback: calc(100vh - (var(--pr-t-spacings-200) * 2)); --components-dialog-borderRadius: var(--commons-borderRadius-L); --components-dialog-inset: 0; --components-dialog-animationOpening: scaleIn; diff --git a/packages/scss/src/components/emptyState/component.scss b/packages/scss/src/components/emptyState/component.scss index 8491552ac0..e9a23c54b2 100644 --- a/packages/scss/src/components/emptyState/component.scss +++ b/packages/scss/src/components/emptyState/component.scss @@ -1,3 +1,5 @@ +@use '@lucca-front/scss/src/components/title/exports' as title; + @mixin component($atRoot: 'without: rule') { display: flex; flex-direction: column; @@ -32,12 +34,20 @@ } .emptyState-content-heading { + @include title.component; + @include title.h3; + margin-bottom: 0; } + .emptyState-content-description { + margin: 0; + } + .emptyState-actions { display: flex; flex-wrap: wrap; + margin-top: var(--pr-t-spacings-200); gap: var(--pr-t-spacings-100); .button { diff --git a/packages/scss/src/components/emptyState/mods.scss b/packages/scss/src/components/emptyState/mods.scss index a39183f6fa..6530e02a21 100644 --- a/packages/scss/src/components/emptyState/mods.scss +++ b/packages/scss/src/components/emptyState/mods.scss @@ -21,6 +21,8 @@ } .emptyState-content-heading { + @include title.h1; + @include media.max('XXS') { @include title.h2; } diff --git a/packages/scss/src/components/errorPage/component.scss b/packages/scss/src/components/errorPage/component.scss index 68be549c33..d5f41f026e 100644 --- a/packages/scss/src/components/errorPage/component.scss +++ b/packages/scss/src/components/errorPage/component.scss @@ -1,3 +1,5 @@ +@use '@lucca-front/scss/src/components/title/exports' as title; + @mixin component { background-color: var(--components-errorPage-background); height: 100vh; @@ -24,12 +26,13 @@ } .errorPage-section-info-title { - color: var(--components-errorPage-header-color); - font-size: 2.5rem; + @include title.component; + @include title.XXXL; } .errorPage-section-info-text { - font-size: 1.5rem; + font-size: var(--sizes-L-fontSize); + line-height: var(--sizes-L-lineHeight); } .errorPage-section-image { diff --git a/packages/scss/src/components/errorPage/vars.scss b/packages/scss/src/components/errorPage/vars.scss index 8c4f6ed9d5..e02e11bc8c 100644 --- a/packages/scss/src/components/errorPage/vars.scss +++ b/packages/scss/src/components/errorPage/vars.scss @@ -1,4 +1,3 @@ @mixin vars { --components-errorPage-background: var(--pr-t-elevation-surface-raised); - --components-errorPage-header-color: #ff7a1a; } diff --git a/packages/scss/src/components/footer/component.scss b/packages/scss/src/components/footer/component.scss index 41f1e1cf62..a7b2a2652d 100644 --- a/packages/scss/src/components/footer/component.scss +++ b/packages/scss/src/components/footer/component.scss @@ -1,37 +1,37 @@ -@use '@lucca-front/scss/src/commons/utils/media'; -@use '@lucca-front/scss/src/components/button/exports' as button; +@use '@lucca-front/scss/src/components/container/exports' as container; @mixin component($atRoot: 'without: rule') { background-color: var(--pr-t-elevation-surface-raised); padding: var(--pr-t-spacings-200) var(--pr-t-spacings-300); display: flex; + justify-content: space-between; gap: var(--pr-t-spacings-200); - align-items: center; + align-items: var(--components-footer-alignItems); box-shadow: var(--pr-t-elevation-shadow-overflow); - - @include media.max('XXS') { - flex-direction: column; - } + bottom: 0; + position: var(--components-footer-position); + flex-direction: var(--components-footer-direction); @at-root ($atRoot) { + .footer-content { + flex-grow: 1; + } + .footer-actions { display: flex; - margin-left: auto; gap: var(--pr-t-spacings-200); + flex-direction: var(--components-footer-direction); + } - .button { - margin: 0; - } - - @include media.max('XXS') { - flex-direction: column; - margin-left: inherit; - width: 100%; + .footer-containerOptional { + --components-container-padding: 0; - .button { - @include button.block; - } - } + display: flex; + gap: var(--pr-t-spacings-200); + align-items: var(--components-footer-alignItems); + flex-grow: 1; + justify-content: space-between; + flex-direction: var(--components-footer-direction); } } } diff --git a/packages/scss/src/components/footer/index.scss b/packages/scss/src/components/footer/index.scss index bc73251f0d..809d230508 100644 --- a/packages/scss/src/components/footer/index.scss +++ b/packages/scss/src/components/footer/index.scss @@ -1,4 +1,5 @@ @use 'exports' as *; +@use '@lucca-front/scss/src/commons/utils/media'; .footer { @include vars; @@ -7,4 +8,29 @@ &.mod-sticky { @include sticky; } + + &:not([class*='mod-narrow']), + &.mod-narrowAtMediaMaxXXS { + @include media.max('XXS') { + @include narrow; + } + } + + &.mod-narrowAtMediaMaxXS { + @include media.max('XS') { + @include narrow; + } + } + + &.mod-narrowAtMediaMaxS { + @include media.max('S') { + @include narrow; + } + } + + &.mod-narrowAtMediaMaxM { + @include media.max('M') { + @include narrow; + } + } } diff --git a/packages/scss/src/components/footer/mods.scss b/packages/scss/src/components/footer/mods.scss index 48dbd14489..262518d549 100644 --- a/packages/scss/src/components/footer/mods.scss +++ b/packages/scss/src/components/footer/mods.scss @@ -1,4 +1,8 @@ @mixin sticky { - position: sticky; - bottom: 0; + --components-footer-position: sticky; +} + +@mixin narrow { + --components-footer-direction: column; + --components-footer-alignItems: stretch; } diff --git a/packages/scss/src/components/footer/vars.scss b/packages/scss/src/components/footer/vars.scss index 50f7fd0a14..7eae1c8bd7 100644 --- a/packages/scss/src/components/footer/vars.scss +++ b/packages/scss/src/components/footer/vars.scss @@ -1,2 +1,5 @@ @mixin vars { + --components-footer-position: static; + --components-footer-direction: row; + --components-footer-alignItems: center; } diff --git a/packages/scss/src/components/form/component.scss b/packages/scss/src/components/form/component.scss index e420203160..d18885c0b4 100644 --- a/packages/scss/src/components/form/component.scss +++ b/packages/scss/src/components/form/component.scss @@ -19,6 +19,25 @@ position: relative; @at-root ($atRoot) { + .form-header { + margin-bottom: var(--spacings-M); + } + + .form-header-title { + margin: 0; + padding: 0; + } + + .form-header-mandatory { + font-size: var(--sizes-S-fontSize); + line-height: var(--sizes-S-lineHeight); + color: var(--palettes-grey-700); + } + + .form-header-mandatory-asterisk { + color: var(--palettes-error-700); + } + .form-field { position: relative; display: flex; diff --git a/packages/scss/src/components/form/index.scss b/packages/scss/src/components/form/index.scss index 39aec6e47a..e54b5a6498 100644 --- a/packages/scss/src/components/form/index.scss +++ b/packages/scss/src/components/form/index.scss @@ -6,6 +6,10 @@ .form { @include component; + + &.mod-maxWidth { + @include maxWidth; + } } .form-fieldset { @@ -38,7 +42,7 @@ @include checkable; } - &:has(.textField-input-value[aria-invalid='true']) { + &:has(.textField-input-value[aria-invalid='true'], .timePicker-fieldset-group-textfield-input[aria-invalid='true']) { @include invalid; } diff --git a/packages/scss/src/components/form/mods.scss b/packages/scss/src/components/form/mods.scss index 3e3a623107..82f975aa72 100644 --- a/packages/scss/src/components/form/mods.scss +++ b/packages/scss/src/components/form/mods.scss @@ -7,11 +7,16 @@ @use '@lucca-front/scss/src/components/textField/exports' as textField; @use '@lucca-front/scss/src/components/switchField/exports' as switchField; @use '@lucca-front/scss/src/components/checkboxField/exports' as checkboxField; +@use '@lucca-front/scss/src/components/radioField/exports' as radioField; @use '@lucca-front/scss/src/components/simpleSelect/exports' as simpleSelect; @use '@lucca-front/scss/src/components/multiSelect/exports' as multiSelect; -@use '@lucca-front/scss/src/components/radioField/exports' as radioField; +@use '@lucca-front/scss/src/components/timepicker/exports' as timepicker; @use '@lucca-front/scss/src/components/box/exports' as box; +@mixin maxWidth { + max-width: var(--components-form-maxWidth); +} + @mixin S { .formLabel { @include formLabel.S; @@ -40,6 +45,10 @@ .multiSelect { @include multiSelect.S; } + + .timePicker { + @include timepicker.S; + } } @mixin XS { @@ -279,12 +288,6 @@ color: var(--palettes-error-700); display: inline-block; margin-left: 0.2em; - - @supports (content: '*' / '') { - content: '*' / ''; - } - - @supports not (content: '*' / '') { - content: '*'; - } + content: '*'; + content: '*' / ''; } diff --git a/packages/scss/src/components/form/vars.scss b/packages/scss/src/components/form/vars.scss index 90e94e18f8..2db17beed5 100644 --- a/packages/scss/src/components/form/vars.scss +++ b/packages/scss/src/components/form/vars.scss @@ -1,11 +1,9 @@ @mixin vars { + --components-form-maxWidth: 40rem; --components-form-group-margin-bottom: 1.2rem; - --components-form-field-margin-bottom: var(--pr-t-spacings-200); - --components-form-label-font-size: var(--sizes-M-fontSize); --components-form-label-margin-bottom: var(--pr-t-spacings-50); - --components-field-framed-side-padding: var(--pr-t-spacings-200); --components-field-framed-top-padding: var(--pr-t-spacings-400); --components-field-framed-bottom-padding: var(--pr-t-spacings-200); diff --git a/packages/scss/src/components/formLabel/component.scss b/packages/scss/src/components/formLabel/component.scss index eb5e1da65a..0c4a690289 100644 --- a/packages/scss/src/components/formLabel/component.scss +++ b/packages/scss/src/components/formLabel/component.scss @@ -1,3 +1,5 @@ +@use '@lucca-front/scss/src/commons/utils/a11y'; + @mixin component($atRoot: 'without: rule') { color: var(--components-formLabel-color); display: flex; @@ -27,6 +29,20 @@ top: 0; } + .formLabel-info { + &:focus-visible { + outline: none; + + .lucca-icon { + &::before { + border-radius: 50%; + + @include a11y.focusVisible($offset: 0); + } + } + } + } + .formLabel-counter { margin-left: auto; margin-bottom: var(--pr-t-spacings-25); diff --git a/packages/scss/src/components/index.scss b/packages/scss/src/components/index.scss index 0c2d97d462..37886f2409 100644 --- a/packages/scss/src/components/index.scss +++ b/packages/scss/src/components/index.scss @@ -7,7 +7,6 @@ @forward 'chip'; // 1 Ko @forward 'title'; // 1 Ko @forward 'label'; // 1 Ko -@forward 'status'; // 1 Ko @forward 'filterBar'; // 1 Ko @forward 'filters'; // 1 Ko @forward 'divider'; // 1 Ko @@ -36,7 +35,6 @@ @forward 'switch'; // 4 Ko @forward 'switchField'; // new component for switch @forward 'file'; // 5 Ko -@forward 'toast'; // 5 Ko @forward 'layout'; // 5 Ko @forward 'radioButtons'; // 5 Ko @forward 'table'; // 7 Ko @@ -49,9 +47,9 @@ @forward 'textField'; // new component for checkbox @forward 'navside'; // 15 Ko @forward 'form'; // 25 Ko -@forward 'tableFixed'; // 33 Ko +@forward 'tableFixed'; // 2 Ko @forward 'grid'; -@forward 'tableSticked'; // 67 Ko +@forward 'tableSticked'; // 8 Ko @forward 'timepicker'; // @forward 'notchBox'; @forward 'statusBadge'; @@ -77,8 +75,16 @@ @forward 'avatar'; @forward 'indexTable'; @forward 'indexTableSorted'; +@forward 'tooltip'; @forward 'userPopover'; +@forward 'scrollBox'; +@forward 'comment'; +@forward 'toast'; // 5 Ko +@forward 'popover'; // Deprecated CSS components // @forward 'gridLegacy'; // 40 Ko // @forward 'emptyStateDeprecated'; + +// @forward 'tableFixedDeprecated'; // 33 Ko +// @forward 'tableStickedDeprecated'; // 67 Ko diff --git a/packages/scss/src/components/loading/component.scss b/packages/scss/src/components/loading/component.scss index e5afec1834..b5ca2adac6 100644 --- a/packages/scss/src/components/loading/component.scss +++ b/packages/scss/src/components/loading/component.scss @@ -3,13 +3,27 @@ @mixin component { @include loading.spinner(); - min-width: 1.5rem; - min-height: 1.5rem; - padding-left: var(--pr-t-spacings-400); - display: inline-block; + @supports not (height: 1dvh) { + --components-loading-transform: var(--components-loading-transformFallback); + } + + min-height: var(--components-loading-size); + padding: var(--components-loading-padding); + margin: var(--components-loading-margin); + display: var(--components-loading-display); + transform: var(--components-loading-transform); + color: var(--components-loading-color); position: relative; + text-align: center; + vertical-align: top; + + &:not(:empty) { + --components-loading-padding: 0 0 0 var(--pr-t-spacings-400); + } &::after { - margin: 0; + width: var(--components-loading-size); + height: var(--components-loading-size); + margin: var(--components-loading-spinnerMargin); } } diff --git a/packages/scss/src/components/loading/index.scss b/packages/scss/src/components/loading/index.scss index 025b9dfcec..733900051f 100644 --- a/packages/scss/src/components/loading/index.scss +++ b/packages/scss/src/components/loading/index.scss @@ -12,16 +12,20 @@ @include block; } - &.mod-fullPage { + &[class~='mod-fullPage' i] { @include fullPage; } - &.mod-sidePanel { - @include sidePanel; + // .mod-dialog is deprecated + &.mod-popin, + &.mod-dialog { + @include popin; } - &.mod-dialog { - @include dialog; + // .mod-sidePanel is deprecated + &.mod-drawer, + &.mod-sidePanel { + @include drawer; } &.mod-invert { diff --git a/packages/scss/src/components/loading/mods.scss b/packages/scss/src/components/loading/mods.scss index e138a65bb2..2cc40270df 100644 --- a/packages/scss/src/components/loading/mods.scss +++ b/packages/scss/src/components/loading/mods.scss @@ -1,80 +1,51 @@ @use '@lucca-front/scss/src/commons/utils/color'; -@mixin L { - height: var(--components-loading-size-big); - padding: var(--components-loading-size-big) 0 0; - text-align: center; - width: 100%; +@mixin block { + --components-loading-display: block; + --components-loading-margin: 0 auto; + --components-loading-spinnerMargin: 0 auto; - &::after { - margin: 0 auto; - width: var(--components-loading-size-big); - height: var(--components-loading-size-big); + &:not(:empty) { + --components-loading-padding: var(--components-loading-size) 0 0; } } -@mixin block { - display: block; - margin-bottom: var(--pr-t-spacings-400); - padding: var(--pr-t-spacings-600) 0 0; - text-align: center; - width: 100%; +@mixin L { + @include block; - &::after { - margin: auto; - } + --components-loading-size: var(--components-loading-size-big); } @mixin fullPage { - display: block; - margin: 0 auto; - transform: translateY(30vh); + @include block; + @include L; - &::after { - margin: 0 auto; - width: var(--components-loading-size-big); - height: var(--components-loading-size-big); - } + --components-loading-transform: translateY(calc((100dvh - var(--commons-banner-height)) / 2)); + --components-loading-transformFallback: translateY(calc((100vh - var(--commons-banner-height)) / 2)); } -@mixin dialog { - display: block; - text-align: center; - position: relative; - padding: 8rem 0 0; - margin: 0 var(--pr-t-spacings-400) var(--pr-t-spacings-400); +@mixin invert { + --components-loading-color: var(--colors-white-color); &::after { - margin: auto; - width: var(--components-loading-size-big); - height: var(--components-loading-size-big); - left: 0; - right: 0; + --commons-loading-frontground: color.transparentize(var(--colors-white-color), 0.66); } } -@mixin sidePanel { - display: block; - text-align: center; - position: relative; - padding: 8rem 0 0; - margin: 0 var(--pr-t-spacings-400) var(--pr-t-spacings-400); - top: 35vh; +@mixin popin { + @include block; + @include L; - &::after { - margin: auto; - width: var(--components-loading-size-big); - height: var(--components-loading-size-big); - left: 0; - right: 0; + &, + &:not(:empty) { + --components-loading-padding: 8rem 0 0; } -} -@mixin invert { - color: var(--colors-white-color); + --components-loading-margin: 0 var(--pr-t-spacings-400) var(--pr-t-spacings-400); + --components-loading-spinnerMargin: auto; +} - &::after { - border-color: color.transparentize(var(--colors-white-color), 0.66); - border-top-color: transparent; - } +@mixin drawer { + @include fullPage; + @include popin; } diff --git a/packages/scss/src/components/loading/vars.scss b/packages/scss/src/components/loading/vars.scss index db12370918..55fdc3adf3 100644 --- a/packages/scss/src/components/loading/vars.scss +++ b/packages/scss/src/components/loading/vars.scss @@ -1,3 +1,11 @@ @mixin vars { - --components-loading-size-big: 3rem; + --components-loading-display: inline-block; + --components-loading-size: var(--pr-t-spacings-300); + --components-loading-size-big: var(--pr-t-spacings-600); + --components-loading-padding: 0 0 0 var(--components-loading-size); + --components-loading-margin: 0; + --components-loading-spinnerMargin: 0; + --components-loading-color: currentColor; + --components-loading-transform: none; + --components-loading-transformFallback: var(--components-loading-transform); } diff --git a/packages/scss/src/components/menu/component.scss b/packages/scss/src/components/menu/component.scss index 2cf63b3864..6a21216691 100644 --- a/packages/scss/src/components/menu/component.scss +++ b/packages/scss/src/components/menu/component.scss @@ -1,28 +1,25 @@ @use '@lucca-front/scss/src/commons/utils/reset'; @mixin component($atRoot: 'without: rule') { + position: relative; column-gap: var(--pr-t-spacings-400); align-items: center; display: flex; position: relative; flex-wrap: wrap; - &:not(.mod-noBorder) { - &::after { - border-bottom-width: var(--commons-divider-width); - border-bottom-color: var(--commons-divider-color); - border-bottom-style: solid; - position: absolute; - height: 1px; - bottom: 0; - left: 0; - right: 0; - content: ''; - } + &::after { + content: var(--components-menu-borderContent); + border-bottom-width: var(--commons-divider-width); + border-bottom-color: var(--commons-divider-color); + border-bottom-style: solid; + position: absolute; + height: 1px; + inset: auto 0 0; } + // .label is deprecated .label { - // deprecated margin-right: 0; background-color: var(--palettes-neutral-100); color: var(--palettes-neutral-700); @@ -32,41 +29,48 @@ .menu-list { @include reset.list; - align-items: flex-end; - column-gap: var(--pr-t-spacings-400); + align-items: var(--components-menu-listAlign); + gap: var(--components-menu-listGap); + flex-direction: var(--components-menu-listDirection); display: flex; + flex-grow: 1; flex-wrap: wrap; + padding: var(--components-menu-listPadding); } - .menu-link, // legacy syntax - .menu-list-item-action { + // .menu-link is deprecated + .menu-list-item-action, + .menu-link { @include reset.button; - padding: var(--components-menu-padding); + + font-size: var(--components-menu-listItemActionFontSize); + line-height: var(--components-menu-listItemActionLineHeight); + padding: var(--components-menu-listItemActionPadding); border-radius: var(--commons-borderRadius-M); - color: var(--palettes-neutral-800); - display: inline-flex; - align-items: center; - text-align: center; - gap: var(--pr-t-spacings-100); + color: var(--components-menu-listItemActionColor); + display: var(--components-menu-listItemActionDisplay); + text-align: var(--components-menu-listItemActionAlign); transition-duration: var(--commons-animations-durations-fast); + gap: var(--pr-t-spacings-100); + align-items: center; transition-property: color; position: relative; text-decoration: none; width: auto; z-index: 1; + scroll-margin-inline: var(--spacings-S); &::after { background-color: var(--palettes-700, var(--palettes-product-700)); - border-radius: var(--commons-borderRadius-M) var(--commons-borderRadius-M) 0 0; + border-radius: var(--components-menu-listItemActionRadius); transition-duration: var(--commons-animations-durations-fast); + height: var(--components-menu-listItemActionRadiusHeight); + width: var(--components-menu-listItemActionRadiusWidth); + transform: var(--components-menu-listItemActionTransform); + inset: var(--components-menu-listItemActionInset); transition-property: transform; display: block; position: absolute; - bottom: 0; - height: 2px; - left: 0; - right: 0; - transform: scale(0, 1); z-index: 1; content: ''; } @@ -77,14 +81,14 @@ color: var(--palettes-neutral-900); } + // .label is deprecated .label { - // deprecated background-color: var(--palettes-100, var(--palettes-product-100)); color: var(--palettes-700, var(--palettes-product-700)); } &::after { - transform: scale(0.75, 1); + --components-menu-listItemActionTransform: scale(0.75, 1); } } } diff --git a/packages/scss/src/components/menu/index.scss b/packages/scss/src/components/menu/index.scss index c0a7b52580..dfcaa6f606 100644 --- a/packages/scss/src/components/menu/index.scss +++ b/packages/scss/src/components/menu/index.scss @@ -11,16 +11,42 @@ &.mod-S { @include S; } + + &.mod-noBorder { + @include noBorder; + } + + &.mod-vertical { + @include vertical; + + .menu-list-item-action { + &[aria-current='page'], + &.is-active { + @include activeVertical; + } + } + + &.mod-S { + @include verticalS; + } + } } -// legacy syntax -.menu-link, -.menu-list-item-action { - &:is(.is-active, .active, [aria-current='page']) { +// .menu-link is deprecated +.menu-list-item-action, +.menu-link { + // .active is deprecated + &[aria-current='page'], + &.is-active, + &.active { @include active; } - &:is(.is-disabled, .disabled, &[disabled]) { + // .disabled is deprecated + // [disabled] is deprecated + &.is-disabled, + &.disabled, + &[disabled] { @include disabled; } } diff --git a/packages/scss/src/components/menu/mods.scss b/packages/scss/src/components/menu/mods.scss index 622b63c2ee..54796da097 100644 --- a/packages/scss/src/components/menu/mods.scss +++ b/packages/scss/src/components/menu/mods.scss @@ -1,25 +1,77 @@ +@use '@lucca-front/scss/src/components/numericBadge/exports' as numericBadge; + @mixin header { - padding: 0 2.5rem; + --components-menu-listPadding: 0 var(--pr-t-spacings-500); } @mixin S { - // legacy syntax - .menu-link, - .menu-list-item-action { - font-size: var(--sizes-S-fontSize); - line-height: var(--sizes-S-lineHeight); - padding: var(--pr-t-spacings-150) 0; + // .menu-link is deprecated + .menu-list-item-action, + .menu-link { + --components-menu-listItemActionFontSize: var(--sizes-S-fontSize); + --components-menu-listItemActionLineHeight: var(--sizes-S-lineHeight); + --components-menu-listItemActionPadding: var(--pr-t-spacings-150) 0; } - .label { // deprecated + // .menu-link is deprecated + .menu-link { + margin-right: var(--pr-t-spacings-300); + } + + // .label is deprecated + .label { height: var(--sizes-S-lineHeight); min-width: var(--sizes-S-lineHeight); line-height: var(--sizes-S-lineHeight); padding: 0; } - // legacy syntax - .menu-link { - margin-right: var(--pr-t-spacings-300); + .numericBadge { + @include numericBadge.S; + } +} + +@mixin noBorder { + &::after { + --components-menu-borderContent: none; + } +} + +@mixin vertical { + @include noBorder; + + .menu-list { + --components-menu-listDirection: column; + --components-menu-listGap: 0; + --components-menu-listAlign: stretch; + } + + .menu-list-item-action { + --components-menu-listItemActionPadding: var(--pr-t-spacings-50) var(--pr-t-spacings-200); + --components-menu-listItemActionAlign: left; + --components-menu-listItemActionDisplay: block; + + &::after { + --components-menu-listItemActionTransform: scale(1, 0); + --components-menu-listItemActionInset: 0 auto 0 0; + --components-menu-listItemActionRadius: 0 var(--commons-borderRadius-M) var(--commons-borderRadius-M) 0; + --components-menu-listItemActionRadiusWidth: var(--components-menu-listItemActionSize); + --components-menu-listItemActionRadiusHeight: auto; + } + + &, + &[aria-current='page'] { + &:hover { + &::after { + --components-menu-listItemActionTransform: scale(1, 0.75); + } + } + } + } +} + +@mixin verticalS { + .menu-list-item-action { + --components-menu-listItemActionPadding: var(--pr-t-spacings-50) var(--pr-t-spacings-150); } } diff --git a/packages/scss/src/components/menu/states.scss b/packages/scss/src/components/menu/states.scss index 44549a918d..fa049010bd 100644 --- a/packages/scss/src/components/menu/states.scss +++ b/packages/scss/src/components/menu/states.scss @@ -1,22 +1,21 @@ @use '@lucca-front/scss/src/components/numericBadge/exports' as numericBadge; @mixin active { - color: var(--palettes-700, var(--palettes-product-700)); + --components-menu-listItemActionColor: var(--palettes-700, var(--palettes-product-700)); + // .label is deprecated .label { - // deprecated background-color: var(--palettes-100, var(--palettes-product-100)); color: var(--palettes-700, var(--palettes-product-700)); } &::after { - background-color: var(--palettes-700, var(--palettes-product-700)); - transform: scale(1); + --components-menu-listItemActionTransform: scale(1); } &:focus-visible { &::after { - transform: scale(0.75, 1); + --components-menu-listItemActionTransform: scale(0.75, 1); } } @@ -26,9 +25,9 @@ } @mixin disabled { + // .label is deprecated &, .label { - // deprecated color: var(--palettes-neutral-500); pointer-events: none; } @@ -37,3 +36,9 @@ @include numericBadge.disabled; } } + +@mixin activeVertical { + &::after { + --components-menu-listItemActionTransform: scale(1); + } +} diff --git a/packages/scss/src/components/menu/vars.scss b/packages/scss/src/components/menu/vars.scss index 9fb0c24a8b..4d4e46d4c1 100644 --- a/packages/scss/src/components/menu/vars.scss +++ b/packages/scss/src/components/menu/vars.scss @@ -1,3 +1,19 @@ @mixin vars { - --components-menu-padding: var(--pr-t-spacings-200) 0; + --components-menu-borderContent: ''; + --components-menu-listPadding: 0; + --components-menu-listItemActionPadding: var(--pr-t-spacings-200) 0; + --components-menu-listGap: 0 var(--pr-t-spacings-400); + --components-menu-listDirection: row; + --components-menu-listAlign: flex-end; + --components-menu-listItemActionAlign: center; + --components-menu-listItemActionDisplay: inline-flex; + --components-menu-listItemActionTransform: scale(0, 1); + --components-menu-listItemActionColor: var(--palettes-grey-800); + --components-menu-listItemActionSize: 2px; + --components-menu-listItemActionFontSize: inherit; + --components-menu-listItemActionLineHeight: inherit; + --components-menu-listItemActionInset: auto 0 0 0; + --components-menu-listItemActionRadius: var(--commons-borderRadius-M) var(--commons-borderRadius-M) 0 0; + --components-menu-listItemActionRadiusWidth: auto; + --components-menu-listItemActionRadiusHeight: var(--components-menu-listItemActionSize); } diff --git a/packages/scss/src/components/navside/component.scss b/packages/scss/src/components/navside/component.scss index 88bd44c46a..56610aa037 100644 --- a/packages/scss/src/components/navside/component.scss +++ b/packages/scss/src/components/navside/component.scss @@ -110,25 +110,6 @@ font-weight: 600; } - // .navSide-item-alert is deprecated - .navSide-item-alert { - font-size: var(--sizes-XS-fontSize); - font-weight: 600; - background-color: var(--components-navSide-fullwidth-palette-alert-color); - color: var(--components-navSide-fullwidth-palette-alert-text); - transition-duration: var(--commons-animations-durations-standard); - transition-property: background-color; - margin-left: auto; - border-radius: 6px; - height: var(--sizes-S-lineHeight); - line-height: var(--sizes-S-lineHeight); - margin-right: 0; - padding: 0 var(--pr-t-spacings-50); - min-width: 1.25rem; - text-align: center; - flex-shrink: 0; - } - .navSide-item-arrow { @include icon.S; @@ -204,12 +185,6 @@ color: var(--components-navSide-bottom-section-palette-hovered-text); } } - - // .navSide-item-alert is deprecated - .navSide-item-alert { - background-color: var(--components-navSide-bottom-section-palette-alert-color); - color: var(--components-navSide-bottom-section-palette-alert-text); - } } .navSide-item-placeholder { diff --git a/packages/scss/src/components/navside/mods.scss b/packages/scss/src/components/navside/mods.scss index 8ec68d7a51..c0fbbd0baf 100644 --- a/packages/scss/src/components/navside/mods.scss +++ b/packages/scss/src/components/navside/mods.scss @@ -30,15 +30,6 @@ margin-left: inherit; } - .navSide-item-alert { - // deprecated - background-color: var(--components-navSide-compact-palette-alert-color); - color: var(--components-navSide-compact-palette-alert-text); - padding: 0 var(--pr-t-spacings-100); - margin: auto; - position: relative; - } - .navSide-item-placeholder { flex-direction: column; @@ -83,12 +74,6 @@ background-color: var(--components-navSide-compact-palette-selected-bg); color: var(--components-navSide-compact-palette-selected-text); opacity: 1; - - .navSide-item-alert { - // deprecated - background-color: var(--components-navSide-compact-palette-selected-alert-color); - color: var(--components-navSide-compact-palette-selected-alert-text); - } } @mixin banner { diff --git a/packages/scss/src/components/navside/states.scss b/packages/scss/src/components/navside/states.scss index 30febb5d32..eb57a59049 100644 --- a/packages/scss/src/components/navside/states.scss +++ b/packages/scss/src/components/navside/states.scss @@ -2,12 +2,6 @@ background-color: var(--components-navSide-fullwidth-palette-selected-bg); color: var(--components-navSide-fullwidth-palette-selected-text); opacity: 1; - - .navSide-item-alert { - // deprecated - background-color: var(--components-navSide-fullwidth-palette-selected-alert-color); - color: var(--components-navSide-fullwidth-palette-selected-alert-text); - } } @mixin expanded { diff --git a/packages/scss/src/components/popover/component.scss b/packages/scss/src/components/popover/component.scss new file mode 100644 index 0000000000..52ec1a38c1 --- /dev/null +++ b/packages/scss/src/components/popover/component.scss @@ -0,0 +1,50 @@ +@use '@lucca-front/scss/src/components/button/exports' as button; +@use '@lucca-front/scss/src/commons/utils/a11y'; + +@mixin component($atRoot: 'without: rule') { + display: block; + background-color: var(--pr-t-elevation-surface-raised); + box-shadow: var(--pr-t-elevation-shadow-overlay); + border-radius: var(--commons-borderRadius-L); + position: relative; + min-height: var(--pr-t-spacings-500); + min-width: var(--pr-t-spacings-500); + animation: popup var(--commons-animations-durations-fast) ease 1 forwards; + + // need of a higher specificity + .popover-close { + --components-button-padding: var(--pr-t-spacings-50); + } + + @at-root { + .popover-contentOptional { + padding: var(--pr-t-spacings-100) var(--pr-t-spacings-150); + } + + .popover-close { + @include button.text; + @include button.XS; + @include button.onlyIconXS; + + position: absolute; + right: var(--pr-t-spacings-150); + top: var(--pr-t-spacings-100); + z-index: 2; + + &:not(:focus-visible) { + @include a11y.mask; + } + } + } + + @keyframes popup { + from { + transform: scale(0.95); + opacity: 0.5; + } + to { + transform: scale(1); + opacity: 1; + } + } +} diff --git a/packages/scss/src/components/popover/exports.scss b/packages/scss/src/components/popover/exports.scss new file mode 100644 index 0000000000..2c2986a26b --- /dev/null +++ b/packages/scss/src/components/popover/exports.scss @@ -0,0 +1,4 @@ +@forward 'vars'; +@forward 'mods'; +@forward 'states'; +@forward 'component'; diff --git a/packages/scss/src/components/popover/index.scss b/packages/scss/src/components/popover/index.scss new file mode 100644 index 0000000000..05914c52b2 --- /dev/null +++ b/packages/scss/src/components/popover/index.scss @@ -0,0 +1,6 @@ +@use 'exports' as *; + +.popover { + @include vars; + @include component; +} diff --git a/packages/scss/src/components/popover/mods.scss b/packages/scss/src/components/popover/mods.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/scss/src/components/popover/states.scss b/packages/scss/src/components/popover/states.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/scss/src/components/status/vars.scss b/packages/scss/src/components/popover/vars.scss similarity index 100% rename from packages/scss/src/components/status/vars.scss rename to packages/scss/src/components/popover/vars.scss diff --git a/packages/scss/src/components/scrollBox/component.scss b/packages/scss/src/components/scrollBox/component.scss new file mode 100644 index 0000000000..fec153ac20 --- /dev/null +++ b/packages/scss/src/components/scrollBox/component.scss @@ -0,0 +1,114 @@ +@use '@lucca-front/scss/src/commons/utils/color'; + +@mixin component($atRoot: 'without: rule') { + background-color: var(--components-scrollBox-backgroundColor); + position: relative; + display: flex; + overflow: auto; + scrollbar-width: thin; + + @media (hover: none) { + scrollbar-width: none; + + &::-webkit-scrollbar { + display: none; + } + } + + &::before, + &::after { + content: ''; + pointer-events: none; + position: sticky; + flex-shrink: 0; + width: var(--components-scrollBox-shadowWidth); + top: 0; + bottom: 0; + background-repeat: no-repeat; + background-size: 75% 100%, 25% 100%, 1px 100%; + } + + &::before { + left: 0; + background-position: 0% 50%; + background-image: radial-gradient( + farthest-side at 0% 50%, + color.transparentize(var(--components-scrollBox-shadowColor), 0.24), + color.transparentize(var(--colors-black-color), 0) + ), + radial-gradient( + farthest-side at 0% 50%, + color.transparentize(var(--components-scrollBox-shadowColor), 0.32) 50%, + color.transparentize(var(--colors-black-color), 0) + ), + radial-gradient( + farthest-side at 0% 50%, + color.transparentize(var(--components-scrollBox-shadowColor), 1) calc(100% - 1px), + color.transparentize(var(--colors-black-color), 0) + ); + } + + &::after { + right: 0; + background-position: 100% 50%; + background-image: radial-gradient( + farthest-side at 100% 50%, + color.transparentize(var(--components-scrollBox-shadowColor), 0.24), + color.transparentize(var(--colors-black-color), 0) + ), + radial-gradient( + farthest-side at 100% 50%, + color.transparentize(var(--components-scrollBox-shadowColor), 0.32) 50%, + color.transparentize(var(--colors-black-color), 0) + ), + radial-gradient( + farthest-side at 100% 50%, + color.transparentize(var(--components-scrollBox-shadowColor), 1) calc(100% - 1px), + color.transparentize(var(--colors-black-color), 0) + ); + } + + @at-root ($atRoot) { + .scrollBox-inner { + flex-shrink: 0; + position: relative; + + &::before, + &::after { + content: ''; + position: absolute; + z-index: 1; + display: block; + top: 1px; + bottom: 1px; + width: calc(var(--components-scrollBox-shadowWidth) * 2); + pointer-events: none; + } + + &::before { + left: calc(var(--components-scrollBox-shadowWidth) * -1); + background-image: linear-gradient( + to right, + var(--components-scrollBox-backgroundColor) var(--components-scrollBox-shadowWidth), + color.transparentize(var(--colors-black-color), 0) + ); + } + + &::after { + right: calc(var(--components-scrollBox-shadowWidth) * -1); + background-image: linear-gradient( + to left, + var(--components-scrollBox-backgroundColor) var(--components-scrollBox-shadowWidth), + color.transparentize(var(--colors-black-color), 0) + ); + } + } + + .scrollBox-inner-content { + margin-left: calc(var(--components-scrollBox-shadowWidth) * -1); + margin-right: calc(var(--components-scrollBox-shadowWidth) * -1); + position: relative; + z-index: 2; + } + } +} diff --git a/packages/scss/src/components/scrollBox/exports.scss b/packages/scss/src/components/scrollBox/exports.scss new file mode 100644 index 0000000000..2c2986a26b --- /dev/null +++ b/packages/scss/src/components/scrollBox/exports.scss @@ -0,0 +1,4 @@ +@forward 'vars'; +@forward 'mods'; +@forward 'states'; +@forward 'component'; diff --git a/packages/scss/src/components/scrollBox/index.scss b/packages/scss/src/components/scrollBox/index.scss new file mode 100644 index 0000000000..2f932cada5 --- /dev/null +++ b/packages/scss/src/components/scrollBox/index.scss @@ -0,0 +1,6 @@ +@use 'exports' as *; + +.scrollBox { + @include vars; + @include component; +} diff --git a/packages/scss/src/components/scrollBox/mods.scss b/packages/scss/src/components/scrollBox/mods.scss new file mode 100644 index 0000000000..b1d475da82 --- /dev/null +++ b/packages/scss/src/components/scrollBox/mods.scss @@ -0,0 +1,2 @@ +@mixin mod { +} diff --git a/packages/scss/src/components/scrollBox/states.scss b/packages/scss/src/components/scrollBox/states.scss new file mode 100644 index 0000000000..c643d3a117 --- /dev/null +++ b/packages/scss/src/components/scrollBox/states.scss @@ -0,0 +1,2 @@ +@mixin state { +} diff --git a/packages/scss/src/components/scrollBox/vars.scss b/packages/scss/src/components/scrollBox/vars.scss new file mode 100644 index 0000000000..5748cdd5e8 --- /dev/null +++ b/packages/scss/src/components/scrollBox/vars.scss @@ -0,0 +1,5 @@ +@mixin vars { + --components-scrollBox-backgroundColor: var(--pr-t-elevation-surface-default); + --components-scrollBox-shadowColor: var(--palettes-neutral-400); + --components-scrollBox-shadowWidth: var(--pr-t-spacings-200); +} diff --git a/packages/scss/src/components/status/component.scss b/packages/scss/src/components/status/component.scss deleted file mode 100644 index 38b83da0d2..0000000000 --- a/packages/scss/src/components/status/component.scss +++ /dev/null @@ -1,47 +0,0 @@ -@mixin component($atRoot: 'without: rule') { - display: inline-flex; - align-items: center; - white-space: nowrap; - - @at-root ($atRoot) { - .status-dot { - aspect-ratio: 1; - width: var(--pr-t-spacings-100); - border-radius: var(--commons-borderRadius-full); - background-color: currentColor; - margin: calc(var(--pr-t-spacings-50) / 2); - margin-right: var(--pr-t-spacings-100); - position: relative; - z-index: 1; - display: inline-flex; - } - - .status-dot-important { - @keyframes status { - 0% { - transform: scale(1); - opacity: 1; - } - 70% { - transform: scale(2.25); - opacity: 0; - } - 100% { - transform: scale(2.25); - opacity: 0; - } - } - - inset: 0; - position: absolute; - border-radius: var(--commons-borderRadius-full); - animation: status 2s infinite; - background-color: currentColor; - } - - .status-label { - font-size: var(--sizes-S-fontSize); - color: var(--palettes-neutral-800); - } - } -} diff --git a/packages/scss/src/components/status/index.scss b/packages/scss/src/components/status/index.scss deleted file mode 100644 index 75c9f2d5eb..0000000000 --- a/packages/scss/src/components/status/index.scss +++ /dev/null @@ -1,18 +0,0 @@ -@use 'exports' as *; - -.status { - @include vars; - @include component; - - &:is(.success, .is-success) { - @include success; - } - - &:is(.warning, .is-warning) { - @include warning; - } - - &:is(.error, .is-error) { - @include error; - } -} diff --git a/packages/scss/src/components/status/states.scss b/packages/scss/src/components/status/states.scss deleted file mode 100644 index 066d99296d..0000000000 --- a/packages/scss/src/components/status/states.scss +++ /dev/null @@ -1,17 +0,0 @@ -@mixin success { - .status-dot { - color: var(--palettes-success-700); - } -} - -@mixin error { - .status-dot { - color: var(--palettes-error-700); - } -} - -@mixin warning { - .status-dot { - color: var(--palettes-warning-700); - } -} diff --git a/packages/scss/src/components/table/index.scss b/packages/scss/src/components/table/index.scss index 4866f767a2..f6db6961ec 100644 --- a/packages/scss/src/components/table/index.scss +++ b/packages/scss/src/components/table/index.scss @@ -32,10 +32,6 @@ @include S; } - &.mod-layoutFixed { - @include layoutFixed; - } - &.mod-noOffset { @include noOffset; } diff --git a/packages/scss/src/components/table/mods.scss b/packages/scss/src/components/table/mods.scss index dc4c6e05f3..dce0250654 100644 --- a/packages/scss/src/components/table/mods.scss +++ b/packages/scss/src/components/table/mods.scss @@ -347,10 +347,6 @@ text-align: right; } -@mixin layoutFixed { - table-layout: fixed; -} - @mixin noOffset { .table-head-row-cell, .table-body-row-cell, diff --git a/packages/scss/src/components/tableFixed/index.scss b/packages/scss/src/components/tableFixed/index.scss index 8279c50229..785ffdf6e6 100644 --- a/packages/scss/src/components/tableFixed/index.scss +++ b/packages/scss/src/components/tableFixed/index.scss @@ -1,21 +1,18 @@ -@use '@lucca-front/scss/src/commons/config'; -@use '@lucca-front/scss/src/commons/utils/media'; @use 'exports' as *; -.table-head-row-cell, -.table-body-row-cell, -.table-foot-row-cell { - @for $i from 2 through 20 { - &.mod-layoutFixed-#{$i} { - @include layoutFixed($i); - } +.table { + // 1 - Layout fixed + &.mod-layoutFixed { + @include layoutFixed; + } + + // 2 - Layout fixed starting at breakpoint + &[class*='mod-layoutFixedAtMediaMin'] { + @include layoutFixedWithBreakpoint; + } - @each $breakpoint, $value in config.$breakpoints { - @include media.min($breakpoint) { - &.mod-layoutFixed-#{$i}\@mediaMin#{$breakpoint} { - @include layoutFixed($i); - } - } - } + // Cells management for 1 & 2 + &[class*='mod-layoutFixed'] { + @include layoutFixedCells; } } diff --git a/packages/scss/src/components/tableFixed/mods.scss b/packages/scss/src/components/tableFixed/mods.scss index 8d5a9b86bd..fa82712014 100644 --- a/packages/scss/src/components/tableFixed/mods.scss +++ b/packages/scss/src/components/tableFixed/mods.scss @@ -1,5 +1,49 @@ -@mixin layoutFixed($i) { - min-width: $i * 1rem; - max-width: $i * 1rem; - width: $i * 1rem; +@use '@lucca-front/scss/src/commons/config'; +@use '@lucca-front/scss/src/commons/utils/media'; + +@mixin layoutFixed { + table-layout: fixed; +} + +@mixin layoutFixedWithBreakpoint { + @each $breakpoint, $value in config.$breakpoints { + @include media.min($breakpoint) { + &.mod-layoutFixedAtMediaMin#{$breakpoint} { + table-layout: fixed; + } + } + } +} + +@mixin layoutFixedCells { + .table-head-row-cell, + .table-body-row-cell, + .table-foot-row-cell { + --cell-width: var(--table-layoutFixed-width); + } + + &.mod-layoutFixed { + .table-head-row-cell, + .table-body-row-cell, + .table-foot-row-cell { + @include cellFixedWidth; + } + } + + @each $breakpoint, $value in config.$breakpoints { + @include media.min($breakpoint) { + &.mod-layoutFixedAtMediaMin#{$breakpoint} { + .table-head-row-cell, + .table-body-row-cell, + .table-foot-row-cell { + @include cellFixedWidth; + } + } + } + } +} + +@mixin cellFixedWidth { + min-width: var(--cell-width, auto); + width: var(--cell-width, auto); } diff --git a/packages/scss/src/components/tableFixed/vars.scss b/packages/scss/src/components/tableFixed/vars.scss index e69de29bb2..18998b2cf0 100644 --- a/packages/scss/src/components/tableFixed/vars.scss +++ b/packages/scss/src/components/tableFixed/vars.scss @@ -0,0 +1,3 @@ +@mixin vars { + +} diff --git a/packages/scss/src/components/tableFixedDeprecated/component.scss b/packages/scss/src/components/tableFixedDeprecated/component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/scss/src/components/tableFixedDeprecated/exports.scss b/packages/scss/src/components/tableFixedDeprecated/exports.scss new file mode 100644 index 0000000000..2c2986a26b --- /dev/null +++ b/packages/scss/src/components/tableFixedDeprecated/exports.scss @@ -0,0 +1,4 @@ +@forward 'vars'; +@forward 'mods'; +@forward 'states'; +@forward 'component'; diff --git a/packages/scss/src/components/tableFixedDeprecated/index.scss b/packages/scss/src/components/tableFixedDeprecated/index.scss new file mode 100644 index 0000000000..8279c50229 --- /dev/null +++ b/packages/scss/src/components/tableFixedDeprecated/index.scss @@ -0,0 +1,21 @@ +@use '@lucca-front/scss/src/commons/config'; +@use '@lucca-front/scss/src/commons/utils/media'; +@use 'exports' as *; + +.table-head-row-cell, +.table-body-row-cell, +.table-foot-row-cell { + @for $i from 2 through 20 { + &.mod-layoutFixed-#{$i} { + @include layoutFixed($i); + } + + @each $breakpoint, $value in config.$breakpoints { + @include media.min($breakpoint) { + &.mod-layoutFixed-#{$i}\@mediaMin#{$breakpoint} { + @include layoutFixed($i); + } + } + } + } +} diff --git a/packages/scss/src/components/tableFixedDeprecated/mods.scss b/packages/scss/src/components/tableFixedDeprecated/mods.scss new file mode 100644 index 0000000000..8d5a9b86bd --- /dev/null +++ b/packages/scss/src/components/tableFixedDeprecated/mods.scss @@ -0,0 +1,5 @@ +@mixin layoutFixed($i) { + min-width: $i * 1rem; + max-width: $i * 1rem; + width: $i * 1rem; +} diff --git a/packages/scss/src/components/tableFixedDeprecated/states.scss b/packages/scss/src/components/tableFixedDeprecated/states.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/scss/src/components/tableFixedDeprecated/vars.scss b/packages/scss/src/components/tableFixedDeprecated/vars.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/scss/src/components/tableSticked/index.scss b/packages/scss/src/components/tableSticked/index.scss index 883952365a..25489d63f4 100644 --- a/packages/scss/src/components/tableSticked/index.scss +++ b/packages/scss/src/components/tableSticked/index.scss @@ -5,51 +5,29 @@ .table { @include vars; - &.mod-stickyColumn { + //For both mod-stickyColumn + responsive variant + &[class*='mod-stickyColumn'] { @include stickyColumn; } - @each $breakpoint, $value in config.$breakpoints { - @include media.min($breakpoint) { - &.mod-stickyColumn\@mediaMin#{$breakpoint} { - @include stickyColumn; - } - } - } - - &.mod-stickyColumn-shadow { - @include shadow; + &.mod-stickyColumn { + @include stickyColumnOffset; } - &[class*='mod-stickyColumn'] { - .table-head-row-cell, - .table-body-row-cell, - .table-foot-row-cell { - @for $i from 0 through 50 { - &.mod-stickyColumn-leftOffset#{$i} { - @include leftOffset($i); - } - - &.mod-stickyColumn-rightOffset#{$i} { - @include rightOffset($i); - } + @each $breakpoint, $value in config.$breakpoints { + @include media.min($breakpoint) { + &.mod-stickyColumnAtMediaMin#{$breakpoint} { + @include stickyColumnOffset; } } } - [class*='sticky'][class*='shadow-wrapper'] { - @include wrapper; - } - + //For both stickyHeader + -withBanner variant &[class*='mod-stickyHeader'] { @include stickyHeaderCommon; - @each $breakpoint, $value in config.$breakpoints { - @include media.max($breakpoint) { - &.mod-stickyColumn\@mediaMin#{$breakpoint} { - @include stickyColumnBreakpoint; - } - } + .mod-stickyHeader-shadow { + @include stickyHeaderShadow; } } @@ -61,10 +39,3 @@ @include stickyHeaderBanner; } } - -.table-body-row, -.table-foot-row { - &.mod-stickyHeader-shadow { - @include stickyHeaderShadow; - } -} diff --git a/packages/scss/src/components/tableSticked/mods.scss b/packages/scss/src/components/tableSticked/mods.scss index 5bf7047453..f3ed618de7 100644 --- a/packages/scss/src/components/tableSticked/mods.scss +++ b/packages/scss/src/components/tableSticked/mods.scss @@ -1,212 +1,171 @@ @use 'sass:color'; - +@use '@lucca-front/scss/src/commons/utils/media'; +@use '@lucca-front/scss/src/commons/config'; @use '@lucca-front/icons/src/commons/utils/icon'; @use '@lucca-front/scss/src/commons/utils/reset'; -@mixin stickyColumn($shadowColor: #2a3551) { +@mixin stickyColumn { width: auto; min-width: 100%; - background-color: var(--pr-t-elevation-surface-raised); + background-color: var(--colors-white-color); - .table-head-row-cell, - .table-body-row-cell, - .table-foot-row-cell { - &[class*='mod-stickyColumn-'] { - position: sticky; - background-color: var(--pr-t-elevation-surface-raised); - z-index: 3; - } - - &.mod-stickyColumn-shadow { - z-index: 1; - min-width: var(--components-table-fixed-column-sticky-shadow-width); - max-width: var(--components-table-fixed-column-sticky-shadow-width); - width: var(--components-table-fixed-column-sticky-shadow-width); - padding: 0; - background: transparent; - } - - .stickyColumn-shadow-wrapper { - display: flex; - } + //All stickies columns + [class*='mod-stickyColumn-'] { + background-color: var(--colors-white-color); + z-index: 3; } + //Left sticked columns [class*='mod-stickyColumn-left'] { - .stickyColumn-shadow-wrapper { - left: calc(var(--components-table-fixed-column-sticky-shadow-width) * -1); + left: var(--components-tableSticked-column-sticky-offset); - &::after { - background-image: linear-gradient(to right, color.adjust($shadowColor, $alpha: -0.75), color.adjust($shadowColor, $alpha: -1)); - } + //left sticked columns shadow + &.mod-stickyColumn-shadow, + .stickyColumn-shadow-wrapper::before { + left: calc(var(--components-tableSticked-column-sticky-offset) - var(--components-tableSticked-column-sticky-shadow-width)); + } + .stickyColumn-shadow-wrapper::after { + left: var(--components-tableSticked-column-sticky-offset); + background-image: linear-gradient(to right, var(--components-tableSticked-column-sticky-shadow-color), transparent); } } + //Right sticked columns [class*='mod-stickyColumn-right'] { - .stickyColumn-shadow-wrapper { - right: calc(var(--components-table-fixed-column-sticky-shadow-width) * -1); + right: var(--components-tableSticked-column-sticky-offset); - &::after { - background-image: linear-gradient(to left, color.adjust($shadowColor, $alpha: -0.75), color.adjust($shadowColor, $alpha: -1)); - } + //right sticked columns shadow + .stickyColumn-shadow-wrapper { + justify-items: end; + width: calc(var(--components-tableSticked-column-sticky-shadow-width) * 3); + right: calc(var(--components-tableSticked-column-sticky-shadow-width) * -1); + } + &.mod-stickyColumn-shadow, + .stickyColumn-shadow-wrapper::before { + right: calc(var(--components-tableSticked-column-sticky-offset) - var(--components-tableSticked-column-sticky-shadow-width)); + } + .stickyColumn-shadow-wrapper::after { + right: var(--components-tableSticked-column-sticky-offset); + background-image: linear-gradient(to left, var(--components-tableSticked-column-sticky-shadow-color), transparent); } } - &[class*='mod-stickyHeader'] { - &[class*='mod-stickyColumn'] { - .table-head-row-cell { - &[class*='mod-stickyColumn'] { - z-index: 6; - - &:not(.mod-stickyColumn-shadow) { - z-index: 7; - } - } - - &.mod-columnSticky-shadowMask { - &::before { - width: var(--components-table-fixed-column-sticky-shadow-width); - left: calc(var(--components-table-fixed-column-sticky-shadow-width) * -1); - background: var(--pr-t-elevation-surface-raised); - top: 0; - bottom: 0; - z-index: 4; - position: absolute; - content: ''; - } - } - - &:not(.mod-columnSticky-shadowMask) { - &:not(.mod-stickyColumn-shadow) { - + .mod-columnSticky-shadowMask { - &::before { - left: auto; - right: calc(var(--components-table-fixed-column-sticky-shadow-width) * -1); - } - } - } - } - } - } + //Sticky columns drop shadow + .mod-stickyColumn-shadow { + display: none; + width: 0; + min-width: 0; + padding: 0; } -} -@mixin shadow { - width: 0; - position: static; + .stickyColumn-shadow-wrapper { + position: absolute; + top: 0; + bottom: 0; + display: grid; + grid-template-columns: calc(var(--components-tableSticked-column-sticky-shadow-width) * 2); + grid-template-areas: 'cell'; + width: calc(var(--components-tableSticked-column-sticky-shadow-width) * 2); + + &::before, + &::after { + content: ''; + position: sticky; + grid-area: cell; + } + &::after { + width: var(--components-tableSticked-column-sticky-shadow-width); + } + &::before { + z-index: 1; + width: var(--components-tableSticked-column-sticky-shadow-width); + background-color: var(--colors-white-color); + } + } } -@mixin leftOffset($i) { - left: calc(#{$i} * var(--pr-t-spacings-200)); +@mixin stickyColumnOffset { + [class*='mod-stickyColumn-'] { + --components-tableSticked-column-sticky-offset: var(--table-stickyColumn-offset, 0rem); - &.mod-stickyColumn-shadow, - .stickyColumn-shadow-wrapper::after { - left: calc(#{$i} * var(--pr-t-spacings-200) + var(--components-table-fixed-column-sticky-shadow-width)); + position: sticky; + } + .mod-stickyColumn-shadow { + display: table-cell; } } -@mixin rightOffset($i) { - right: calc(#{$i} * var(--pr-t-spacings-200)); +/***** + Sticky header +****/ - &.mod-stickyColumn-shadow, - .stickyColumn-shadow-wrapper::after { - right: calc(#{$i} * var(--pr-t-spacings-200) + var(--components-table-fixed-column-sticky-shadow-width)); +@mixin stickyHeader { + .table-head-row-cell { + top: 0; + } + .mod-stickyHeader-shadow .table-body-row-cell { + top: calc(var(--table-stickyHeader-shadow-offset) + var(--components-tableSticked-column-sticky-shadow-width)); } } -@mixin wrapper { - bottom: calc(var(--commons-divider-width) * -1); - width: var(--components-table-fixed-column-sticky-shadow-width); - border-bottom-width: var(--commons-divider-width); - border-bottom-color: var(--commons-divider-color); - border-bottom-style: solid; - display: flex; - position: absolute; - top: 0; - - &::after { - width: var(--components-table-fixed-column-sticky-shadow-width); - position: sticky; - display: block; - background-color: transparent; - height: 100%; - content: ''; +@mixin stickyHeaderBanner { + .table-head-row-cell { + top: var(--commons-banner-height); + } + .mod-stickyHeader-shadow .table-body-row-cell { + top: calc( + var(--table-stickyHeader-shadow-offset) + var(--commons-banner-height) + var(--components-tableSticked-column-sticky-shadow-width) + ); } } @mixin stickyHeaderCommon { + margin-top: var(--components-tableSticked-column-sticky-shadow-width); .table-head-row-cell { - background-color: var(--pr-t-elevation-surface-raised); + background-color: var(--colors-white-color); position: sticky; z-index: 5; + &[class*='mod-stickyColumn'] { + z-index: 7; + } } } -@mixin stickyColumnBreakpoint { - .table-head-row-cell { - left: auto !important; - right: auto !important; - } -} +/***** + Sticky header drop shadow +****/ -@mixin stickyHeaderShadow($shadowColor: #2a3551) { - .table-body-row-cell, - .table-foot-row-cell { - top: calc(var(--sticky-header-shadow-offset-top) + var(--components-table-fixed-column-sticky-shadow-width)); +@mixin stickyHeaderShadow { + [class*='row-cell'] { + position: sticky; + top: var(--table-stickyHeader-shadow-offset); z-index: 4; height: 0; padding: 0; border: 0; - position: sticky; background: transparent; } .stickyHeader-shadow-wrapper { - top: calc(var(--components-table-fixed-column-sticky-shadow-width) * -1); + position: absolute; + top: calc(var(--components-tableSticked-column-sticky-shadow-width) * -1); width: 100%; height: 0; border: 0; &::after { - top: calc(var(--sticky-header-shadow-offset-top) + var(--components-table-fixed-column-sticky-shadow-width)); - height: var(--components-table-fixed-column-sticky-shadow-width); - background-image: linear-gradient(to bottom, color.adjust($shadowColor, $alpha: -0.75), color.adjust($shadowColor, $alpha: -1)); + content: ''; + display: block; + height: var(--components-tableSticked-column-sticky-shadow-width); width: 100%; - opacity: 0.5; + background-image: linear-gradient(to bottom, var(--components-tableSticked-column-sticky-shadow-color), transparent); } } + .table-body-row, + .table-foot-row { - .table-body-row-cell, - .table-foot-row-cell { + [class*='row-cell'] { border-top: 0; } } } - -@mixin stickyHeader { - .table-head-row-cell { - top: 0; - } -} - -@mixin stickyHeaderBanner { - .table-head-row-cell { - top: var(commons-banner-height); - } - - .table-body-row-cell, - .table-foot-row-cell { - top: calc( - var(commons-banner-height) + var(--sticky-header-shadow-offset-top) + var(--components-table-fixed-column-sticky-shadow-width) - ); - - .stickyHeader-shadow-wrapper { - &::after { - top: calc( - var(commons-banner-height) + var(--sticky-header-shadow-offset-top) + var(--components-table-fixed-column-sticky-shadow-width) - ); - } - } - } -} diff --git a/packages/scss/src/components/tableSticked/vars.scss b/packages/scss/src/components/tableSticked/vars.scss index c293870b74..a04113e515 100644 --- a/packages/scss/src/components/tableSticked/vars.scss +++ b/packages/scss/src/components/tableSticked/vars.scss @@ -1,8 +1,6 @@ -@mixin vars { - // --components-table-sticky-column-max-offset: 50; - // --components-table-fixed-column-min-col-width: 2; - // --components-table-fixed-column-max-col-width: 20; - // --components-table-fixed-column-sticky-shadow-color: #2a3551; +@use '@lucca-front/scss/src/commons/utils/color'; - --components-table-fixed-column-sticky-shadow-width: 0.625rem; +@mixin vars { + --components-tableSticked-column-sticky-shadow-width: 0.5rem; + --components-tableSticked-column-sticky-shadow-color: #{color.transparentize(var(--palettes-neutral-400), 0.24)}; } diff --git a/packages/scss/src/components/tableStickedDeprecated/component.scss b/packages/scss/src/components/tableStickedDeprecated/component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/scss/src/components/tableStickedDeprecated/exports.scss b/packages/scss/src/components/tableStickedDeprecated/exports.scss new file mode 100644 index 0000000000..2c2986a26b --- /dev/null +++ b/packages/scss/src/components/tableStickedDeprecated/exports.scss @@ -0,0 +1,4 @@ +@forward 'vars'; +@forward 'mods'; +@forward 'states'; +@forward 'component'; diff --git a/packages/scss/src/components/tableStickedDeprecated/index.scss b/packages/scss/src/components/tableStickedDeprecated/index.scss new file mode 100644 index 0000000000..883952365a --- /dev/null +++ b/packages/scss/src/components/tableStickedDeprecated/index.scss @@ -0,0 +1,70 @@ +@use '@lucca-front/scss/src/commons/config'; +@use '@lucca-front/scss/src/commons/utils/media'; +@use 'exports' as *; + +.table { + @include vars; + + &.mod-stickyColumn { + @include stickyColumn; + } + + @each $breakpoint, $value in config.$breakpoints { + @include media.min($breakpoint) { + &.mod-stickyColumn\@mediaMin#{$breakpoint} { + @include stickyColumn; + } + } + } + + &.mod-stickyColumn-shadow { + @include shadow; + } + + &[class*='mod-stickyColumn'] { + .table-head-row-cell, + .table-body-row-cell, + .table-foot-row-cell { + @for $i from 0 through 50 { + &.mod-stickyColumn-leftOffset#{$i} { + @include leftOffset($i); + } + + &.mod-stickyColumn-rightOffset#{$i} { + @include rightOffset($i); + } + } + } + } + + [class*='sticky'][class*='shadow-wrapper'] { + @include wrapper; + } + + &[class*='mod-stickyHeader'] { + @include stickyHeaderCommon; + + @each $breakpoint, $value in config.$breakpoints { + @include media.max($breakpoint) { + &.mod-stickyColumn\@mediaMin#{$breakpoint} { + @include stickyColumnBreakpoint; + } + } + } + } + + &.mod-stickyHeader { + @include stickyHeader; + } + + &.mod-stickyHeader-withBanner { + @include stickyHeaderBanner; + } +} + +.table-body-row, +.table-foot-row { + &.mod-stickyHeader-shadow { + @include stickyHeaderShadow; + } +} diff --git a/packages/scss/src/components/tableStickedDeprecated/mods.scss b/packages/scss/src/components/tableStickedDeprecated/mods.scss new file mode 100644 index 0000000000..de9471f6c0 --- /dev/null +++ b/packages/scss/src/components/tableStickedDeprecated/mods.scss @@ -0,0 +1,212 @@ +@use 'sass:color'; + +@use '@lucca-front/icons/src/commons/utils/icon'; +@use '@lucca-front/scss/src/commons/utils/reset'; + +@mixin stickyColumn($shadowColor: #2a3551) { + width: auto; + min-width: 100%; + background-color: var(--pr-t-elevation-surface-raised); + + .table-head-row-cell, + .table-body-row-cell, + .table-foot-row-cell { + &[class*='mod-stickyColumn-'] { + position: sticky; + background-color: var(--pr-t-elevation-surface-raised); + z-index: 3; + } + + &.mod-stickyColumn-shadow { + z-index: 1; + min-width: var(--components-tableFixed-column-sticky-shadow-width); + max-width: var(--components-tableFixed-column-sticky-shadow-width); + width: var(--components-tableFixed-column-sticky-shadow-width); + padding: 0; + background: transparent; + } + + .stickyColumn-shadow-wrapper { + display: flex; + } + } + + [class*='mod-stickyColumn-left'] { + .stickyColumn-shadow-wrapper { + left: calc(var(--components-tableFixed-column-sticky-shadow-width) * -1); + + &::after { + background-image: linear-gradient(to right, color.adjust($shadowColor, $alpha: -0.75), color.adjust($shadowColor, $alpha: -1)); + } + } + } + + [class*='mod-stickyColumn-right'] { + .stickyColumn-shadow-wrapper { + right: calc(var(--components-tableFixed-column-sticky-shadow-width) * -1); + + &::after { + background-image: linear-gradient(to left, color.adjust($shadowColor, $alpha: -0.75), color.adjust($shadowColor, $alpha: -1)); + } + } + } + + &[class*='mod-stickyHeader'] { + &[class*='mod-stickyColumn'] { + .table-head-row-cell { + &[class*='mod-stickyColumn'] { + z-index: 6; + + &:not(.mod-stickyColumn-shadow) { + z-index: 7; + } + } + + &.mod-columnSticky-shadowMask { + &::before { + width: var(--components-tableFixed-column-sticky-shadow-width); + left: calc(var(--components-tableFixed-column-sticky-shadow-width) * -1); + background: var(--pr-t-elevation-surface-raised); + top: 0; + bottom: 0; + z-index: 4; + position: absolute; + content: ''; + } + } + + &:not(.mod-columnSticky-shadowMask) { + &:not(.mod-stickyColumn-shadow) { + + .mod-columnSticky-shadowMask { + &::before { + left: auto; + right: calc(var(--components-tableFixed-column-sticky-shadow-width) * -1); + } + } + } + } + } + } + } +} + +@mixin shadow { + width: 0; + position: static; +} + +@mixin leftOffset($i) { + left: calc(#{$i} * var(--pr-t-spacings-200)); + + &.mod-stickyColumn-shadow, + .stickyColumn-shadow-wrapper::after { + left: calc(#{$i} * var(--pr-t-spacings-200) + var(--components-tableFixed-column-sticky-shadow-width)); + } +} + +@mixin rightOffset($i) { + right: calc(#{$i} * var(--pr-t-spacings-200)); + + &.mod-stickyColumn-shadow, + .stickyColumn-shadow-wrapper::after { + right: calc(#{$i} * var(--pr-t-spacings-200) + var(--components-tableFixed-column-sticky-shadow-width)); + } +} + +@mixin wrapper { + bottom: calc(var(--commons-divider-width) * -1); + width: var(--components-tableFixed-column-sticky-shadow-width); + border-bottom-width: var(--commons-divider-width); + border-bottom-color: var(--commons-divider-color); + border-bottom-style: solid; + display: flex; + position: absolute; + top: 0; + + &::after { + width: var(--components-tableFixed-column-sticky-shadow-width); + position: sticky; + display: block; + background-color: transparent; + height: 100%; + content: ''; + } +} + +@mixin stickyHeaderCommon { + .table-head-row-cell { + background-color: var(--pr-t-elevation-surface-raised); + position: sticky; + z-index: 5; + } +} + +@mixin stickyColumnBreakpoint { + .table-head-row-cell { + left: auto !important; + right: auto !important; + } +} + +@mixin stickyHeaderShadow($shadowColor: #2a3551) { + .table-body-row-cell, + .table-foot-row-cell { + top: calc(var(--sticky-header-shadow-offset-top) + var(--components-tableFixed-column-sticky-shadow-width)); + z-index: 4; + height: 0; + padding: 0; + border: 0; + position: sticky; + background: transparent; + } + + .stickyHeader-shadow-wrapper { + top: calc(var(--components-tableFixed-column-sticky-shadow-width) * -1); + width: 100%; + height: 0; + border: 0; + + &::after { + top: calc(var(--sticky-header-shadow-offset-top) + var(--components-tableFixed-column-sticky-shadow-width)); + height: var(--components-tableFixed-column-sticky-shadow-width); + background-image: linear-gradient(to bottom, color.adjust($shadowColor, $alpha: -0.75), color.adjust($shadowColor, $alpha: -1)); + width: 100%; + opacity: 0.5; + } + } + + + .table-body-row, + + .table-foot-row { + .table-body-row-cell, + .table-foot-row-cell { + border-top: 0; + } + } +} + +@mixin stickyHeader { + .table-head-row-cell { + top: 0; + } +} + +@mixin stickyHeaderBanner { + .table-head-row-cell { + top: var(commons-banner-height); + } + + .table-body-row-cell, + .table-foot-row-cell { + top: calc( + var(commons-banner-height) + var(--sticky-header-shadow-offset-top) + var(--components-tableFixed-column-sticky-shadow-width) + ); + + .stickyHeader-shadow-wrapper { + &::after { + top: calc( + var(commons-banner-height) + var(--sticky-header-shadow-offset-top) + var(--components-tableFixed-column-sticky-shadow-width) + ); + } + } + } +} diff --git a/packages/scss/src/components/tableStickedDeprecated/states.scss b/packages/scss/src/components/tableStickedDeprecated/states.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/scss/src/components/tableStickedDeprecated/vars.scss b/packages/scss/src/components/tableStickedDeprecated/vars.scss new file mode 100644 index 0000000000..e1437ec436 --- /dev/null +++ b/packages/scss/src/components/tableStickedDeprecated/vars.scss @@ -0,0 +1,8 @@ +@mixin vars { + // --components-table-sticky-column-max-offset: 50; + // --components-tableFixed-column-min-col-width: 2; + // --components-tableFixed-column-max-col-width: 20; + // --components-tableFixed-column-sticky-shadow-color: #2a3551; + + --components-tableFixed-column-sticky-shadow-width: 0.625rem; +} diff --git a/packages/scss/src/components/textField/component.scss b/packages/scss/src/components/textField/component.scss index 8c580535ec..9bdddb7d80 100644 --- a/packages/scss/src/components/textField/component.scss +++ b/packages/scss/src/components/textField/component.scss @@ -8,6 +8,7 @@ align-items: stretch; border-radius: var(--commons-borderRadius-M); background-color: var(--component-textField-background); + box-shadow: 0 0 0 1px var(--component-textField-border); &:has(.textField-input-value:focus-visible) { @include a11y.focusVisible($offset: 3px); @@ -18,7 +19,6 @@ display: flex; align-items: center; width: 100%; - box-shadow: 0 0 0 1px var(--component-textField-border); border-radius: var(--commons-borderRadius-M); background-color: var(--component-textField-background); position: relative; @@ -66,7 +66,10 @@ &:is(textarea) { resize: vertical; min-height: calc(2lh + var(--component-textField-padding) * 2); - height: calc(3lh + var(--component-textField-padding) * 2); + + &:not([rows]) { + height: calc(3lh + var(--component-textField-padding) * 2); + } } } @@ -97,12 +100,11 @@ .textField-prefix { display: flex; - padding: 0 var(--component-textField-padding); + padding-left: var(--component-textField-padding); align-items: center; color: var(--component-textField-prefix-color); line-height: var(--component-textField-lineHeight); font-size: var(--component-textField-fontSize); - box-shadow: 0 0 0 1px var(--component-textField-border); border-top-left-radius: var(--commons-borderRadius-M); border-bottom-left-radius: var(--commons-borderRadius-M); @@ -114,12 +116,11 @@ .textField-suffix { display: flex; - padding: 0 var(--component-textField-padding); + padding-right: var(--component-textField-padding); align-items: center; color: var(--component-textField-prefix-color); line-height: var(--component-textField-lineHeight); font-size: var(--component-textField-fontSize); - box-shadow: 0 0 0 1px var(--component-textField-border); border-top-right-radius: var(--commons-borderRadius-M); border-bottom-right-radius: var(--commons-borderRadius-M); order: 1; diff --git a/packages/scss/src/components/textField/index.scss b/packages/scss/src/components/textField/index.scss index b24cc9ab2d..3ba2234d8c 100644 --- a/packages/scss/src/components/textField/index.scss +++ b/packages/scss/src/components/textField/index.scss @@ -12,11 +12,17 @@ @include XS; } - &.is-invalid, &:has(.textField-input-value[aria-invalid='true']) { + &.mod-valueAlignRight { + @include valueAlignRight; + } + + &.is-invalid, + &:has(.textField-input-value[aria-invalid='true']) { @include invalid; } - &.is-disabled, &:has(.textField-input-value:disabled) { + &.is-disabled, + &:has(.textField-input-value:disabled) { @include disabled; } } diff --git a/packages/scss/src/components/textField/mods.scss b/packages/scss/src/components/textField/mods.scss index 3649aa1db9..c6fefb597c 100644 --- a/packages/scss/src/components/textField/mods.scss +++ b/packages/scss/src/components/textField/mods.scss @@ -4,7 +4,7 @@ @mixin S { --component-textField-fontSize: var(--sizes-S-fontSize); --component-textField-lineHeight: var(--sizes-S-lineHeight); - --component-textField-padding: var(--pr-t-spacings-75); + --component-textField-padding: var(--pr-t-spacings-75); .textField-input-affix-clear { @include clear.S; @@ -18,9 +18,10 @@ @mixin XS { --component-textField-fontSize: var(--sizes-XS-fontSize); --component-textField-lineHeight: var(--sizes-XS-lineHeight); - --component-textField-padding: var(--pr-t-spacings-50); + --component-textField-padding: var(--pr-t-spacings-50); - .textField-prefix, .textField-suffix { + .textField-prefix, + .textField-suffix { @include icon.XS; } @@ -32,3 +33,9 @@ @include clear.S; } } + +@mixin valueAlignRight { + .textField-input-value { + text-align: right; + } +} diff --git a/packages/scss/src/components/textfields/mods.scss b/packages/scss/src/components/textfields/mods.scss index f6a5b87bcb..74053bf570 100644 --- a/packages/scss/src/components/textfields/mods.scss +++ b/packages/scss/src/components/textfields/mods.scss @@ -32,29 +32,6 @@ bottom: var(--pr-t-spacings-150); right: var(--pr-t-spacings-100); } - - .textfield-actionClear { - // deprecated - text-align: center; - position: absolute; - bottom: var(--pr-t-spacings-150); - right: var(--pr-t-spacings-100); - width: 1rem; - height: 1rem; - padding: 0; - line-height: 0; - border-radius: var(--commons-borderRadius-full); - background-color: var(--palettes-neutral-700); - - &:hover { - background-color: var(--palettes-neutral-600); - } - - .lucca-icon { - font-size: var(--sizes-XS-lineHeight); - color: white; - } - } } @mixin clearableS { @@ -62,12 +39,6 @@ bottom: var(--pr-t-spacings-100); right: var(--pr-t-spacings-50); } - - .textfield-actionClear { - // deprecated - bottom: var(--pr-t-spacings-50); - right: var(--pr-t-spacings-50); - } } @mixin clearableXS { @@ -75,29 +46,12 @@ bottom: var(--pr-t-spacings-50); right: var(--pr-t-spacings-50); } - - .textfield-actionClear { - // deprecated - bottom: var(--pr-t-spacings-50); - right: var(--pr-t-spacings-50); - height: 1rem; - width: 1rem; - - .lucca-icon { - font-size: 1rem; - } - } } @mixin suffix { .textfield-input { padding-right: var(--components-textfield-suffix-padding-right); } - - .textfield-actionClear { - // deprecated - right: 2rem; - } } @mixin noLabel { @@ -236,11 +190,6 @@ } } } - - .textfield-actionClear { - // deprecated - right: 2.5rem; - } } @mixin searchClearable { @@ -251,11 +200,6 @@ .textfield-clear { right: 2.5rem; } - - .textfield-actionClear { - // deprecated - right: 2.5rem; - } } @mixin searchS { @@ -269,18 +213,6 @@ .textfield-input { padding-right: 2rem; } - - .textfield-actionClear { - // deprecated - right: 2.125rem; - bottom: 0.625rem; - width: 0.75rem; - height: 0.75rem; - - .lucca-icon { - font-size: 0.75rem; - } - } } @mixin searchClearableS { @@ -294,12 +226,6 @@ right: 2.125rem; bottom: 0.625rem; } - - .textfield-actionClear { - // deprecated - right: 2.125rem; - bottom: 0.625rem; - } } @mixin searchXS { @@ -313,18 +239,6 @@ .textfield-input { padding-right: 1.5rem; } - - .textfield-actionClear { - // deprecated - right: 1.75rem; - bottom: 0.375rem; - width: 0.75rem; - height: 0.75rem; - - .lucca-icon { - font-size: 0.75rem; - } - } } @mixin searchClearableXS { @@ -338,18 +252,6 @@ right: 1.75rem; bottom: var(--pr-t-spacings-75); } - - .textfield-actionClear { - // deprecated - right: 1.75rem; - bottom: 0.375rem; - width: 0.75rem; - height: 0.75rem; - - .lucca-icon { - font-size: 0.75rem; - } - } } @mixin radio { diff --git a/packages/scss/src/components/textfields/states.scss b/packages/scss/src/components/textfields/states.scss index 5b682a8db0..ca14582166 100644 --- a/packages/scss/src/components/textfields/states.scss +++ b/packages/scss/src/components/textfields/states.scss @@ -24,12 +24,6 @@ --components-clear-cross-color: var(--palettes-neutral-500) !important; pointer-events: none; } - - ~ .textfield-actionClear { - // deprecated - color: var(--palettes-neutral-500) !important; - pointer-events: none; - } } @mixin filterHover { diff --git a/packages/scss/src/components/timepicker/component.scss b/packages/scss/src/components/timepicker/component.scss index 952d1cbb01..1225073a5c 100644 --- a/packages/scss/src/components/timepicker/component.scss +++ b/packages/scss/src/components/timepicker/component.scss @@ -1,91 +1,141 @@ @use '@lucca-front/scss/src/commons/utils/a11y'; +@use '@lucca-front/icons/src/icon/exports' as icons; @mixin component($atRoot: 'without: rule') { padding: var(--components-timepicker-padding); - border: 0; - border-radius: var(--commons-borderRadius-M); - box-shadow: 0 0 0 1px var(--palettes-neutral-300); - display: inline-flex; - background-color: var(--pr-t-elevation-surface-raised); - transition: box-shadow var(--commons-animations-durations-fast); - - &:focus-within { - @include a11y.focusVisible($offset: 3px); - background-color: transparent; - } + width: fit-content; @at-root ($atRoot) { - .timepicker-field { + .timePicker-fieldset { + display: flex; + align-items: center; + box-shadow: 0 0 0 1px var(--components-timepicker-border); + border-radius: var(--commons-borderRadius-M); + padding: 0; + border: 0; + margin: 0; + background-color: var(--components-timepicker-background); + color: var(--components-timepicker-color); + font-size: var(--components-timepicker-fontSize); + line-height: var(--components-timepicker-lineHeight); position: relative; - display: inline-block; + cursor: text; + + &:hover { + --components-timepicker-border: var(--palettes-neutral-400); + } + + &:focus-within { + @include a11y.focusVisible($offset: 3px); + } } - .timepicker-field-input { + .timePicker-fieldset-groupSeparator { + text-align: center; + position: absolute; + inset: 0; + pointer-events: none; + display: grid; + place-items: center; + } + + .timePicker-fieldset-group { + position: relative; + } + + .timePicker-fieldset-group-textfield { background-color: transparent; - border-radius: var(--commons-borderRadius-M); + } + + .timePicker-fieldset-group-textfield-input { + display: flex; + align-items: center; + justify-content: center; + border: 0; text-align: center; - color: var(--palettes-neutral-800); - width: var(--components-timepicker-input-width); height: var(--components-timepicker-input-height); - border: 0; - padding: 0; - -moz-appearance: textfield; + width: var(--components-timepicker-input-width); + outline: none; + color: inherit; + background-color: transparent; + text-align: center; + padding: var(--components-timepicker-paddingInput); + box-sizing: content-box; - &::-webkit-outer-spin-button, - &::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; + //&:has(+ .timePicker-fieldset-group-textfield-display) { + opacity: 0.0001; + //} + + /* + &[type='number'] { + -moz-appearance: textfield; + + &::-webkit-outer-spin-button, + &::-webkit-inner-spin-button { + -webkit-appearance: none; + } + } + */ + + &::placeholder { + color: var(--component-textField-placeholder); } - &:hover, - &:focus, &:focus-visible { - background-color: var(--palettes-100, var(--palettes-product-100)); - outline: none; + & + .timePicker-fieldset-group-textfield-display { + background-color: var(--palettes-primary-100); + } } } - .timepicker-field-increment { - cursor: pointer; + .timePicker-fieldset-group-textfield-display { + position: absolute; + inset: var(--components-timepicker-paddingInput); + border-radius: var(--commons-borderRadius-M); + pointer-events: none; + display: grid; + place-items: center; + } + + .timePicker-fieldset-group-stepper { position: absolute; - bottom: calc(100% + 0.5rem + 1px); - left: 0; + bottom: calc(100% + var(--pr-t-spacings-100) + 1px); + left: var(--pr-t-spacings-100); + right: var(--pr-t-spacings-100); border: 0; - height: 1.25rem; + padding: 0; + height: var(--pr-t-spacings-200); background-color: transparent; color: var(--palettes-neutral-600); display: inline-flex; justify-content: center; align-items: center; border-radius: var(--commons-borderRadius-M); - width: var(--components-timepicker-input-width); - padding: 0; - - &:last-child { - top: calc(100% + 0.5rem + 1px); - bottom: auto; - } + outline: none; + opacity: 1; + transition-property: opacity; + transition-duration: var(--commons-animations-durations-fast); + cursor: pointer; &:hover { background-color: var(--palettes-neutral-50); color: var(--palettes-neutral-800); } - &:focus { - background-color: var(--palettes-neutral-100); - color: var(--palettes-neutral-800); + &:disabled { + cursor: default; + color: var(--palettes-neutral-500); + pointer-events: none; } .lucca-icon { - font-size: 1rem; + @include icons.XS; } - } - .timepicker-separator { - margin: 0 var(--pr-t-spacings-50); - text-align: center; - width: 0.5rem; - line-height: var(--components-timepicker-input-height); + + .timePicker-fieldset-group-stepper { + top: calc(100% + var(--pr-t-spacings-100) + 1px); + bottom: auto; + } } } } diff --git a/packages/scss/src/components/timepicker/index.scss b/packages/scss/src/components/timepicker/index.scss index 9b1422669d..2b272f202d 100644 --- a/packages/scss/src/components/timepicker/index.scss +++ b/packages/scss/src/components/timepicker/index.scss @@ -1,6 +1,7 @@ @use 'exports' as *; +@use '@lucca-front/scss/src/commons/utils/a11y'; -.timepicker { +.timePicker { @include vars; @include component; @@ -8,7 +9,19 @@ @include S; } - &:is(.is-disabled, .disabled, [disabled]) { + &.mod-stepper { + @include stepper; + } + + &.mod-stepperHover { + @include stepperHover; + } + + &:has([aria-invalid='true']) { + @include invalid; + } + + &:has([disabled]) { @include disabled; } } diff --git a/packages/scss/src/components/timepicker/mods.scss b/packages/scss/src/components/timepicker/mods.scss index 6c200147fa..09e53f3221 100644 --- a/packages/scss/src/components/timepicker/mods.scss +++ b/packages/scss/src/components/timepicker/mods.scss @@ -1,4 +1,21 @@ +@use '@lucca-front/scss/src/commons/utils/a11y'; + @mixin S { - --components-timepicker-input-height: 1.5rem; - --components-timepicker-padding: var(--pr-t-spacings-50); + --components-timepicker-fontSize: var(--sizes-S-fontSize); + --components-timepicker-lineHeight: var(--sizes-S-lineHeight); + --components-timepicker-paddingInput: var(--pr-t-spacings-25) var(--pr-t-spacings-75); + --components-timepicker-input-height: 1.75rem; + --components-timepicker-input-width: 1.25rem; +} + +@mixin stepper { + --components-timepicker-padding: var(--pr-t-spacings-300) 0; +} + +@mixin stepperHover { + &:not(:hover, :focus-within) { + .timePicker-fieldset-group-stepper { + opacity: 0; + } + } } diff --git a/packages/scss/src/components/timepicker/states.scss b/packages/scss/src/components/timepicker/states.scss index d52ffd02f2..e203ac77b2 100644 --- a/packages/scss/src/components/timepicker/states.scss +++ b/packages/scss/src/components/timepicker/states.scss @@ -1,13 +1,16 @@ -@mixin disabled { - background-color: var(--palettes-neutral-100); - color: var(--palettes-neutral-600); +@use '@lucca-front/scss/src/commons/utils/a11y'; - .timepicker-field-input { - background: transparent; - color: var(--palettes-neutral-600); - } +@mixin invalid { + --components-timepicker-background: var(--palettes-error-50); + --components-timepicker-border: var(--palettes-error-400); - .timepicker-field-increment { - display: none; + &:hover { + --components-timepicker-border: var(--palettes-error-600); } } + +@mixin disabled { + --components-timepicker-background: var(--palettes-neutral-100); + --components-timepicker-border: var(--palettes-neutral-400); + --components-timepicker-color: var(--palettes-neutral-600); +} diff --git a/packages/scss/src/components/timepicker/vars.scss b/packages/scss/src/components/timepicker/vars.scss index a1b74197ff..756d13f682 100644 --- a/packages/scss/src/components/timepicker/vars.scss +++ b/packages/scss/src/components/timepicker/vars.scss @@ -1,5 +1,11 @@ @mixin vars { - --components-timepicker-input-width: 1.25rem; - --components-timepicker-input-height: 2rem; - --components-timepicker-padding: var(--pr-t-spacings-50) var(--pr-t-spacings-100); + --components-timepicker-border: var(--palettes-neutral-300); + --components-timepicker-background: var(--colors-white-color); + --components-timepicker-color: var(--palettes-neutral-800); + --components-timepicker-fontSize: var(--sizes-M-fontSize); + --components-timepicker-lineHeight: var(--sizes-M-lineHeight); + --components-timepicker-input-height: 2rem; + --components-timepicker-input-width: 1.5rem; + --components-timepicker-padding: 0; + --components-timepicker-paddingInput: var(--pr-t-spacings-50) var(--pr-t-spacings-100); } diff --git a/packages/scss/src/components/timepickerDeprecated/component.scss b/packages/scss/src/components/timepickerDeprecated/component.scss new file mode 100644 index 0000000000..952d1cbb01 --- /dev/null +++ b/packages/scss/src/components/timepickerDeprecated/component.scss @@ -0,0 +1,91 @@ +@use '@lucca-front/scss/src/commons/utils/a11y'; + +@mixin component($atRoot: 'without: rule') { + padding: var(--components-timepicker-padding); + border: 0; + border-radius: var(--commons-borderRadius-M); + box-shadow: 0 0 0 1px var(--palettes-neutral-300); + display: inline-flex; + background-color: var(--pr-t-elevation-surface-raised); + transition: box-shadow var(--commons-animations-durations-fast); + + &:focus-within { + @include a11y.focusVisible($offset: 3px); + background-color: transparent; + } + + @at-root ($atRoot) { + .timepicker-field { + position: relative; + display: inline-block; + } + + .timepicker-field-input { + background-color: transparent; + border-radius: var(--commons-borderRadius-M); + text-align: center; + color: var(--palettes-neutral-800); + width: var(--components-timepicker-input-width); + height: var(--components-timepicker-input-height); + border: 0; + padding: 0; + -moz-appearance: textfield; + + &::-webkit-outer-spin-button, + &::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + + &:hover, + &:focus, + &:focus-visible { + background-color: var(--palettes-100, var(--palettes-product-100)); + outline: none; + } + } + + .timepicker-field-increment { + cursor: pointer; + position: absolute; + bottom: calc(100% + 0.5rem + 1px); + left: 0; + border: 0; + height: 1.25rem; + background-color: transparent; + color: var(--palettes-neutral-600); + display: inline-flex; + justify-content: center; + align-items: center; + border-radius: var(--commons-borderRadius-M); + width: var(--components-timepicker-input-width); + padding: 0; + + &:last-child { + top: calc(100% + 0.5rem + 1px); + bottom: auto; + } + + &:hover { + background-color: var(--palettes-neutral-50); + color: var(--palettes-neutral-800); + } + + &:focus { + background-color: var(--palettes-neutral-100); + color: var(--palettes-neutral-800); + } + + .lucca-icon { + font-size: 1rem; + } + } + + .timepicker-separator { + margin: 0 var(--pr-t-spacings-50); + text-align: center; + width: 0.5rem; + line-height: var(--components-timepicker-input-height); + } + } +} diff --git a/packages/scss/src/components/timepickerDeprecated/exports.scss b/packages/scss/src/components/timepickerDeprecated/exports.scss new file mode 100644 index 0000000000..150ea9d703 --- /dev/null +++ b/packages/scss/src/components/timepickerDeprecated/exports.scss @@ -0,0 +1,5 @@ +@forward 'vars'; +@forward 'mods'; +@forward 'states'; +@forward 'component'; +@forward 'todo-new-timepicker'; diff --git a/packages/scss/src/components/timepickerDeprecated/index.scss b/packages/scss/src/components/timepickerDeprecated/index.scss new file mode 100644 index 0000000000..9b1422669d --- /dev/null +++ b/packages/scss/src/components/timepickerDeprecated/index.scss @@ -0,0 +1,14 @@ +@use 'exports' as *; + +.timepicker { + @include vars; + @include component; + + &.mod-S { + @include S; + } + + &:is(.is-disabled, .disabled, [disabled]) { + @include disabled; + } +} diff --git a/packages/scss/src/components/timepickerDeprecated/mods.scss b/packages/scss/src/components/timepickerDeprecated/mods.scss new file mode 100644 index 0000000000..5eb0116a74 --- /dev/null +++ b/packages/scss/src/components/timepickerDeprecated/mods.scss @@ -0,0 +1,4 @@ +@mixin S { + --components-timepicker-input-height: 1.5rem; + --components-timepicker-padding: var(--pr-t-spacings-50); +} diff --git a/packages/scss/src/components/timepickerDeprecated/states.scss b/packages/scss/src/components/timepickerDeprecated/states.scss new file mode 100644 index 0000000000..d52ffd02f2 --- /dev/null +++ b/packages/scss/src/components/timepickerDeprecated/states.scss @@ -0,0 +1,13 @@ +@mixin disabled { + background-color: var(--palettes-neutral-100); + color: var(--palettes-neutral-600); + + .timepicker-field-input { + background: transparent; + color: var(--palettes-neutral-600); + } + + .timepicker-field-increment { + display: none; + } +} diff --git a/packages/scss/src/components/timepickerDeprecated/vars.scss b/packages/scss/src/components/timepickerDeprecated/vars.scss new file mode 100644 index 0000000000..a1b74197ff --- /dev/null +++ b/packages/scss/src/components/timepickerDeprecated/vars.scss @@ -0,0 +1,5 @@ +@mixin vars { + --components-timepicker-input-width: 1.25rem; + --components-timepicker-input-height: 2rem; + --components-timepicker-padding: var(--pr-t-spacings-50) var(--pr-t-spacings-100); +} diff --git a/packages/scss/src/components/toast/component.scss b/packages/scss/src/components/toast/component.scss index 56461cd814..54930348a1 100644 --- a/packages/scss/src/components/toast/component.scss +++ b/packages/scss/src/components/toast/component.scss @@ -1,76 +1,77 @@ -@use '@lucca-front/scss/src/commons/utils/reset'; -@use '@lucca-front/icons/src/commons/utils/icon'; +@use '@lucca-front/scss/src/components/button/exports' as button; @mixin component($atRoot: 'without: rule') { - @keyframes toast { - 0% { - transform: translateY(var(--pr-t-spacings-200)); - opacity: 0; - } - - 100% { - opacity: 1; - } - } - - right: var(--components-toasts-right); - top: var(--components-toasts-top); max-width: var(--components-toasts-maxwidth); display: flex; flex-direction: column; align-items: flex-end; position: fixed; z-index: 9999; + inset: var(--components-toasts-inset); @at-root ($atRoot) { .toasts-item { display: flex; - gap: var(--pr-t-spacings-150); + gap: var(--pr-t-spacings-50); color: var(--components-toasts-color); - padding: var(--components-toasts-padding); + padding: var(--pr-t-spacings-50); margin-bottom: var(--components-toasts-margin-bottom); - background-color: var(--palettes-800, var(--components-toasts-background)); - animation-name: toast; + background-color: var(--palettes-neutral-800); + animation-name: toastsItem; animation-duration: var(--commons-animations-durations-standard); animation-iteration-count: 1; - border-radius: var(--commons-borderRadius-M); + border-radius: var(--commons-borderRadius-XL); overflow: hidden; position: relative; transform-origin: top; + + @keyframes toastsItem { + 0% { + transform: translateY(var(--pr-t-spacings-200)); + opacity: 0; + } + + 100% { + opacity: 1; + } + } + + &:hover, + &:focus-within { + .toasts-item-kill { + animation-play-state: paused; + } + } } .toast-item-icon { - margin-top: 2px; + background: var(--palettes-700, var(--palettes-product-700)); + border-radius: var(--commons-borderRadius-L); + padding: var(--pr-t-spacings-100) var(--pr-t-spacings-50); } .toast-item-content { - flex-grow: 1; display: flex; + flex-grow: 1; flex-direction: column; - gap: var(--pr-t-spacings-100); + gap: var(--pr-t-spacings-50); + padding: var(--pr-t-spacings-100) 0 var(--pr-t-spacings-100) var(--pr-t-spacings-100); } .toasts-item-kill { - @include reset.button; - width: auto; - color: var(--colors-white-color); - transition-property: opacity; - transition-duration: var(--commons-animations-durations-fast); - height: 1.25rem; - min-width: 1.25rem; - cursor: pointer; - position: relative; - border: 0; - background: transparent; - margin-top: 2px; + // the button class should be added to the component, but in the meantime we initialize the component here + @include button.vars; + @include button.component; - &:hover { - opacity: 0.66; - } + @include button.onlyIcon; + @include button.text; + @include button.inverted; - &::after { - @include icon.generate('sign_close'); - } + @keyframes timer {} + + align-self: flex-start; + border-radius: var(--commons-borderRadius-L); + animation-name: timer; } } } diff --git a/packages/scss/src/components/toast/index.scss b/packages/scss/src/components/toast/index.scss index 199b2c6a6b..6bde5b2fe4 100644 --- a/packages/scss/src/components/toast/index.scss +++ b/packages/scss/src/components/toast/index.scss @@ -7,8 +7,4 @@ &.mod-bottom { @include bottom; } - - &.mod-withCircularGauge { - @include circularGauge; - } } diff --git a/packages/scss/src/components/toast/mods.scss b/packages/scss/src/components/toast/mods.scss index 680617f69e..41ddc35e8d 100644 --- a/packages/scss/src/components/toast/mods.scss +++ b/packages/scss/src/components/toast/mods.scss @@ -1,95 +1,3 @@ @mixin bottom { - top: auto; - bottom: var(--pr-t-spacings-300); -} - -@mixin circularGauge { - @keyframes stroke { - 0% { - stroke-dashoffset: 100.5; - } - - 100% { - stroke-dashoffset: 0; - } - } - - &:hover { - .circularGauge { - circle { - animation-play-state: paused; - } - } - } - - &:focus-within { - .circularGauge { - circle { - animation-play-state: paused; - } - } - } - - .toasts-item-kill { - transition: transform 100ms, opacity 100ms; - - .lucca-icon { - position: absolute; - inset: 0; - display: flex; - align-items: center; - justify-content: center; - z-index: 2; - } - - &::after { - content: none; - } - - &:hover, - &:focus { - outline: 0; - opacity: 0.66; - } - - .circularGauge { - color: transparent; - height: 1.25rem; - pointer-events: none; - position: absolute; - top: 0; - left: 0; - width: 1.25rem; - - &::after { - position: absolute; - background-color: transparent; - left: 2px; - top: 2px; - width: calc(100% - 4px); - height: calc(100% - 4px); - z-index: 1; - border-radius: var(--commons-borderRadius-full); - content: ''; - } - - svg { - transform: rotate(-90deg); - border-radius: var(--commons-borderRadius-full); - width: 100%; - height: auto; - display: block; - } - - circle { - stroke-width: 20%; - stroke-dasharray: 100.5, 100.5; - stroke: var(--colors-white-color); - fill: currentColor; - animation-name: stroke; - animation-timing-function: linear; - animation-fill-mode: forwards; - } - } - } + --components-toasts-inset: auto var(--components-toasts-right) var(--components-toasts-bottom) auto; } diff --git a/packages/scss/src/components/toast/vars.scss b/packages/scss/src/components/toast/vars.scss index e72ea8b43e..8ae82837a7 100644 --- a/packages/scss/src/components/toast/vars.scss +++ b/packages/scss/src/components/toast/vars.scss @@ -1,11 +1,14 @@ @mixin vars { - --components-toasts-background: var(--palettes-neutral-900); --components-toasts-color: var(--colors-white-color); --components-toasts-top: var(--pr-t-spacings-300); --components-toasts-right: var(--pr-t-spacings-300); --components-toasts-left: var(--pr-t-spacings-300); --components-toasts-bottom: var(--pr-t-spacings-300); - --components-toasts-margin-bottom: var(--pr-t-spacings-100); + --components-toasts-margin-bottom: var(--pr-t-spacings-50); --components-toasts-maxwidth: 22.5rem; + --components-toasts-inset: var(--components-toasts-top) var(--components-toasts-right) auto auto; + + // Deprecated + --components-toasts-background: var(--palettes-neutral-800); --components-toasts-padding: var(--pr-t-spacings-100) var(--pr-t-spacings-200); } diff --git a/packages/scss/src/components/tooltip/component.scss b/packages/scss/src/components/tooltip/component.scss new file mode 100644 index 0000000000..319c62c0b0 --- /dev/null +++ b/packages/scss/src/components/tooltip/component.scss @@ -0,0 +1,24 @@ +@use '@lucca-front/scss/src/commons/utils/keyframe'; + +@mixin component($atRoot: 'without: rule') { + @include keyframe.scaleIn; + + background-color: var(--components-tooltip-background-color); + color: var(--components-tooltip-color); + padding: var(--pr-t-spacings-50) var(--pr-t-spacings-100); + max-width: var(--components-tooltip-max-width); + border-radius: var(--commons-borderRadius-M); + font-size: var(--sizes-XS-fontSize); + line-height: var(--sizes-XS-lineHeight); + transform-origin: var(--components-tooltip-transformOrigin); + margin: var(--components-tooltip-margin); + text-align: center; + width: fit-content; + animation-name: scaleIn; + animation-duration: var(--commons-animations-durations-fast); + animation-iteration-count: 1; + + &:empty { + display: none; + } +} diff --git a/packages/scss/src/components/tooltip/exports.scss b/packages/scss/src/components/tooltip/exports.scss new file mode 100644 index 0000000000..2c2986a26b --- /dev/null +++ b/packages/scss/src/components/tooltip/exports.scss @@ -0,0 +1,4 @@ +@forward 'vars'; +@forward 'mods'; +@forward 'states'; +@forward 'component'; diff --git a/packages/scss/src/components/tooltip/index.scss b/packages/scss/src/components/tooltip/index.scss new file mode 100644 index 0000000000..cda170225a --- /dev/null +++ b/packages/scss/src/components/tooltip/index.scss @@ -0,0 +1,38 @@ +@use 'exports' as *; + +.tooltip { + @include vars; + @include component; + + &.is-above { + @include above; + } + + &.is-below { + @include below; + } + + &.is-before { + @include before; + + &.is-above { + @include beforeAbove; + } + + &.is-below { + @include beforeBelow; + } + } + + &.is-after { + @include after; + + &.is-above { + @include afterAbove; + } + + &.is-below { + @include afterBelow; + } + } +} diff --git a/packages/scss/src/components/tooltip/mods.scss b/packages/scss/src/components/tooltip/mods.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/scss/src/components/tooltip/states.scss b/packages/scss/src/components/tooltip/states.scss new file mode 100644 index 0000000000..8bfe288dce --- /dev/null +++ b/packages/scss/src/components/tooltip/states.scss @@ -0,0 +1,31 @@ +@mixin above { + --components-tooltip-transformOrigin: bottom center; +} + +@mixin below { + --components-tooltip-transformOrigin: top center; +} + +@mixin before { + --components-tooltip-transformOrigin: center right; +} + +@mixin after { + --components-tooltip-transformOrigin: center left; +} + +@mixin beforeAbove { + --components-tooltip-transformOrigin: bottom right; +} + +@mixin beforeBelow { + --components-tooltip-transformOrigin: top right; +} + +@mixin afterAbove { + --components-tooltip-transformOrigin: bottom left; +} + +@mixin afterBelow { + --components-tooltip-transformOrigin: top left; +} diff --git a/packages/scss/src/components/tooltip/vars.scss b/packages/scss/src/components/tooltip/vars.scss new file mode 100644 index 0000000000..90d56d764a --- /dev/null +++ b/packages/scss/src/components/tooltip/vars.scss @@ -0,0 +1,7 @@ +@mixin vars { + --components-tooltip-background-color: var(--palettes-neutral-900); + --components-tooltip-color: var(--colors-white-color); + --components-tooltip-max-width: 15rem; + --components-tooltip-transformOrigin: center; + --components-tooltip-margin: 0; +} diff --git a/packages/scss/src/components/userPopover/component.scss b/packages/scss/src/components/userPopover/component.scss index e142d82e35..96823b9bc2 100644 --- a/packages/scss/src/components/userPopover/component.scss +++ b/packages/scss/src/components/userPopover/component.scss @@ -1,48 +1,44 @@ -@use '@lucca-front/scss/src/commons/utils/text'; - @mixin component($atRoot: 'without: rule') { - width: 22.5rem; + width: 23.5rem; max-width: calc(100vw - var(--spacings-S) * 2); padding: var(--spacings-S); @at-root ($atRoot) { .userPopover-details { - --components-user-picture-image-size: 5.25rem; + --components-user-picture-image-size: var(--components-userPicture-XXXL-image); + display: flex; - align-items: center; + align-items: flex-start; gap: var(--spacings-S); } .userPopover-details-avatar { - --components-user-picture-font-size: var(--sizes-XXL-fontSize); + --components-user-picture-font-size: var(--components-userPicture-XXXL-fontSize); margin: var(--spacings-XXS) 0; } .userPopover-details-info { - width: calc(100% - var(--components-user-picture-image-size) - var(--spacings-S)); + min-width: 0; } .userPopover-details-info-name { - @include text.ellipsis; - - margin: 0; - padding: 0; - } - - .userPopover-details-info-name-link { - color: var(--palettes-grey-900); + margin: calc(var(--pr-t-spacings-50) * -1); + padding: var(--pr-t-spacings-50); font-size: var(--sizes-L-fontSize); line-height: var(--sizes-L-lineHeight); font-weight: 700; + color: currentColor; + } + + .userPopover-details-info-name-linkOptional { + color: currentColor; text-decoration: underline; text-decoration-thickness: 0.75px; text-underline-offset: 3px; - &:hover, - &:active, - &:focus { - color: var(--palettes-grey-900); + &:hover { + color: currentColor; text-decoration-thickness: 1.5px; } } @@ -55,19 +51,15 @@ .userPopover-details-info-detail-workplace { display: flex; - align-items: center; + align-items: flex-start; gap: var(--spacings-XXS); - margin-top: var(--spacings-XS); - color: var(--palettes-grey-800); + color: currentColor; text-decoration: none; - &.mod-link { - text-decoration: none; - + &:is(a, button) { &:hover, - &:active, &:focus { - color: var(--palettes-grey-800); + color: currentColor; .userPopover-details-info-detail-workplace-state { text-decoration: underline; @@ -75,10 +67,5 @@ } } } - - .userPopover-details-info-detail, - .userPopover-details-info-detail-link-state { - @include text.ellipsis; - } } } diff --git a/stories/documentation/actions/button/angular/button-basic.stories.ts b/stories/documentation/actions/button/angular/button-basic.stories.ts index 5f42dc42f1..adf5eac30b 100644 --- a/stories/documentation/actions/button/angular/button-basic.stories.ts +++ b/stories/documentation/actions/button/angular/button-basic.stories.ts @@ -7,7 +7,7 @@ export default { component: ButtonComponent, render: ({ luButton, ...inputs }, { argTypes }) => { return { - template: ``, }; }, diff --git a/stories/documentation/feedback/callout/html&css/callout-tiny.stories.ts b/stories/documentation/feedback/callout/html&css/callout-tiny.stories.ts deleted file mode 100644 index 33e7aa9292..0000000000 --- a/stories/documentation/feedback/callout/html&css/callout-tiny.stories.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Meta, StoryFn } from '@storybook/angular'; - -interface CalloutTinyStory { - s: boolean; - palette: string; - icon: string; -} - -export default { - title: 'Documentation/Feedback/Callout/HTML & CSS/Tiny', - argTypes: { - s: { - control: { - type: 'boolean', - }, - description: 'Taille : Small', - }, - palette: { - options: ['', 'palette-success', 'palette-warning', 'palette-error'], - control: { - type: 'select', - }, - }, - icon: { - options: ['icon-signHelp', 'icon-signSuccess', 'icon-signWarning', 'icon-signError'], - control: { - type: 'select', - }, - }, - }, -} as Meta; - -function getTemplate(args: CalloutTinyStory): string { - const s = args.s ? ` mod-S` : ''; - let palette = args.palette; - const icon = args.icon ? ' ' + args.icon : ''; - palette = ' ' + palette; - return `
-
- -
-
- 99 -
-
`; -} - -const Template: StoryFn = (args) => ({ - props: args, - template: getTemplate(args), -}); - -export const Tiny = Template.bind({}); -Tiny.args = { s: false, icon: 'icon-signHelp', palette: '' }; diff --git a/stories/documentation/feedback/empty-state/angular/empty-state-page.stories.ts b/stories/documentation/feedback/empty-state/angular/empty-state-page.stories.ts index ae7b633174..e8acaf9f2f 100644 --- a/stories/documentation/feedback/empty-state/angular/empty-state-page.stories.ts +++ b/stories/documentation/feedback/empty-state/angular/empty-state-page.stories.ts @@ -12,7 +12,7 @@ export default { }), ], render: (args: EmptyStatePageComponent) => { - const { title, description, icon, topRightBackground, topRightForeground, bottomLeftBackground, bottomLeftForeground, contentBackgroundColor } = args; + const { title, description, icon, topRightBackground, topRightForeground, bottomLeftBackground, bottomLeftForeground, contentBackgroundColor, hx } = args; const paramIcon = args.icon === '' ? '' : 'icon="' + args.icon + '"'; return { @@ -34,6 +34,7 @@ export default { bottomLeftBackground="${bottomLeftBackground}" bottomLeftForeground="${bottomLeftForeground}" contentBackgroundColor="${contentBackgroundColor}" + hx="${hx}" > @@ -133,6 +134,13 @@ export default { type: 'text', }, }, + hx: { + control: { + type: 'number', + min: 1, + max: 6, + }, + }, }, } as Meta; @@ -146,5 +154,6 @@ export const Page: StoryObj = { bottomLeftBackground: 'https://cdn.lucca.fr/lucca-front/assets/empty-states/poplee/bubbles-bottom-left-01.svg', bottomLeftForeground: 'https://cdn.lucca.fr/lucca-front/assets/empty-states/poplee/core-hr-01.svg', contentBackgroundColor: 'var(--pr-t-elevation-surface-default)', + hx: 1, }, }; diff --git a/stories/documentation/feedback/empty-state/angular/empty-state-section.stories.ts b/stories/documentation/feedback/empty-state/angular/empty-state-section.stories.ts index 1bf4265197..0bcc4f83f9 100644 --- a/stories/documentation/feedback/empty-state/angular/empty-state-section.stories.ts +++ b/stories/documentation/feedback/empty-state/angular/empty-state-section.stories.ts @@ -13,10 +13,10 @@ export default { }), ], render: (args: EmptyStateSectionComponent) => { - const { title, description, center, palette, icon } = args; + const { title, description, center, palette, hx, icon } = args; const paramIcon = args.icon === '' ? '' : 'icon="' + args.icon + '"'; return { -template: ` + template: ` `, @@ -24,6 +24,13 @@ template: `

Empty State

-

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

+

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

diff --git a/stories/documentation/feedback/empty-state/html&css/empty-state-section-center.stories.ts b/stories/documentation/feedback/empty-state/html&css/empty-state-section-center.stories.ts index 2e6145a9eb..6f3f641f17 100644 --- a/stories/documentation/feedback/empty-state/html&css/empty-state-section-center.stories.ts +++ b/stories/documentation/feedback/empty-state/html&css/empty-state-section-center.stories.ts @@ -27,7 +27,7 @@ function getTemplate(args: EmptyStateSectionCenterStory): string { >

Empty State

-

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

+

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

diff --git a/stories/documentation/feedback/empty-state/html&css/empty-state-section-palette.stories.ts b/stories/documentation/feedback/empty-state/html&css/empty-state-section-palette.stories.ts index e13878ccc4..0972c617cb 100644 --- a/stories/documentation/feedback/empty-state/html&css/empty-state-section-palette.stories.ts +++ b/stories/documentation/feedback/empty-state/html&css/empty-state-section-palette.stories.ts @@ -27,7 +27,7 @@ function getTemplate(args: EmptyStateSectionPaletteStory): string { >

Empty State

-

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

+

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

diff --git a/stories/documentation/feedback/empty-state/html&css/empty-state-section.stories.ts b/stories/documentation/feedback/empty-state/html&css/empty-state-section.stories.ts index ea1a352a29..bbc3c38e58 100644 --- a/stories/documentation/feedback/empty-state/html&css/empty-state-section.stories.ts +++ b/stories/documentation/feedback/empty-state/html&css/empty-state-section.stories.ts @@ -1,9 +1,8 @@ -import { Meta, moduleMetadata, StoryFn } from '@storybook/angular'; +import { HttpClientModule } from '@angular/common/http'; import { LuSafeExternalSvgPipe } from '@lucca-front/ng/safe-content'; -import { HttpClientModule } from "@angular/common/http"; +import { Meta, moduleMetadata, StoryFn } from '@storybook/angular'; -interface EmptyStateSectionBasicStory { -} +interface EmptyStateSectionBasicStory {} export default { title: 'Documentation/Feedback/Empty State/HTML&CSS/Section', @@ -12,8 +11,7 @@ export default { imports: [LuSafeExternalSvgPipe, HttpClientModule], }), ], - argTypes: { - }, + argTypes: {}, } as Meta; function getTemplate(args: EmptyStateSectionBasicStory): string { @@ -27,7 +25,7 @@ function getTemplate(args: EmptyStateSectionBasicStory): string { >

Empty State

-

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

+

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

@@ -44,4 +42,4 @@ const Template: StoryFn = (args: EmptyStateSectionB }); export const Section = Template.bind({}); -Section.args = { }; +Section.args = {}; diff --git a/stories/documentation/feedback/error-page/error-page-basic.stories.ts b/stories/documentation/feedback/error-page/error-page-basic.stories.ts index 9269bd3fbd..a3199c756d 100644 --- a/stories/documentation/feedback/error-page/error-page-basic.stories.ts +++ b/stories/documentation/feedback/error-page/error-page-basic.stories.ts @@ -11,8 +11,8 @@ function getTemplate(args: ErrorBasicStory): string {
Erreur 403 diff --git a/stories/documentation/forms/checkbox/checkbox-basic.stories.ts b/stories/documentation/forms/checkbox/checkbox-basic.stories.ts index dd0a11e617..8c8c2b9196 100644 --- a/stories/documentation/forms/checkbox/checkbox-basic.stories.ts +++ b/stories/documentation/forms/checkbox/checkbox-basic.stories.ts @@ -92,7 +92,7 @@ function getTemplate(args: CheckboxBasicStory): string { return `
diff --git a/stories/documentation/forms/examples/angular/form-basic.stories.ts b/stories/documentation/forms/examples/angular/form-basic.stories.ts new file mode 100644 index 0000000000..eb5a731b86 --- /dev/null +++ b/stories/documentation/forms/examples/angular/form-basic.stories.ts @@ -0,0 +1,123 @@ +import { FormsModule } from '@angular/forms'; +import { FormFieldComponent } from '@lucca-front/ng/form-field'; +import { TextInputComponent } from '@lucca-front/ng/forms'; +import { Meta, moduleMetadata, StoryFn } from '@storybook/angular'; + +export default { + title: 'Documentation/Forms/Examples/Angular', + decorators: [ + moduleMetadata({ + imports: [FormFieldComponent, TextInputComponent, FormsModule], + }), + ], + argTypes: {}, +} as Meta; + +function getTemplate(): string { + return ` +
+
+
+

Form title

+ +
+
+ + + + Fieldset title + Helper message + + + +
+
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+
+
+
+
+ + + + Fieldset title + Helper message + + + +
+
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+
+
+
+
+`; +} + +const Template: StoryFn = () => ({ + template: getTemplate(), +}); + +export const Basic = Template.bind({}); +Basic.args = {}; diff --git a/stories/documentation/forms/examples/html&css/form-basic.stories.ts b/stories/documentation/forms/examples/html&css/form-basic.stories.ts new file mode 100644 index 0000000000..8348896b6d --- /dev/null +++ b/stories/documentation/forms/examples/html&css/form-basic.stories.ts @@ -0,0 +1,159 @@ +import { Meta, StoryFn } from '@storybook/angular'; + +interface FieldsetBasicStory {} + +export default { + title: 'Documentation/Forms/Examples/HTML&CSS', + argTypes: {}, +} as Meta; + +function getTemplate(args: FieldsetBasicStory): string { + return ` +
+
+
+

Form title

+ +
+
+ + + + Fieldset title + Helper message + + + +
+
+
+
+ +
+
+ +
+
+
Helper text
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+ + + + Fieldset title + Helper message + + + +
+
+
+
+ +
+
+ +
+
+
Helper text
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
`; +} + +const Template: StoryFn = (args: FieldsetBasicStory) => ({ + props: args, + template: getTemplate(args), +}); + +export const Basic = Template.bind({}); +Basic.args = {}; diff --git a/stories/documentation/forms/fields/number/angular/numberfield.stories.ts b/stories/documentation/forms/fields/number/angular/numberfield.stories.ts index c679072249..7f73599819 100644 --- a/stories/documentation/forms/fields/number/angular/numberfield.stories.ts +++ b/stories/documentation/forms/fields/number/angular/numberfield.stories.ts @@ -1,9 +1,9 @@ -import { NumberInputComponent } from '@lucca-front/ng/forms'; -import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { cleanupTemplate, generateInputs } from 'stories/helpers/stories'; import { FormFieldComponent } from '@lucca-front/ng/form-field'; +import { NumberInputComponent } from '@lucca-front/ng/forms'; +import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; +import { cleanupTemplate, generateInputs } from 'stories/helpers/stories'; export default { title: 'Documentation/Forms/Fields/NumberField/Angular', @@ -70,7 +70,7 @@ export const Basic: StoryObj @@ -18,10 +18,10 @@ function getTemplate(args: SwitchInvlidStory): string {
`; } -const Template: StoryFn = (args) => ({ +const Template: StoryFn = (args) => ({ props: args, template: getTemplate(args), }); -export const Invlid = Template.bind({}); -Invlid.args = {}; +export const Invalid = Template.bind({}); +Invalid.args = {}; diff --git a/stories/documentation/forms/fields/text/angular/textfield.stories.ts b/stories/documentation/forms/fields/text/angular/textfield.stories.ts index a095277e9e..13b32feb69 100644 --- a/stories/documentation/forms/fields/text/angular/textfield.stories.ts +++ b/stories/documentation/forms/fields/text/angular/textfield.stories.ts @@ -2,7 +2,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { FormFieldComponent } from '@lucca-front/ng/form-field'; import { TextInputComponent } from '@lucca-front/ng/forms'; -import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { cleanupTemplate, generateInputs } from 'stories/helpers/stories'; export default { @@ -84,8 +84,9 @@ export const Basic: StoryObj
diff --git a/stories/documentation/forms/fields/text/html&css/textfield-valueAlignRight.stories.ts b/stories/documentation/forms/fields/text/html&css/textfield-valueAlignRight.stories.ts new file mode 100644 index 0000000000..e482510183 --- /dev/null +++ b/stories/documentation/forms/fields/text/html&css/textfield-valueAlignRight.stories.ts @@ -0,0 +1,28 @@ +import { Meta, StoryFn } from '@storybook/angular'; + +interface TextfieldValueAlignRightStory {} + +export default { + title: 'Documentation/Forms/Fields/TextField/HTML&CSS', + argTypes: {}, +} as Meta; + +function getTemplate(args: TextfieldValueAlignRightStory): string { + return `
+ +
+
+ +
+
+
Helper text
+
`; +} + +const Template: StoryFn = (args) => ({ + props: args, + template: getTemplate(args), +}); + +export const ValueAlignRight = Template.bind({}); +ValueAlignRight.args = {}; diff --git a/stories/documentation/forms/fields/textarea/angular/textarea.stories.ts b/stories/documentation/forms/fields/textarea/angular/textarea.stories.ts index 9392952c25..feaacdec1e 100644 --- a/stories/documentation/forms/fields/textarea/angular/textarea.stories.ts +++ b/stories/documentation/forms/fields/textarea/angular/textarea.stories.ts @@ -1,9 +1,9 @@ -import { TextareaInputComponent } from '@lucca-front/ng/forms'; -import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { cleanupTemplate, generateInputs } from 'stories/helpers/stories'; import { FormFieldComponent } from '@lucca-front/ng/form-field'; +import { TextareaInputComponent } from '@lucca-front/ng/forms'; +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { cleanupTemplate, generateInputs } from 'stories/helpers/stories'; export default { title: 'Documentation/Forms/Fields/TextAreaField/Angular', @@ -28,6 +28,9 @@ export default { type: 'select', }, }, + rows: { + control: { type: 'number', min: 2 }, + }, counter: { description: '[v17.4]', }, @@ -73,7 +76,8 @@ export const Basic: StoryObjLabel
- +
Helper text
diff --git a/stories/documentation/forms/form-label/form-label-basic.stories.ts b/stories/documentation/forms/form-label/form-label-basic.stories.ts index 13dabd9bfb..2eca699e26 100644 --- a/stories/documentation/forms/form-label/form-label-basic.stories.ts +++ b/stories/documentation/forms/form-label/form-label-basic.stories.ts @@ -1,16 +1,14 @@ import { Meta, StoryFn } from '@storybook/angular'; -interface FormLabelBasicStory { -} +interface FormLabelBasicStory {} export default { title: 'Documentation/Forms/Form Label Basic', - argTypes: { - }, + argTypes: {}, } as Meta; function getTemplate(args: FormLabelBasicStory): string { - return ``; + return ``; } const Template: StoryFn = (args) => ({ diff --git a/stories/documentation/forms/form-label/form-label-counter.stories.ts b/stories/documentation/forms/form-label/form-label-counter.stories.ts index 62645e73c1..39e9f641d7 100644 --- a/stories/documentation/forms/form-label/form-label-counter.stories.ts +++ b/stories/documentation/forms/form-label/form-label-counter.stories.ts @@ -1,17 +1,15 @@ import { Meta, StoryFn } from '@storybook/angular'; -interface FormLabelCounterStory { -} +interface FormLabelCounterStory {} export default { title: 'Documentation/Forms/Form Label Counter', - argTypes: { - }, + argTypes: {}, } as Meta; function getTemplate(args: FormLabelCounterStory): string { return `

Empty State

-

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

+

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

diff --git a/stories/documentation/listings/table-legacy/table-sticky-columns-breakpoints.stories.ts b/stories/documentation/listings/table-legacy/table-sticky-columns-breakpoints.stories.ts new file mode 100644 index 0000000000..e698727910 --- /dev/null +++ b/stories/documentation/listings/table-legacy/table-sticky-columns-breakpoints.stories.ts @@ -0,0 +1,155 @@ +import { Meta, StoryFn } from '@storybook/angular'; + +interface TableStickyColumnsAndHeaderWithBreakpointsStory {} + +export default { + title: 'Documentation/Listings/Table/Legacy/Sticky Columns And Header With Breakpoints', + argTypes: {}, +} as Meta; + +function getTemplate(args: TableStickyColumnsAndHeaderWithBreakpointsStory): string { + return ` +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Head cell + + Head cell + + Head cell + +
+
Head cellHead cellHead cellHead cellHead cellHead cellHead cellHead cellHead cellHead cell +
+
+ Head cell +
+ Body cell + + Body cell + + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell + Body cell +
+ Body cell + + Body cell + + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell + Body cell +
+ Body cell + + Body cell + + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell + Body cell +
+
+ `; +} + +const Template: StoryFn = (args) => ({ + props: args, + template: getTemplate(args), + styles: [`.demo-wrapper {overflow: auto; height: 10rem;}`], +}); + +export const StickyColumnsAndHeaderWithBreakpoints = Template.bind({}); +StickyColumnsAndHeaderWithBreakpoints.args = {}; diff --git a/stories/documentation/listings/table/table-sticky-columns.stories.ts b/stories/documentation/listings/table-legacy/table-sticky-columns.stories.ts similarity index 98% rename from stories/documentation/listings/table/table-sticky-columns.stories.ts rename to stories/documentation/listings/table-legacy/table-sticky-columns.stories.ts index 26b5928589..a532dcfc30 100644 --- a/stories/documentation/listings/table/table-sticky-columns.stories.ts +++ b/stories/documentation/listings/table-legacy/table-sticky-columns.stories.ts @@ -3,7 +3,7 @@ import { Meta, StoryFn } from '@storybook/angular'; interface TableStickyColumnsStory {} export default { - title: 'Documentation/Listings/Table/Sticky Columns', + title: 'Documentation/Listings/Table/Legacy/Sticky Columns', argTypes: {}, } as Meta; diff --git a/stories/documentation/listings/table-legacy/table-sticky-header.stories.ts b/stories/documentation/listings/table-legacy/table-sticky-header.stories.ts new file mode 100644 index 0000000000..086f29b793 --- /dev/null +++ b/stories/documentation/listings/table-legacy/table-sticky-header.stories.ts @@ -0,0 +1,65 @@ +import { Meta, StoryFn } from '@storybook/angular'; + +interface TableStickyHeaderStory {} + +export default { + title: 'Documentation/Listings/Table/Legacy/Sticky Header', + argTypes: {}, +} as Meta; + +function getTemplate(args: TableStickyHeaderStory): string { + return ` +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Head cellHead cellHead cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
+
+ `; +} + +const Template: StoryFn = (args) => ({ + props: args, + template: getTemplate(args), + styles: [`.demo-wrapper {height: 10rem; overflow: auto;}`], +}); + +export const StickyHeader = Template.bind({}); +StickyHeader.args = {}; diff --git a/stories/documentation/listings/table/table-sticky-columns-breakpoints.stories.ts b/stories/documentation/listings/table/table-sticky-columns-breakpoints.stories.ts index 5260ca83f1..35be47b609 100644 --- a/stories/documentation/listings/table/table-sticky-columns-breakpoints.stories.ts +++ b/stories/documentation/listings/table/table-sticky-columns-breakpoints.stories.ts @@ -3,29 +3,34 @@ import { Meta, StoryFn } from '@storybook/angular'; interface TableStickyColumnsAndHeaderWithBreakpointsStory {} export default { - title: 'Documentation/Listings/Table/Sticky Columns And Header With Breakpoints', + title: 'Documentation/Listings/Table/Sticky Columns And Header With Breakpoints ', argTypes: {}, } as Meta; function getTemplate(args: TableStickyColumnsAndHeaderWithBreakpointsStory): string { - return ` -
- + return ` +
- - - - - @@ -34,121 +39,67 @@ function getTemplate(args: TableStickyColumnsAndHeaderWithBreakpointsStory): str - - + + + + - - - + - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - -
+ + Head cell + + + Head cell + + + Head cell + + + Head cell Head cell Head cell Head cellHead cell Head cell Head cellHead cell + Head cellHead cell + + Head cell
- Body cell - - Body cell - - Body cell - Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell - Body cell -
+
Body cell + Body cell + Body cell Body cellBody cellBody cellBody cellBody cell Body cell Body cell Body cell Body cellBody cell - Body cell -
- Body cell - - Body cell - - Body cell - Body cellBody cellBody cell Body cell Body cell Body cell Body cell Body cell Body cellBody cell + Body cell
-
`; } -const Template: StoryFn = (args) => ({ +const Template: StoryFn = (args: TableStickyColumnsAndHeaderWithBreakpointsStory) => ({ props: args, template: getTemplate(args), - styles: [`.demo-wrapper {overflow: auto; height: 10rem;}`], + styles: [`:host {display: block; overflow: auto; height: 10rem; white-space: nowrap}`], }); export const StickyColumnsAndHeaderWithBreakpoints = Template.bind({}); diff --git a/stories/documentation/listings/table/table-sticky-header.stories.ts b/stories/documentation/listings/table/table-sticky-header.stories.ts index 34e6fb628f..85a4c351bd 100644 --- a/stories/documentation/listings/table/table-sticky-header.stories.ts +++ b/stories/documentation/listings/table/table-sticky-header.stories.ts @@ -8,9 +8,8 @@ export default { } as Meta; function getTemplate(args: TableStickyHeaderStory): string { - return ` -
- + return ` +
@@ -19,8 +18,9 @@ function getTemplate(args: TableStickyHeaderStory): string { - - + @@ -51,14 +51,14 @@ function getTemplate(args: TableStickyHeaderStory): string {
Head cell
-
+ `; } -const Template: StoryFn = (args) => ({ +const Template: StoryFn = (args: TableStickyHeaderStory) => ({ props: args, template: getTemplate(args), - styles: [`.demo-wrapper {height: 10rem; overflow: auto;}`], + styles: [`:host {display: block; height: 10rem; overflow: auto;}`], }); export const StickyHeader = Template.bind({}); diff --git a/stories/documentation/loaders/loadings/loadings-basic.stories.ts b/stories/documentation/loaders/loadings/loadings-basic.stories.ts index cd8432bc03..83ad4dbffd 100644 --- a/stories/documentation/loaders/loadings/loadings-basic.stories.ts +++ b/stories/documentation/loaders/loadings/loadings-basic.stories.ts @@ -3,11 +3,9 @@ import { Meta, StoryFn } from '@storybook/angular'; interface LoadingsBasicStory { label: boolean; block: boolean; - l: boolean; + L: boolean; invert: boolean; - fullpage: boolean; - dialog: boolean; - sidepanel: boolean; + template: string; } export default { @@ -23,30 +21,20 @@ export default { type: 'boolean', }, }, - l: { + L: { control: { type: 'boolean', }, - description: 'Taille : Large', }, invert: { control: { type: 'boolean', }, }, - fullpage: { + template: { + options: ['', 'mod-popin', 'mod-drawer', 'mod-fullpage'], control: { - type: 'boolean', - }, - }, - dialog: { - control: { - type: 'boolean', - }, - }, - sidepanel: { - control: { - type: 'boolean', + type: 'select', }, }, }, @@ -55,13 +43,11 @@ export default { function getTemplate(args: LoadingsBasicStory): string { const label = args.label ? `Loading…` : ''; const block = args.block ? `mod-block` : ''; - const l = args.l ? `mod-L` : ''; + const L = args.L ? `mod-L` : ''; const invert = args.invert ? `mod-invert` : ''; - const fullpage = args.fullpage ? `mod-fullpage` : ''; - const dialog = args.dialog ? `mod-dialog` : ''; - const sidepanel = args.sidepanel ? `mod-sidePanel` : ''; + return ` -
${label}
+
${label}
`; } @@ -72,11 +58,10 @@ const Template: StoryFn = (args) => ({ ` :host { display: block; - min-height: 100px; }`, - args.invert === true ? ':host { background-color: #333333; min-height: 130px; margin: -15px -15px; padding: 15px 15px; }' : '', + args.invert === true ? ':host { background-color: #333333; }' : '', ], }); export const Basic = Template.bind({}); -Basic.args = { label: false, block: false, l: false, invert: false, fullpage: false, dialog: false, sidepanel: false }; +Basic.args = { label: false, block: false, L: false, invert: false, template: '' }; diff --git a/stories/documentation/loaders/skeleton-button/angular/skeleton-button.stories.ts b/stories/documentation/loaders/skeleton-button/angular/skeleton-button.stories.ts new file mode 100644 index 0000000000..6977e20ad0 --- /dev/null +++ b/stories/documentation/loaders/skeleton-button/angular/skeleton-button.stories.ts @@ -0,0 +1,21 @@ +import { SkeletonButtonComponent } from '@lucca-front/ng/skeleton'; +import { Meta, StoryObj } from '@storybook/angular'; + +export default { + title: 'Documentation/Loaders/Skeleton/Skeleton Button', + component: SkeletonButtonComponent, +} as Meta; + +export const Template: StoryObj = { + argTypes: { + dark: { + control: { + type: 'boolean', + }, + }, + }, + + args: { + dark: false, + }, +}; diff --git a/stories/documentation/loaders/skeleton-field/angular/skeleton-field.stories.ts b/stories/documentation/loaders/skeleton-field/angular/skeleton-field.stories.ts new file mode 100644 index 0000000000..3708b1bf97 --- /dev/null +++ b/stories/documentation/loaders/skeleton-field/angular/skeleton-field.stories.ts @@ -0,0 +1,21 @@ +import { SkeletonFieldComponent } from '@lucca-front/ng/skeleton'; +import { Meta, StoryObj } from '@storybook/angular'; + +export default { + title: 'Documentation/Loaders/Skeleton/Skeleton Field', + component: SkeletonFieldComponent, +} as Meta; + +export const Template: StoryObj = { + argTypes: { + dark: { + control: { + type: 'boolean', + }, + }, + }, + + args: { + dark: false, + }, +}; diff --git a/stories/documentation/loaders/skeleton-header/angular/skeleton-header.stories.ts b/stories/documentation/loaders/skeleton-header/angular/skeleton-header.stories.ts new file mode 100644 index 0000000000..07642013ae --- /dev/null +++ b/stories/documentation/loaders/skeleton-header/angular/skeleton-header.stories.ts @@ -0,0 +1,21 @@ +import { SkeletonHeaderComponent } from '@lucca-front/ng/skeleton'; +import { Meta, StoryObj } from '@storybook/angular'; + +export default { + title: 'Documentation/Loaders/Skeleton/Skeleton Header', + component: SkeletonHeaderComponent, +} as Meta; + +export const Template: StoryObj = { + argTypes: { + dark: { + control: { + type: 'boolean', + }, + }, + }, + + args: { + dark: false, + }, +}; diff --git a/stories/documentation/navigation/menu/menu-basic.stories.ts b/stories/documentation/navigation/menu/menu-basic.stories.ts index 4ebcc0042c..02a7a0274d 100644 --- a/stories/documentation/navigation/menu/menu-basic.stories.ts +++ b/stories/documentation/navigation/menu/menu-basic.stories.ts @@ -5,6 +5,7 @@ interface MenuBasicStory { header: boolean; s: boolean; disabled: boolean; + vertical: boolean; } export default { @@ -30,6 +31,11 @@ export default { type: 'boolean', }, }, + vertical: { + control: { + type: 'boolean', + }, + }, }, } as Meta; @@ -37,23 +43,46 @@ function getTemplate(args: MenuBasicStory): string { const noBorder = args.noBorder ? `mod-noBorder` : ''; const header = args.header ? `mod-header` : ''; const s = args.s ? `mod-S` : ''; - const disabled = args.disabled ? `disabled` : ''; - return ` -
- +
+

Actions

+ +
+
+
+
+ Caesarem fama studio memorabili ut latius abscessere amplam Nebridius equitum. Learn more +
+ + +
+
+
+
+
+
+ +

Killable callout (deprecated)

@@ -104,26 +122,31 @@

Callout icon

-
-
-

Callout tiny (deprecated)

- -
+
-
99
-
-
-
-
99
-
-
-
-
99
+
+
+ Caesarem fama studio memorabili ut latius abscessere amplam Nebridius equitum. Learn more +
+ + +
+
+
-
-
-
99
+ +
+
+
+
+ Caesarem fama studio memorabili ut latius abscessere amplam Nebridius equitum. Learn more +
+ + +
+
+
diff --git a/stories/qa/comment/comment.stories.html b/stories/qa/comment/comment.stories.html new file mode 100644 index 0000000000..257b076c1f --- /dev/null +++ b/stories/qa/comment/comment.stories.html @@ -0,0 +1,242 @@ +
+

Commentaire simple

+
+
+ +
+ +
+ Marie Bragoulet&ngsp; + +
+
+
+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus a veniam necessitatibus aut facilis repellendus provident nulla + iste neque ex? +

+
+
+
+ +
+

Commentaire sans avatar

+
+
+
+ Marie Bragoulet&ngsp; + +
+
+
+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus a veniam necessitatibus aut facilis repellendus provident nulla + iste neque ex? +

+
+
+
+ +
+

Commentaire sans auteur

+
+
+ +
+ +
+ +
+
+
+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus a veniam necessitatibus aut facilis repellendus provident nulla + iste neque ex? +

+
+
+
+ +
+

Commentaire sans date

+
+
+ +
+ +
Marie Bragoulet&ngsp;
+
+
+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus a veniam necessitatibus aut facilis repellendus provident nulla + iste neque ex? +

+
+
+
+ +
+

Commentaire sans en-tête

+
+
+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus a veniam necessitatibus aut facilis repellendus provident nulla + iste neque ex? +

+
+
+
+ +
+

Commentaire taille S

+
+
+ +
+ +
+ Marie Bragoulet&ngsp; + +
+
+
+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus a veniam necessitatibus aut facilis repellendus provident nulla + iste neque ex? +

+
+
+
+ +
+

Commentaire avec texte riche

+
+
+ +
+ +
+ Marie Bragoulet&ngsp; + +
+
+
+
+

Lorem, ipsum.

+

+ Lorem ipsum, dolor sit amet consectetur adipisicing elit. Facilis voluptates ex qui iste libero suscipit cum + earum harum animi praesentium, quidem non incidunt vel illum sunt nihil reprehenderit a itaque. +

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque numquam itaque at facilis iusto inventore.

+
+
+
+
+ +
+

Wrapper de commentaires

+ +
    +
  1. +
    +
    + +
    + +
    + Marie Bragoulet&ngsp; + +
    +
    +
    +

    + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus a veniam necessitatibus aut facilis repellendus provident + nulla iste neque ex? +

    +
    +
    +
  2. +
  3. +
    +
    + +
    + +
    + Marie Bragoulet&ngsp; + +
    +
    +
    +

    Lorem ipsum dolor sit amet,

    +
    +
    +
  4. +
  5. +
    +
    + +
    + +
    + Marie Bragoulet&ngsp; + +
    +
    +
    +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit.

    +
    +
    +
  6. +
+
+ +
+

Wrapper de commentaires avec un seul avatar

+ +
    +
  1. +
    +
    + +
    + +
    + Marie Bragoulet&ngsp; + +
    +
    +
    +

    + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus a veniam necessitatibus aut facilis repellendus provident + nulla iste neque ex? +

    +
    +
    +
  2. +
  3. +
    +
    +

    Lorem ipsum dolor sit amet

    +
    +
    +
  4. +
  5. +
    +
    +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit.

    +
    +
    +
  6. +
+
+ + diff --git a/stories/qa/main-menu/main-menu.stories.ts b/stories/qa/comment/comment.stories.ts similarity index 50% rename from stories/qa/main-menu/main-menu.stories.ts rename to stories/qa/comment/comment.stories.ts index 703d2147d5..5cc05ca5a1 100644 --- a/stories/qa/main-menu/main-menu.stories.ts +++ b/stories/qa/comment/comment.stories.ts @@ -3,16 +3,16 @@ import { Meta, StoryFn } from '@storybook/angular'; @Component({ standalone: true, - selector: 'main-menu-stories', - templateUrl: './main-menu.stories.html', + selector: 'comment-stories', + templateUrl: './comment.stories.html', }) -class MainMenuStory {} +class CommentStory {} export default { - title: 'QA/Main Menu', - component: MainMenuStory, + title: 'QA/Comment', + component: CommentStory, } as Meta; -const template: StoryFn = () => ({}); +const template: StoryFn = () => ({}); export const basic = template.bind({}); diff --git a/stories/qa/empty-state/empty-state-page.stories.html b/stories/qa/empty-state/empty-state-page.stories.html index d085e74f5f..53ca5435ea 100644 --- a/stories/qa/empty-state/empty-state-page.stories.html +++ b/stories/qa/empty-state/empty-state-page.stories.html @@ -8,7 +8,7 @@ >

Empty State

-

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

+

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

diff --git a/stories/qa/empty-state/empty-state-section.stories.html b/stories/qa/empty-state/empty-state-section.stories.html index 296dceb5cf..43b379a6ff 100644 --- a/stories/qa/empty-state/empty-state-section.stories.html +++ b/stories/qa/empty-state/empty-state-section.stories.html @@ -8,7 +8,7 @@ >

Empty State

-

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

+

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

@@ -28,7 +28,7 @@

Empty State

>

Empty State

-

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

+

Flatus obsequiorum potest inanes pomerium obsequiorum credi homines vero caelibes orbos potest vile diversitate flatus.

diff --git a/stories/qa/form-label/form-label.stories.html b/stories/qa/form-label/form-label.stories.html index 3b67b795b3..7216b5000b 100644 --- a/stories/qa/form-label/form-label.stories.html +++ b/stories/qa/form-label/form-label.stories.html @@ -2,12 +2,42 @@

Form label

- - - - - - + + + + + +
diff --git a/stories/qa/forms/checkbox.stories.html b/stories/qa/forms/checkbox.stories.html index 5d52798cbe..19703015be 100644 --- a/stories/qa/forms/checkbox.stories.html +++ b/stories/qa/forms/checkbox.stories.html @@ -1,33 +1,59 @@
-
-
-
-
diff --git a/stories/qa/forms/framed.stories.html b/stories/qa/forms/framed.stories.html index 24637d86ba..647efc0e0a 100644 --- a/stories/qa/forms/framed.stories.html +++ b/stories/qa/forms/framed.stories.html @@ -11,8 +11,8 @@

Framed form

You can also modify this distribution by adding classes such as - .mod-4@mediaMinL or - .mod-6@mediaMinXXXS + .mod-4@mediaMinL or + .mod-6@mediaMinXXXS on cols for example.

diff --git a/stories/qa/forms/switch.stories.html b/stories/qa/forms/switch.stories.html index 223fbab7df..22b719f155 100644 --- a/stories/qa/forms/switch.stories.html +++ b/stories/qa/forms/switch.stories.html @@ -1,9 +1,10 @@
-
- + @@ -12,11 +13,20 @@
- + - +
Helper text
@@ -25,22 +35,33 @@

Sizes

- + - +
Helper text
- + - +
Helper text
@@ -49,22 +70,41 @@

Sizes

Disabled

- + - +
Helper text
- + - +
Helper text
@@ -73,22 +113,41 @@

Disabled

Invalid

- + - +
Helper text
- + - +
Helper text
diff --git a/stories/qa/forms/textfield-legacy.stories.html b/stories/qa/forms/textfield-legacy.stories.html index 5d4e42ff91..075991dd3a 100644 --- a/stories/qa/forms/textfield-legacy.stories.html +++ b/stories/qa/forms/textfield-legacy.stories.html @@ -506,32 +506,6 @@

Clearable

Clear - -

Legacy clearer

- - -
diff --git a/stories/qa/forms/textfield.stories.html b/stories/qa/forms/textfield.stories.html index 55834d5439..f5d42e1be7 100644 --- a/stories/qa/forms/textfield.stories.html +++ b/stories/qa/forms/textfield.stories.html @@ -2,28 +2,33 @@

Sizes

-
@@ -43,7 +48,8 @@

Sizes

@@ -52,13 +58,13 @@

Sizes

id="fieldXS" class="textField-input-value" aria-labelledby="fieldXSlabel" - aria-describedby="fieldSmessage" + aria-describedby="fieldXSmessage" placeholder="Placeholder" aria-invalid="false" />
-
Helper text
+
Helper text

Search / Affix

@@ -66,7 +72,7 @@

Search / Affix

@@ -75,13 +81,12 @@

Search / Affix

id="fieldSearch" class="textField-input-value" aria-labelledby="fieldSearchlabel" - aria-describedby="fieldSearchmessage" placeholder="Placeholder" aria-invalid="false" value="Value" />
- @@ -93,7 +98,7 @@

Search / Affix

@@ -102,13 +107,12 @@

Search / Affix

id="fieldSearchXS" class="textField-input-value" aria-labelledby="fieldSearchXSlabel" - aria-describedby="fieldSearchSmessage" placeholder="Placeholder" aria-invalid="false" value="Value" />
- @@ -120,7 +124,7 @@

Search / Affix

@@ -129,13 +133,12 @@

Search / Affix

id="fieldSearchXS" class="textField-input-value" aria-labelledby="fieldSearchXSlabel" - aria-describedby="fieldSearchXSmessage" placeholder="Placeholder" aria-invalid="false" value="Value" />
- @@ -148,7 +151,8 @@

Clear

@@ -157,13 +161,12 @@

Clear

id="fieldClear" class="textField-input-value" aria-labelledby="fieldClearlabel" - aria-describedby="fieldClearmessage" placeholder="Placeholder" aria-invalid="false" value="Value" />
-
@@ -173,7 +176,8 @@

Clear

@@ -182,13 +186,12 @@

Clear

id="fieldClearS" class="textField-input-value" aria-labelledby="fieldClearSlabel" - aria-describedby="fieldClearSmessage" placeholder="Placeholder" aria-invalid="false" value="Value" />
-
@@ -198,7 +201,8 @@

Clear

@@ -207,13 +211,12 @@

Clear

id="fieldClearXS" class="textField-input-value" aria-labelledby="fieldClearXSlabel" - aria-describedby="fieldClearXSmessage" placeholder="Placeholder" aria-invalid="false" value="Value" />
-
@@ -225,7 +228,8 @@

Prefix / Suffix

@@ -240,7 +244,6 @@

Prefix / Suffix

id="fieldPrefixS" class="textField-input-value" aria-labelledby="fieldPrefixSprefix fieldPrefixSlabel fieldPrefixSsuffix" - aria-describedby="fieldPrefixSmessage" placeholder="Placeholder" aria-invalid="false" value="Value" @@ -251,7 +254,8 @@

Prefix / Suffix

@@ -266,7 +270,6 @@

Prefix / Suffix

id="fieldPrefixXS" class="textField-input-value" aria-labelledby="fieldPrefixXSprefix fieldPrefixXSlabel fieldPrefixXSsuffix" - aria-describedby="fieldPrefixXSmessage" placeholder="Placeholder" aria-invalid="false" value="Value" @@ -277,7 +280,8 @@

Prefix / Suffix

@@ -301,11 +305,86 @@

Prefix / Suffix

+

Align right

+
+ +
+
+ +
+
+
+ +
+ +
+ + $ + + + €/j + +
+ +
+
+
+ +
+ +
+
+ +
+ + +
+
+
+
+

States

@@ -313,19 +392,20 @@

States

type="text" id="fieldErrorEmpty" class="textField-input-value" - aria-labelledby="fieldErrorEmptyprefix fieldErrorEmptylabel fieldErrorEmptysuffix" - aria-describedby="fieldErrorEmptymessage" + aria-labelledby="fieldErrorEmptylabel" + aria-describedby="fieldErrorEmptyMessage" placeholder="Placeholder" aria-invalid="true" />
-
Helper text
+
Helper text
@@ -340,24 +420,25 @@

States

id="fieldErrorFilled" class="textField-input-value" aria-labelledby="fieldErrorFilledprefix fieldErrorFilledlabel fieldErrorFilledsuffix" - aria-describedby="fieldErrorFilledmessage" + aria-describedby="fieldErrorFilledMessage" placeholder="Placeholder" aria-invalid="true" value="Value" />
-
-
Helper text
+
Helper text
@@ -365,20 +446,21 @@

States

type="text" id="fieldDisabledEmpty" class="textField-input-value" - aria-labelledby="fieldDisabledEmptyprefix fieldDisabledEmptylabel fieldDisabledEmptysuffix" - aria-describedby="fieldDisabledEmptymessage" + aria-labelledby="fieldDisabledEmptylabel" + aria-describedby="fieldDisabledEmptyMessage" placeholder="Placeholder" aria-invalid="false" disabled />
-
Helper text
+
Helper text
@@ -393,7 +475,7 @@

States

id="fieldDisabledFilled" class="textField-input-value" aria-labelledby="fieldDisabledFilledprefix fieldDisabledFilledlabel fieldDisabledFilledsuffix" - aria-describedby="fieldDisabledFilledmessage" + aria-describedby="fieldDisabledFilledMessage" placeholder="Placeholder" aria-invalid="false" value="Value" @@ -401,14 +483,15 @@

States

/>
-
Helper text
+
Helper text

Everything

@@ -423,20 +506,20 @@

Everything

id="fieldAll" class="textField-input-value" aria-labelledby="fieldAllprefix fieldAlllabel fieldAllsuffix" - aria-describedby="fieldAllmessage" + aria-describedby="fieldAllMessage" placeholder="Placeholder" aria-invalid="false" value="Value" />
-
-
Helper text
+
Helper text
diff --git a/stories/qa/grid/grid.stories.html b/stories/qa/grid/grid.stories.html index ffeffabb94..4eabf8c9eb 100644 --- a/stories/qa/grid/grid.stories.html +++ b/stories/qa/grid/grid.stories.html @@ -20,8 +20,8 @@

Grid

-
grid-7@mediaMinS
-
grid-5@mediaMinS
+
grid-7AtmediaMinS
+
grid-5AtmediaMinS
@@ -38,8 +38,8 @@

Grid

<div class="grid"> <div class="grid-6@mediaMinXXXS">...</div> <div class="grid-6@mediaMinXXXS">...</div> - </div> + ><div class="grid"> <div class="grid-6AtmediaMinXXXS">...</div> <div + class="grid-6AtmediaMinXXXS">...</div> </div> @@ -47,18 +47,18 @@

Grid

Offsets

-
-
grid-8@mediaMinXXXS grid-offset4@mediaMinXXXS
+
+
grid-8AtmediaMinXXXS grid-offset4AtmediaMinXXXS
-
-
grid-6@mediaMinXXXS grid-offset3@mediaMinXXXS
+
+
grid-6AtmediaMinXXXS grid-offset3AtmediaMinXXXS
-
grid-3@mediaMinXXXS
+
grid-3AtmediaMinXXXS
<div class="grid"> <div class="grid-8@mediaMinXXXS grid-offset4@mediaMinXXXS">...</div> </div> + ><div class="grid"> <div class="grid-8AtmediaMinXXXS grid-offset4AtmediaMinXXXS">...</div> </div>
@@ -73,7 +73,7 @@

Auto width

grid mod-auto
<div class="grid"> <div class="grid@mediaMinS">...</div> <div class="grid@mediaMinS">...</div> ... + ><div class="grid"> <div class="gridAtmediaMinS">...</div> <div class="gridAtmediaMinS">...</div> ... </div> Horizontal alignment
- <div class="grid mod-start@mediaMinXXXS"> ... - <div class="grid mod-center@mediaMinXXXS"> ... - <div class="grid mod-end@mediaMinXXXS"> ... + <div class="grid mod-startAtmediaMinXXXS"> ... + <div class="grid mod-centerAtmediaMinXXXS"> ... + <div class="grid mod-endAtmediaMinXXXS"> ... Tip: It will also work with XXS, XS, S, M, L, XL, XXL and @@ -109,21 +109,21 @@

Horizontal alignment

Vertical alignment

You can align columns verticaly inside the grid:

-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
- <div class="grid mod-top@mediaMinXXXS"> ... - <div class="grid mod-middle@mediaMinXXXS"> ... - <div class="grid mod-bottom@mediaMinXXXS"> ... + <div class="grid mod-topAtmediaMinXXXS"> ... + <div class="grid mod-middleAtmediaMinXXXS"> ... + <div class="grid mod-bottomAtmediaMinXXXS"> ... Tip: It will also work with XXS, XS, S, M, L, XL, XXL and @@ -148,8 +148,8 @@

Reorder

4
<div class="grid"> <div class="grid-6@mediaMinXXXS u-last@mediaMinXS">...</div> <div class="grid-6@mediaMinXXXS - u-first@mediaMinXS">...</div> </div> + ><div class="grid"> <div class="grid-6AtmediaMinXXXS u-lastAtmediaMinXS">...</div> <div class="grid-6AtmediaMinXXXS + u-firstAtmediaMinXS">...</div> </div> Tip: It will also work with XXS, XS, S, diff --git a/stories/qa/main-menu/main-menu.stories.html b/stories/qa/secondary-nav/secondary-nav.stories.html similarity index 99% rename from stories/qa/main-menu/main-menu.stories.html rename to stories/qa/secondary-nav/secondary-nav.stories.html index 7d40879965..1f0fda5b61 100644 --- a/stories/qa/main-menu/main-menu.stories.html +++ b/stories/qa/secondary-nav/secondary-nav.stories.html @@ -1,4 +1,4 @@ -

Main menu

+

Secondary nav

diff --git a/stories/qa/secondary-nav/secondary-nav.stories.ts b/stories/qa/secondary-nav/secondary-nav.stories.ts new file mode 100644 index 0000000000..fb7b6a2624 --- /dev/null +++ b/stories/qa/secondary-nav/secondary-nav.stories.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { Meta, StoryFn } from '@storybook/angular'; + +@Component({ + standalone: true, + selector: 'secondary-nav-stories', + templateUrl: './secondary-nav.stories.html', +}) +class SecondaryNavStory {} + +export default { + title: 'QA/Secondary Nav', + component: SecondaryNavStory, +} as Meta; + +const template: StoryFn = () => ({}); + +export const basic = template.bind({}); diff --git a/stories/qa/table/table.stories.html b/stories/qa/table/table.stories.html index dc95272e9e..39736e1859 100644 --- a/stories/qa/table/table.stories.html +++ b/stories/qa/table/table.stories.html @@ -2,7 +2,7 @@

Tables

-

Tables

+

Basic

@@ -560,152 +560,124 @@

Tables borderless

-
-

Sticky Header

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Head cellHead cellHead cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
- Tip: You can align on top with a mod-stickyHeader class or - mod-stickyHeader-withBanner. -

Sticky Header with shadow on scroll

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Head cellHead cellHead cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
Body cellBody cellBody cell
+

Sticky header

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Head cellHead cellHead cellHead cell
Body cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cell
+
Tip: The value of --sticky-header-shadow-offset-top on .table-body-row.mod-stickyHeader-shadow must be equal to the table header height +

Sticky header with shadow on scroll

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Head cellHead cellHead cellHead cell
Body cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cell
+
+

Fixed layout columns

- - + + - - + + @@ -720,21 +692,16 @@

Fixed layout columns

Head cellHead cellFixed 8rem columnFixed 12rem column Head cell
Cell with mod-layoutFixed-8Cell with mod-layoutFixed-12Body cellBody cell Body cell
-

Fixed layout columns starting at breakpoint

- +

Fixed layout columns starting at breakpoint S

+
- - + + - - - - - @@ -747,460 +714,530 @@

Fixed layout columns starting at breakpoint

Head cellHead cellFixed 8rem head cellFixed 12rem head cell Head cell
Cell with mod-layoutFixed-8Cell with mod-layoutFixed-12Body cell
Body cell Body cell
- Tip: the numeric value used in the class will be calculated in rem. Ex - .mod-layoutFixed-8 means a cell width of 8 rem
+

Sticky columns

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Head cellHead cellHead cellHead cellHead cellHead cellHead cellHead cellHead cellHead cell
fixed width: 8 // offset 0fixed width: 7 // offset 8fixed width: 5 // offset 8 + 7 = 15Body cellBody cellBody cellBody cellBody cellBody cellfixed width: 5 // offset 0
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
-

Sticky columns starting at breakpoint

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Head cellHead cellHead cellHead cellHead cellHead cellHead cellHead cellHead cellHead cell
fixed width: 8 // offset 0fixed width: 7 // offset 8fixed width: 5 // offset 8 + 7 = 15Body cellBody cellBody cellBody cellBody cellBody cellfixed width: 5 // offset 0
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Head cell + + Head cell + + Head cell + Head cellHead cellHead cellHead cellHead cellHead cellHead cellHead cellHead cellHead cell + Head cell +
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
+
+ Tip: each sticky cell must have a class mod-stickyColumn-left or + mod-stickyColumn-right and --table-stickyColumn-offsetX where + X equal to the cumulative size of previous cells in the specified axis (from left or from right) Tip: each cell must have a class .mod-stickyColumn-leftOffsetX or - .mod-stickyColumn-righOffsetX with X equal to the cumulative size of - previous cells in the specified axis (from left or from right)Tip: sticky columns can be enabled at breakpoint by replacing mod-layoutFixed and + mod-stickyColumn with mod-layoutFixed@mediaMinS and + mod-stickyColumn@mediaMinS. Replace S by the desired breakpoint
-
-

Sticky columns with shadow on overflow

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Head cellHead cellHead cell -
-
Head cellHead cellHead cellHead cellHead cellHead cell -
-
Head cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
-

Sticky Column with shadow on overflow, starting at breakpoint

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Head cellHead cellHead cell -
-
Head cellHead cellHead cellHead cellHead cellHead cell -
-
Head cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
-

Sticky header + sticky column, with shadow on overflow

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Head cellHead cellHead cell -
-
Head cellHead cellHead cellHead cellHead cellHead cell -
-
Head cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
-

Sticky header + sticky column starting at breakpoint, with shadow on overflow

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Head cellHead cellHead cell -
-
Head cellHead cellHead cellHead cellHead cellHead cell -
-
Head cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
-
+
+

Sticky columns with shadow on scroll

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Head cell + Head cell + + Head cell + +
+
Head cellHead cellHead cellHead cellHead cellHead cellHead cellHead cellHead cellHead cell +
+
Head cell
Body cellBody cell + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cell + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cell + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cell + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cell + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
+
+
+ +
+

Sticky columns + header with shadow on scroll starting at breakpoint S

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Head cell + Head cell + + Head cell + +
+
Head cellHead cellHead cellHead cellHead cellHead cellHead cellHead cellHead cellHead cell +
+
Head cell
Body cellBody cell + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cell + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cell + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cell + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
Body cellBody cell + Body cell + Body cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cellBody cell
+
-