diff --git a/.github/workflows/deploy-storybook.yml b/.github/workflows/deploy-storybook.yml new file mode 100644 index 000000000..6e0c134c7 --- /dev/null +++ b/.github/workflows/deploy-storybook.yml @@ -0,0 +1,55 @@ +name: Deploy Storybook to GitHub Pages + +on: + push: + branches: + - main # Or your default branch name + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + build-and-deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Read .nvmrc + id: nvm + run: echo "NVMRC=$(cat '.nvmrc')" >> $GITHUB_OUTPUT + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ steps.nvm.outputs.NVMRC }} + cache: "npm" + + - name: Install Dependencies + run: npm ci + + - name: Build Storybook + run: npm run ui:build + + - name: Setup Pages + uses: actions/configure-pages@v4 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ui/storybook-static + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/package-lock.json b/package-lock.json index a331e6443..927c1f6c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -135,6 +135,13 @@ "url": "https://dotenvx.com" } }, + "node_modules/@adobe/css-tools": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.1.tgz", + "integrity": "sha512-12WGKBQzjUAI4ayyF4IAtfw2QR/IDoqk6jTddXDhtYTJF9ASmoE1zst7cVtP0aL/F1jUJL5r+JxKXKEgHNbEUQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@algolia/cache-browser-local-storage": { "version": "4.24.0", "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.24.0.tgz", @@ -5441,6 +5448,39 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.4.2.tgz", + "integrity": "sha512-feQ+ntr+8hbVudnsTUapiMN9q8T90XA1d5jn9QzY09sNoj4iD9wi0PY1vsBFTda4ZjEaxRK9S81oarR2nj7TFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "magic-string": "^0.27.0", + "react-docgen-typescript": "^2.2.2" + }, + "peerDependencies": { + "typescript": ">= 4.3.x", + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", @@ -5535,6 +5575,24 @@ "react": "16 - 18" } }, + "node_modules/@mdx-js/react": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz", + "integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, "node_modules/@mui/base": { "version": "5.0.0-beta.40-0", "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40-0.tgz", @@ -9755,6 +9813,747 @@ "resolved": "website", "link": true }, + "node_modules/@storybook/addon-actions": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.5.1.tgz", + "integrity": "sha512-oBBSpOJ6/rCdbdU1JxGCLernaCxALLWDIeZk6tLoQbtbsx/czD1sodqjcujjKwbQwNyZTf8xR8zsCSzG06dWDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@types/uuid": "^9.0.1", + "dequal": "^2.0.2", + "polished": "^4.2.2", + "uuid": "^9.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/addon-actions/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@storybook/addon-backgrounds": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.5.1.tgz", + "integrity": "sha512-4NFRFblPbRP3D4o4sSbJ1x9SMncP4+SHdSqKIovTjb+zOhqYPFYWMTinzEndUnBSDGREldHUvHjROuxrD/0qzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "memoizerific": "^1.11.3", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/addon-controls": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.5.1.tgz", + "integrity": "sha512-RA/SPXW1chfsWaV8Lv/aXJNZJ8hasDEXQ1C5xRCt+T8DFvPqRZGgUfIpsiZ80AKp5RzufT9KL+39piPMljhKXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "dequal": "^2.0.2", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/addon-docs": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.5.1.tgz", + "integrity": "sha512-XhELkuNFOa8q2rF/AXTwnKZth7lCFqkfR5VuEAQ+g9hv2p6I/VGlTddylzjdaZKhiy4p8O9DrzGdLFj+oxOpMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mdx-js/react": "^3.0.0", + "@storybook/blocks": "8.5.1", + "@storybook/csf-plugin": "8.5.1", + "@storybook/react-dom-shim": "8.5.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/addon-essentials": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.5.1.tgz", + "integrity": "sha512-jPGrZ7j+RWistrsgpvjUBvLpWRuOeDNdV014ggHBxDMNX9GWb1GSubWW2Tlo7BfOuUvjICVAjI4KMp/IC/jwZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/addon-actions": "8.5.1", + "@storybook/addon-backgrounds": "8.5.1", + "@storybook/addon-controls": "8.5.1", + "@storybook/addon-docs": "8.5.1", + "@storybook/addon-highlight": "8.5.1", + "@storybook/addon-measure": "8.5.1", + "@storybook/addon-outline": "8.5.1", + "@storybook/addon-toolbars": "8.5.1", + "@storybook/addon-viewport": "8.5.1", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/addon-highlight": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.5.1.tgz", + "integrity": "sha512-nhwx39DuWy2OFP+AQg8EzYP3giM+rQ0OIdAXgAjDVdKk2sGj43gwNYS9wQzXeczEUiSEjQk0JJwBqjF+GtSrag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/addon-interactions": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-interactions/-/addon-interactions-8.5.1.tgz", + "integrity": "sha512-tXCKBIWjwhVuSRRoEiPx+u0D4oqMkctTzysfoCw2sqftIT8t2yHyviX29s87z2NH+DNqzBGGDG1UUaLe5qq3Fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/instrumenter": "8.5.1", + "@storybook/test": "8.5.1", + "polished": "^4.2.2", + "ts-dedent": "^2.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/addon-measure": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.5.1.tgz", + "integrity": "sha512-Goc/IRh0aYT7zfDP9fgwL+DFX52DylanoBf0uGf59IQ7sEJHbwWm0OpiSEDo+NbtytbG83UOQamT7aQxhQo7Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/addon-onboarding": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-onboarding/-/addon-onboarding-8.5.1.tgz", + "integrity": "sha512-ooa59cAz9sJHFbStIL3/kpBpLM9xZGQa2zmSn8TMCMUq1TM/rJARYD4SNj4BeBsLH24wFHI9SXf15Cln8EhASg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/addon-outline": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.5.1.tgz", + "integrity": "sha512-LM3wG5bUgAAEgDS4MD1dw2VStduSYTMc/rNgaTExVVr7pPeuAgkfyIUriP3P0i7x5jweSb2aGzaTuy3PUHAWfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/addon-toolbars": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.5.1.tgz", + "integrity": "sha512-01Odzujfq/g9u1ZTmH/X3I9cCnsNzG/wuyhzFr/T99jerx8QG/U45iYYph2Ytw6A5AtYyCnPYmsTsI+phjUvuA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/addon-viewport": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.5.1.tgz", + "integrity": "sha512-kKCXZT3keUEQulv2tOzRSl/GdFA2JeFjHmks/n7qQLY0zDqdx/C7K9jUECcrOJiLclZwTJvHA3YXrglVJoa6Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "memoizerific": "^1.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/blocks": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.5.1.tgz", + "integrity": "sha512-xUjnOa9udmHhlBTZ+bmMHeU1M9a5OnvnX8urQ0TrNpSyHH7HoPd3xZC4fzz73nSJNMVHIYMZYsz2pj/WfeA/hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/csf": "0.1.12", + "@storybook/icons": "^1.2.12", + "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", + "storybook": "^8.5.1" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-vite": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-8.5.1.tgz", + "integrity": "sha512-m7nzMmXL8ySRDp3AWsd18xB/mRVFdGnCbXeC2HREQVsu1WFkvcHtksvF4x1BOeeL73eokD2/GzgpCjAS0xVvbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/csf-plugin": "8.5.1", + "browser-assert": "^1.2.1", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1", + "vite": "^4.0.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/@storybook/components": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.5.1.tgz", + "integrity": "sha512-dgZfIIRdI7yA9bYb1rhWzbvU4AnbndAeNhLouxHJkUR5r2Ycp9mJba5UNynN1slgDOxB+VMnq1fWKyfWQrBqnw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/core": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.5.1.tgz", + "integrity": "sha512-4zxjclENpZYuNY1fZJE4a7hd8Ho/SiOSN2B57fsIi1qCpKax3JU3J59ZcAWT0iidy5qgM2qMcWbrl0Bl/tWamA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/csf": "0.1.12", + "better-opn": "^3.0.2", + "browser-assert": "^1.2.1", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0", + "esbuild-register": "^3.5.0", + "jsdoc-type-pratt-parser": "^4.0.0", + "process": "^0.11.10", + "recast": "^0.23.5", + "semver": "^7.6.2", + "util": "^0.12.5", + "ws": "^8.2.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/@storybook/core/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@storybook/csf": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.12.tgz", + "integrity": "sha512-9/exVhabisyIVL0VxTCxo01Tdm8wefIXKXfltAPTSr8cbLn5JAxGQ6QV3mjdecLGEOucfoVhAKtJfVHxEK1iqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^2.19.0" + } + }, + "node_modules/@storybook/csf-plugin": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.5.1.tgz", + "integrity": "sha512-8GFrQgJ+/hzWAj9o4XK8m7UFPLxf0w3RwX0ZMPeb6zDhq/1BUE97AjKFb4Oexkh4I67Pycv4gRUOY9+tXF/1DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "unplugin": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/csf-plugin/node_modules/unplugin": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.16.1.tgz", + "integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@storybook/csf-plugin/node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/csf/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT" + }, + "node_modules/@storybook/icons": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.3.1.tgz", + "integrity": "sha512-tgiD2v9v/4sjGOliemoP/8bUe4+ZFpehcqdCVQcPiGZfV0kSBv34Ge+MafeKqM7SLwvGesrbOEOakaogSqGxiQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "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/instrumenter": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.5.1.tgz", + "integrity": "sha512-wMAhsIzwOh/xXKANAP3IbtXxRWFAZtpRisB0sy8WVTPS3a1L1cA6X+U80Ex/omek6L0FZwKZSKmmfkDeZkYnCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@vitest/utils": "^2.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/manager-api": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.5.1.tgz", + "integrity": "sha512-Oj9kPYbp/82LRQ+rsc0ZH0fkzeiT2U1kvubmNiRjtopQHCP3UTVnvWIXC9zSRFKmS+NaAdd0JYsIBvE8fjnoqQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/preview-api": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.5.1.tgz", + "integrity": "sha512-fLR7nvAbjHVLazDA6CLy9O/bpBzKDKqxyBp6SybTBPYa76IzsX8ITSMMt1YcP6rOGhVgcKNA9iBNxRddjLIV0Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/react": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-8.5.1.tgz", + "integrity": "sha512-wKhR9SZUbpYUxRDAYUHH4fZHVxiNG43PxT1uvLfX/i7TPMw+wW+G3Q2yrgms1oHmqqRCvlnGHwT5/t9FFxN31w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/components": "8.5.1", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "8.5.1", + "@storybook/preview-api": "8.5.1", + "@storybook/react-dom-shim": "8.5.1", + "@storybook/theming": "8.5.1" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@storybook/test": "8.5.1", + "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", + "storybook": "^8.5.1", + "typescript": ">= 4.2.x" + }, + "peerDependenciesMeta": { + "@storybook/test": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-dom-shim": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.5.1.tgz", + "integrity": "sha512-peDiT6A1zyODKd7tVQIiFNU42Iolca67h3kkOQPb7nm/Czf2yIa/BHw+yiNDZx82eCIEvBy1Xf7lnjH8PD61xA==", + "dev": true, + "license": "MIT", + "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", + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/react-vite": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-8.5.1.tgz", + "integrity": "sha512-ccsPJXjR7WMS/t7R5nJpPtqRzJxjsllqVMNGk9xxoLasWDf3vOLohgyCgt63ws8iOMh26lqZsFyPyWFcpKW/hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@joshwooding/vite-plugin-react-docgen-typescript": "0.4.2", + "@rollup/pluginutils": "^5.0.2", + "@storybook/builder-vite": "8.5.1", + "@storybook/react": "8.5.1", + "find-up": "^5.0.0", + "magic-string": "^0.30.0", + "react-docgen": "^7.0.0", + "resolve": "^1.22.8", + "tsconfig-paths": "^4.2.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@storybook/test": "8.5.1", + "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", + "storybook": "^8.5.1", + "vite": "^4.0.0 || ^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "@storybook/test": { + "optional": true + } + } + }, + "node_modules/@storybook/react-vite/node_modules/@rollup/pluginutils": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", + "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@storybook/react-vite/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/react-vite/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react-vite/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react-vite/node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/@storybook/react-vite/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react-vite/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@storybook/react-vite/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@storybook/react-vite/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/test": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.5.1.tgz", + "integrity": "sha512-V0sEXqL5kS0YKugCqWgmCpNODdlCCiVlPqm3i+E2+G97DR980BwXf8J6VPscQDRS9ZG39BrM83Aau6Anxrt1Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/csf": "0.1.12", + "@storybook/global": "^5.0.0", + "@storybook/instrumenter": "8.5.1", + "@testing-library/dom": "10.4.0", + "@testing-library/jest-dom": "6.5.0", + "@testing-library/user-event": "14.5.2", + "@vitest/expect": "2.0.5", + "@vitest/spy": "2.0.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.5.1" + } + }, + "node_modules/@storybook/theming": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.5.1.tgz", + "integrity": "sha512-sg61vY1gM8w42CIi28vo//6E1gHgHLNBNaRhkfvLFpu9PuhAcVWLwBDZq0BoKmDMxRxbSPV2gvIKeXdOtbSCJw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, "node_modules/@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", @@ -10120,6 +10919,137 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/dom/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.5.0.tgz", + "integrity": "sha512-xGGHpBXYSHUUr6XsKBfs85TWlYKpTc37cSBBVrXcib2MkHLboWlkClhWF37JKlDb9KEq3dHs+f2xR7XJEWGBxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/user-event": { + "version": "14.5.2", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", + "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -10180,6 +11110,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -10338,6 +11275,13 @@ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "license": "MIT" }, + "node_modules/@types/doctrine": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", + "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/eslint": { "version": "8.56.12", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", @@ -10550,6 +11494,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -10906,6 +11857,13 @@ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", "license": "MIT" }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/vimeo__player": { "version": "2.18.3", "resolved": "https://registry.npmjs.org/@types/vimeo__player/-/vimeo__player-2.18.3.tgz", @@ -11349,6 +12307,102 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, + "node_modules/@vitest/expect": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.0.5.tgz", + "integrity": "sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.0.5", + "@vitest/utils": "2.0.5", + "chai": "^5.1.1", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/expect/node_modules/@vitest/pretty-format": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.0.5.tgz", + "integrity": "sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/expect/node_modules/@vitest/utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.0.5.tgz", + "integrity": "sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.0.5", + "estree-walker": "^3.0.3", + "loupe": "^3.1.1", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/expect/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz", + "integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.0.5.tgz", + "integrity": "sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz", + "integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.8", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -12170,6 +13224,16 @@ "safer-buffer": "~2.1.0" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/ast-types": { "version": "0.13.4", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", @@ -12683,6 +13747,50 @@ "tweetnacl": "^0.14.3" } }, + "node_modules/better-opn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", + "integrity": "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "open": "^8.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/better-opn/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/better-opn/node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bfj": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.1.0.tgz", @@ -12901,6 +14009,12 @@ "base64-js": "^1.1.2" } }, + "node_modules/browser-assert": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", + "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", + "dev": true + }, "node_modules/browser-process-hrtime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", @@ -13206,6 +14320,23 @@ "node": ">=4" } }, + "node_modules/chai": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", + "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -13238,6 +14369,16 @@ "dev": true, "license": "MIT" }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/check-types": { "version": "11.2.3", "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz", @@ -14677,6 +15818,13 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, "node_modules/cssdb": { "version": "7.11.2", "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.11.2.tgz", @@ -15177,6 +16325,16 @@ } } }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/deep-equal": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", @@ -15363,6 +16521,16 @@ "node": ">= 0.8" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -15501,6 +16669,13 @@ "node": ">=6.0.0" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, "node_modules/dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -16215,6 +17390,44 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/esbuild-register": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", + "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, + "node_modules/esbuild-register/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild-register/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -19746,7 +20959,6 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=8" } @@ -22566,6 +23778,16 @@ "dev": true, "license": "MIT" }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/jsdom": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", @@ -23478,6 +24700,13 @@ "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==", "license": "MIT" }, + "node_modules/loupe": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", + "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", + "dev": true, + "license": "MIT" + }, "node_modules/lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", @@ -23544,6 +24773,16 @@ "node": ">=12" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -23618,6 +24857,13 @@ "tmpl": "1.0.5" } }, + "node_modules/map-or-similar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", + "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", + "dev": true, + "license": "MIT" + }, "node_modules/markdown-it": { "version": "13.0.2", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz", @@ -23752,6 +24998,16 @@ "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", "license": "MIT" }, + "node_modules/memoizerific": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", + "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", + "dev": true, + "license": "MIT", + "dependencies": { + "map-or-similar": "^1.5.0" + } + }, "node_modules/mensch": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", @@ -23846,6 +25102,16 @@ "node": ">=6" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/mini-css-extract-plugin": { "version": "2.9.2", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", @@ -25685,6 +26951,16 @@ "node": ">=8" } }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, "node_modules/pdfkit": { "version": "0.15.2", "resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.15.2.tgz", @@ -25971,6 +27247,19 @@ "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz", "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==" }, + "node_modules/polished": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", + "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/portfinder": { "version": "1.0.32", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz", @@ -28466,6 +29755,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/react-docgen": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-7.1.0.tgz", + "integrity": "sha512-APPU8HB2uZnpl6Vt/+0AFoVYgSRtfiP6FLrZgPPTDmqSb2R4qZRbgd0A3VzIFxDt5e+Fozjx79WjLWnF69DK8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.18.9", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "@types/babel__core": "^7.18.0", + "@types/babel__traverse": "^7.18.0", + "@types/doctrine": "^0.0.9", + "@types/resolve": "^1.20.2", + "doctrine": "^3.0.0", + "resolve": "^1.22.1", + "strip-indent": "^4.0.0" + }, + "engines": { + "node": ">=16.14.0" + } + }, + "node_modules/react-docgen-typescript": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz", + "integrity": "sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">= 4.3.x" + } + }, + "node_modules/react-docgen/node_modules/@types/resolve": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", + "integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==", + "dev": true, + "license": "MIT" + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -30142,6 +31470,46 @@ "node": ">=8.10.0" } }, + "node_modules/recast": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.9.tgz", + "integrity": "sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/recast/node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/recast/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/recharts": { "version": "2.15.0", "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.0.tgz", @@ -30192,6 +31560,33 @@ "node": ">=6.0.0" } }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/redux": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", @@ -32150,6 +33545,33 @@ "node": ">= 0.4" } }, + "node_modules/storybook": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.5.1.tgz", + "integrity": "sha512-HuaAFA97j2w4i/1EHKj6X4iDiVzPrXzQpmTEE1tLD1QXzqrQKKHse+Ggc8AGMuLTAzxA6xmrX9xibgMNWCgvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/core": "8.5.1" + }, + "bin": { + "getstorybook": "bin/index.cjs", + "sb": "bin/index.cjs", + "storybook": "bin/index.cjs" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, "node_modules/stream-chain": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", @@ -32476,6 +33898,22 @@ "node": ">=6" } }, + "node_modules/strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -33627,6 +35065,26 @@ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", "license": "MIT" }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", @@ -33752,6 +35210,16 @@ "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", "license": "MIT" }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, "node_modules/ts-deepmerge": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-2.0.7.tgz", @@ -34651,6 +36119,20 @@ "integrity": "sha512-QXo+O/QkLP/x1nyi54uQiG0XrODxdysuQvE5dtVqv7F5K2Qb6FsN+qbr6KhF5wQ20tfcV3VQp0/2x1e1MRSPWg==", "license": "MIT" }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -36251,10 +37733,18 @@ "react": ">=18.3.1", "react-dom": ">=18.3.1", "react-hook-form": "^7.52.1", + "tailwind-merge": "^2.5.3", "tailwindcss-animate": "^1.0.7", "zod": "^3.23.8" }, "devDependencies": { + "@storybook/addon-essentials": "^8.5.1", + "@storybook/addon-interactions": "^8.5.1", + "@storybook/addon-onboarding": "^8.5.1", + "@storybook/blocks": "^8.5.1", + "@storybook/react": "^8.5.1", + "@storybook/react-vite": "^8.5.1", + "@storybook/test": "^8.5.1", "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.13", "@types/react": "^18.3.18", @@ -36266,6 +37756,7 @@ "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "storybook": "^8.5.1", "tailwind-merge": "^2.4.0", "tailwindcss": "^3.4.4" } diff --git a/package.json b/package.json index 2e97eaef7..187f9f5d8 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,9 @@ "website:test:e2e:update": "npm --workspace=@socialincome/website run test:e2e:update", "website:test:e2e:update:emulator": "npm --workspace=@socialincome/website run test:e2e:update:emulator", "website:extract-translations": "npm --workspace=@socialincome/website run extract-translations", - "website:check-translations": "npm --workspace=@socialincome/website run check-translations" + "website:check-translations": "npm --workspace=@socialincome/website run check-translations", + "ui:serve": "npm --workspace=@socialincome/ui run storybook", + "ui:build": "npm --workspace=@socialincome/ui run build-storybook" }, "devDependencies": { "firebase-tools": "13.29.1", diff --git a/ui/.gitignore b/ui/.gitignore index bcc318b81..dc0ff257b 100644 --- a/ui/.gitignore +++ b/ui/.gitignore @@ -1,2 +1,4 @@ storybook-static dist + +*storybook.log diff --git a/ui/.storybook/main.js b/ui/.storybook/main.js new file mode 100644 index 000000000..78408f9d1 --- /dev/null +++ b/ui/.storybook/main.js @@ -0,0 +1,40 @@ +import { dirname, join } from 'path'; + +/** + * This function is used to resolve the absolute path of a package. + * It is needed in projects that use Yarn PnP or are set up within a monorepo. + */ +function getAbsolutePath(value) { + return dirname(require.resolve(join(value, 'package.json'))); +} + +/** @type { import('@storybook/react-vite').StorybookConfig } */ +const config = { + stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + + addons: [ + getAbsolutePath('@storybook/addon-onboarding'), + getAbsolutePath('@storybook/addon-essentials'), + getAbsolutePath('@storybook/addon-interactions'), + ], + + framework: { + name: getAbsolutePath('@storybook/react-vite'), + options: {}, + }, + + viteFinal: async (config) => { + // Use PostCSS config from postcss.config.js + config.css = { + postcss: true, + }; + return config; + }, + + docs: {}, + + typescript: { + reactDocgen: 'react-docgen-typescript', + }, +}; +export default config; diff --git a/ui/.storybook/preview.js b/ui/.storybook/preview.js new file mode 100644 index 000000000..731568931 --- /dev/null +++ b/ui/.storybook/preview.js @@ -0,0 +1,17 @@ +import '../src/globals.css'; + +/** @type { import('@storybook/react').Preview } */ +const preview = { + parameters: { + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + }, + + tags: ['autodocs'], +}; + +export default preview; diff --git a/ui/package.json b/ui/package.json index 91bc6931b..5a5c94ee8 100644 --- a/ui/package.json +++ b/ui/package.json @@ -40,9 +40,17 @@ "react-dom": ">=18.3.1", "react-hook-form": "^7.52.1", "tailwindcss-animate": "^1.0.7", + "tailwind-merge": "^2.5.3", "zod": "^3.23.8" }, "devDependencies": { + "@storybook/addon-essentials": "^8.5.1", + "@storybook/addon-interactions": "^8.5.1", + "@storybook/addon-onboarding": "^8.5.1", + "@storybook/blocks": "^8.5.1", + "@storybook/react": "^8.5.1", + "@storybook/react-vite": "^8.5.1", + "@storybook/test": "^8.5.1", "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.13", "@types/react": "^18.3.18", @@ -54,7 +62,12 @@ "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "storybook": "^8.5.1", "tailwind-merge": "^2.4.0", "tailwindcss": "^3.4.4" + }, + "scripts": { + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" } } diff --git a/ui/src/components/button.tsx b/ui/src/components/button.tsx index 8499b6c1f..3384bfa4f 100644 --- a/ui/src/components/button.tsx +++ b/ui/src/components/button.tsx @@ -1,8 +1,8 @@ import { Slot } from '@radix-ui/react-slot'; -import { SpinnerIcon } from '@socialincome/website/src/components/logos/spinner-icon'; import { cva, type VariantProps } from 'class-variance-authority'; import * as React from 'react'; import { ComponentType } from 'react'; +import { SpinnerIcon } from '../icons/spinner'; import { cn } from '../lib/utils'; const buttonVariants = cva( diff --git a/ui/src/components/dropdown-menu.tsx b/ui/src/components/dropdown-menu.tsx deleted file mode 100644 index 38a9ac392..000000000 --- a/ui/src/components/dropdown-menu.tsx +++ /dev/null @@ -1,180 +0,0 @@ -'use client'; - -import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'; -import { Check, ChevronRight, Circle } from 'lucide-react'; -import * as React from 'react'; -import { cn } from '../lib/utils'; - -const DropdownMenu = DropdownMenuPrimitive.Root; - -const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; - -const DropdownMenuGroup = DropdownMenuPrimitive.Group; - -const DropdownMenuPortal = DropdownMenuPrimitive.Portal; - -const DropdownMenuSub = DropdownMenuPrimitive.Sub; - -const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; - -const DropdownMenuSubTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, children, ...props }, ref) => ( - - {children} - - -)); -DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName; - -const DropdownMenuSubContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName; - -const DropdownMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( - - - -)); -DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; - -const DropdownMenuItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, ...props }, ref) => ( - -)); -DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; - -const DropdownMenuCheckboxItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, checked, ...props }, ref) => ( - - - - - - - {children} - -)); -DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName; - -const DropdownMenuRadioItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - - - - {children} - -)); -DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; - -const DropdownMenuLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, ...props }, ref) => ( - -)); -DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; - -const DropdownMenuSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; - -const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes) => { - return ; -}; -DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'; - -export { - DropdownMenu, - DropdownMenuCheckboxItem, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuPortal, - DropdownMenuRadioGroup, - DropdownMenuRadioItem, - DropdownMenuSeparator, - DropdownMenuShortcut, - DropdownMenuSub, - DropdownMenuSubContent, - DropdownMenuSubTrigger, - DropdownMenuTrigger, -}; diff --git a/ui/src/components/menubar.tsx b/ui/src/components/menubar.tsx deleted file mode 100644 index 80010fd45..000000000 --- a/ui/src/components/menubar.tsx +++ /dev/null @@ -1,208 +0,0 @@ -'use client'; - -import * as MenubarPrimitive from '@radix-ui/react-menubar'; -import { Check, ChevronRight, Circle } from 'lucide-react'; -import * as React from 'react'; -import { cn } from '../lib/utils'; - -const MenubarMenu = MenubarPrimitive.Menu; - -const MenubarGroup = MenubarPrimitive.Group; - -const MenubarPortal = MenubarPrimitive.Portal; - -const MenubarSub = MenubarPrimitive.Sub; - -const MenubarRadioGroup = MenubarPrimitive.RadioGroup; - -const Menubar = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -Menubar.displayName = MenubarPrimitive.Root.displayName; - -const MenubarTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName; - -const MenubarSubTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, children, ...props }, ref) => ( - - {children} - - -)); -MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName; - -const MenubarSubContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName; - -const MenubarContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, align = 'start', alignOffset = -4, sideOffset = 8, ...props }, ref) => ( - - - -)); -MenubarContent.displayName = MenubarPrimitive.Content.displayName; - -const MenubarItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, ...props }, ref) => ( - -)); -MenubarItem.displayName = MenubarPrimitive.Item.displayName; - -const MenubarCheckboxItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, checked, ...props }, ref) => ( - - - - - - - {children} - -)); -MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName; - -const MenubarRadioItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - - - - {children} - -)); -MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName; - -const MenubarLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, ...props }, ref) => ( - -)); -MenubarLabel.displayName = MenubarPrimitive.Label.displayName; - -const MenubarSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName; - -const MenubarShortcut = ({ className, ...props }: React.HTMLAttributes) => { - return ; -}; -MenubarShortcut.displayname = 'MenubarShortcut'; - -export { - Menubar, - MenubarCheckboxItem, - MenubarContent, - MenubarGroup, - MenubarItem, - MenubarLabel, - MenubarMenu, - MenubarPortal, - MenubarRadioGroup, - MenubarRadioItem, - MenubarSeparator, - MenubarShortcut, - MenubarSub, - MenubarSubContent, - MenubarSubTrigger, - MenubarTrigger, -}; diff --git a/ui/src/components/navigation-menu.tsx b/ui/src/components/navigation-menu.tsx deleted file mode 100644 index cb8554310..000000000 --- a/ui/src/components/navigation-menu.tsx +++ /dev/null @@ -1,121 +0,0 @@ -'use client'; - -import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu'; -import { cva } from 'class-variance-authority'; -import { ChevronDown } from 'lucide-react'; -import * as React from 'react'; -import { cn } from '../lib/utils'; - -const NavigationMenu = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - {children} - - -)); -NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName; - -const NavigationMenuList = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName; - -const NavigationMenuItem = NavigationMenuPrimitive.Item; - -const navigationMenuTriggerStyle = cva( - 'group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-lg font-medium transition-colors hover:bg-muted hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50', -); - -const NavigationMenuTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - {children}{' '} - -)); -NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName; - -const NavigationMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName; - -const NavigationMenuLink = NavigationMenuPrimitive.Link; - -const NavigationMenuViewport = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( -
- -
-)); -NavigationMenuViewport.displayName = NavigationMenuPrimitive.Viewport.displayName; - -const NavigationMenuIndicator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -
- -)); -NavigationMenuIndicator.displayName = NavigationMenuPrimitive.Indicator.displayName; - -export { - NavigationMenu, - NavigationMenuContent, - NavigationMenuIndicator, - NavigationMenuItem, - NavigationMenuLink, - NavigationMenuList, - NavigationMenuTrigger, - navigationMenuTriggerStyle, - NavigationMenuViewport, -}; diff --git a/website/src/components/logos/donate-icon.tsx b/ui/src/icons/donate.tsx similarity index 96% rename from website/src/components/logos/donate-icon.tsx rename to ui/src/icons/donate.tsx index 75b7a774e..7d4d6e0d2 100644 --- a/website/src/components/logos/donate-icon.tsx +++ b/ui/src/icons/donate.tsx @@ -8,9 +8,12 @@ export function DonateIcon({ className, ...props }: HTMLAttributes) height="19" viewBox="0 0 19 19" fill="currentColor" + aria-labelledby="donate-icon-title" xmlns="http://www.w3.org/2000/svg" className={twMerge('text-accent', className)} + {...props} > + ) { xmlSpace="preserve" fill="currentColor" aria-hidden={true} - aria-labelledby="si-icon" + aria-labelledby="si-icon-title" viewBox="0 0 816 815.8" className={twMerge('text-accent', className)} {...props} > - Social Income Icon + Social Income Icon diff --git a/website/src/components/logos/spinner-icon.tsx b/ui/src/icons/spinner.tsx similarity index 87% rename from website/src/components/logos/spinner-icon.tsx rename to ui/src/icons/spinner.tsx index 85c5845bf..5b4087321 100644 --- a/website/src/components/logos/spinner-icon.tsx +++ b/ui/src/icons/spinner.tsx @@ -9,11 +9,12 @@ export function SpinnerIcon({ className, ...props }: HTMLAttributes) xmlSpace="preserve" fill="none" aria-hidden={true} - aria-labelledby="si-logo-title" + aria-labelledby="spinner-icon-title" viewBox="0 0 24 24" className={twMerge('h-5 w-5 animate-spin', className)} {...props} > + Loading spinner ; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + type: 'single', + collapsible: true, + className: 'w-[400px]', + }, + render: () => ( + + + Is it accessible? + Yes. It adheres to the WAI-ARIA design pattern. + + + + Is it styled? + + Yes. It comes with default styles that match the other components' aesthetic. + + + + + Is it animated? + Yes. It's animated by default, but you can disable it if you prefer. + + + ), +}; + +export const Multiple: Story = { + args: { + type: 'multiple', + className: 'w-[400px]', + }, + render: () => ( + + + Can I open multiple items? + Yes. Just set the type prop to "multiple" on the Accordion component. + + + + Is it responsive? + Yes. The accordion adjusts to different screen sizes. + + + + Can I customize the styles? + Yes. You can use the className prop to override the default styles. + + + ), +}; diff --git a/ui/src/stories/alert.stories.tsx b/ui/src/stories/alert.stories.tsx new file mode 100644 index 000000000..49c6d7db9 --- /dev/null +++ b/ui/src/stories/alert.stories.tsx @@ -0,0 +1,86 @@ +import { ExclamationTriangleIcon, InformationCircleIcon } from '@heroicons/react/24/outline'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Alert, AlertDescription, AlertTitle } from '../components/alert'; + +const meta: Meta = { + title: 'Components/Alert', + component: Alert, + tags: ['autodocs'], +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + Default Alert + This is a default alert message. + + ), +}; + +export const Primary: Story = { + render: () => ( + + + Primary Alert + This is a primary alert with an icon. + + ), +}; + +export const Secondary: Story = { + render: () => ( + + Secondary Alert + This is a secondary alert message. + + ), +}; + +export const Accent: Story = { + render: () => ( + + Accent Alert + This is an accent alert message. + + ), +}; + +export const Destructive: Story = { + render: () => ( + + + Destructive Alert + This is a destructive alert with a warning icon. + + ), +}; + +export const WithoutTitle: Story = { + render: () => ( + + This is an alert without a title. + + ), +}; + +export const WithoutDescription: Story = { + render: () => ( + + Alert without description + + ), +}; + +export const CustomContent: Story = { + render: () => ( + + Custom Styled Alert + + This alert has custom styling applied through className props. + + + ), +}; diff --git a/ui/src/stories/avatar.stories.tsx b/ui/src/stories/avatar.stories.tsx new file mode 100644 index 000000000..1edd13379 --- /dev/null +++ b/ui/src/stories/avatar.stories.tsx @@ -0,0 +1,77 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Avatar, AvatarFallback, AvatarImage } from '../components/avatar'; + +const meta = { + title: 'Components/Avatar', + component: Avatar, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Avatar with Image +export const WithImage: Story = { + render: () => ( + + + CN + + ), +}; + +// Avatar with Fallback +export const WithFallback: Story = { + render: () => ( + + JD + + ), +}; + +// Avatar with Failed Image Load +export const WithFailedImage: Story = { + render: () => ( + + + 404 + + ), +}; + +// Custom Sized Avatar +export const CustomSize: Story = { + render: () => ( +
+ + + LG + + + + MD + + + + SM + +
+ ), +}; + +// Custom Styled Avatar +export const CustomStyled: Story = { + render: () => ( +
+ + P + + + S + + + A + +
+ ), +}; diff --git a/ui/src/stories/badge.stories.tsx b/ui/src/stories/badge.stories.tsx new file mode 100644 index 000000000..55059394d --- /dev/null +++ b/ui/src/stories/badge.stories.tsx @@ -0,0 +1,86 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Badge } from '../components/badge'; + +const meta = { + title: 'Components/Badge', + component: Badge, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Default Badge +export const Default: Story = { + render: () => Default Badge, +}; + +// All Variants +export const Variants: Story = { + render: () => ( +
+ Default + Secondary + Destructive + Muted + Accent + Outline +
+ ), +}; + +// Interactive States +export const Interactive: Story = { + render: () => ( +
+ Clickable Badge + + Clickable Secondary + + + Clickable Destructive + +
+ ), +}; + +// With Icons +export const WithIcons: Story = { + render: () => ( +
+ + Online + + + New + + + + Critical + +
+ ), +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( +
+ Custom Blue + Custom Green + Custom Border + Custom Rounded +
+ ), +}; + +// Different Sizes +export const Sizes: Story = { + render: () => ( +
+ Small + Default + Large + Extra Large +
+ ), +}; diff --git a/ui/src/stories/button.stories.tsx b/ui/src/stories/button.stories.tsx new file mode 100644 index 000000000..3a2b5478b --- /dev/null +++ b/ui/src/stories/button.stories.tsx @@ -0,0 +1,128 @@ +import { ArrowRightIcon, ChevronRightIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/outline'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Button } from '../components/button'; + +const meta = { + title: 'Components/Button', + component: Button, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Variants +export const Variants: Story = { + render: () => ( +
+ + + + + + +
+ ), +}; + +// Sizes +export const Sizes: Story = { + render: () => ( +
+ + + + +
+ ), +}; + +// With Icons +export const WithIcons: Story = { + render: () => ( +
+ + + + +
+ ), +}; + +// Loading State +export const Loading: Story = { + render: () => ( +
+ + + +
+ ), +}; + +// Disabled State +export const Disabled: Story = { + render: () => ( +
+ + + + +
+ ), +}; + +// Icon Only Buttons +export const IconOnly: Story = { + render: () => ( +
+ + + + +
+ ), +}; + +// Combined Features +export const Combined: Story = { + render: () => ( +
+ + + +
+ ), +}; diff --git a/ui/src/stories/card.stories.tsx b/ui/src/stories/card.stories.tsx new file mode 100644 index 000000000..078a3d136 --- /dev/null +++ b/ui/src/stories/card.stories.tsx @@ -0,0 +1,111 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Button } from '../components/button'; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '../components/card'; + +const meta = { + title: 'Components/Card', + component: Card, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Card +export const Basic: Story = { + render: () => ( + + + Card Title + Card Description + + +

Card Content

+
+
+ ), +}; + +// Card with Footer +export const WithFooter: Story = { + render: () => ( + + + Newsletter + Get updates on our latest features. + + +

Subscribe to our newsletter to stay updated with our latest news and features.

+
+ + + + +
+ ), +}; + +// Interactive Card +export const Interactive: Story = { + render: () => ( + + + Interactive Card + This card has hover and click effects + + +

Click or hover over this card to see the effects.

+
+
+ ), +}; + +// Custom Styled Card +export const CustomStyled: Story = { + render: () => ( + + + Custom Theme + Custom styled card with primary theme + + +

This card uses custom background and text colors.

+
+ + + +
+ ), +}; + +// Multiple Cards Layout +export const GridLayout: Story = { + render: () => ( +
+ + + Card 1 + + Content 1 + + + + Card 2 + + Content 2 + + + + Card 3 + + Content 3 + + + + Card 4 + + Content 4 + +
+ ), +}; diff --git a/ui/src/stories/carousel.stories.tsx b/ui/src/stories/carousel.stories.tsx new file mode 100644 index 000000000..55838daaf --- /dev/null +++ b/ui/src/stories/carousel.stories.tsx @@ -0,0 +1,158 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import React from 'react'; +import { Card, CardContent } from '../components/card'; +import { Carousel, CarouselContent } from '../components/carousel'; + +const meta = { + title: 'Components/Carousel', + component: Carousel, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Helper component for demo slides +const DemoSlide = ({ children }: { children: React.ReactNode }) => ( + + + {children} + + +); + +// Basic Carousel +export const Basic: Story = { + render: () => ( + + + 1 + + + 2 + + + 3 + + + ), +}; + +// With Controls +export const WithControls: Story = { + render: () => ( + + + 1 + + + 2 + + + 3 + + + ), +}; + +// With Dots +export const WithDots: Story = { + render: () => ( + + + 1 + + + 2 + + + 3 + + + ), +}; + +// With Both Controls and Dots +export const WithControlsAndDots: Story = { + render: () => ( + + + 1 + + + 2 + + + 3 + + + ), +}; + +// Multiple Slides +export const MultipleSlides: Story = { + render: () => ( + + {[1, 2, 3, 4, 5, 6].map((num) => ( + + {num} + + ))} + + ), +}; + +// Autoplay +export const Autoplay: Story = { + render: () => ( + + + 1 + + + 2 + + + 3 + + + ), +}; + +// Custom Content +export const CustomContent: Story = { + render: () => ( + + +
+
+ Custom 1 +
+
+
+ +
+
+ Custom 2 +
+
+
+ +
+
+ Custom 3 +
+
+
+
+ ), +}; diff --git a/ui/src/stories/checkbox.stories.tsx b/ui/src/stories/checkbox.stories.tsx new file mode 100644 index 000000000..be8d84abe --- /dev/null +++ b/ui/src/stories/checkbox.stories.tsx @@ -0,0 +1,102 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import React from 'react'; +import { Checkbox } from '../components/checkbox'; +import { Label } from '../components/label'; + +const meta = { + title: 'Components/Checkbox', + component: Checkbox, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Checkbox +export const Basic: Story = { + render: () => , +}; + +// With Label +export const WithLabel: Story = { + render: () => ( +
+ + +
+ ), +}; + +// Checked State +export const Checked: Story = { + render: () => , +}; + +// Disabled States +export const Disabled: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ ), +}; + +// Form Example +export const FormExample: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ + +
+
+ ), +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ + +
+
+ ), +}; + +// Interactive Example +export const Interactive: Story = { + render: () => { + const [checked, setChecked] = React.useState(false); + return ( +
+ setChecked(Boolean(checkedState))} /> + +
+ ); + }, +}; diff --git a/ui/src/stories/collapsible.stories.tsx b/ui/src/stories/collapsible.stories.tsx new file mode 100644 index 000000000..eb2222bbb --- /dev/null +++ b/ui/src/stories/collapsible.stories.tsx @@ -0,0 +1,138 @@ +import { ChevronDownIcon } from '@heroicons/react/24/outline'; +import type { Meta, StoryObj } from '@storybook/react'; +import React from 'react'; +import { Button } from '../components/button'; +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../components/collapsible'; + +const meta = { + title: 'Components/Collapsible', + component: Collapsible, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Collapsible +export const Basic: Story = { + render: () => { + const [isOpen, setIsOpen] = React.useState(false); + return ( + +
+

What is a Collapsible?

+ + + +
+ +
+ A collapsible is a component that can be expanded or collapsed to show or hide content. +
+
+
+ ); + }, +}; + +// Multiple Sections +export const MultipleSections: Story = { + render: () => { + const [openSections, setOpenSections] = React.useState([]); + + const toggleSection = (index: number) => { + setOpenSections((current) => + current.includes(index) ? current.filter((i) => i !== index) : [...current, index], + ); + }; + + return ( +
+ {[1, 2, 3].map((section) => ( + toggleSection(section)} + className="rounded-lg border" + > +
+

Section {section}

+ + + +
+ +
Content for section {section}
+
+
+ ))} +
+ ); + }, +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => { + const [isOpen, setIsOpen] = React.useState(false); + return ( + +
+

Custom Styled Collapsible

+ + + +
+ +
+ This is a custom styled collapsible with primary color theme. +
+
+
+ ); + }, +}; + +// With Animation +export const WithAnimation: Story = { + render: () => { + const [isOpen, setIsOpen] = React.useState(false); + return ( + +
+

Animated Collapsible

+ + + +
+ +
+
+ This collapsible has smooth animations for both the chevron and content. +
+
+
+
+ ); + }, +}; diff --git a/ui/src/stories/dialog.stories.tsx b/ui/src/stories/dialog.stories.tsx new file mode 100644 index 000000000..a623e9271 --- /dev/null +++ b/ui/src/stories/dialog.stories.tsx @@ -0,0 +1,146 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Button } from '../components/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '../components/dialog'; + +const meta = { + title: 'Components/Dialog', + component: Dialog, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Dialog +export const Basic: Story = { + render: () => ( + + + + + + + Dialog Title + This is a basic dialog with a title and description. + + + + ), +}; + +// Dialog with Footer Actions +export const WithActions: Story = { + render: () => ( + + + + + + + Confirm Action + Are you sure you want to perform this action? This cannot be undone. + + + + + + + + ), +}; + +// Form Dialog +export const FormDialog: Story = { + render: () => ( + + + + + + + Edit Profile + Make changes to your profile here. Click save when you're done. + +
+
+ + +
+
+ + +
+
+ + + +
+
+ ), +}; + +// Custom Styled Dialog +export const CustomStyled: Story = { + render: () => ( + + + + + + + Custom Theme + + This dialog uses custom background and text colors. + + +
+

Custom styled content goes here.

+
+ + + +
+
+ ), +}; + +// Alert Dialog +export const AlertDialog: Story = { + render: () => ( + + + + + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete your account and remove your data from our + servers. + + + + + + + + + ), +}; diff --git a/ui/src/stories/form.stories.tsx b/ui/src/stories/form.stories.tsx new file mode 100644 index 000000000..324765e3a --- /dev/null +++ b/ui/src/stories/form.stories.tsx @@ -0,0 +1,215 @@ +import { zodResolver } from '@hookform/resolvers/zod'; +import type { Meta, StoryObj } from '@storybook/react'; +import { useForm } from 'react-hook-form'; +import * as z from 'zod'; +import { Button } from '../components/button'; +import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '../components/form'; +import { Input } from '../components/input'; + +const meta = { + title: 'Components/Form', + component: Form, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Form Schema +const formSchema = z.object({ + username: z.string().min(2, { + message: 'Username must be at least 2 characters.', + }), + email: z.string().email({ + message: 'Please enter a valid email address.', + }), +}); + +// Basic Form +export const Basic: Story = { + render: () => { + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + username: '', + email: '', + }, + }); + + function onSubmit(values: z.infer) { + console.log(values); + } + + return ( +
+ + ( + + Username + + + + This is your public display name. + + + )} + /> + ( + + Email + + + + We'll never share your email with anyone else. + + + )} + /> + + + + ); + }, +}; + +// Form with Validation +export const WithValidation: Story = { + render: () => { + const form = useForm>({ + resolver: zodResolver(formSchema), + mode: 'onChange', + }); + + function onSubmit(values: z.infer) { + console.log(values); + } + + return ( +
+ + ( + + Username + + + + + + )} + /> + ( + + Email + + + + + + )} + /> + + + + ); + }, +}; + +// Form with Custom Styling +export const CustomStyled: Story = { + render: () => { + const form = useForm>(); + + return ( +
+ + ( + + Username + + + + Custom styled form field + + + )} + /> + + + + ); + }, +}; + +// Form with Different States +export const DifferentStates: Story = { + render: () => { + const form = useForm(); + + return ( +
+
+ ( + + Default State + + + + + )} + /> + + +
+ ( + + Disabled State + + + + + )} + /> + + +
+ ( + + Error State + + + + This is an error message + + )} + /> + +
+ ); + }, +}; diff --git a/ui/src/stories/hover-card.stories.tsx b/ui/src/stories/hover-card.stories.tsx new file mode 100644 index 000000000..ffd4741b7 --- /dev/null +++ b/ui/src/stories/hover-card.stories.tsx @@ -0,0 +1,161 @@ +import { CalendarIcon, UserIcon } from '@heroicons/react/24/outline'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Button } from '../components/button'; +import { HoverCard, HoverCardContent, HoverCardTrigger } from '../components/hover-card'; + +const meta = { + title: 'Components/HoverCard', + component: HoverCard, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Hover Card +export const Basic: Story = { + render: () => ( +
+ + + + + +
+
+
+ +
+
+

@username

+

Full Name

+
+
+

Frontend developer and UI designer. Love creating beautiful user interfaces.

+
+
+
+
+ ), +}; + +// With Rich Content +export const RichContent: Story = { + render: () => ( +
+ + + + + +
+
+

@johndoe

+

The quick brown fox jumps over the lazy dog.

+
+ + Joined December 2021 +
+
+
+
+
+
+ + +
+ ), +}; + +// Different Positions +export const Positions: Story = { + render: () => ( +
+ + + + + +

This card appears on top

+
+
+ + + + + + +

This card appears at the bottom

+
+
+ + + + + + +

This card appears on the left

+
+
+ + + + + + +

This card appears on the right

+
+
+
+ ), +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( +
+ + + + + +
+

Custom Styled Card

+

This hover card has custom background and text colors.

+
+
+
+
+ ), +}; + +// With Interactive Content +export const WithInteractiveContent: Story = { + render: () => ( +
+ + + + + +
+
+

Interactive Content

+

This card contains interactive elements.

+
+
+ + +
+
+
+
+
+ ), +}; diff --git a/ui/src/stories/icons.stories.tsx b/ui/src/stories/icons.stories.tsx new file mode 100644 index 000000000..89e9071bd --- /dev/null +++ b/ui/src/stories/icons.stories.tsx @@ -0,0 +1,64 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { DonateIcon } from '../icons/donate'; +import { SIIcon } from '../icons/si'; +import { SpinnerIcon } from '../icons/spinner'; + +const meta = { + title: 'Components/Icons', + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const AllIcons: Story = { + render: () => ( +
+
+ + DonateIcon +
+
+ + SIIcon +
+
+ + SpinnerIcon +
+
+ ), +}; + +export const Sizes: Story = { + render: () => ( +
+ + + + +
+ ), +}; + +export const Colors: Story = { + render: () => ( +
+ + + + +
+ ), +}; + +export const AnimatedSpinner: Story = { + render: () => ( +
+ + + + +
+ ), +}; diff --git a/ui/src/stories/input.stories.tsx b/ui/src/stories/input.stories.tsx new file mode 100644 index 000000000..a6ac391da --- /dev/null +++ b/ui/src/stories/input.stories.tsx @@ -0,0 +1,107 @@ +import { MagnifyingGlassIcon } from '@heroicons/react/24/outline'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Input } from '../components/input'; + +const meta = { + title: 'Components/Input', + component: Input, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Input +export const Basic: Story = { + render: () => , +}; + +// Input Types +export const Types: Story = { + render: () => ( +
+ + + + + + + +
+ ), +}; + +// States +export const States: Story = { + render: () => ( +
+ + + + +
+ ), +}; + +// With Icon +export const WithIcon: Story = { + render: () => ( +
+ + +
+ ), +}; + +// Sizes +export const Sizes: Story = { + render: () => ( +
+ + + +
+ ), +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( +
+ + + +
+ ), +}; + +// With Label and Error +export const WithLabelAndError: Story = { + render: () => ( +
+
+ + +
+
+ + +

Please enter a valid email address

+
+
+ ), +}; + +// With Button +export const WithButton: Story = { + render: () => ( +
+ + +
+ ), +}; diff --git a/ui/src/stories/label.stories.tsx b/ui/src/stories/label.stories.tsx new file mode 100644 index 000000000..f6f73ae43 --- /dev/null +++ b/ui/src/stories/label.stories.tsx @@ -0,0 +1,116 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Checkbox } from '../components/checkbox'; +import { Input } from '../components/input'; +import { Label } from '../components/label'; +import { Switch } from '../components/switch'; + +const meta = { + title: 'Components/Label', + component: Label, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Label +export const Basic: Story = { + render: () => , +}; + +// With Input +export const WithInput: Story = { + render: () => ( +
+ + +
+ ), +}; + +// With Required Field +export const Required: Story = { + render: () => ( +
+ + +
+ ), +}; + +// With Checkbox +export const WithCheckbox: Story = { + render: () => ( +
+ + +
+ ), +}; + +// With Switch +export const WithSwitch: Story = { + render: () => ( +
+ + +
+ ), +}; + +// Different States +export const States: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ + +
+
+ ), +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ ), +}; + +// With Description +export const WithDescription: Story = { + render: () => ( +
+ + +

Accepted formats: .jpg, .png, .gif

+
+ ), +}; diff --git a/ui/src/stories/popover.stories.tsx b/ui/src/stories/popover.stories.tsx new file mode 100644 index 000000000..36a42026b --- /dev/null +++ b/ui/src/stories/popover.stories.tsx @@ -0,0 +1,136 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Button } from '../components/button'; +import { Popover, PopoverContent, PopoverTrigger } from '../components/popover'; + +const meta = { + title: 'Components/Popover', + component: Popover, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Popover +export const Basic: Story = { + render: () => ( + + + + + +
+
+

Dimensions

+

Set the dimensions for the layer.

+
+
+
+
+ ), +}; + +// With Form Elements +export const WithFormElements: Story = { + render: () => ( + + + + + +
+
+

Profile

+

Update your profile information.

+
+
+
+ + +
+
+ + +
+
+
+
+
+ ), +}; + +// With Custom Delay +export const WithCustomDelay: Story = { + render: () => ( + + + + + +

This popover has a custom open delay of 500ms and close delay of 300ms.

+
+
+ ), +}; + +// With Rich Content +export const WithRichContent: Story = { + render: () => ( + + + + + +
+
+

Product Details

+
+
+
+

Premium Package

+

Access to all premium features

+

$99/month

+
+
+
+
+ + +
+
+ + + ), +}; + +// With Custom Positioning +export const WithCustomPositioning: Story = { + render: () => ( +
+ + + + + +
+ + + +
+
+
+
+ ), +}; diff --git a/ui/src/stories/progress.stories.tsx b/ui/src/stories/progress.stories.tsx new file mode 100644 index 000000000..cd55bc223 --- /dev/null +++ b/ui/src/stories/progress.stories.tsx @@ -0,0 +1,132 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import React from 'react'; +import { Progress } from '../components/progress'; + +const meta = { + title: 'Components/Progress', + component: Progress, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Progress +export const Basic: Story = { + render: () => ( +
+ +
+ ), +}; + +// Different Values +export const DifferentValues: Story = { + render: () => ( +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ ), +}; + +// Animated Progress +export const Animated: Story = { + render: () => { + const [progress, setProgress] = React.useState(0); + + React.useEffect(() => { + const timer = setInterval(() => { + setProgress((prevProgress) => (prevProgress >= 100 ? 0 : prevProgress + 10)); + }, 1000); + + return () => { + clearInterval(timer); + }; + }, []); + + return ( +
+ +
+ ); + }, +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( +
+
+ +
+
+ +
+
+ ), +}; + +// With Label +export const WithLabel: Story = { + render: () => { + const value = 75; + return ( +
+
+ Progress + {value}% +
+
+ +
+
+ ); + }, +}; + +// Different Sizes +export const DifferentSizes: Story = { + render: () => ( +
+
+ +
+
+ +
+
+ +
+
+ ), +}; diff --git a/ui/src/stories/radio-group.stories.tsx b/ui/src/stories/radio-group.stories.tsx new file mode 100644 index 000000000..993040faf --- /dev/null +++ b/ui/src/stories/radio-group.stories.tsx @@ -0,0 +1,134 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Label } from '../components/label'; +import { RadioGroup, RadioGroupItem } from '../components/radio-group'; + +const meta = { + title: 'Components/RadioGroup', + component: RadioGroup, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Radio Group +export const Basic: Story = { + render: () => ( + +
+ + +
+
+ + +
+
+ + +
+
+ ), +}; + +// With Description +export const WithDescription: Story = { + render: () => ( + +
+ +
+ +

System default spacing for controls and content.

+
+
+
+ +
+ +

Additional spacing for better readability.

+
+
+
+ +
+ +

Reduced spacing to show more content.

+
+
+
+ ), +}; + +// Disabled State +export const DisabledState: Story = { + render: () => ( + +
+ + +
+
+ + +
+
+ ), +}; + +// With Form +export const WithForm: Story = { + render: () => ( +
{ + e.preventDefault(); + // Handle form submission + }} + > +
+
+

Notification Preferences

+ +
+ + +
+
+ + +
+
+ + +
+
+
+ +
+
+ ), +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( + +
+ + +
+
+ + +
+
+ ), +}; diff --git a/ui/src/stories/select.stories.tsx b/ui/src/stories/select.stories.tsx new file mode 100644 index 000000000..0f6a93513 --- /dev/null +++ b/ui/src/stories/select.stories.tsx @@ -0,0 +1,160 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectSeparator, + SelectTrigger, + SelectValue, +} from '../components/select'; + +const meta = { + title: 'Components/Select', + component: Select, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Select +export const Basic: Story = { + render: () => ( + + ), +}; + +// With Groups and Labels +export const WithGroupsAndLabels: Story = { + render: () => ( + + ), +}; + +// Disabled State +export const DisabledState: Story = { + render: () => ( + + ), +}; + +// With Form +export const WithForm: Story = { + render: () => ( +
{ + e.preventDefault(); + // Handle form submission + }} + > +
+
+ + +
+ +
+
+ ), +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( + + ), +}; + +// With Error State +export const WithErrorState: Story = { + render: () => ( +
+ +

Please select an option

+
+ ), +}; diff --git a/ui/src/stories/separator.stories.tsx b/ui/src/stories/separator.stories.tsx new file mode 100644 index 000000000..dda99b215 --- /dev/null +++ b/ui/src/stories/separator.stories.tsx @@ -0,0 +1,101 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Separator } from '../components/separator'; + +const meta = { + title: 'Components/Separator', + component: Separator, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Horizontal Separator +export const BasicHorizontal: Story = { + render: () => ( +
+
Above
+ +
Below
+
+ ), +}; + +// Vertical Separator +export const Vertical: Story = { + render: () => ( +
+
Left
+ +
Right
+
+ ), +}; + +// With Content +export const WithContent: Story = { + render: () => ( +
+

Section 1

+

This is the first section of the content.

+ +

Section 2

+

This is the second section of the content.

+
+ ), +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( +
+ + + +
+
Left
+ +
Right
+
+
+ ), +}; + +// In Card Layout +export const InCardLayout: Story = { + render: () => ( +
+
+

Account Settings

+ +
+ +
+
+

Email

+

john@example.com

+
+ +
+

Password

+

Last changed 3 months ago

+
+
+
+ ), +}; + +// List Separator +export const ListSeparator: Story = { + render: () => ( +
+
Item 1
+ +
Item 2
+ +
Item 3
+ +
Item 4
+
+ ), +}; diff --git a/ui/src/stories/switch.stories.tsx b/ui/src/stories/switch.stories.tsx new file mode 100644 index 000000000..4ac55591c --- /dev/null +++ b/ui/src/stories/switch.stories.tsx @@ -0,0 +1,114 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import React from 'react'; +import { Label } from '../components/label'; +import { Switch } from '../components/switch'; + +const meta = { + title: 'Components/Switch', + component: Switch, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Switch +export const Basic: Story = { + render: () => , +}; + +// With Label +export const WithLabel: Story = { + render: () => ( +
+ + +
+ ), +}; + +// Disabled State +export const DisabledState: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ ), +}; + +// With Form +export const WithForm: Story = { + render: () => ( +
{ + e.preventDefault(); + // Handle form submission + }} + > +
+
+

Notification Settings

+
+ + +
+
+ + +
+
+ +
+
+ ), +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ + +
+
+ ), +}; + +// Interactive Example +export const InteractiveExample: Story = { + render: () => { + const [isEnabled, setIsEnabled] = React.useState(false); + + return ( +
+
+ + +
+

Current state: {isEnabled ? 'On' : 'Off'}

+
+ ); + }, +}; diff --git a/ui/src/stories/table.stories.tsx b/ui/src/stories/table.stories.tsx new file mode 100644 index 000000000..29845cf58 --- /dev/null +++ b/ui/src/stories/table.stories.tsx @@ -0,0 +1,189 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { + Table, + TableBody, + TableCaption, + TableCell, + TableFooter, + TableHead, + TableHeader, + TableRow, +} from '../components/table'; + +const meta = { + title: 'Components/Table', + component: Table, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Table +export const Basic: Story = { + render: () => ( + + + + Name + Email + Role + + + + + John Doe + john@example.com + Admin + + + Jane Smith + jane@example.com + User + + +
+ ), +}; + +// With Caption +export const WithCaption: Story = { + render: () => ( + + A list of recent users and their roles. + + + Name + Email + Role + + + + + John Doe + john@example.com + Admin + + + Jane Smith + jane@example.com + User + + +
+ ), +}; + +// With Footer +export const WithFooter: Story = { + render: () => ( + + + + Item + Amount + Price + + + + + Product A + 2 + $20.00 + + + Product B + 1 + $15.00 + + + + + Total + 3 + $35.00 + + +
+ ), +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( + + + + Product + Stock + Price + + + + + Product A + 32 + $20.00 + + + Product B + 12 + $15.00 + + + Product C + 4 + $25.00 + + +
+ ), +}; + +// With Status Column +export const WithStatusColumn: Story = { + render: () => ( + + + + Order + Status + Last Updated + Amount + + + + + #123 + + + Completed + + + 2 hours ago + $25.00 + + + #124 + + + Pending + + + 3 hours ago + $42.00 + + + #125 + + + Failed + + + 5 hours ago + $15.00 + + +
+ ), +}; diff --git a/ui/src/stories/tabs.stories.tsx b/ui/src/stories/tabs.stories.tsx new file mode 100644 index 000000000..d08f004aa --- /dev/null +++ b/ui/src/stories/tabs.stories.tsx @@ -0,0 +1,157 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Tabs, TabsContent, TabsList, TabsTrigger } from '../components/tabs'; + +const meta = { + title: 'Components/Tabs', + component: Tabs, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic +export const Basic: Story = { + render: () => ( + + + Account + Password + + Make changes to your account here. + Change your password here. + + ), +}; + +// Multiple Tabs +export const MultipleTabs: Story = { + render: () => ( + + + Tab 1 + Tab 2 + Tab 3 + Tab 4 + + Content of tab 1 + Content of tab 2 + Content of tab 3 + Content of tab 4 + + ), +}; + +// With Disabled +export const WithDisabled: Story = { + render: () => ( + + + Active + + Disabled + + Active 2 + + This tab is active + This tab is disabled + This is another active tab + + ), +}; + +// Full Width +export const FullWidth: Story = { + render: () => ( + + + Messages + Notifications + Settings + + Messages content + Notifications content + Settings content + + ), +}; + +// With Icons +export const WithIcons: Story = { + render: () => ( + + + + + + + Messages + + + + + + + Settings + + + Messages content + Settings content + + ), +}; + +// With Rich Content +export const WithRichContent: Story = { + render: () => ( + + + Account + Preferences + + +
+

Account Settings

+

Manage your account settings and preferences.

+
+
+
+ +
+
+
+ +
+

Preferences

+

Customize your application preferences.

+
+
+ +
+
+
+ ), +}; diff --git a/ui/src/stories/toggle.stories.tsx b/ui/src/stories/toggle.stories.tsx new file mode 100644 index 000000000..7f3e52c42 --- /dev/null +++ b/ui/src/stories/toggle.stories.tsx @@ -0,0 +1,180 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Toggle } from '../components/toggle'; + +const meta = { + title: 'Components/Toggle', + component: Toggle, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Toggle +export const Basic: Story = { + render: () => ( + + + + + + + + ), +}; + +// With Text +export const WithText: Story = { + render: () => ( + + + + + + Bold + + ), +}; + +// Different Sizes +export const DifferentSizes: Story = { + render: () => ( +
+ + Small + + + Default + + + Large + +
+ ), +}; + +// Variants +export const Variants: Story = { + render: () => ( +
+ + Default + + + Outline + +
+ ), +}; + +// Disabled State +export const DisabledState: Story = { + render: () => ( +
+ + Disabled + + + Disabled Pressed + +
+ ), +}; + +// With Icons Group +export const WithIconsGroup: Story = { + render: () => ( +
+ + + + + + + + + + + + + + + + + + + +
+ ), +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( +
+ + Custom + + + Custom + +
+ ), +}; diff --git a/ui/src/stories/tooltip.stories.tsx b/ui/src/stories/tooltip.stories.tsx new file mode 100644 index 000000000..8f741c522 --- /dev/null +++ b/ui/src/stories/tooltip.stories.tsx @@ -0,0 +1,187 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import React from 'react'; +import { Button } from '../components/button'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../components/tooltip'; + +const meta = { + title: 'Components/Tooltip', + component: Tooltip, + tags: ['autodocs'], + decorators: [ + (Story) => ( + + + + ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Basic Tooltip +export const Basic: Story = { + render: () => ( + + + + + +

Add to library

+
+
+ ), +}; + +// With Icon +export const WithIcon: Story = { + render: () => ( + + + + + +

More information

+
+
+ ), +}; + +// Different Positions +export const DifferentPositions: Story = { + render: () => ( +
+ + + + + +

Tooltip on top

+
+
+ + + + + +

Tooltip on right

+
+
+ + + + + +

Tooltip on bottom

+
+
+ + + + + +

Tooltip on left

+
+
+
+ ), +}; + +// With Rich Content +export const WithRichContent: Story = { + render: () => ( + + + + + +
+

John Doe

+

Software Engineer at Example Corp

+
+ + + + + San Francisco, CA +
+
+
+
+ ), +}; + +// Custom Styled +export const CustomStyled: Story = { + render: () => ( + + + + + +

Custom styled tooltip

+
+
+ ), +}; + +// With Delay +export const WithDelay: Story = { + render: () => ( + + + + + +

This tooltip has a 700ms delay

+
+
+ ), +}; + +// Interactive Example +export const InteractiveExample: Story = { + render: () => { + const [isOpen, setIsOpen] = React.useState(false); + + return ( + + + + + +

This tooltip can be controlled programmatically

+
+
+ ); + }, +}; diff --git a/ui/src/stories/typography.stories.tsx b/ui/src/stories/typography.stories.tsx new file mode 100644 index 000000000..51925bc57 --- /dev/null +++ b/ui/src/stories/typography.stories.tsx @@ -0,0 +1,145 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Typography } from '../components/typography'; +import type { FontColor } from '../interfaces/color'; + +// Sample colors for the demo since we can't use the enum directly +const FONT_COLORS: FontColor[] = [ + 'background', + 'foreground', + 'primary', + 'primary-foreground', + 'secondary', + 'secondary-foreground', + 'accent', + 'accent-foreground', + 'destructive', + 'destructive-foreground', + 'muted', + 'muted-foreground', + 'card', + 'card-foreground', + 'popover', + 'popover-foreground', +]; + +const meta = { + title: 'Components/Typography', + component: Typography, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Font Sizes +export const Sizes: Story = { + render: () => ( +
+ 6XL Typography + 5XL Typography + 4XL Typography + 3XL Typography + 2XL Typography + XL Typography + Large Typography + Medium Typography + Small Typography + XS Typography +
+ ), +}; + +// Font Weights +export const Weights: Story = { + render: () => ( +
+ Bold Text + Medium Text + Normal Text +
+ ), +}; + +// Line Heights +export const LineHeights: Story = { + render: () => ( +
+ + Line Height None - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut + labore et dolore magna aliqua. + + + Line Height Tight - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut + labore et dolore magna aliqua. + + + Line Height Snug - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut + labore et dolore magna aliqua. + + + Line Height Normal - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt + ut labore et dolore magna aliqua. + + + Line Height Relaxed - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt + ut labore et dolore magna aliqua. + + + Line Height Loose - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut + labore et dolore magna aliqua. + +
+ ), +}; + +// Colors +export const Colors: Story = { + render: () => ( +
+ {FONT_COLORS.map((color) => ( + + {color} Text Color + + ))} +
+ ), +}; + +// Different HTML Elements +export const Elements: Story = { + render: () => ( +
+ + Heading 1 + + + Heading 2 + + + Heading 3 + + Regular paragraph text + + Small span text + +
+ ), +}; + +// Combined Properties +export const Combined: Story = { + render: () => ( +
+ + Primary Heading + + + Secondary Subheading + + + Muted body text with relaxed line height. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. + +
+ ), +}; diff --git a/website/src/app/[lang]/[region]/(website)/me/contributions/contributions-table.tsx b/website/src/app/[lang]/[region]/(website)/me/contributions/contributions-table.tsx index 1e2caf889..6117e32f6 100644 --- a/website/src/app/[lang]/[region]/(website)/me/contributions/contributions-table.tsx +++ b/website/src/app/[lang]/[region]/(website)/me/contributions/contributions-table.tsx @@ -2,10 +2,18 @@ import { DefaultParams } from '@/app/[lang]/[region]'; import { useContributions } from '@/app/[lang]/[region]/(website)/me/hooks'; -import { SpinnerIcon } from '@/components/logos/spinner-icon'; import { useTranslator } from '@/hooks/useTranslator'; import { toDateTime } from '@socialincome/shared/src/utils/date'; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from '@socialincome/ui'; +import { + SpinnerIcon, + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, + Typography, +} from '@socialincome/ui'; import _ from 'lodash'; type ContributionsTableProps = { diff --git a/website/src/app/[lang]/[region]/(website)/me/donation-certificates/donation-certificates-table.tsx b/website/src/app/[lang]/[region]/(website)/me/donation-certificates/donation-certificates-table.tsx index ec93dffb5..cae003c80 100644 --- a/website/src/app/[lang]/[region]/(website)/me/donation-certificates/donation-certificates-table.tsx +++ b/website/src/app/[lang]/[region]/(website)/me/donation-certificates/donation-certificates-table.tsx @@ -2,8 +2,17 @@ import { DefaultParams } from '@/app/[lang]/[region]'; import { useDonationCertificates } from '@/app/[lang]/[region]/(website)/me/hooks'; -import { SpinnerIcon } from '@/components/logos/spinner-icon'; -import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from '@socialincome/ui'; +import { + Button, + SpinnerIcon, + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, + Typography, +} from '@socialincome/ui'; import Link from 'next/link'; type ContributionsTableProps = { diff --git a/website/src/app/[lang]/[region]/(website)/me/subscriptions/subscriptions-client.tsx b/website/src/app/[lang]/[region]/(website)/me/subscriptions/subscriptions-client.tsx index a564fae6a..c4ca4e028 100644 --- a/website/src/app/[lang]/[region]/(website)/me/subscriptions/subscriptions-client.tsx +++ b/website/src/app/[lang]/[region]/(website)/me/subscriptions/subscriptions-client.tsx @@ -3,11 +3,20 @@ import { DefaultParams } from '@/app/[lang]/[region]'; import { useSubscriptions } from '@/app/[lang]/[region]/(website)/me/hooks'; import { BillingPortalButton } from '@/app/[lang]/[region]/(website)/me/subscriptions/billing-portal-button'; -import { SpinnerIcon } from '@/components/logos/spinner-icon'; import { useTranslator } from '@/hooks/useTranslator'; import { PlusCircleIcon } from '@heroicons/react/24/outline'; import { toDateTime } from '@socialincome/shared/src/utils/date'; -import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from '@socialincome/ui'; +import { + Button, + SpinnerIcon, + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, + Typography, +} from '@socialincome/ui'; import Link from 'next/link'; type SubscriptionsTableProps = { diff --git a/website/src/app/[lang]/[region]/(website)/me/work-info/employers-list.tsx b/website/src/app/[lang]/[region]/(website)/me/work-info/employers-list.tsx index 51396c329..692453e82 100644 --- a/website/src/app/[lang]/[region]/(website)/me/work-info/employers-list.tsx +++ b/website/src/app/[lang]/[region]/(website)/me/work-info/employers-list.tsx @@ -6,8 +6,7 @@ import { useDeleteEmployer, useEmployers, } from '@/app/[lang]/[region]/(website)/me/hooks'; -import { SpinnerIcon } from '@/components/logos/spinner-icon'; -import { Button, Table, TableBody, TableCell, TableRow, Typography } from '@socialincome/ui'; +import { Button, SpinnerIcon, Table, TableBody, TableCell, TableRow, Typography } from '@socialincome/ui'; import { DefaultParams } from '../../..'; import { AddEmployerForm, AddEmployerFormProps } from './add-employer-form'; diff --git a/website/src/app/[lang]/[region]/(website)/newsletter/subscription-info-form.tsx b/website/src/app/[lang]/[region]/(website)/newsletter/subscription-info-form.tsx index f611521da..66ff38b43 100644 --- a/website/src/app/[lang]/[region]/(website)/newsletter/subscription-info-form.tsx +++ b/website/src/app/[lang]/[region]/(website)/newsletter/subscription-info-form.tsx @@ -1,11 +1,20 @@ 'use client'; import { DefaultParams } from '@/app/[lang]/[region]'; -import { SpinnerIcon } from '@/components/logos/spinner-icon'; import { useApi } from '@/hooks/useApi'; import { zodResolver } from '@hookform/resolvers/zod'; import { NewsletterSubscriptionData } from '@socialincome/shared/src/sendgrid/SendgridSubscriptionClient'; -import { Button, Form, FormControl, FormField, FormItem, FormLabel, FormMessage, Input } from '@socialincome/ui'; +import { + Button, + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, + Input, + SpinnerIcon, +} from '@socialincome/ui'; import { useState } from 'react'; import { useForm } from 'react-hook-form'; import toast from 'react-hot-toast'; diff --git a/website/src/components/navbar/navbar-client.tsx b/website/src/components/navbar/navbar-client.tsx index af90fdd57..0ccc6ea13 100644 --- a/website/src/components/navbar/navbar-client.tsx +++ b/website/src/components/navbar/navbar-client.tsx @@ -1,15 +1,13 @@ 'use client'; import { DefaultParams } from '@/app/[lang]/[region]'; -import { DonateIcon } from '@/components/logos/donate-icon'; import { SIAnimatedLogo } from '@/components/logos/si-animated-logo'; -import { SIIcon } from '@/components/logos/si-icon'; import { SILogo } from '@/components/logos/si-logo'; import { useI18n } from '@/components/providers/context-providers'; import { useGlobalStateProvider } from '@/components/providers/global-state-provider'; import { WebsiteCurrency, WebsiteLanguage, WebsiteRegion } from '@/i18n'; import { Bars3Icon, CheckIcon, ChevronLeftIcon, XMarkIcon } from '@heroicons/react/24/outline'; -import { Typography } from '@socialincome/ui'; +import { DonateIcon, SIIcon, Typography } from '@socialincome/ui'; import { getFlagImageURL } from '@socialincome/ui/src/lib/utils'; import classNames from 'classnames'; import _ from 'lodash';