diff --git a/.gitignore b/.gitignore index 9564298..dbaee90 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,8 @@ /docs .pnpm-store/ -tsconfig.tsbuildinfo \ No newline at end of file +tsconfig.tsbuildinfo + +# System files +.DS_Store +**/.DS_Store diff --git a/.storybook/main.ts b/.storybook/main.ts index 0656ad6..c8c5ac4 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,32 +1,35 @@ -import type { StorybookConfig } from "@storybook/react-webpack5"; +import type { StorybookConfig } from "@storybook/react-vite"; const config: StorybookConfig = { stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"], addons: [ - "@storybook/addon-webpack5-compiler-swc", "@storybook/addon-essentials", "@chromatic-com/storybook", "@storybook/addon-interactions", "@storybook/addon-links", "storybook-dark-mode", + "@storybook/addon-themes", + "@storybook/addon-a11y", ], - framework: { - name: "@storybook/react-webpack5", - options: { - builder: { - useSWC: true, + framework: { name: "@storybook/react-vite", options: {} }, + docs: { autodocs: true }, + typescript: { + check: false, + reactDocgen: "react-docgen", + reactDocgenTypescriptOptions: { + compilerOptions: { + allowSyntheticDefaultImports: false, + esModuleInterop: false, }, + shouldExtractLiteralValuesFromEnum: true, + shouldRemoveUndefinedFromOptional: true, + propFilter: (prop) => + prop.parent + ? !/node_modules\/(?!@mui)/.test(prop.parent.fileName) + : true, }, }, staticDirs: ["../src/public/"], - swc: () => ({ - jsc: { - transform: { - react: { - runtime: "automatic", - }, - }, - }, - }), }; + export default config; diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 4de2bdc..28bed05 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -1,39 +1,79 @@ -import React from "react"; +import React, { useLayoutEffect } from "react"; import { CssBaseline } from "@mui/material"; import type { Preview } from "@storybook/react"; - +import "@fontsource-variable/inter"; +import "./storybook.css"; /* Storybook CSS override */ import { ThemeProvider } from "../src"; -import { GenericTheme, DiamondTheme } from "../src"; - +import { + GenericTheme, + DiamondTheme, + DiamondDSTheme, + DiamondDSThemeDark, +} from "../src"; import { Context, ThemeSwapper, TextLight, TextDark } from "./ThemeSwapper"; const TextThemeBase = "Theme: Generic"; const TextThemeDiamond = "Theme: Diamond"; +const TextThemeDiamondDS = "Theme: DiamondDS"; + +function resolveTheme(selectedTheme: string, mode: "light" | "dark") { + switch (selectedTheme) { + case TextThemeBase: + return GenericTheme; + case TextThemeDiamondDS: + return mode === "dark" ? DiamondDSThemeDark : DiamondDSTheme; + case TextThemeDiamond: + default: + return DiamondTheme; + } +} + +function ApplyModeToPreviewDoc({ + mode, + doc, +}: { + mode: "light" | "dark"; + doc: Document; +}) { + useLayoutEffect(() => { + const root = doc.documentElement; // + root.setAttribute("data-mode", mode); + + // Optional: keep class too if your CSS supports it + root.classList.toggle("dark", mode === "dark"); + root.classList.toggle("light", mode === "light"); + + root.style.colorScheme = mode; + }, [mode, doc]); + + return null; +} + export const decorators = [ - (StoriesWithPadding: React.FC) => { - return ( -
- -
- ); - }, - (StoriesWithThemeSwapping: React.FC, context: Context) => { - return ( - - - - ); - }, + (StoriesWithPadding: React.FC) => ( +
+ +
+ ), + (StoriesWithThemeSwapping: React.FC, context: Context) => ( + + + + ), (StoriesWithThemeProvider: React.FC, context: Context) => { const selectedTheme = context.globals.theme || TextThemeBase; const selectedThemeMode = context.globals.themeMode || TextLight; + const mode = selectedThemeMode === TextLight ? "light" : "dark"; + // ensure we target the preview iframe document + const doc: Document = context?.canvasElement?.ownerDocument ?? document; return ( + @@ -48,7 +88,7 @@ const preview: Preview = { toolbar: { title: "Theme", icon: "cog", - items: [TextThemeBase, TextThemeDiamond], + items: [TextThemeBase, TextThemeDiamond, TextThemeDiamondDS], dynamicTitle: true, }, }, @@ -63,11 +103,12 @@ const preview: Preview = { }, }, initialGlobals: { - theme: "Theme: Diamond", - themeMode: "Mode: Light", + theme: TextThemeDiamondDS, + themeMode: TextLight, }, parameters: { controls: { + expanded: true, matchers: { color: /(background|color)$/i, date: /Date$/i, @@ -75,23 +116,9 @@ const preview: Preview = { }, backgrounds: { disable: true }, layout: "fullscreen", - options: { - storySort: { - order: [ - "Introduction", - "Components", - "Theme", - "Theme/Logos", - "Theme/Colours", - "Helpers", - ], - }, - }, }, argTypes: { - linkComponent: { - control: false, - }, + linkComponent: { control: false }, }, }; diff --git a/.storybook/storybook.css b/.storybook/storybook.css new file mode 100644 index 0000000..3ceb267 --- /dev/null +++ b/.storybook/storybook.css @@ -0,0 +1,58 @@ +:root { + --ds-font-body: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; + + --ds-font-heading: 'Outfit', system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; + + --ds-font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, + Consolas, 'Liberation Mono', 'Courier New', monospace; + } + + /* Docs root */ + .sbdocs, .sbdocs p, .sbdocs li,.sb-unstyled, .sb-unstyled ul, .sb-unstyled li { + font-family: var(--ds-font-body); + font-size: 16px !important; + line-height: 1.6; + } + + /* Lists */ + .sbdocs li { + font-size: 16px !important; + } + + /* Headings use Outfit or Inter */ + + .sbdocs h1 { + font-family: var(--ds-font-heading); + } + + .sbdocs h3, + .sbdocs h4, + .sbdocs h5, + .sbdocs h6 { + font-family: var(--ds-font-body); + } + + /* Code uses IBM Plex Mono */ + .sbdocs code, + .sbdocs pre, + .sbdocs kbd, + .sbdocs samp, + .token { + font-family: var(--ds-font-mono); + font-size: 1em; + } + + /* Neutralise Storybook Docs inline preview background wrapper */ + .sbdocs-preview div[style*="background-color"], #storybook-root div[style*="background-color"] { + background-color: transparent !important; + } + + .light .sbdocs-preview div[style*="background-color"] { + background-color: #f6f6f6 !important; + } + + .dark .sbdocs-preview div[style*="background-color"]{ + background-color: #212121 !important; + } diff --git a/package.json b/package.json index 9eb2726..901c535 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "storybook:publish": "gh-pages -b storybook/publish -d storybook-static" }, "dependencies": { + "@fontsource-variable/inter": "^5.2.8", "keycloak-js": "^26.2.1", "react-icons": "^5.3.0", "utif": "^3.1.0" @@ -48,23 +49,27 @@ "@babel/preset-typescript": "^7.26.0", "@chromatic-com/storybook": "^3.2.2", "@eslint/eslintrc": "^3.2.0", + "@fontsource/ibm-plex-mono": "^5.2.7", + "@fontsource/inter": "^5.2.8", + "@fontsource/outfit": "^5.2.8", "@rollup/plugin-commonjs": "^28.0.1", "@rollup/plugin-image": "^3.0.3", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^12.1.1", - "@storybook/addon-actions": "^8.4.4", - "@storybook/addon-controls": "^8.4.4", - "@storybook/addon-essentials": "^8.4.4", - "@storybook/addon-interactions": "^8.4.4", - "@storybook/addon-links": "^8.4.4", - "@storybook/addon-toolbars": "^8.4.4", - "@storybook/addon-webpack5-compiler-swc": "^1.0.5", - "@storybook/blocks": "^8.4.4", - "@storybook/react": "^8.4.4", - "@storybook/react-webpack5": "^8.4.4", - "@storybook/test": "^8.4.4", + "@storybook/addon-a11y": "^8.6.14", + "@storybook/addon-actions": "^8.4.7", + "@storybook/addon-controls": "^8.4.7", + "@storybook/addon-essentials": "^8.6.14", + "@storybook/addon-interactions": "^8.6.14", + "@storybook/addon-links": "^8.6.14", + "@storybook/addon-themes": "^8.6.14", + "@storybook/addon-toolbars": "^8.4.7", + "@storybook/blocks": "^8.4.7", + "@storybook/react": "^8.6.14", + "@storybook/react-vite": "^8.6.14", + "@storybook/test": "^8.6.14", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.1.0", "@types/node": "^20.19.21", @@ -80,13 +85,14 @@ "eslint-plugin-react-hooks": "^5.1.0", "file-loader": "^6.2.0", "gh-pages": "^6.2.0", + "react-docgen": "^8.0.2", "react-dom": "^18.3.1", "react-router-dom": "^7.5.3", "rollup": "^4.27.3", "rollup-plugin-dts": "^6.1.1", "rollup-plugin-peer-deps-external": "^2.2.4", "rollup-plugin-postcss": "^4.0.2", - "storybook": "^8.4.4", + "storybook": "^8.6.14", "storybook-dark-mode": "^4.0.2", "tslib": "^2.8.1", "typedoc": "^0.28.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f3b6b6d..f5bfffd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@emotion/styled': specifier: ^11.13.0 version: 11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@18.3.1))(@types/react@18.3.18)(react@18.3.1) + '@fontsource-variable/inter': + specifier: ^5.2.8 + version: 5.2.8 '@jsonforms/core': specifier: ^3.6.0 version: 3.6.0 @@ -56,10 +59,19 @@ importers: version: 7.26.0(@babel/core@7.26.0) '@chromatic-com/storybook': specifier: ^3.2.2 - version: 3.2.3(react@18.3.1)(storybook@8.4.7(prettier@3.4.2)) + version: 3.2.3(react@18.3.1)(storybook@8.6.14(prettier@3.4.2)) '@eslint/eslintrc': specifier: ^3.2.0 version: 3.2.0 + '@fontsource/ibm-plex-mono': + specifier: ^5.2.7 + version: 5.2.7 + '@fontsource/inter': + specifier: ^5.2.8 + version: 5.2.8 + '@fontsource/outfit': + specifier: ^5.2.8 + version: 5.2.8 '@rollup/plugin-commonjs': specifier: ^28.0.1 version: 28.0.2(rollup@4.30.0) @@ -78,39 +90,42 @@ importers: '@rollup/plugin-typescript': specifier: ^12.1.1 version: 12.1.2(rollup@4.30.0)(tslib@2.8.1)(typescript@5.7.2) + '@storybook/addon-a11y': + specifier: ^8.6.14 + version: 8.6.14(storybook@8.6.14(prettier@3.4.2)) '@storybook/addon-actions': - specifier: ^8.4.4 - version: 8.4.7(storybook@8.4.7(prettier@3.4.2)) + specifier: ^8.4.7 + version: 8.4.7(storybook@8.6.14(prettier@3.4.2)) '@storybook/addon-controls': - specifier: ^8.4.4 - version: 8.4.7(storybook@8.4.7(prettier@3.4.2)) + specifier: ^8.4.7 + version: 8.4.7(storybook@8.6.14(prettier@3.4.2)) '@storybook/addon-essentials': - specifier: ^8.4.4 - version: 8.4.7(@types/react@18.3.18)(storybook@8.4.7(prettier@3.4.2)) + specifier: ^8.6.14 + version: 8.6.14(@types/react@18.3.18)(storybook@8.6.14(prettier@3.4.2)) '@storybook/addon-interactions': - specifier: ^8.4.4 - version: 8.4.7(storybook@8.4.7(prettier@3.4.2)) + specifier: ^8.6.14 + version: 8.6.14(storybook@8.6.14(prettier@3.4.2)) '@storybook/addon-links': - specifier: ^8.4.4 - version: 8.4.7(react@18.3.1)(storybook@8.4.7(prettier@3.4.2)) + specifier: ^8.6.14 + version: 8.6.14(react@18.3.1)(storybook@8.6.14(prettier@3.4.2)) + '@storybook/addon-themes': + specifier: ^8.6.14 + version: 8.6.14(storybook@8.6.14(prettier@3.4.2)) '@storybook/addon-toolbars': - specifier: ^8.4.4 - version: 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/addon-webpack5-compiler-swc': - specifier: ^1.0.5 - version: 1.0.6(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)) + specifier: ^8.4.7 + version: 8.4.7(storybook@8.6.14(prettier@3.4.2)) '@storybook/blocks': - specifier: ^8.4.4 - version: 8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2)) + specifier: ^8.4.7 + version: 8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.4.2)) '@storybook/react': - specifier: ^8.4.4 - version: 8.4.7(@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2) - '@storybook/react-webpack5': - specifier: ^8.4.4 - version: 8.4.7(@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2)))(@swc/core@1.10.4)(esbuild@0.24.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2) + specifier: ^8.6.14 + version: 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.4.2))(typescript@5.7.2) + '@storybook/react-vite': + specifier: ^8.6.14 + version: 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.30.0)(storybook@8.6.14(prettier@3.4.2))(typescript@5.7.2)(vite@7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0)) '@storybook/test': - specifier: ^8.4.4 - version: 8.4.7(storybook@8.4.7(prettier@3.4.2)) + specifier: ^8.6.14 + version: 8.6.14(storybook@8.6.14(prettier@3.4.2)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -131,31 +146,34 @@ importers: version: 3.0.5 '@typescript-eslint/eslint-plugin': specifier: ^8.18.1 - version: 8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.17.0)(typescript@5.7.2))(eslint@9.17.0)(typescript@5.7.2) + version: 8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2) '@typescript-eslint/parser': specifier: ^8.18.1 - version: 8.19.0(eslint@9.17.0)(typescript@5.7.2) + version: 8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2) eslint: specifier: ^9.17.0 - version: 9.17.0 + version: 9.17.0(jiti@1.21.7) eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@9.17.0) + version: 9.1.0(eslint@9.17.0(jiti@1.21.7)) eslint-plugin-prettier: specifier: ^5.2.1 - version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.17.0))(eslint@9.17.0)(prettier@3.4.2) + version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.17.0(jiti@1.21.7)))(eslint@9.17.0(jiti@1.21.7))(prettier@3.4.2) eslint-plugin-react: specifier: ^7.37.2 - version: 7.37.3(eslint@9.17.0) + version: 7.37.3(eslint@9.17.0(jiti@1.21.7)) eslint-plugin-react-hooks: specifier: ^5.1.0 - version: 5.1.0(eslint@9.17.0) + version: 5.1.0(eslint@9.17.0(jiti@1.21.7)) file-loader: specifier: ^6.2.0 - version: 6.2.0(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)) + version: 6.2.0(webpack@5.97.1(esbuild@0.25.11)) gh-pages: specifier: ^6.2.0 version: 6.3.0 + react-docgen: + specifier: ^8.0.2 + version: 8.0.2 react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) @@ -173,13 +191,13 @@ importers: version: 2.2.4(rollup@4.30.0) rollup-plugin-postcss: specifier: ^4.0.2 - version: 4.0.2(postcss@8.4.49) + version: 4.0.2(postcss@8.5.6) storybook: - specifier: ^8.4.4 - version: 8.4.7(prettier@3.4.2) + specifier: ^8.6.14 + version: 8.6.14(prettier@3.4.2) storybook-dark-mode: specifier: ^4.0.2 - version: 4.0.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2)) + version: 4.0.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.4.2)) tslib: specifier: ^2.8.1 version: 2.8.1 @@ -191,10 +209,10 @@ importers: version: 5.7.2 typescript-eslint: specifier: ^8.15.0 - version: 8.19.0(eslint@9.17.0)(typescript@5.7.2) + version: 8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2) vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@20.19.21)(jsdom@20.0.3)(terser@5.37.0)(yaml@2.8.0) + version: 3.2.4(@types/node@20.19.21)(jiti@1.21.7)(jsdom@20.0.3)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0) packages: @@ -209,18 +227,34 @@ packages: resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.26.3': resolution: {integrity: sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==} engines: {node: '>=6.9.0'} + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + engines: {node: '>=6.9.0'} + '@babel/core@7.26.0': resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} engines: {node: '>=6.9.0'} + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.26.3': resolution: {integrity: sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==} engines: {node: '>=6.9.0'} + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.25.9': resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} engines: {node: '>=6.9.0'} @@ -229,6 +263,10 @@ packages: resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-create-class-features-plugin@7.25.9': resolution: {integrity: sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==} engines: {node: '>=6.9.0'} @@ -246,6 +284,10 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + '@babel/helper-member-expression-to-functions@7.25.9': resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} engines: {node: '>=6.9.0'} @@ -254,12 +296,22 @@ packages: resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-transforms@7.26.0': resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-optimise-call-expression@7.25.9': resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} engines: {node: '>=6.9.0'} @@ -288,14 +340,26 @@ packages: resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.25.9': resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.25.9': resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + '@babel/helper-wrap-function@7.25.9': resolution: {integrity: sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==} engines: {node: '>=6.9.0'} @@ -304,11 +368,20 @@ packages: resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} engines: {node: '>=6.9.0'} + '@babel/helpers@7.28.4': + resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + engines: {node: '>=6.9.0'} + '@babel/parser@7.26.3': resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==} engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9': resolution: {integrity: sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==} engines: {node: '>=6.9.0'} @@ -736,14 +809,26 @@ packages: resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.26.4': resolution: {integrity: sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + '@babel/types@7.26.3': resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} engines: {node: '>=6.9.0'} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + '@chromatic-com/storybook@3.2.3': resolution: {integrity: sha512-3+hfANx79kIjP1qrOSLxpoAXOiYUA0S7A0WI0A24kASrv7USFNNW8etR5TjUilMb0LmqKUn3wDwUK2h6aceQ9g==} engines: {node: '>=16.0.0', yarn: '>=1.22.18'} @@ -815,252 +900,126 @@ packages: '@emotion/weak-memoize@0.4.0': resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@esbuild/aix-ppc64@0.24.2': - resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.25.11': resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.24.2': - resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.25.11': resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.24.2': - resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.25.11': resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.24.2': - resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.25.11': resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.24.2': - resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.25.11': resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.24.2': - resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.25.11': resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.24.2': - resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.25.11': resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.24.2': - resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.25.11': resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.24.2': - resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.25.11': resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.24.2': - resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.25.11': resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.24.2': - resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.25.11': resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.24.2': - resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.25.11': resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.24.2': - resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.25.11': resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.24.2': - resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.25.11': resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.24.2': - resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.25.11': resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.24.2': - resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.25.11': resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.24.2': - resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.25.11': resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.24.2': - resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.25.11': resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.24.2': - resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.25.11': resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.24.2': - resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.25.11': resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.24.2': - resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.25.11': resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} engines: {node: '>=18'} @@ -1073,48 +1032,24 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.24.2': - resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.25.11': resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.24.2': - resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.25.11': resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.24.2': - resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.25.11': resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.24.2': - resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.25.11': resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} engines: {node: '>=18'} @@ -1155,6 +1090,18 @@ packages: resolution: {integrity: sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@fontsource-variable/inter@5.2.8': + resolution: {integrity: sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==} + + '@fontsource/ibm-plex-mono@5.2.7': + resolution: {integrity: sha512-MKAb8qV+CaiMQn2B0dIi1OV3565NYzp3WN5b4oT6LTkk+F0jR6j0ZN+5BKJiIhffDC3rtBULsYZE65+0018z9w==} + + '@fontsource/inter@5.2.8': + resolution: {integrity: sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==} + + '@fontsource/outfit@5.2.8': + resolution: {integrity: sha512-rXC6g0MqD7cOBjht0bMqc43qM6lRqDLML9KXsmg9uykz0wLQhy8Z/ajrMG6iyoT3NJR+MYgU+OEHp7uHoTb+Yw==} + '@gerrit0/mini-shiki@3.7.0': resolution: {integrity: sha512-7iY9wg4FWXmeoFJpUL2u+tsmh0d0jcEJHAIzVxl3TG4KL493JNnisdLAILZ77zcD+z3J0keEXZ+lFzUgzQzPDg==} @@ -1178,10 +1125,29 @@ packages: resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} engines: {node: '>=18.18'} + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0': + resolution: {integrity: sha512-qYDdL7fPwLRI+bJNurVcis+tNgJmvWjH4YTBGXTA8xMuxFrnAz6E5o35iyzyKbq5J5Lr8mJGfrR5GXl+WGwhgQ==} + peerDependencies: + typescript: '>= 4.3.x' + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/gen-mapping@0.3.8': resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -1199,6 +1165,9 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@jsonforms/core@3.6.0': resolution: {integrity: sha512-Qz7qJPf/yP4ybqknZ500zggIDZRJfcufu+3efp/xNWf05mpXvxN9TdfmA++BdXi5Nr4UAgjos2kFmQpZpQaCDw==} @@ -1372,6 +1341,10 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@pkgr/core@0.1.1': resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -1666,73 +1639,94 @@ packages: '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@storybook/addon-a11y@8.6.14': + resolution: {integrity: sha512-fozv6enO9IgpWq2U8qqS8MZ21Nt+MVHiRQe3CjnCpBOejTyo/ATm690PeYYRVHVG6M/15TVePb0h3ngKQbrrzQ==} + peerDependencies: + storybook: ^8.6.14 + '@storybook/addon-actions@8.4.7': resolution: {integrity: sha512-mjtD5JxcPuW74T6h7nqMxWTvDneFtokg88p6kQ5OnC1M259iAXb//yiSZgu/quunMHPCXSiqn4FNOSgASTSbsA==} peerDependencies: storybook: ^8.4.7 - '@storybook/addon-backgrounds@8.4.7': - resolution: {integrity: sha512-I4/aErqtFiazcoWyKafOAm3bLpxTj6eQuH/woSbk1Yx+EzN+Dbrgx1Updy8//bsNtKkcrXETITreqHC+a57DHQ==} + '@storybook/addon-actions@8.6.14': + resolution: {integrity: sha512-mDQxylxGGCQSK7tJPkD144J8jWh9IU9ziJMHfB84PKpI/V5ZgqMDnpr2bssTrUaGDqU5e1/z8KcRF+Melhs9pQ==} peerDependencies: - storybook: ^8.4.7 + storybook: ^8.6.14 + + '@storybook/addon-backgrounds@8.6.14': + resolution: {integrity: sha512-l9xS8qWe5n4tvMwth09QxH2PmJbCctEvBAc1tjjRasAfrd69f7/uFK4WhwJAstzBTNgTc8VXI4w8ZR97i1sFbg==} + peerDependencies: + storybook: ^8.6.14 '@storybook/addon-controls@8.4.7': resolution: {integrity: sha512-377uo5IsJgXLnQLJixa47+11V+7Wn9KcDEw+96aGCBCfLbWNH8S08tJHHnSu+jXg9zoqCAC23MetntVp6LetHA==} peerDependencies: storybook: ^8.4.7 - '@storybook/addon-docs@8.4.7': - resolution: {integrity: sha512-NwWaiTDT5puCBSUOVuf6ME7Zsbwz7Y79WF5tMZBx/sLQ60vpmJVQsap6NSjvK1Ravhc21EsIXqemAcBjAWu80w==} + '@storybook/addon-controls@8.6.14': + resolution: {integrity: sha512-IiQpkNJdiRyA4Mq9mzjZlvQugL/aE7hNgVxBBGPiIZG6wb6Ht9hNnBYpap5ZXXFKV9p2qVI0FZK445ONmAa+Cw==} peerDependencies: - storybook: ^8.4.7 + storybook: ^8.6.14 - '@storybook/addon-essentials@8.4.7': - resolution: {integrity: sha512-+BtZHCBrYtQKILtejKxh0CDRGIgTl9PumfBOKRaihYb4FX1IjSAxoV/oo/IfEjlkF5f87vouShWsRa8EUauFDw==} + '@storybook/addon-docs@8.6.14': + resolution: {integrity: sha512-Obpd0OhAF99JyU5pp5ci17YmpcQtMNgqW2pTXV8jAiiipWpwO++hNDeQmLmlSXB399XjtRDOcDVkoc7rc6JzdQ==} peerDependencies: - storybook: ^8.4.7 + storybook: ^8.6.14 - '@storybook/addon-highlight@8.4.7': - resolution: {integrity: sha512-whQIDBd3PfVwcUCrRXvCUHWClXe9mQ7XkTPCdPo4B/tZ6Z9c6zD8JUHT76ddyHivixFLowMnA8PxMU6kCMAiNw==} + '@storybook/addon-essentials@8.6.14': + resolution: {integrity: sha512-5ZZSHNaW9mXMOFkoPyc3QkoNGdJHETZydI62/OASR0lmPlJ1065TNigEo5dJddmZNn0/3bkE8eKMAzLnO5eIdA==} peerDependencies: - storybook: ^8.4.7 + storybook: ^8.6.14 - '@storybook/addon-interactions@8.4.7': - resolution: {integrity: sha512-fnufT3ym8ht3HHUIRVXAH47iOJW/QOb0VSM+j269gDuvyDcY03D1civCu1v+eZLGaXPKJ8vtjr0L8zKQ/4P0JQ==} + '@storybook/addon-highlight@8.6.14': + resolution: {integrity: sha512-4H19OJlapkofiE9tM6K/vsepf4ir9jMm9T+zw5L85blJZxhKZIbJ6FO0TCG9PDc4iPt3L6+aq5B0X29s9zicNQ==} peerDependencies: - storybook: ^8.4.7 + storybook: ^8.6.14 + + '@storybook/addon-interactions@8.6.14': + resolution: {integrity: sha512-8VmElhm2XOjh22l/dO4UmXxNOolGhNiSpBcls2pqWSraVh4a670EyYBZsHpkXqfNHo2YgKyZN3C91+9zfH79qQ==} + peerDependencies: + storybook: ^8.6.14 - '@storybook/addon-links@8.4.7': - resolution: {integrity: sha512-L/1h4dMeMKF+MM0DanN24v5p3faNYbbtOApMgg7SlcBT/tgo3+cAjkgmNpYA8XtKnDezm+T2mTDhB8mmIRZpIQ==} + '@storybook/addon-links@8.6.14': + resolution: {integrity: sha512-DRlXHIyZzOruAZkxmXfVgTF+4d6K27pFcH4cUsm3KT1AXuZbr23lb5iZHpUZoG6lmU85Sru4xCEgewSTXBIe1w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.4.7 + storybook: ^8.6.14 peerDependenciesMeta: react: optional: true - '@storybook/addon-measure@8.4.7': - resolution: {integrity: sha512-QfvqYWDSI5F68mKvafEmZic3SMiK7zZM8VA0kTXx55hF/+vx61Mm0HccApUT96xCXIgmwQwDvn9gS4TkX81Dmw==} + '@storybook/addon-measure@8.6.14': + resolution: {integrity: sha512-1Tlyb72NX8aAqm6I6OICsUuGOP6hgnXcuFlXucyhKomPa6j3Eu2vKu561t/f0oGtAK2nO93Z70kVaEh5X+vaGw==} peerDependencies: - storybook: ^8.4.7 + storybook: ^8.6.14 - '@storybook/addon-outline@8.4.7': - resolution: {integrity: sha512-6LYRqUZxSodmAIl8icr585Oi8pmzbZ90aloZJIpve+dBAzo7ydYrSQxxoQEVltXbKf3VeVcrs64ouAYqjisMYA==} + '@storybook/addon-outline@8.6.14': + resolution: {integrity: sha512-CW857JvN6OxGWElqjlzJO2S69DHf+xO3WsEfT5mT3ZtIjmsvRDukdWfDU9bIYUFyA2lFvYjncBGjbK+I91XR7w==} peerDependencies: - storybook: ^8.4.7 + storybook: ^8.6.14 + + '@storybook/addon-themes@8.6.14': + resolution: {integrity: sha512-/HJCgskA3OFGectuoLEBQ3JX1nQhE7lnpSv5gH13CWyyaMEk/mP8JYF1uO25YQqwGuSgL2gaEox+aK7UmglAmQ==} + peerDependencies: + storybook: ^8.6.14 '@storybook/addon-toolbars@8.4.7': resolution: {integrity: sha512-OSfdv5UZs+NdGB+nZmbafGUWimiweJ/56gShlw8Neo/4jOJl1R3rnRqqY7MYx8E4GwoX+i3GF5C3iWFNQqlDcw==} peerDependencies: storybook: ^8.4.7 - '@storybook/addon-viewport@8.4.7': - resolution: {integrity: sha512-hvczh/jjuXXcOogih09a663sRDDSATXwbE866al1DXgbDFraYD/LxX/QDb38W9hdjU9+Qhx8VFIcNWoMQns5HQ==} + '@storybook/addon-toolbars@8.6.14': + resolution: {integrity: sha512-W/wEXT8h3VyZTVfWK/84BAcjAxTdtRiAkT2KAN0nbSHxxB5KEM1MjKpKu2upyzzMa3EywITqbfy4dP6lpkVTwQ==} peerDependencies: - storybook: ^8.4.7 + storybook: ^8.6.14 - '@storybook/addon-webpack5-compiler-swc@1.0.6': - resolution: {integrity: sha512-QiZheKKYsUCAtPn9phwtmOBAWBNxnxyfu5E+HUSQIbX94pTwc3ROufJ3g1R/RMQZcklOYXpSI0V8FS1m6aUVkg==} - engines: {node: '>=18'} + '@storybook/addon-viewport@8.6.14': + resolution: {integrity: sha512-gNzVQbMqRC+/4uQTPI2ZrWuRHGquTMZpdgB9DrD88VTEjNudP+J6r8myLfr2VvGksBbUMHkGHMXHuIhrBEnXYA==} + peerDependencies: + storybook: ^8.6.14 '@storybook/blocks@8.4.7': resolution: {integrity: sha512-+QH7+JwXXXIyP3fRCxz/7E2VZepAanXJM7G8nbR3wWsqWgrRp4Wra6MvybxAYCxU7aNfJX5c+RW84SNikFpcIA==} @@ -1746,42 +1740,51 @@ packages: react-dom: optional: true - '@storybook/builder-webpack5@8.4.7': - resolution: {integrity: sha512-O8LpsQ+4g2x5kh7rI9+jEUdX8k1a5egBQU1lbudmHchqsV0IKiVqBD9LL5Gj3wpit4vB8coSW4ZWTFBw8FQb4Q==} + '@storybook/blocks@8.6.14': + resolution: {integrity: sha512-rBMHAfA39AGHgkrDze4RmsnQTMw1ND5fGWobr9pDcJdnDKWQWNRD7Nrlxj0gFlN3n4D9lEZhWGdFrCbku7FVAQ==} peerDependencies: - storybook: ^8.4.7 - typescript: '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + storybook: ^8.6.14 peerDependenciesMeta: - typescript: + react: optional: true + react-dom: + optional: true + + '@storybook/builder-vite@8.6.14': + resolution: {integrity: sha512-ajWYhy32ksBWxwWHrjwZzyC0Ii5ZTeu5lsqA95Q/EQBB0P5qWlHWGM3AVyv82Mz/ND03ebGy123uVwgf6olnYQ==} + peerDependencies: + storybook: ^8.6.14 + vite: ^4.0.0 || ^5.0.0 || ^6.0.0 '@storybook/components@8.4.7': resolution: {integrity: sha512-uyJIcoyeMWKAvjrG9tJBUCKxr2WZk+PomgrgrUwejkIfXMO76i6jw9BwLa0NZjYdlthDv30r9FfbYZyeNPmF0g==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/core-events@8.4.7': - resolution: {integrity: sha512-D5WhJBVfywIVBurNZ7mwSjXT18a8Ct5AfZFEukIBPLaezY21TgN/7sE2OU5dkMQsm11oAZzsdLPOzms2e9HsRg==} + '@storybook/components@8.6.14': + resolution: {integrity: sha512-HNR2mC5I4Z5ek8kTrVZlIY/B8gJGs5b3XdZPBPBopTIN6U/YHXiDyOjY3JlaS4fSG1fVhp/Qp1TpMn1w/9m1pw==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/core-webpack@8.4.7': - resolution: {integrity: sha512-Tj+CjQLpFyBJxhhMms+vbPT3+gTRAiQlrhY3L1IEVwBa3wtRMS0qjozH26d1hK4G6mUIEdwu13L54HMU/w33Sg==} + '@storybook/core-events@8.4.7': + resolution: {integrity: sha512-D5WhJBVfywIVBurNZ7mwSjXT18a8Ct5AfZFEukIBPLaezY21TgN/7sE2OU5dkMQsm11oAZzsdLPOzms2e9HsRg==} peerDependencies: - storybook: ^8.4.7 + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/core@8.4.7': - resolution: {integrity: sha512-7Z8Z0A+1YnhrrSXoKKwFFI4gnsLbWzr8fnDCU6+6HlDukFYh8GHRcZ9zKfqmy6U3hw2h8H5DrHsxWfyaYUUOoA==} + '@storybook/core@8.6.14': + resolution: {integrity: sha512-1P/w4FSNRqP8j3JQBOi3yGt8PVOgSRbP66Ok520T78eJBeqx9ukCfl912PQZ7SPbW3TIunBwLXMZOjZwBB/JmA==} peerDependencies: prettier: ^2 || ^3 peerDependenciesMeta: prettier: optional: true - '@storybook/csf-plugin@8.4.7': - resolution: {integrity: sha512-Fgogplu4HImgC+AYDcdGm1rmL6OR1rVdNX1Be9C/NEXwOCpbbBwi0BxTf/2ZxHRk9fCeaPEcOdP5S8QHfltc1g==} + '@storybook/csf-plugin@8.6.14': + resolution: {integrity: sha512-dErtc9teAuN+eelN8FojzFE635xlq9cNGGGEu0WEmMUQ4iJ8pingvBO1N8X3scz4Ry7KnxX++NNf3J3gpxS8qQ==} peerDependencies: - storybook: ^8.4.7 + storybook: ^8.6.14 '@storybook/csf@0.1.13': resolution: {integrity: sha512-7xOOwCLGB3ebM87eemep89MYRFTko+D8qE7EdAAq74lgdqRR5cOUtYWJLjO2dLtP94nqoOdHJo6MdLLKzg412Q==} @@ -1796,66 +1799,54 @@ packages: 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/instrumenter@8.4.7': - resolution: {integrity: sha512-k6NSD3jaRCCHAFtqXZ7tw8jAzD/yTEWXGya+REgZqq5RCkmJ+9S4Ytp/6OhQMPtPFX23gAuJJzTQVLcCr+gjRg==} + '@storybook/instrumenter@8.6.14': + resolution: {integrity: sha512-iG4MlWCcz1L7Yu8AwgsnfVAmMbvyRSk700Mfy2g4c8y5O+Cv1ejshE1LBBsCwHgkuqU0H4R0qu4g23+6UnUemQ==} peerDependencies: - storybook: ^8.4.7 + storybook: ^8.6.14 '@storybook/manager-api@8.4.7': resolution: {integrity: sha512-ELqemTviCxAsZ5tqUz39sDmQkvhVAvAgiplYy9Uf15kO0SP2+HKsCMzlrm2ue2FfkUNyqbDayCPPCB0Cdn/mpQ==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/preset-react-webpack@8.4.7': - resolution: {integrity: sha512-geTSBKyrBagVihil5MF7LkVFynbfHhCinvnbCZZqXW7M1vgcxvatunUENB+iV8eWg/0EJ+8O7scZL+BAxQ/2qg==} - engines: {node: '>=18.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 - storybook: ^8.4.7 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@storybook/preview-api@8.4.7': - resolution: {integrity: sha512-0QVQwHw+OyZGHAJEXo6Knx+6/4er7n2rTDE5RYJ9F2E2Lg42E19pfdLlq2Jhoods2Xrclo3wj6GWR//Ahi39Eg==} + '@storybook/manager-api@8.6.14': + resolution: {integrity: sha512-ez0Zihuy17udLbfHZQXkGqwtep0mSGgHcNzGN7iZrMP1m+VmNo+7aGCJJdvXi7+iU3yq8weXSQFWg5DqWgLS7g==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0': - resolution: {integrity: sha512-KUqXC3oa9JuQ0kZJLBhVdS4lOneKTOopnNBK4tUAgoxWQ3u/IjzdueZjFr7gyBrXMoU6duutk3RQR9u8ZpYJ4Q==} + '@storybook/preview-api@8.6.14': + resolution: {integrity: sha512-2GhcCd4dNMrnD7eooEfvbfL4I83qAqEyO0CO7JQAmIO6Rxb9BsOLLI/GD5HkvQB73ArTJ+PT50rfaO820IExOQ==} peerDependencies: - typescript: '>= 4.x' - webpack: '>= 4' + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/react-dom-shim@8.4.7': - resolution: {integrity: sha512-6bkG2jvKTmWrmVzCgwpTxwIugd7Lu+2btsLAqhQSzDyIj2/uhMNp8xIMr/NBDtLgq3nomt9gefNa9xxLwk/OMg==} + '@storybook/react-dom-shim@8.6.14': + resolution: {integrity: sha512-0hixr3dOy3f3M+HBofp3jtMQMS+sqzjKNgl7Arfuj3fvjmyXOks/yGjDImySR4imPtEllvPZfhiQNlejheaInw==} 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.4.7 + storybook: ^8.6.14 - '@storybook/react-webpack5@8.4.7': - resolution: {integrity: sha512-T9GLqlsP4It4El7cC8rSkBPRWvORAsTDULeWlO36RST2TrYnmBOUytsi22mk7cAAAVhhD6rTrs1YdqWRMpfa1w==} + '@storybook/react-vite@8.6.14': + resolution: {integrity: sha512-FZU0xMPxa4/TO87FgcWwappOxLBHZV5HSRK5K+2bJD7rFJAoNorbHvB4Q1zvIAk7eCMjkr2GPCPHx9PRB9vJFg==} engines: {node: '>=18.0.0'} peerDependencies: + '@storybook/test': 8.6.14 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.4.7 - typescript: '>= 4.2.x' + storybook: ^8.6.14 + vite: ^4.0.0 || ^5.0.0 || ^6.0.0 peerDependenciesMeta: - typescript: + '@storybook/test': optional: true - '@storybook/react@8.4.7': - resolution: {integrity: sha512-nQ0/7i2DkaCb7dy0NaT95llRVNYWQiPIVuhNfjr1mVhEP7XD090p0g7eqUmsx8vfdHh2BzWEo6CoBFRd3+EXxw==} + '@storybook/react@8.6.14': + resolution: {integrity: sha512-BOepx5bBFwl/CPI+F+LnmMmsG1wQYmrX/UQXgUbHQUU9Tj7E2ndTnNbpIuSLc8IrM03ru+DfwSg1Co3cxWtT+g==} engines: {node: '>=18.0.0'} peerDependencies: - '@storybook/test': 8.4.7 + '@storybook/test': 8.6.14 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.4.7 + storybook: ^8.6.14 typescript: '>= 4.2.x' peerDependenciesMeta: '@storybook/test': @@ -1863,90 +1854,20 @@ packages: typescript: optional: true - '@storybook/test@8.4.7': - resolution: {integrity: sha512-AhvJsu5zl3uG40itSQVuSy5WByp3UVhS6xAnme4FWRwgSxhvZjATJ3AZkkHWOYjnnk+P2/sbz/XuPli1FVCWoQ==} + '@storybook/test@8.6.14': + resolution: {integrity: sha512-GkPNBbbZmz+XRdrhMtkxPotCLOQ1BaGNp/gFZYdGDk2KmUWBKmvc5JxxOhtoXM2703IzNFlQHSSNnhrDZYuLlw==} peerDependencies: - storybook: ^8.4.7 + storybook: ^8.6.14 '@storybook/theming@8.4.7': resolution: {integrity: sha512-99rgLEjf7iwfSEmdqlHkSG3AyLcK0sfExcr0jnc6rLiAkBhzuIsvcHjjUwkR210SOCgXqBPW0ZA6uhnuyppHLw==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@swc/core-darwin-arm64@1.10.4': - resolution: {integrity: sha512-sV/eurLhkjn/197y48bxKP19oqcLydSel42Qsy2zepBltqUx+/zZ8+/IS0Bi7kaWVFxerbW1IPB09uq8Zuvm3g==} - engines: {node: '>=10'} - cpu: [arm64] - os: [darwin] - - '@swc/core-darwin-x64@1.10.4': - resolution: {integrity: sha512-gjYNU6vrAUO4+FuovEo9ofnVosTFXkF0VDuo1MKPItz6e2pxc2ale4FGzLw0Nf7JB1sX4a8h06CN16/pLJ8Q2w==} - engines: {node: '>=10'} - cpu: [x64] - os: [darwin] - - '@swc/core-linux-arm-gnueabihf@1.10.4': - resolution: {integrity: sha512-zd7fXH5w8s+Sfvn2oO464KDWl+ZX1MJiVmE4Pdk46N3PEaNwE0koTfgx2vQRqRG4vBBobzVvzICC3618WcefOA==} - engines: {node: '>=10'} - cpu: [arm] - os: [linux] - - '@swc/core-linux-arm64-gnu@1.10.4': - resolution: {integrity: sha512-+UGfoHDxsMZgFD3tABKLeEZHqLNOkxStu+qCG7atGBhS4Slri6h6zijVvf4yI5X3kbXdvc44XV/hrP/Klnui2A==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux] - - '@swc/core-linux-arm64-musl@1.10.4': - resolution: {integrity: sha512-cDDj2/uYsOH0pgAnDkovLZvKJpFmBMyXkxEG6Q4yw99HbzO6QzZ5HDGWGWVq/6dLgYKlnnmpjZCPPQIu01mXEg==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux] - - '@swc/core-linux-x64-gnu@1.10.4': - resolution: {integrity: sha512-qJXh9D6Kf5xSdGWPINpLGixAbB5JX8JcbEJpRamhlDBoOcQC79dYfOMEIxWPhTS1DGLyFakAx2FX/b2VmQmj0g==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux] - - '@swc/core-linux-x64-musl@1.10.4': - resolution: {integrity: sha512-A76lIAeyQnHCVt0RL/pG+0er8Qk9+acGJqSZOZm67Ve3B0oqMd871kPtaHBM0BW3OZAhoILgfHW3Op9Q3mx3Cw==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux] - - '@swc/core-win32-arm64-msvc@1.10.4': - resolution: {integrity: sha512-e6j5kBu4fIY7fFxFxnZI0MlEovRvp50Lg59Fw+DVbtqHk3C85dckcy5xKP+UoXeuEmFceauQDczUcGs19SRGSQ==} - engines: {node: '>=10'} - cpu: [arm64] - os: [win32] - - '@swc/core-win32-ia32-msvc@1.10.4': - resolution: {integrity: sha512-RSYHfdKgNXV/amY5Tqk1EWVsyQnhlsM//jeqMLw5Fy9rfxP592W9UTumNikNRPdjI8wKKzNMXDb1U29tQjN0dg==} - engines: {node: '>=10'} - cpu: [ia32] - os: [win32] - - '@swc/core-win32-x64-msvc@1.10.4': - resolution: {integrity: sha512-1ujYpaqfqNPYdwKBlvJnOqcl+Syn3UrQ4XE0Txz6zMYgyh6cdU6a3pxqLqIUSJ12MtXRA9ZUhEz1ekU3LfLWXw==} - engines: {node: '>=10'} - cpu: [x64] - os: [win32] - - '@swc/core@1.10.4': - resolution: {integrity: sha512-ut3zfiTLORMxhr6y/GBxkHmzcGuVpwJYX4qyXWuBKkpw/0g0S5iO1/wW7RnLnZbAi8wS/n0atRZoaZlXWBkeJg==} - engines: {node: '>=10'} + '@storybook/theming@8.6.14': + resolution: {integrity: sha512-r4y+LsiB37V5hzpQo+BM10PaCsp7YlZ0YcZzQP1OCkPlYXmUAFy2VvDKaFRpD8IeNPKug2u4iFm/laDEbs03dg==} peerDependencies: - '@swc/helpers': '*' - peerDependenciesMeta: - '@swc/helpers': - optional: true - - '@swc/counter@0.1.3': - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - - '@swc/types@0.1.17': - resolution: {integrity: sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==} + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 '@testing-library/dom@10.4.0': resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} @@ -2004,6 +1925,9 @@ packages: '@types/babel__traverse@7.20.6': resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/chai@5.2.2': resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} @@ -2028,9 +1952,6 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - '@types/html-minifier-terser@6.1.0': - resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==} - '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -2040,9 +1961,6 @@ packages: '@types/node@20.19.21': resolution: {integrity: sha512-CsGG2P3I5y48RPMfprQGfy4JPRZ6csfC3ltBZSRItG3ngggmNY/qs2uZKp4p9VbrpqNNSMzUZNFZKzgOGnd/VA==} - '@types/node@22.18.10': - resolution: {integrity: sha512-anNG/V/Efn/YZY4pRzbACnKxNKoBng2VTFydVu8RRs5hQjikP8CQfaeAV59VFSCzKNp90mXiVXW2QzV56rwMrg==} - '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -2068,9 +1986,6 @@ packages: '@types/resolve@1.20.6': resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} - '@types/semver@7.5.8': - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} @@ -2279,11 +2194,6 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - ansi-html-community@0.0.8: - resolution: {integrity: sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==} - engines: {'0': node >= 0.8.0} - hasBin: true - ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -2300,9 +2210,9 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -2364,6 +2274,10 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + axe-core@4.11.0: + resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} + engines: {node: '>=4'} + babel-plugin-macros@3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} @@ -2393,10 +2307,6 @@ packages: big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -2441,23 +2351,12 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - camel-case@4.1.2: - resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} - caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} caniuse-lite@1.0.30001690: resolution: {integrity: sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==} - case-sensitive-paths-webpack-plugin@2.4.0: - resolution: {integrity: sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==} - engines: {node: '>=4'} - - chai@5.1.2: - resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} - engines: {node: '>=12'} - chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} @@ -2474,10 +2373,6 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - chromatic@11.22.0: resolution: {integrity: sha512-u1kAPR9lj9aFzsCp0iWPXBbsKgcxFU7iJO6mFbgNHGVg+YPBqiJMuvgB8EQHdNbHjk5amFnGnIz/Ww8fK3t9Hw==} hasBin: true @@ -2494,13 +2389,6 @@ packages: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} - cjs-module-lexer@1.4.1: - resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} - - clean-css@5.3.3: - resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} - engines: {node: '>= 10.0'} - clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -2515,9 +2403,6 @@ packages: colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} - colorette@2.0.20: - resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -2533,10 +2418,6 @@ packages: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} - commander@8.3.0: - resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} - engines: {node: '>= 12'} - commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} @@ -2546,9 +2427,6 @@ packages: concat-with-sourcemaps@1.1.0: resolution: {integrity: sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==} - constants-browserify@1.0.0: - resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} - convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -2559,6 +2437,9 @@ packages: resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} engines: {node: '>=18'} + copy-anything@2.0.6: + resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} + core-js-compat@3.39.0: resolution: {integrity: sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==} @@ -2576,18 +2457,6 @@ packages: peerDependencies: postcss: ^8.0.9 - css-loader@6.11.0: - resolution: {integrity: sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==} - engines: {node: '>= 12.13.0'} - peerDependencies: - '@rspack/core': 0.x || 1.x - webpack: ^5.0.0 - peerDependenciesMeta: - '@rspack/core': - optional: true - webpack: - optional: true - css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} @@ -2682,9 +2551,6 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - dedent@0.7.0: - resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} - deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} @@ -2734,9 +2600,6 @@ packages: dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - dom-converter@0.2.0: - resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==} - dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} @@ -2758,26 +2621,29 @@ packages: domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} - dot-case@3.0.4: - resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} - dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + electron-to-chromium@1.5.76: resolution: {integrity: sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==} email-addresses@5.0.0: resolution: {integrity: sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + emojis-list@3.0.0: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} engines: {node: '>= 4'} - endent@2.1.0: - resolution: {integrity: sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==} - enhanced-resolve@5.18.0: resolution: {integrity: sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==} engines: {node: '>=10.13.0'} @@ -2793,6 +2659,10 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} @@ -2812,9 +2682,6 @@ packages: resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} - es-module-lexer@1.6.0: - resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} - es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} @@ -2838,11 +2705,6 @@ packages: peerDependencies: esbuild: '>=0.12 <1' - esbuild@0.24.2: - resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.25.11: resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} engines: {node: '>=18'} @@ -2982,9 +2844,6 @@ packages: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} - fast-json-parse@1.0.3: - resolution: {integrity: sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==} - fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -3055,10 +2914,6 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -3069,31 +2924,18 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - fork-ts-checker-webpack-plugin@8.0.0: - resolution: {integrity: sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==} - engines: {node: '>=12.13.0', yarn: '>=1.0.0'} - peerDependencies: - typescript: '>3.6.0' - webpack: ^5.11.0 + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} form-data@4.0.4: resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} engines: {node: '>= 6'} - fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} - fs-extra@11.2.0: resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} engines: {node: '>=14.14'} - fs-monkey@1.0.6: - resolution: {integrity: sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -3144,9 +2986,9 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + hasBin: true globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} @@ -3201,10 +3043,6 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} @@ -3212,29 +3050,6 @@ packages: resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} engines: {node: '>=12'} - html-entities@2.5.2: - resolution: {integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==} - - html-minifier-terser@6.1.0: - resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} - engines: {node: '>=12'} - hasBin: true - - html-webpack-plugin@5.6.3: - resolution: {integrity: sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==} - engines: {node: '>=10.13.0'} - peerDependencies: - '@rspack/core': 0.x || 1.x - webpack: ^5.20.0 - peerDependenciesMeta: - '@rspack/core': - optional: true - webpack: - optional: true - - htmlparser2@6.1.0: - resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} - http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} @@ -3260,6 +3075,11 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + image-size@0.5.5: + resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} + engines: {node: '>=0.10.0'} + hasBin: true + import-cwd@3.0.0: resolution: {integrity: sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==} engines: {node: '>=8'} @@ -3280,10 +3100,6 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -3310,10 +3126,6 @@ packages: resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} engines: {node: '>= 0.4'} - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - is-boolean-object@1.2.1: resolution: {integrity: sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==} engines: {node: '>= 0.4'} @@ -3347,6 +3159,10 @@ packages: resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-generator-function@1.1.0: resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} engines: {node: '>= 0.4'} @@ -3412,6 +3228,9 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} + is-what@3.14.1: + resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} @@ -3426,10 +3245,17 @@ packages: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + hasBin: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3496,6 +3322,11 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + less@4.5.1: + resolution: {integrity: sha512-UKgI3/KON4u6ngSsnDADsUERqhZknsVZbnuzlRZXLQCmfC/MDld42fTydUE9B+Mla1AL6SJ/Pp6SlEFi/AVGfw==} + engines: {node: '>=14'} + hasBin: true + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -3558,8 +3389,8 @@ packages: loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} - lower-case@2.0.2: - resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -3571,9 +3402,17 @@ packages: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true + magic-string@0.27.0: + resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} + engines: {node: '>=12'} + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} @@ -3595,10 +3434,6 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - memfs@3.5.3: - resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} - engines: {node: '>= 4.0.0'} - memoizerific@1.11.3: resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} @@ -3621,6 +3456,11 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -3639,6 +3479,10 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -3647,30 +3491,20 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanoid@3.3.8: - resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + needle@3.3.1: + resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==} + engines: {node: '>= 4.4.x'} + hasBin: true + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - no-case@3.0.4: - resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - - node-abort-controller@3.1.1: - resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - normalize-url@6.1.0: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} @@ -3709,12 +3543,6 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - objectorarray@1.0.5: - resolution: {integrity: sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} @@ -3759,12 +3587,12 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - param-case@3.0.4: - resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} - parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -3773,23 +3601,17 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-node-version@1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - pascal-case@3.1.2: - resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} - - path-browserify@1.0.1: - resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -3797,6 +3619,10 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -3823,6 +3649,10 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + pify@5.0.0: resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} engines: {node: '>=10'} @@ -4052,10 +3882,6 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.4.49: - resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -4073,9 +3899,6 @@ packages: engines: {node: '>=14'} hasBin: true - pretty-error@4.0.0: - resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==} - pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -4091,6 +3914,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + psl@1.15.0: resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} @@ -4098,17 +3924,10 @@ packages: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} - punycode@1.4.1: - resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.13.1: - resolution: {integrity: sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==} - engines: {node: '>=0.6'} - querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -4118,10 +3937,6 @@ packages: randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - react-confetti@6.2.2: resolution: {integrity: sha512-K+kTyOPgX+ZujMZ+Rmb7pZdHBvg+DzinG/w4Eh52WOB8/pfO38efnnrtEZNJmjTvLxc16RBYO+tPM68Fg8viBA==} engines: {node: '>=16'} @@ -4137,6 +3952,10 @@ packages: resolution: {integrity: sha512-APPU8HB2uZnpl6Vt/+0AFoVYgSRtfiP6FLrZgPPTDmqSb2R4qZRbgd0A3VzIFxDt5e+Fozjx79WjLWnF69DK8g==} engines: {node: '>=16.14.0'} + react-docgen@8.0.2: + resolution: {integrity: sha512-+NRMYs2DyTP4/tqWz371Oo50JqmWltR1h2gcdgUMAWZJIAvrd0/SqlCfx7tpzpl/s36rzw6qH2MjoNrxtRNYhA==} + engines: {node: ^20.9.0 || >=22} + react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: @@ -4183,10 +4002,6 @@ packages: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - recast@0.23.9: resolution: {integrity: sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==} engines: {node: '>= 4'} @@ -4227,13 +4042,6 @@ packages: resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==} hasBin: true - relateurl@0.2.7: - resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} - engines: {node: '>= 0.10'} - - renderkid@3.0.0: - resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==} - require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} @@ -4262,11 +4070,6 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rollup-plugin-dts@6.1.1: resolution: {integrity: sha512-aSHRcJ6KG2IHIioYlvAOcEq6U99sVtqDDKVhnwt70rW6tsz3tv5OSjEiWcgzfsHdLyGXZ/3b/7b/+Za3Y6r1XA==} engines: {node: '>=16'} @@ -4322,6 +4125,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sax@1.4.3: + resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} + saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -4337,6 +4143,10 @@ packages: resolution: {integrity: sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==} engines: {node: '>= 10.13.0'} + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -4391,6 +4201,10 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -4426,8 +4240,8 @@ packages: storybook-dark-mode@4.0.2: resolution: {integrity: sha512-zjcwwQ01R5t1VsakA6alc2JDIRVtavryW8J3E3eKLDIlAMcvsgtpxlelWkZs2cuNspk6Z10XzhQVrUWtYc3F0w==} - storybook@8.4.7: - resolution: {integrity: sha512-RP/nMJxiWyFc8EVMH5gp20ID032Wvk+Yr3lmKidoegto5Iy+2dVQnUoElZb2zpbVXNHWakGuAkfI0dY1Hfp/vw==} + storybook@8.6.14: + resolution: {integrity: sha512-sVKbCj/OTx67jhmauhxc2dcr1P+yOgz/x3h0krwjyMgdc5Oubvxyg4NYDZmzAw+ym36g/lzH8N0Ccp4dwtdfxw==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -4438,6 +4252,14 @@ packages: string-hash@1.1.3: resolution: {integrity: sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + string.prototype.matchall@4.0.12: resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} @@ -4491,12 +4313,6 @@ packages: style-inject@0.3.0: resolution: {integrity: sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==} - style-loader@3.3.4: - resolution: {integrity: sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==} - engines: {node: '>= 12.13.0'} - peerDependencies: - webpack: ^5.0.0 - stylehacks@5.1.1: resolution: {integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==} engines: {node: ^10 || ^12 || >=14.0} @@ -4523,12 +4339,6 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - swc-loader@0.2.6: - resolution: {integrity: sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==} - peerDependencies: - '@swc/core': ^1.2.147 - webpack: '>=2' - symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -4726,10 +4536,6 @@ packages: url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - url@0.11.4: - resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} - engines: {node: '>= 0.4'} - utif@3.1.0: resolution: {integrity: sha512-WEo4D/xOvFW53K5f5QTaTbbiORcm2/pCL9P6qmJnup+17eYfKaEhDeX9PeQkuyEoIxlbGklDuGl8xwuXYMrrXQ==} @@ -4739,9 +4545,6 @@ packages: util@0.12.5: resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - utila@0.4.0: - resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} - uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true @@ -4831,18 +4634,6 @@ packages: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} - webpack-dev-middleware@6.1.3: - resolution: {integrity: sha512-A4ChP0Qj8oGociTs6UdlRUGANIGrCDL3y+pmQMc+dSsraXHCatFpmMey4mYELA+juqwUqwQsUgJJISXl1KWmiw==} - engines: {node: '>= 14.15.0'} - peerDependencies: - webpack: ^5.0.0 - peerDependenciesMeta: - webpack: - optional: true - - webpack-hot-middleware@2.26.1: - resolution: {integrity: sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A==} - webpack-sources@3.2.3: resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} engines: {node: '>=10.13.0'} @@ -4863,6 +4654,7 @@ packages: whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-mimetype@3.0.0: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} @@ -4902,20 +4694,13 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} - ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} - 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 + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} ws@8.18.3: resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} @@ -4967,8 +4752,16 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/compat-data@7.26.3': {} + '@babel/compat-data@7.28.5': {} + '@babel/core@7.26.0': dependencies: '@ampproject/remapping': 2.3.0 @@ -4989,6 +4782,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/generator@7.26.3': dependencies: '@babel/parser': 7.26.3 @@ -4997,6 +4810,14 @@ snapshots: '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.1.0 + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.25.9': dependencies: '@babel/types': 7.26.3 @@ -5009,6 +4830,14 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.24.3 + lru-cache: 5.1.1 + semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -5040,6 +4869,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-globals@7.28.0': {} + '@babel/helper-member-expression-to-functions@7.25.9': dependencies: '@babel/traverse': 7.26.4 @@ -5054,6 +4885,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -5063,6 +4901,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + '@babel/helper-optimise-call-expression@7.25.9': dependencies: '@babel/types': 7.26.3 @@ -5096,10 +4943,16 @@ snapshots: '@babel/helper-string-parser@7.25.9': {} + '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-validator-identifier@7.25.9': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-option@7.25.9': {} + '@babel/helper-validator-option@7.27.1': {} + '@babel/helper-wrap-function@7.25.9': dependencies: '@babel/template': 7.25.9 @@ -5113,10 +4966,19 @@ snapshots: '@babel/template': 7.25.9 '@babel/types': 7.26.3 + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + '@babel/parser@7.26.3': dependencies: '@babel/types': 7.26.3 + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -5656,6 +5518,12 @@ snapshots: '@babel/parser': 7.26.3 '@babel/types': 7.26.3 + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@babel/traverse@7.26.4': dependencies: '@babel/code-frame': 7.26.2 @@ -5668,18 +5536,35 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + '@babel/types@7.26.3': dependencies: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@chromatic-com/storybook@3.2.3(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))': + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@chromatic-com/storybook@3.2.3(react@18.3.1)(storybook@8.6.14(prettier@3.4.2))': dependencies: chromatic: 11.22.0 filesize: 10.1.6 jsonfile: 6.1.0 react-confetti: 6.2.2(react@18.3.1) - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) strip-ansi: 7.1.0 transitivePeerDependencies: - '@chromatic-com/cypress' @@ -5777,162 +5662,87 @@ snapshots: '@emotion/weak-memoize@0.4.0': {} - '@esbuild/aix-ppc64@0.24.2': - optional: true - '@esbuild/aix-ppc64@0.25.11': optional: true - '@esbuild/android-arm64@0.24.2': - optional: true - '@esbuild/android-arm64@0.25.11': optional: true - '@esbuild/android-arm@0.24.2': - optional: true - '@esbuild/android-arm@0.25.11': optional: true - '@esbuild/android-x64@0.24.2': - optional: true - '@esbuild/android-x64@0.25.11': optional: true - '@esbuild/darwin-arm64@0.24.2': - optional: true - '@esbuild/darwin-arm64@0.25.11': optional: true - '@esbuild/darwin-x64@0.24.2': - optional: true - '@esbuild/darwin-x64@0.25.11': optional: true - '@esbuild/freebsd-arm64@0.24.2': - optional: true - '@esbuild/freebsd-arm64@0.25.11': optional: true - '@esbuild/freebsd-x64@0.24.2': - optional: true - '@esbuild/freebsd-x64@0.25.11': optional: true - '@esbuild/linux-arm64@0.24.2': - optional: true - '@esbuild/linux-arm64@0.25.11': optional: true - '@esbuild/linux-arm@0.24.2': - optional: true - '@esbuild/linux-arm@0.25.11': optional: true - '@esbuild/linux-ia32@0.24.2': - optional: true - '@esbuild/linux-ia32@0.25.11': optional: true - '@esbuild/linux-loong64@0.24.2': - optional: true - '@esbuild/linux-loong64@0.25.11': optional: true - '@esbuild/linux-mips64el@0.24.2': - optional: true - '@esbuild/linux-mips64el@0.25.11': optional: true - '@esbuild/linux-ppc64@0.24.2': - optional: true - '@esbuild/linux-ppc64@0.25.11': optional: true - '@esbuild/linux-riscv64@0.24.2': - optional: true - '@esbuild/linux-riscv64@0.25.11': optional: true - '@esbuild/linux-s390x@0.24.2': - optional: true - '@esbuild/linux-s390x@0.25.11': optional: true - '@esbuild/linux-x64@0.24.2': - optional: true - '@esbuild/linux-x64@0.25.11': optional: true - '@esbuild/netbsd-arm64@0.24.2': - optional: true - '@esbuild/netbsd-arm64@0.25.11': optional: true - '@esbuild/netbsd-x64@0.24.2': - optional: true - '@esbuild/netbsd-x64@0.25.11': optional: true - '@esbuild/openbsd-arm64@0.24.2': - optional: true - '@esbuild/openbsd-arm64@0.25.11': optional: true - '@esbuild/openbsd-x64@0.24.2': - optional: true - '@esbuild/openbsd-x64@0.25.11': optional: true '@esbuild/openharmony-arm64@0.25.11': optional: true - '@esbuild/sunos-x64@0.24.2': - optional: true - '@esbuild/sunos-x64@0.25.11': optional: true - '@esbuild/win32-arm64@0.24.2': - optional: true - '@esbuild/win32-arm64@0.25.11': optional: true - '@esbuild/win32-ia32@0.24.2': - optional: true - '@esbuild/win32-ia32@0.25.11': optional: true - '@esbuild/win32-x64@0.24.2': - optional: true - '@esbuild/win32-x64@0.25.11': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@9.17.0)': + '@eslint-community/eslint-utils@4.4.1(eslint@9.17.0(jiti@1.21.7))': dependencies: - eslint: 9.17.0 + eslint: 9.17.0(jiti@1.21.7) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -5971,6 +5781,14 @@ snapshots: dependencies: levn: 0.4.1 + '@fontsource-variable/inter@5.2.8': {} + + '@fontsource/ibm-plex-mono@5.2.7': {} + + '@fontsource/inter@5.2.8': {} + + '@fontsource/outfit@5.2.8': {} + '@gerrit0/mini-shiki@3.7.0': dependencies: '@shikijs/engine-oniguruma': 3.7.0 @@ -5992,12 +5810,40 @@ snapshots: '@humanwhocodes/retry@0.4.1': {} + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.7.2)(vite@7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0))': + dependencies: + glob: 10.5.0 + magic-string: 0.27.0 + react-docgen-typescript: 2.2.2(typescript@5.7.2) + vite: 7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0) + optionalDependencies: + typescript: 5.7.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/set-array@1.2.1': {} @@ -6014,6 +5860,11 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jsonforms/core@3.6.0': dependencies: '@types/json-schema': 7.0.15 @@ -6172,6 +6023,9 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.18.0 + '@pkgjs/parseargs@0.11.0': + optional: true + '@pkgr/core@0.1.1': {} '@popperjs/core@2.11.8': {} @@ -6379,194 +6233,197 @@ snapshots: '@shikijs/vscode-textmate@10.0.2': {} - '@storybook/addon-actions@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/addon-a11y@8.6.14(storybook@8.6.14(prettier@3.4.2))': + dependencies: + '@storybook/addon-highlight': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + '@storybook/global': 5.0.0 + '@storybook/test': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + axe-core: 4.11.0 + storybook: 8.6.14(prettier@3.4.2) + + '@storybook/addon-actions@8.4.7(storybook@8.6.14(prettier@3.4.2))': + dependencies: + '@storybook/global': 5.0.0 + '@types/uuid': 9.0.8 + dequal: 2.0.3 + polished: 4.3.1 + storybook: 8.6.14(prettier@3.4.2) + uuid: 9.0.1 + + '@storybook/addon-actions@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: '@storybook/global': 5.0.0 '@types/uuid': 9.0.8 dequal: 2.0.3 polished: 4.3.1 - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) uuid: 9.0.1 - '@storybook/addon-backgrounds@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/addon-backgrounds@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: '@storybook/global': 5.0.0 memoizerific: 1.11.3 - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) + ts-dedent: 2.2.0 + + '@storybook/addon-controls@8.4.7(storybook@8.6.14(prettier@3.4.2))': + dependencies: + '@storybook/global': 5.0.0 + dequal: 2.0.3 + storybook: 8.6.14(prettier@3.4.2) ts-dedent: 2.2.0 - '@storybook/addon-controls@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/addon-controls@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: '@storybook/global': 5.0.0 dequal: 2.0.3 - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) ts-dedent: 2.2.0 - '@storybook/addon-docs@8.4.7(@types/react@18.3.18)(storybook@8.4.7(prettier@3.4.2))': + '@storybook/addon-docs@8.6.14(@types/react@18.3.18)(storybook@8.6.14(prettier@3.4.2))': dependencies: '@mdx-js/react': 3.1.0(@types/react@18.3.18)(react@18.3.1) - '@storybook/blocks': 8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2)) - '@storybook/csf-plugin': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/react-dom-shim': 8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2)) + '@storybook/blocks': 8.6.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.4.2)) + '@storybook/csf-plugin': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + '@storybook/react-dom-shim': 8.6.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.4.2)) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - '@storybook/addon-essentials@8.4.7(@types/react@18.3.18)(storybook@8.4.7(prettier@3.4.2))': - dependencies: - '@storybook/addon-actions': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/addon-backgrounds': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/addon-controls': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/addon-docs': 8.4.7(@types/react@18.3.18)(storybook@8.4.7(prettier@3.4.2)) - '@storybook/addon-highlight': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/addon-measure': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/addon-outline': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/addon-toolbars': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/addon-viewport': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - storybook: 8.4.7(prettier@3.4.2) + '@storybook/addon-essentials@8.6.14(@types/react@18.3.18)(storybook@8.6.14(prettier@3.4.2))': + dependencies: + '@storybook/addon-actions': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + '@storybook/addon-backgrounds': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + '@storybook/addon-controls': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + '@storybook/addon-docs': 8.6.14(@types/react@18.3.18)(storybook@8.6.14(prettier@3.4.2)) + '@storybook/addon-highlight': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + '@storybook/addon-measure': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + '@storybook/addon-outline': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + '@storybook/addon-toolbars': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + '@storybook/addon-viewport': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + storybook: 8.6.14(prettier@3.4.2) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - '@storybook/addon-highlight@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/addon-highlight@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: '@storybook/global': 5.0.0 - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) - '@storybook/addon-interactions@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/addon-interactions@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/test': 8.4.7(storybook@8.4.7(prettier@3.4.2)) + '@storybook/instrumenter': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + '@storybook/test': 8.6.14(storybook@8.6.14(prettier@3.4.2)) polished: 4.3.1 - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) ts-dedent: 2.2.0 - '@storybook/addon-links@8.4.7(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))': + '@storybook/addon-links@8.6.14(react@18.3.1)(storybook@8.6.14(prettier@3.4.2))': dependencies: - '@storybook/csf': 0.1.13 '@storybook/global': 5.0.0 - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) ts-dedent: 2.2.0 optionalDependencies: react: 18.3.1 - '@storybook/addon-measure@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/addon-measure@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: '@storybook/global': 5.0.0 - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) tiny-invariant: 1.3.3 - '@storybook/addon-outline@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/addon-outline@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: '@storybook/global': 5.0.0 - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) ts-dedent: 2.2.0 - '@storybook/addon-toolbars@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/addon-themes@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) + ts-dedent: 2.2.0 - '@storybook/addon-viewport@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/addon-toolbars@8.4.7(storybook@8.6.14(prettier@3.4.2))': dependencies: - memoizerific: 1.11.3 - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) - '@storybook/addon-webpack5-compiler-swc@1.0.6(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2))': + '@storybook/addon-toolbars@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: - '@swc/core': 1.10.4 - swc-loader: 0.2.6(@swc/core@1.10.4)(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)) - transitivePeerDependencies: - - '@swc/helpers' - - webpack + storybook: 8.6.14(prettier@3.4.2) + + '@storybook/addon-viewport@8.6.14(storybook@8.6.14(prettier@3.4.2))': + dependencies: + memoizerific: 1.11.3 + storybook: 8.6.14(prettier@3.4.2) - '@storybook/blocks@8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))': + '@storybook/blocks@8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.4.2))': dependencies: '@storybook/csf': 0.1.13 '@storybook/icons': 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) ts-dedent: 2.2.0 optionalDependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/builder-webpack5@8.4.7(@swc/core@1.10.4)(esbuild@0.24.2)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2)': + '@storybook/blocks@8.6.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.4.2))': dependencies: - '@storybook/core-webpack': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@types/node': 22.18.10 - '@types/semver': 7.5.8 - browser-assert: 1.2.1 - case-sensitive-paths-webpack-plugin: 2.4.0 - cjs-module-lexer: 1.4.1 - constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)) - es-module-lexer: 1.6.0 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)) - html-webpack-plugin: 5.6.3(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)) - magic-string: 0.30.17 - path-browserify: 1.0.1 - process: 0.11.10 - semver: 7.6.3 - storybook: 8.4.7(prettier@3.4.2) - style-loader: 3.3.4(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)) - terser-webpack-plugin: 5.3.11(@swc/core@1.10.4)(esbuild@0.24.2)(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)) + '@storybook/icons': 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 8.6.14(prettier@3.4.2) ts-dedent: 2.2.0 - url: 0.11.4 - util: 0.12.5 - util-deprecate: 1.0.2 - webpack: 5.97.1(@swc/core@1.10.4)(esbuild@0.24.2) - webpack-dev-middleware: 6.1.3(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)) - webpack-hot-middleware: 2.26.1 - webpack-virtual-modules: 0.6.2 optionalDependencies: - typescript: 5.7.2 - transitivePeerDependencies: - - '@rspack/core' - - '@swc/core' - - esbuild - - uglify-js - - webpack-cli + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + + '@storybook/builder-vite@8.6.14(storybook@8.6.14(prettier@3.4.2))(vite@7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0))': + dependencies: + '@storybook/csf-plugin': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + browser-assert: 1.2.1 + storybook: 8.6.14(prettier@3.4.2) + ts-dedent: 2.2.0 + vite: 7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0) - '@storybook/components@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/components@8.4.7(storybook@8.6.14(prettier@3.4.2))': dependencies: - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) - '@storybook/core-events@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/components@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) - '@storybook/core-webpack@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/core-events@8.4.7(storybook@8.6.14(prettier@3.4.2))': dependencies: - '@types/node': 22.18.10 - storybook: 8.4.7(prettier@3.4.2) - ts-dedent: 2.2.0 + storybook: 8.6.14(prettier@3.4.2) - '@storybook/core@8.4.7(prettier@3.4.2)': + '@storybook/core@8.6.14(prettier@3.4.2)(storybook@8.6.14(prettier@3.4.2))': dependencies: - '@storybook/csf': 0.1.13 + '@storybook/theming': 8.6.14(storybook@8.6.14(prettier@3.4.2)) better-opn: 3.0.2 browser-assert: 1.2.1 - esbuild: 0.24.2 - esbuild-register: 3.6.0(esbuild@0.24.2) + esbuild: 0.25.11 + esbuild-register: 3.6.0(esbuild@0.25.11) jsdoc-type-pratt-parser: 4.1.0 process: 0.11.10 recast: 0.23.9 semver: 7.6.3 util: 0.12.5 - ws: 8.18.0 + ws: 8.18.3 optionalDependencies: prettier: 3.4.2 transitivePeerDependencies: - bufferutil + - storybook - supports-color - utf-8-validate - '@storybook/csf-plugin@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/csf-plugin@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) unplugin: 1.16.0 '@storybook/csf@0.1.13': @@ -6580,169 +6437,85 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/instrumenter@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/instrumenter@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: '@storybook/global': 5.0.0 '@vitest/utils': 2.1.8 - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) - '@storybook/manager-api@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/manager-api@8.4.7(storybook@8.6.14(prettier@3.4.2))': dependencies: - storybook: 8.4.7(prettier@3.4.2) - - '@storybook/preset-react-webpack@8.4.7(@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2)))(@swc/core@1.10.4)(esbuild@0.24.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2)': - dependencies: - '@storybook/core-webpack': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/react': 8.4.7(@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)) - '@types/node': 22.18.10 - '@types/semver': 7.5.8 - find-up: 5.0.0 - magic-string: 0.30.17 - react: 18.3.1 - react-docgen: 7.1.0 - react-dom: 18.3.1(react@18.3.1) - resolve: 1.22.10 - semver: 7.6.3 - storybook: 8.4.7(prettier@3.4.2) - tsconfig-paths: 4.2.0 - webpack: 5.97.1(@swc/core@1.10.4)(esbuild@0.24.2) - optionalDependencies: - typescript: 5.7.2 - transitivePeerDependencies: - - '@storybook/test' - - '@swc/core' - - esbuild - - supports-color - - uglify-js - - webpack-cli + storybook: 8.6.14(prettier@3.4.2) - '@storybook/preview-api@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/manager-api@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2))': + '@storybook/preview-api@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: - debug: 4.4.0 - endent: 2.1.0 - find-cache-dir: 3.3.2 - flat-cache: 3.2.0 - micromatch: 4.0.8 - react-docgen-typescript: 2.2.2(typescript@5.7.2) - tslib: 2.8.1 - typescript: 5.7.2 - webpack: 5.97.1(@swc/core@1.10.4)(esbuild@0.24.2) - transitivePeerDependencies: - - supports-color + storybook: 8.6.14(prettier@3.4.2) - '@storybook/react-dom-shim@8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))': + '@storybook/react-dom-shim@8.6.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.4.2))': dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) - '@storybook/react-webpack5@8.4.7(@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2)))(@swc/core@1.10.4)(esbuild@0.24.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2)': + '@storybook/react-vite@8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.30.0)(storybook@8.6.14(prettier@3.4.2))(typescript@5.7.2)(vite@7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0))': dependencies: - '@storybook/builder-webpack5': 8.4.7(@swc/core@1.10.4)(esbuild@0.24.2)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2) - '@storybook/preset-react-webpack': 8.4.7(@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2)))(@swc/core@1.10.4)(esbuild@0.24.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2) - '@storybook/react': 8.4.7(@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2) - '@types/node': 22.18.10 + '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.7.2)(vite@7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0)) + '@rollup/pluginutils': 5.1.4(rollup@4.30.0) + '@storybook/builder-vite': 8.6.14(storybook@8.6.14(prettier@3.4.2))(vite@7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0)) + '@storybook/react': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.4.2))(typescript@5.7.2) + find-up: 5.0.0 + magic-string: 0.30.17 react: 18.3.1 + react-docgen: 7.1.0 react-dom: 18.3.1(react@18.3.1) - storybook: 8.4.7(prettier@3.4.2) + resolve: 1.22.10 + storybook: 8.6.14(prettier@3.4.2) + tsconfig-paths: 4.2.0 + vite: 7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0) optionalDependencies: - typescript: 5.7.2 + '@storybook/test': 8.6.14(storybook@8.6.14(prettier@3.4.2)) transitivePeerDependencies: - - '@rspack/core' - - '@storybook/test' - - '@swc/core' - - esbuild + - rollup - supports-color - - uglify-js - - webpack-cli + - typescript - '@storybook/react@8.4.7(@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2)': + '@storybook/react@8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.4.2))(typescript@5.7.2)': dependencies: - '@storybook/components': 8.4.7(storybook@8.4.7(prettier@3.4.2)) + '@storybook/components': 8.6.14(storybook@8.6.14(prettier@3.4.2)) '@storybook/global': 5.0.0 - '@storybook/manager-api': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/preview-api': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/react-dom-shim': 8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2)) - '@storybook/theming': 8.4.7(storybook@8.4.7(prettier@3.4.2)) + '@storybook/manager-api': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + '@storybook/preview-api': 8.6.14(storybook@8.6.14(prettier@3.4.2)) + '@storybook/react-dom-shim': 8.6.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.4.2)) + '@storybook/theming': 8.6.14(storybook@8.6.14(prettier@3.4.2)) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook: 8.4.7(prettier@3.4.2) + storybook: 8.6.14(prettier@3.4.2) optionalDependencies: - '@storybook/test': 8.4.7(storybook@8.4.7(prettier@3.4.2)) + '@storybook/test': 8.6.14(storybook@8.6.14(prettier@3.4.2)) typescript: 5.7.2 - '@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2))': + '@storybook/test@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: - '@storybook/csf': 0.1.13 '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.4.7(storybook@8.4.7(prettier@3.4.2)) + '@storybook/instrumenter': 8.6.14(storybook@8.6.14(prettier@3.4.2)) '@testing-library/dom': 10.4.0 '@testing-library/jest-dom': 6.5.0 '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) '@vitest/expect': 2.0.5 '@vitest/spy': 2.0.5 - storybook: 8.4.7(prettier@3.4.2) - - '@storybook/theming@8.4.7(storybook@8.4.7(prettier@3.4.2))': - dependencies: - storybook: 8.4.7(prettier@3.4.2) - - '@swc/core-darwin-arm64@1.10.4': - optional: true + storybook: 8.6.14(prettier@3.4.2) - '@swc/core-darwin-x64@1.10.4': - optional: true - - '@swc/core-linux-arm-gnueabihf@1.10.4': - optional: true - - '@swc/core-linux-arm64-gnu@1.10.4': - optional: true - - '@swc/core-linux-arm64-musl@1.10.4': - optional: true - - '@swc/core-linux-x64-gnu@1.10.4': - optional: true - - '@swc/core-linux-x64-musl@1.10.4': - optional: true - - '@swc/core-win32-arm64-msvc@1.10.4': - optional: true - - '@swc/core-win32-ia32-msvc@1.10.4': - optional: true - - '@swc/core-win32-x64-msvc@1.10.4': - optional: true - - '@swc/core@1.10.4': + '@storybook/theming@8.4.7(storybook@8.6.14(prettier@3.4.2))': dependencies: - '@swc/counter': 0.1.3 - '@swc/types': 0.1.17 - optionalDependencies: - '@swc/core-darwin-arm64': 1.10.4 - '@swc/core-darwin-x64': 1.10.4 - '@swc/core-linux-arm-gnueabihf': 1.10.4 - '@swc/core-linux-arm64-gnu': 1.10.4 - '@swc/core-linux-arm64-musl': 1.10.4 - '@swc/core-linux-x64-gnu': 1.10.4 - '@swc/core-linux-x64-musl': 1.10.4 - '@swc/core-win32-arm64-msvc': 1.10.4 - '@swc/core-win32-ia32-msvc': 1.10.4 - '@swc/core-win32-x64-msvc': 1.10.4 - - '@swc/counter@0.1.3': {} + storybook: 8.6.14(prettier@3.4.2) - '@swc/types@0.1.17': + '@storybook/theming@8.6.14(storybook@8.6.14(prettier@3.4.2))': dependencies: - '@swc/counter': 0.1.3 + storybook: 8.6.14(prettier@3.4.2) '@testing-library/dom@10.4.0': dependencies: @@ -6816,6 +6589,10 @@ snapshots: dependencies: '@babel/types': 7.26.3 + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.5 + '@types/chai@5.2.2': dependencies: '@types/deep-eql': 4.0.2 @@ -6827,11 +6604,11 @@ snapshots: '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 '@types/eslint@9.6.1': dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 '@types/json-schema': 7.0.15 '@types/estree@1.0.6': {} @@ -6842,8 +6619,6 @@ snapshots: dependencies: '@types/unist': 3.0.3 - '@types/html-minifier-terser@6.1.0': {} - '@types/json-schema@7.0.15': {} '@types/mdx@2.0.13': {} @@ -6852,10 +6627,6 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/node@22.18.10': - dependencies: - undici-types: 6.21.0 - '@types/parse-json@4.0.2': {} '@types/prop-types@15.7.14': {} @@ -6877,8 +6648,6 @@ snapshots: '@types/resolve@1.20.6': {} - '@types/semver@7.5.8': {} - '@types/unist@3.0.3': {} '@types/utif@3.0.5': @@ -6887,15 +6656,15 @@ snapshots: '@types/uuid@9.0.8': {} - '@typescript-eslint/eslint-plugin@8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.17.0)(typescript@5.7.2))(eslint@9.17.0)(typescript@5.7.2)': + '@typescript-eslint/eslint-plugin@8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.19.0(eslint@9.17.0)(typescript@5.7.2) + '@typescript-eslint/parser': 8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2) '@typescript-eslint/scope-manager': 8.19.0 - '@typescript-eslint/type-utils': 8.19.0(eslint@9.17.0)(typescript@5.7.2) - '@typescript-eslint/utils': 8.19.0(eslint@9.17.0)(typescript@5.7.2) + '@typescript-eslint/type-utils': 8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2) + '@typescript-eslint/utils': 8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2) '@typescript-eslint/visitor-keys': 8.19.0 - eslint: 9.17.0 + eslint: 9.17.0(jiti@1.21.7) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -6904,14 +6673,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.19.0(eslint@9.17.0)(typescript@5.7.2)': + '@typescript-eslint/parser@8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2)': dependencies: '@typescript-eslint/scope-manager': 8.19.0 '@typescript-eslint/types': 8.19.0 '@typescript-eslint/typescript-estree': 8.19.0(typescript@5.7.2) '@typescript-eslint/visitor-keys': 8.19.0 debug: 4.4.0 - eslint: 9.17.0 + eslint: 9.17.0(jiti@1.21.7) typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -6921,12 +6690,12 @@ snapshots: '@typescript-eslint/types': 8.19.0 '@typescript-eslint/visitor-keys': 8.19.0 - '@typescript-eslint/type-utils@8.19.0(eslint@9.17.0)(typescript@5.7.2)': + '@typescript-eslint/type-utils@8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2)': dependencies: '@typescript-eslint/typescript-estree': 8.19.0(typescript@5.7.2) - '@typescript-eslint/utils': 8.19.0(eslint@9.17.0)(typescript@5.7.2) + '@typescript-eslint/utils': 8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2) debug: 4.4.0 - eslint: 9.17.0 + eslint: 9.17.0(jiti@1.21.7) ts-api-utils: 1.4.3(typescript@5.7.2) typescript: 5.7.2 transitivePeerDependencies: @@ -6948,13 +6717,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.19.0(eslint@9.17.0)(typescript@5.7.2)': + '@typescript-eslint/utils@8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@1.21.7)) '@typescript-eslint/scope-manager': 8.19.0 '@typescript-eslint/types': 8.19.0 '@typescript-eslint/typescript-estree': 8.19.0(typescript@5.7.2) - eslint: 9.17.0 + eslint: 9.17.0(jiti@1.21.7) typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -6968,7 +6737,7 @@ snapshots: dependencies: '@vitest/spy': 2.0.5 '@vitest/utils': 2.0.5 - chai: 5.1.2 + chai: 5.3.3 tinyrainbow: 1.2.0 '@vitest/expect@3.2.4': @@ -6979,13 +6748,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.1.10(@types/node@20.19.21)(terser@5.37.0)(yaml@2.8.0))': + '@vitest/mocker@3.2.4(vite@7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 7.1.10(@types/node@20.19.21)(terser@5.37.0)(yaml@2.8.0) + vite: 7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0) '@vitest/pretty-format@2.0.5': dependencies: @@ -7023,13 +6792,13 @@ snapshots: dependencies: '@vitest/pretty-format': 2.0.5 estree-walker: 3.0.3 - loupe: 3.1.2 + loupe: 3.2.1 tinyrainbow: 1.2.0 '@vitest/utils@2.1.8': dependencies: '@vitest/pretty-format': 2.1.8 - loupe: 3.1.2 + loupe: 3.2.1 tinyrainbow: 1.2.0 '@vitest/utils@3.2.4': @@ -7138,8 +6907,7 @@ snapshots: acorn@8.14.0: {} - acorn@8.15.0: - optional: true + acorn@8.15.0: {} agent-base@6.0.2: dependencies: @@ -7175,8 +6943,6 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ansi-html-community@0.0.8: {} - ansi-regex@5.0.1: {} ansi-regex@6.1.0: {} @@ -7187,10 +6953,7 @@ snapshots: ansi-styles@5.2.0: {} - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 + ansi-styles@6.2.3: {} argparse@2.0.1: {} @@ -7272,6 +7035,8 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 + axe-core@4.11.0: {} + babel-plugin-macros@3.1.0: dependencies: '@babel/runtime': 7.26.0 @@ -7310,8 +7075,6 @@ snapshots: big.js@5.2.2: {} - binary-extensions@2.3.0: {} - boolbase@1.0.0: {} brace-expansion@1.1.11: @@ -7359,11 +7122,6 @@ snapshots: callsites@3.1.0: {} - camel-case@4.1.2: - dependencies: - pascal-case: 3.1.2 - tslib: 2.8.1 - caniuse-api@3.0.0: dependencies: browserslist: 4.24.3 @@ -7373,16 +7131,6 @@ snapshots: caniuse-lite@1.0.30001690: {} - case-sensitive-paths-webpack-plugin@2.4.0: {} - - chai@5.1.2: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.1 - deep-eql: 5.0.2 - loupe: 3.1.2 - pathval: 2.0.0 - chai@5.3.3: dependencies: assertion-error: 2.0.1 @@ -7403,27 +7151,9 @@ snapshots: check-error@2.1.1: {} - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - chromatic@11.22.0: {} - chrome-trace-event@1.0.4: {} - - cjs-module-lexer@1.4.1: {} - - clean-css@5.3.3: - dependencies: - source-map: 0.6.1 + chrome-trace-event@1.0.4: {} clsx@2.1.1: {} @@ -7435,8 +7165,6 @@ snapshots: colord@2.9.3: {} - colorette@2.0.20: {} - combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -7448,8 +7176,6 @@ snapshots: commander@7.2.0: {} - commander@8.3.0: {} - commondir@1.0.1: {} concat-map@0.0.1: {} @@ -7458,14 +7184,17 @@ snapshots: dependencies: source-map: 0.6.1 - constants-browserify@1.0.0: {} - convert-source-map@1.9.0: {} convert-source-map@2.0.0: {} cookie@1.0.2: {} + copy-anything@2.0.6: + dependencies: + is-what: 3.14.1 + optional: true + core-js-compat@3.39.0: dependencies: browserslist: 4.24.3 @@ -7484,22 +7213,9 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-declaration-sorter@6.4.1(postcss@8.4.49): - dependencies: - postcss: 8.4.49 - - css-loader@6.11.0(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)): + css-declaration-sorter@6.4.1(postcss@8.5.6): dependencies: - icss-utils: 5.1.0(postcss@8.4.49) - postcss: 8.4.49 - postcss-modules-extract-imports: 3.1.0(postcss@8.4.49) - postcss-modules-local-by-default: 4.2.0(postcss@8.4.49) - postcss-modules-scope: 3.2.1(postcss@8.4.49) - postcss-modules-values: 4.0.0(postcss@8.4.49) - postcss-value-parser: 4.2.0 - semver: 7.6.3 - optionalDependencies: - webpack: 5.97.1(@swc/core@1.10.4)(esbuild@0.24.2) + postcss: 8.5.6 css-select@4.3.0: dependencies: @@ -7520,48 +7236,48 @@ snapshots: cssesc@3.0.0: {} - cssnano-preset-default@5.2.14(postcss@8.4.49): - dependencies: - css-declaration-sorter: 6.4.1(postcss@8.4.49) - cssnano-utils: 3.1.0(postcss@8.4.49) - postcss: 8.4.49 - postcss-calc: 8.2.4(postcss@8.4.49) - postcss-colormin: 5.3.1(postcss@8.4.49) - postcss-convert-values: 5.1.3(postcss@8.4.49) - postcss-discard-comments: 5.1.2(postcss@8.4.49) - postcss-discard-duplicates: 5.1.0(postcss@8.4.49) - postcss-discard-empty: 5.1.1(postcss@8.4.49) - postcss-discard-overridden: 5.1.0(postcss@8.4.49) - postcss-merge-longhand: 5.1.7(postcss@8.4.49) - postcss-merge-rules: 5.1.4(postcss@8.4.49) - postcss-minify-font-values: 5.1.0(postcss@8.4.49) - postcss-minify-gradients: 5.1.1(postcss@8.4.49) - postcss-minify-params: 5.1.4(postcss@8.4.49) - postcss-minify-selectors: 5.2.1(postcss@8.4.49) - postcss-normalize-charset: 5.1.0(postcss@8.4.49) - postcss-normalize-display-values: 5.1.0(postcss@8.4.49) - postcss-normalize-positions: 5.1.1(postcss@8.4.49) - postcss-normalize-repeat-style: 5.1.1(postcss@8.4.49) - postcss-normalize-string: 5.1.0(postcss@8.4.49) - postcss-normalize-timing-functions: 5.1.0(postcss@8.4.49) - postcss-normalize-unicode: 5.1.1(postcss@8.4.49) - postcss-normalize-url: 5.1.0(postcss@8.4.49) - postcss-normalize-whitespace: 5.1.1(postcss@8.4.49) - postcss-ordered-values: 5.1.3(postcss@8.4.49) - postcss-reduce-initial: 5.1.2(postcss@8.4.49) - postcss-reduce-transforms: 5.1.0(postcss@8.4.49) - postcss-svgo: 5.1.0(postcss@8.4.49) - postcss-unique-selectors: 5.1.1(postcss@8.4.49) - - cssnano-utils@3.1.0(postcss@8.4.49): - dependencies: - postcss: 8.4.49 - - cssnano@5.1.15(postcss@8.4.49): - dependencies: - cssnano-preset-default: 5.2.14(postcss@8.4.49) + cssnano-preset-default@5.2.14(postcss@8.5.6): + dependencies: + css-declaration-sorter: 6.4.1(postcss@8.5.6) + cssnano-utils: 3.1.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-calc: 8.2.4(postcss@8.5.6) + postcss-colormin: 5.3.1(postcss@8.5.6) + postcss-convert-values: 5.1.3(postcss@8.5.6) + postcss-discard-comments: 5.1.2(postcss@8.5.6) + postcss-discard-duplicates: 5.1.0(postcss@8.5.6) + postcss-discard-empty: 5.1.1(postcss@8.5.6) + postcss-discard-overridden: 5.1.0(postcss@8.5.6) + postcss-merge-longhand: 5.1.7(postcss@8.5.6) + postcss-merge-rules: 5.1.4(postcss@8.5.6) + postcss-minify-font-values: 5.1.0(postcss@8.5.6) + postcss-minify-gradients: 5.1.1(postcss@8.5.6) + postcss-minify-params: 5.1.4(postcss@8.5.6) + postcss-minify-selectors: 5.2.1(postcss@8.5.6) + postcss-normalize-charset: 5.1.0(postcss@8.5.6) + postcss-normalize-display-values: 5.1.0(postcss@8.5.6) + postcss-normalize-positions: 5.1.1(postcss@8.5.6) + postcss-normalize-repeat-style: 5.1.1(postcss@8.5.6) + postcss-normalize-string: 5.1.0(postcss@8.5.6) + postcss-normalize-timing-functions: 5.1.0(postcss@8.5.6) + postcss-normalize-unicode: 5.1.1(postcss@8.5.6) + postcss-normalize-url: 5.1.0(postcss@8.5.6) + postcss-normalize-whitespace: 5.1.1(postcss@8.5.6) + postcss-ordered-values: 5.1.3(postcss@8.5.6) + postcss-reduce-initial: 5.1.2(postcss@8.5.6) + postcss-reduce-transforms: 5.1.0(postcss@8.5.6) + postcss-svgo: 5.1.0(postcss@8.5.6) + postcss-unique-selectors: 5.1.1(postcss@8.5.6) + + cssnano-utils@3.1.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + cssnano@5.1.15(postcss@8.5.6): + dependencies: + cssnano-preset-default: 5.2.14(postcss@8.5.6) lilconfig: 2.1.0 - postcss: 8.4.49 + postcss: 8.5.6 yaml: 1.10.2 csso@4.2.0: @@ -7619,8 +7335,6 @@ snapshots: decimal.js@10.6.0: optional: true - dedent@0.7.0: {} - deep-eql@5.0.2: {} deep-is@0.1.4: {} @@ -7662,10 +7376,6 @@ snapshots: dom-accessibility-api@0.6.3: {} - dom-converter@0.2.0: - dependencies: - utila: 0.4.0 - dom-helpers@5.2.1: dependencies: '@babel/runtime': 7.26.0 @@ -7694,28 +7404,23 @@ snapshots: domelementtype: 2.3.0 domhandler: 4.3.1 - dot-case@3.0.4: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.1 es-errors: 1.3.0 gopd: 1.2.0 + eastasianwidth@0.2.0: {} + electron-to-chromium@1.5.76: {} email-addresses@5.0.0: {} - emojis-list@3.0.0: {} + emoji-regex@8.0.0: {} - endent@2.1.0: - dependencies: - dedent: 0.7.0 - fast-json-parse: 1.0.3 - objectorarray: 1.0.5 + emoji-regex@9.2.2: {} + + emojis-list@3.0.0: {} enhanced-resolve@5.18.0: dependencies: @@ -7729,6 +7434,11 @@ snapshots: entities@6.0.1: optional: true + errno@0.1.8: + dependencies: + prr: 1.0.1 + optional: true + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 @@ -7810,8 +7520,6 @@ snapshots: iterator.prototype: 1.1.5 safe-array-concat: 1.1.3 - es-module-lexer@1.6.0: {} - es-module-lexer@1.7.0: {} es-object-atoms@1.0.0: @@ -7835,41 +7543,13 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - esbuild-register@3.6.0(esbuild@0.24.2): + esbuild-register@3.6.0(esbuild@0.25.11): dependencies: - debug: 4.4.0 - esbuild: 0.24.2 + debug: 4.4.3 + esbuild: 0.25.11 transitivePeerDependencies: - supports-color - esbuild@0.24.2: - optionalDependencies: - '@esbuild/aix-ppc64': 0.24.2 - '@esbuild/android-arm': 0.24.2 - '@esbuild/android-arm64': 0.24.2 - '@esbuild/android-x64': 0.24.2 - '@esbuild/darwin-arm64': 0.24.2 - '@esbuild/darwin-x64': 0.24.2 - '@esbuild/freebsd-arm64': 0.24.2 - '@esbuild/freebsd-x64': 0.24.2 - '@esbuild/linux-arm': 0.24.2 - '@esbuild/linux-arm64': 0.24.2 - '@esbuild/linux-ia32': 0.24.2 - '@esbuild/linux-loong64': 0.24.2 - '@esbuild/linux-mips64el': 0.24.2 - '@esbuild/linux-ppc64': 0.24.2 - '@esbuild/linux-riscv64': 0.24.2 - '@esbuild/linux-s390x': 0.24.2 - '@esbuild/linux-x64': 0.24.2 - '@esbuild/netbsd-arm64': 0.24.2 - '@esbuild/netbsd-x64': 0.24.2 - '@esbuild/openbsd-arm64': 0.24.2 - '@esbuild/openbsd-x64': 0.24.2 - '@esbuild/sunos-x64': 0.24.2 - '@esbuild/win32-arm64': 0.24.2 - '@esbuild/win32-ia32': 0.24.2 - '@esbuild/win32-x64': 0.24.2 - esbuild@0.25.11: optionalDependencies: '@esbuild/aix-ppc64': 0.25.11 @@ -7914,25 +7594,25 @@ snapshots: source-map: 0.6.1 optional: true - eslint-config-prettier@9.1.0(eslint@9.17.0): + eslint-config-prettier@9.1.0(eslint@9.17.0(jiti@1.21.7)): dependencies: - eslint: 9.17.0 + eslint: 9.17.0(jiti@1.21.7) - eslint-plugin-prettier@5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.17.0))(eslint@9.17.0)(prettier@3.4.2): + eslint-plugin-prettier@5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.17.0(jiti@1.21.7)))(eslint@9.17.0(jiti@1.21.7))(prettier@3.4.2): dependencies: - eslint: 9.17.0 + eslint: 9.17.0(jiti@1.21.7) prettier: 3.4.2 prettier-linter-helpers: 1.0.0 synckit: 0.9.2 optionalDependencies: '@types/eslint': 9.6.1 - eslint-config-prettier: 9.1.0(eslint@9.17.0) + eslint-config-prettier: 9.1.0(eslint@9.17.0(jiti@1.21.7)) - eslint-plugin-react-hooks@5.1.0(eslint@9.17.0): + eslint-plugin-react-hooks@5.1.0(eslint@9.17.0(jiti@1.21.7)): dependencies: - eslint: 9.17.0 + eslint: 9.17.0(jiti@1.21.7) - eslint-plugin-react@7.37.3(eslint@9.17.0): + eslint-plugin-react@7.37.3(eslint@9.17.0(jiti@1.21.7)): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -7940,7 +7620,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.17.0 + eslint: 9.17.0(jiti@1.21.7) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -7968,9 +7648,9 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.17.0: + eslint@9.17.0(jiti@1.21.7): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@1.21.7)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.19.1 '@eslint/core': 0.9.1 @@ -8004,6 +7684,8 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 + optionalDependencies: + jiti: 1.21.7 transitivePeerDependencies: - supports-color @@ -8055,8 +7737,6 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 - fast-json-parse@1.0.3: {} - fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -8079,11 +7759,11 @@ snapshots: dependencies: flat-cache: 4.0.1 - file-loader@6.2.0(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)): + file-loader@6.2.0(webpack@5.97.1(esbuild@0.25.11)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.97.1(@swc/core@1.10.4)(esbuild@0.24.2) + webpack: 5.97.1(esbuild@0.25.11) filename-reserved-regex@2.0.0: {} @@ -8117,12 +7797,6 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - flat-cache@3.2.0: - dependencies: - flatted: 3.3.2 - keyv: 4.5.4 - rimraf: 3.0.2 - flat-cache@4.0.1: dependencies: flatted: 3.3.2 @@ -8134,22 +7808,10 @@ snapshots: dependencies: is-callable: 1.2.7 - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)): + foreground-child@3.3.1: dependencies: - '@babel/code-frame': 7.26.2 - chalk: 4.1.2 - chokidar: 3.6.0 - cosmiconfig: 7.1.0 - deepmerge: 4.3.1 - fs-extra: 10.1.0 - memfs: 3.5.3 - minimatch: 3.1.2 - node-abort-controller: 3.1.1 - schema-utils: 3.3.0 - semver: 7.6.3 - tapable: 2.2.1 - typescript: 5.7.2 - webpack: 5.97.1(@swc/core@1.10.4)(esbuild@0.24.2) + cross-spawn: 7.0.6 + signal-exit: 4.1.0 form-data@4.0.4: dependencies: @@ -8160,22 +7822,12 @@ snapshots: mime-types: 2.1.35 optional: true - fs-extra@10.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - fs-extra@11.2.0: dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.1 - fs-monkey@1.0.6: {} - - fs.realpath@1.0.0: {} - fsevents@2.3.3: optional: true @@ -8242,14 +7894,14 @@ snapshots: glob-to-regexp@0.4.1: {} - glob@7.2.3: + glob@10.5.0: dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 globals@11.12.0: {} @@ -8297,8 +7949,6 @@ snapshots: dependencies: function-bind: 1.1.2 - he@1.2.0: {} - hoist-non-react-statics@3.3.2: dependencies: react-is: 16.13.1 @@ -8308,35 +7958,6 @@ snapshots: whatwg-encoding: 2.0.0 optional: true - html-entities@2.5.2: {} - - html-minifier-terser@6.1.0: - dependencies: - camel-case: 4.1.2 - clean-css: 5.3.3 - commander: 8.3.0 - he: 1.2.0 - param-case: 3.0.4 - relateurl: 0.2.7 - terser: 5.37.0 - - html-webpack-plugin@5.6.3(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)): - dependencies: - '@types/html-minifier-terser': 6.1.0 - html-minifier-terser: 6.1.0 - lodash: 4.17.21 - pretty-error: 4.0.0 - tapable: 2.2.1 - optionalDependencies: - webpack: 5.97.1(@swc/core@1.10.4)(esbuild@0.24.2) - - htmlparser2@6.1.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 4.3.1 - domutils: 2.8.0 - entities: 2.2.0 - http-proxy-agent@5.0.0: dependencies: '@tootallnate/once': 2.0.0 @@ -8361,12 +7982,15 @@ snapshots: icss-replace-symbols@1.1.0: {} - icss-utils@5.1.0(postcss@8.4.49): + icss-utils@5.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 ignore@5.3.2: {} + image-size@0.5.5: + optional: true + import-cwd@3.0.0: dependencies: import-from: 3.0.0 @@ -8384,11 +8008,6 @@ snapshots: indent-string@4.0.0: {} - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - inherits@2.0.4: {} internal-slot@1.1.0: @@ -8421,10 +8040,6 @@ snapshots: dependencies: has-bigints: 1.1.0 - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - is-boolean-object@1.2.1: dependencies: call-bound: 1.0.3 @@ -8455,6 +8070,8 @@ snapshots: dependencies: call-bound: 1.0.3 + is-fullwidth-code-point@3.0.0: {} + is-generator-function@1.1.0: dependencies: call-bound: 1.0.3 @@ -8523,6 +8140,9 @@ snapshots: call-bound: 1.0.3 get-intrinsic: 1.2.7 + is-what@3.14.1: + optional: true + is-wsl@2.2.0: dependencies: is-docker: 2.2.1 @@ -8540,12 +8160,21 @@ snapshots: has-symbols: 1.1.0 set-function-name: 2.0.2 + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jest-worker@27.5.1: dependencies: '@types/node': 20.19.21 merge-stream: 2.0.0 supports-color: 8.1.1 + jiti@1.21.7: + optional: true + js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -8625,6 +8254,21 @@ snapshots: dependencies: json-buffer: 3.0.1 + less@4.5.1: + dependencies: + copy-anything: 2.0.6 + parse-node-version: 1.0.1 + tslib: 2.8.1 + optionalDependencies: + errno: 0.1.8 + graceful-fs: 4.2.11 + image-size: 0.5.5 + make-dir: 2.1.0 + mime: 1.6.0 + needle: 3.3.1 + source-map: 0.6.1 + optional: true + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -8676,9 +8320,7 @@ snapshots: loupe@3.2.1: {} - lower-case@2.0.2: - dependencies: - tslib: 2.8.1 + lru-cache@10.4.3: {} lru-cache@5.1.1: dependencies: @@ -8688,10 +8330,20 @@ snapshots: lz-string@1.5.0: {} + magic-string@0.27.0: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + make-dir@2.1.0: + dependencies: + pify: 4.0.1 + semver: 5.7.2 + optional: true + make-dir@3.1.0: dependencies: semver: 6.3.1 @@ -8713,10 +8365,6 @@ snapshots: mdurl@2.0.0: {} - memfs@3.5.3: - dependencies: - fs-monkey: 1.0.6 - memoizerific@1.11.3: dependencies: map-or-similar: 1.5.0 @@ -8736,6 +8384,9 @@ snapshots: dependencies: mime-db: 1.52.0 + mime@1.6.0: + optional: true + min-indent@1.0.1: {} mini-svg-data-uri@1.4.4: {} @@ -8750,27 +8401,24 @@ snapshots: minimist@1.2.8: {} + minipass@7.1.2: {} + ms@2.1.3: {} nanoid@3.3.11: {} - nanoid@3.3.8: {} - natural-compare@1.4.0: {} - neo-async@2.6.2: {} - - no-case@3.0.4: + needle@3.3.1: dependencies: - lower-case: 2.0.2 - tslib: 2.8.1 + iconv-lite: 0.6.3 + sax: 1.4.3 + optional: true - node-abort-controller@3.1.1: {} + neo-async@2.6.2: {} node-releases@2.0.19: {} - normalize-path@3.0.0: {} - normalize-url@6.1.0: {} nth-check@2.1.1: @@ -8815,12 +8463,6 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 - objectorarray@1.0.5: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - open@8.4.2: dependencies: define-lazy-prop: 2.0.0 @@ -8871,12 +8513,9 @@ snapshots: p-try@2.2.0: {} - pako@1.0.11: {} + package-json-from-dist@1.0.1: {} - param-case@3.0.4: - dependencies: - dot-case: 3.0.4 - tslib: 2.8.1 + pako@1.0.11: {} parent-module@1.0.1: dependencies: @@ -8889,26 +8528,25 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-node-version@1.0.1: + optional: true + parse5@7.3.0: dependencies: entities: 6.0.1 optional: true - pascal-case@3.1.2: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - - path-browserify@1.0.1: {} - path-exists@4.0.0: {} - path-is-absolute@1.0.1: {} - path-key@3.1.1: {} path-parse@1.0.7: {} + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + path-type@4.0.0: {} pathe@2.0.3: {} @@ -8923,6 +8561,9 @@ snapshots: picomatch@4.0.3: {} + pify@4.0.1: + optional: true + pify@5.0.0: {} pkg-dir@4.2.0: @@ -8935,181 +8576,181 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-calc@8.2.4(postcss@8.4.49): + postcss-calc@8.2.4(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 - postcss-colormin@5.3.1(postcss@8.4.49): + postcss-colormin@5.3.1(postcss@8.5.6): dependencies: browserslist: 4.24.3 caniuse-api: 3.0.0 colord: 2.9.3 - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-convert-values@5.1.3(postcss@8.4.49): + postcss-convert-values@5.1.3(postcss@8.5.6): dependencies: browserslist: 4.24.3 - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-discard-comments@5.1.2(postcss@8.4.49): + postcss-discard-comments@5.1.2(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 - postcss-discard-duplicates@5.1.0(postcss@8.4.49): + postcss-discard-duplicates@5.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 - postcss-discard-empty@5.1.1(postcss@8.4.49): + postcss-discard-empty@5.1.1(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 - postcss-discard-overridden@5.1.0(postcss@8.4.49): + postcss-discard-overridden@5.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 - postcss-load-config@3.1.4(postcss@8.4.49): + postcss-load-config@3.1.4(postcss@8.5.6): dependencies: lilconfig: 2.1.0 yaml: 1.10.2 optionalDependencies: - postcss: 8.4.49 + postcss: 8.5.6 - postcss-merge-longhand@5.1.7(postcss@8.4.49): + postcss-merge-longhand@5.1.7(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - stylehacks: 5.1.1(postcss@8.4.49) + stylehacks: 5.1.1(postcss@8.5.6) - postcss-merge-rules@5.1.4(postcss@8.4.49): + postcss-merge-rules@5.1.4(postcss@8.5.6): dependencies: browserslist: 4.24.3 caniuse-api: 3.0.0 - cssnano-utils: 3.1.0(postcss@8.4.49) - postcss: 8.4.49 + cssnano-utils: 3.1.0(postcss@8.5.6) + postcss: 8.5.6 postcss-selector-parser: 6.1.2 - postcss-minify-font-values@5.1.0(postcss@8.4.49): + postcss-minify-font-values@5.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-minify-gradients@5.1.1(postcss@8.4.49): + postcss-minify-gradients@5.1.1(postcss@8.5.6): dependencies: colord: 2.9.3 - cssnano-utils: 3.1.0(postcss@8.4.49) - postcss: 8.4.49 + cssnano-utils: 3.1.0(postcss@8.5.6) + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-minify-params@5.1.4(postcss@8.4.49): + postcss-minify-params@5.1.4(postcss@8.5.6): dependencies: browserslist: 4.24.3 - cssnano-utils: 3.1.0(postcss@8.4.49) - postcss: 8.4.49 + cssnano-utils: 3.1.0(postcss@8.5.6) + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-minify-selectors@5.2.1(postcss@8.4.49): + postcss-minify-selectors@5.2.1(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-selector-parser: 6.1.2 - postcss-modules-extract-imports@3.1.0(postcss@8.4.49): + postcss-modules-extract-imports@3.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 - postcss-modules-local-by-default@4.2.0(postcss@8.4.49): + postcss-modules-local-by-default@4.2.0(postcss@8.5.6): dependencies: - icss-utils: 5.1.0(postcss@8.4.49) - postcss: 8.4.49 + icss-utils: 5.1.0(postcss@8.5.6) + postcss: 8.5.6 postcss-selector-parser: 7.0.0 postcss-value-parser: 4.2.0 - postcss-modules-scope@3.2.1(postcss@8.4.49): + postcss-modules-scope@3.2.1(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-selector-parser: 7.0.0 - postcss-modules-values@4.0.0(postcss@8.4.49): + postcss-modules-values@4.0.0(postcss@8.5.6): dependencies: - icss-utils: 5.1.0(postcss@8.4.49) - postcss: 8.4.49 + icss-utils: 5.1.0(postcss@8.5.6) + postcss: 8.5.6 - postcss-modules@4.3.1(postcss@8.4.49): + postcss-modules@4.3.1(postcss@8.5.6): dependencies: generic-names: 4.0.0 icss-replace-symbols: 1.1.0 lodash.camelcase: 4.3.0 - postcss: 8.4.49 - postcss-modules-extract-imports: 3.1.0(postcss@8.4.49) - postcss-modules-local-by-default: 4.2.0(postcss@8.4.49) - postcss-modules-scope: 3.2.1(postcss@8.4.49) - postcss-modules-values: 4.0.0(postcss@8.4.49) + postcss: 8.5.6 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.6) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.6) + postcss-modules-scope: 3.2.1(postcss@8.5.6) + postcss-modules-values: 4.0.0(postcss@8.5.6) string-hash: 1.1.3 - postcss-normalize-charset@5.1.0(postcss@8.4.49): + postcss-normalize-charset@5.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 - postcss-normalize-display-values@5.1.0(postcss@8.4.49): + postcss-normalize-display-values@5.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-normalize-positions@5.1.1(postcss@8.4.49): + postcss-normalize-positions@5.1.1(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-normalize-repeat-style@5.1.1(postcss@8.4.49): + postcss-normalize-repeat-style@5.1.1(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-normalize-string@5.1.0(postcss@8.4.49): + postcss-normalize-string@5.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-normalize-timing-functions@5.1.0(postcss@8.4.49): + postcss-normalize-timing-functions@5.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-normalize-unicode@5.1.1(postcss@8.4.49): + postcss-normalize-unicode@5.1.1(postcss@8.5.6): dependencies: browserslist: 4.24.3 - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-normalize-url@5.1.0(postcss@8.4.49): + postcss-normalize-url@5.1.0(postcss@8.5.6): dependencies: normalize-url: 6.1.0 - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-normalize-whitespace@5.1.1(postcss@8.4.49): + postcss-normalize-whitespace@5.1.1(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-ordered-values@5.1.3(postcss@8.4.49): + postcss-ordered-values@5.1.3(postcss@8.5.6): dependencies: - cssnano-utils: 3.1.0(postcss@8.4.49) - postcss: 8.4.49 + cssnano-utils: 3.1.0(postcss@8.5.6) + postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-reduce-initial@5.1.2(postcss@8.4.49): + postcss-reduce-initial@5.1.2(postcss@8.5.6): dependencies: browserslist: 4.24.3 caniuse-api: 3.0.0 - postcss: 8.4.49 + postcss: 8.5.6 - postcss-reduce-transforms@5.1.0(postcss@8.4.49): + postcss-reduce-transforms@5.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 postcss-selector-parser@6.1.2: @@ -9122,25 +8763,19 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-svgo@5.1.0(postcss@8.4.49): + postcss-svgo@5.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-value-parser: 4.2.0 svgo: 2.8.0 - postcss-unique-selectors@5.1.1(postcss@8.4.49): + postcss-unique-selectors@5.1.1(postcss@8.5.6): dependencies: - postcss: 8.4.49 + postcss: 8.5.6 postcss-selector-parser: 6.1.2 postcss-value-parser@4.2.0: {} - postcss@8.4.49: - dependencies: - nanoid: 3.3.8 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -9155,11 +8790,6 @@ snapshots: prettier@3.4.2: {} - pretty-error@4.0.0: - dependencies: - lodash: 4.17.21 - renderkid: 3.0.0 - pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 @@ -9176,6 +8806,9 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + prr@1.0.1: + optional: true + psl@1.15.0: dependencies: punycode: 2.3.1 @@ -9183,14 +8816,8 @@ snapshots: punycode.js@2.3.1: {} - punycode@1.4.1: {} - punycode@2.3.1: {} - qs@6.13.1: - dependencies: - side-channel: 1.1.0 - querystringify@2.2.0: optional: true @@ -9200,8 +8827,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - range-parser@1.2.1: {} - react-confetti@6.2.2(react@18.3.1): dependencies: react: 18.3.1 @@ -9226,6 +8851,21 @@ snapshots: transitivePeerDependencies: - supports-color + react-docgen@8.0.2: + dependencies: + '@babel/core': 7.28.5 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.28.0 + '@types/doctrine': 0.0.9 + '@types/resolve': 1.20.6 + doctrine: 3.0.0 + resolve: 1.22.10 + strip-indent: 4.0.0 + transitivePeerDependencies: + - supports-color + react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 @@ -9270,10 +8910,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 - recast@0.23.9: dependencies: ast-types: 0.16.1 @@ -9334,16 +8970,6 @@ snapshots: dependencies: jsesc: 3.0.2 - relateurl@0.2.7: {} - - renderkid@3.0.0: - dependencies: - css-select: 4.3.0 - dom-converter: 0.2.0 - htmlparser2: 6.1.0 - lodash: 4.17.21 - strip-ansi: 6.0.1 - require-from-string@2.0.2: {} requires-port@1.0.0: @@ -9367,10 +8993,6 @@ snapshots: reusify@1.0.4: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - rollup-plugin-dts@6.1.1(rollup@4.30.0)(typescript@5.7.2): dependencies: magic-string: 0.30.17 @@ -9383,17 +9005,17 @@ snapshots: dependencies: rollup: 4.30.0 - rollup-plugin-postcss@4.0.2(postcss@8.4.49): + rollup-plugin-postcss@4.0.2(postcss@8.5.6): dependencies: chalk: 4.1.2 concat-with-sourcemaps: 1.1.0 - cssnano: 5.1.15(postcss@8.4.49) + cssnano: 5.1.15(postcss@8.5.6) import-cwd: 3.0.0 p-queue: 6.6.2 pify: 5.0.0 - postcss: 8.4.49 - postcss-load-config: 3.1.4(postcss@8.4.49) - postcss-modules: 4.3.1(postcss@8.4.49) + postcss: 8.5.6 + postcss-load-config: 3.1.4(postcss@8.5.6) + postcss-modules: 4.3.1(postcss@8.5.6) promise.series: 0.2.0 resolve: 1.22.10 rollup-pluginutils: 2.8.2 @@ -9489,6 +9111,9 @@ snapshots: safer-buffer@2.1.2: optional: true + sax@1.4.3: + optional: true + saxes@6.0.0: dependencies: xmlchars: 2.2.0 @@ -9511,6 +9136,9 @@ snapshots: ajv-formats: 2.1.1(ajv@8.17.1) ajv-keywords: 5.1.0(ajv@8.17.1) + semver@5.7.2: + optional: true + semver@6.3.1: {} semver@7.6.3: {} @@ -9579,6 +9207,8 @@ snapshots: siginfo@2.0.0: {} + signal-exit@4.1.0: {} + slash@3.0.0: {} smob@1.5.0: {} @@ -9600,14 +9230,14 @@ snapshots: std-env@3.10.0: {} - storybook-dark-mode@4.0.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2)): + storybook-dark-mode@4.0.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.4.2)): dependencies: - '@storybook/components': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/core-events': 8.4.7(storybook@8.4.7(prettier@3.4.2)) + '@storybook/components': 8.4.7(storybook@8.6.14(prettier@3.4.2)) + '@storybook/core-events': 8.4.7(storybook@8.6.14(prettier@3.4.2)) '@storybook/global': 5.0.0 '@storybook/icons': 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/manager-api': 8.4.7(storybook@8.4.7(prettier@3.4.2)) - '@storybook/theming': 8.4.7(storybook@8.4.7(prettier@3.4.2)) + '@storybook/manager-api': 8.4.7(storybook@8.6.14(prettier@3.4.2)) + '@storybook/theming': 8.4.7(storybook@8.6.14(prettier@3.4.2)) fast-deep-equal: 3.1.3 memoizerific: 1.11.3 transitivePeerDependencies: @@ -9615,9 +9245,9 @@ snapshots: - react-dom - storybook - storybook@8.4.7(prettier@3.4.2): + storybook@8.6.14(prettier@3.4.2): dependencies: - '@storybook/core': 8.4.7(prettier@3.4.2) + '@storybook/core': 8.6.14(prettier@3.4.2)(storybook@8.6.14(prettier@3.4.2)) optionalDependencies: prettier: 3.4.2 transitivePeerDependencies: @@ -9627,6 +9257,18 @@ snapshots: string-hash@1.1.3: {} + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + string.prototype.matchall@4.0.12: dependencies: call-bind: 1.0.8 @@ -9701,14 +9343,10 @@ snapshots: style-inject@0.3.0: {} - style-loader@3.3.4(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)): - dependencies: - webpack: 5.97.1(@swc/core@1.10.4)(esbuild@0.24.2) - - stylehacks@5.1.1(postcss@8.4.49): + stylehacks@5.1.1(postcss@8.5.6): dependencies: browserslist: 4.24.3 - postcss: 8.4.49 + postcss: 8.5.6 postcss-selector-parser: 6.1.2 stylis@4.2.0: {} @@ -9733,12 +9371,6 @@ snapshots: picocolors: 1.1.1 stable: 0.1.8 - swc-loader@0.2.6(@swc/core@1.10.4)(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)): - dependencies: - '@swc/core': 1.10.4 - '@swc/counter': 0.1.3 - webpack: 5.97.1(@swc/core@1.10.4)(esbuild@0.24.2) - symbol-tree@3.2.4: optional: true @@ -9749,17 +9381,16 @@ snapshots: tapable@2.2.1: {} - terser-webpack-plugin@5.3.11(@swc/core@1.10.4)(esbuild@0.24.2)(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)): + terser-webpack-plugin@5.3.11(esbuild@0.25.11)(webpack@5.97.1(esbuild@0.25.11)): dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.0 serialize-javascript: 6.0.2 terser: 5.37.0 - webpack: 5.97.1(@swc/core@1.10.4)(esbuild@0.24.2) + webpack: 5.97.1(esbuild@0.25.11) optionalDependencies: - '@swc/core': 1.10.4 - esbuild: 0.24.2 + esbuild: 0.25.11 terser@5.37.0: dependencies: @@ -9876,12 +9507,12 @@ snapshots: typescript: 5.7.2 yaml: 2.8.0 - typescript-eslint@8.19.0(eslint@9.17.0)(typescript@5.7.2): + typescript-eslint@8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.17.0)(typescript@5.7.2))(eslint@9.17.0)(typescript@5.7.2) - '@typescript-eslint/parser': 8.19.0(eslint@9.17.0)(typescript@5.7.2) - '@typescript-eslint/utils': 8.19.0(eslint@9.17.0)(typescript@5.7.2) - eslint: 9.17.0 + '@typescript-eslint/eslint-plugin': 8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2) + '@typescript-eslint/parser': 8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2) + '@typescript-eslint/utils': 8.19.0(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2) + eslint: 9.17.0(jiti@1.21.7) typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -9936,11 +9567,6 @@ snapshots: requires-port: 1.0.0 optional: true - url@0.11.4: - dependencies: - punycode: 1.4.1 - qs: 6.13.1 - utif@3.1.0: dependencies: pako: 1.0.11 @@ -9955,17 +9581,15 @@ snapshots: is-typed-array: 1.1.15 which-typed-array: 1.1.18 - utila@0.4.0: {} - uuid@9.0.1: {} - vite-node@3.2.4(@types/node@20.19.21)(terser@5.37.0)(yaml@2.8.0): + vite-node@3.2.4(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.1.10(@types/node@20.19.21)(terser@5.37.0)(yaml@2.8.0) + vite: 7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0) transitivePeerDependencies: - '@types/node' - jiti @@ -9980,7 +9604,7 @@ snapshots: - tsx - yaml - vite@7.1.10(@types/node@20.19.21)(terser@5.37.0)(yaml@2.8.0): + vite@7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0): dependencies: esbuild: 0.25.11 fdir: 6.5.0(picomatch@4.0.3) @@ -9991,14 +9615,16 @@ snapshots: optionalDependencies: '@types/node': 20.19.21 fsevents: 2.3.3 + jiti: 1.21.7 + less: 4.5.1 terser: 5.37.0 yaml: 2.8.0 - vitest@3.2.4(@types/node@20.19.21)(jsdom@20.0.3)(terser@5.37.0)(yaml@2.8.0): + vitest@3.2.4(@types/node@20.19.21)(jiti@1.21.7)(jsdom@20.0.3)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.10(@types/node@20.19.21)(terser@5.37.0)(yaml@2.8.0)) + '@vitest/mocker': 3.2.4(vite@7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -10016,8 +9642,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.1.10(@types/node@20.19.21)(terser@5.37.0)(yaml@2.8.0) - vite-node: 3.2.4(@types/node@20.19.21)(terser@5.37.0)(yaml@2.8.0) + vite: 7.1.10(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0) + vite-node: 3.2.4(@types/node@20.19.21)(jiti@1.21.7)(less@4.5.1)(terser@5.37.0)(yaml@2.8.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.19.21 @@ -10049,38 +9675,22 @@ snapshots: webidl-conversions@7.0.0: optional: true - webpack-dev-middleware@6.1.3(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)): - dependencies: - colorette: 2.0.20 - memfs: 3.5.3 - mime-types: 2.1.35 - range-parser: 1.2.1 - schema-utils: 4.3.0 - optionalDependencies: - webpack: 5.97.1(@swc/core@1.10.4)(esbuild@0.24.2) - - webpack-hot-middleware@2.26.1: - dependencies: - ansi-html-community: 0.0.8 - html-entities: 2.5.2 - strip-ansi: 6.0.1 - webpack-sources@3.2.3: {} webpack-virtual-modules@0.6.2: {} - webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2): + webpack@5.97.1(esbuild@0.25.11): dependencies: '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.14.0 + acorn: 8.15.0 browserslist: 4.24.3 chrome-trace-event: 1.0.4 enhanced-resolve: 5.18.0 - es-module-lexer: 1.6.0 + es-module-lexer: 1.7.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -10091,7 +9701,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.11(@swc/core@1.10.4)(esbuild@0.24.2)(webpack@5.97.1(@swc/core@1.10.4)(esbuild@0.24.2)) + terser-webpack-plugin: 5.3.11(esbuild@0.25.11)(webpack@5.97.1(esbuild@0.25.11)) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -10164,12 +9774,19 @@ snapshots: word-wrap@1.2.5: {} - wrappy@1.0.2: {} + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 - ws@8.18.0: {} + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.1.0 - ws@8.18.3: - optional: true + ws@8.18.3: {} xml-name-validator@4.0.0: optional: true diff --git a/src/components/MUI/DataDisplay/Avatar.stories.tsx b/src/components/MUI/DataDisplay/Avatar.stories.tsx new file mode 100644 index 0000000..c9cc4ed --- /dev/null +++ b/src/components/MUI/DataDisplay/Avatar.stories.tsx @@ -0,0 +1,115 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Avatar } from "./Avatar"; +import FolderIcon from "@mui/icons-material/Folder"; +import PageviewIcon from "@mui/icons-material/Pageview"; +import AssignmentIcon from "@mui/icons-material/Assignment"; + +import { Stack } from "../Layout/Stack"; +import { AvatarGroup } from "./AvatarGroup"; + +const meta: Meta = { + title: "MUI/Data Display/Avatar", + component: Avatar, + tags: ["autodocs"], + parameters: { + controls: { expanded: true }, + layout: "padded", + }, + argTypes: { + variant: { + control: { type: "select" }, + options: ["circular", "rounded", "square"], + }, + children: { name: "initials", control: "text" }, + alt: { control: "text" }, + src: { control: "text" }, + imgProps: { control: false }, + sx: { control: "object" }, + }, + args: { + variant: "circular", + children: "AB", + alt: "User avatar", + src: "", + sx: { width: 56, height: 56, bgcolor: "primary" }, + }, +}; +export default meta; + +type Story = StoryObj; + +export const Basic: Story = { + render: (args) => {args.children}, +}; + +export const Variants: Story = { + render: (args) => ( + + + AB + + + CD + + + EF + + + ), +}; + +export const WithIcon: Story = { + render: (args) => ( + + + + + + + + + + + + ), +}; + +export const Grouped: Story = { + render: (args) => ( + + AB + CD + EF + IJ + KL + + ), +}; + +export const Sizes: Story = { + render: (args) => ( + + + SM + + + MD + + + LG + + + ), +}; diff --git a/src/components/MUI/DataDisplay/Avatar.tsx b/src/components/MUI/DataDisplay/Avatar.tsx new file mode 100644 index 0000000..4916615 --- /dev/null +++ b/src/components/MUI/DataDisplay/Avatar.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import MuiAvatar, { AvatarProps as MuiAvatarProps } from "@mui/material/Avatar"; + +export type AvatarProps = MuiAvatarProps; + +export const Avatar = React.forwardRef( + ({ children, ...rest }, ref) => ( + + {children} + + ), +); + +Avatar.displayName = "Avatar"; diff --git a/src/components/MUI/DataDisplay/AvatarGroup.tsx b/src/components/MUI/DataDisplay/AvatarGroup.tsx new file mode 100644 index 0000000..1e1361d --- /dev/null +++ b/src/components/MUI/DataDisplay/AvatarGroup.tsx @@ -0,0 +1,16 @@ +import * as React from "react"; +import MuiAvatarGroup, { + AvatarGroupProps as MuiAvatarGroupProps, +} from "@mui/material/AvatarGroup"; + +export type AvatarGroupProps = MuiAvatarGroupProps; + +export const AvatarGroup = React.forwardRef( + ({ children, ...rest }, ref) => ( + + {children} + + ), +); + +AvatarGroup.displayName = "AvatarGroup"; diff --git a/src/components/MUI/DataDisplay/Badge.stories.tsx b/src/components/MUI/DataDisplay/Badge.stories.tsx new file mode 100644 index 0000000..b9812a5 --- /dev/null +++ b/src/components/MUI/DataDisplay/Badge.stories.tsx @@ -0,0 +1,76 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Badge } from "./Badge"; +import MailIcon from "@mui/icons-material/Mail"; +import NotificationsIcon from "@mui/icons-material/Notifications"; + +const childMap = { + mail: , + notifications: , +} as const; + +const meta: Meta = { + title: "MUI/Data Display/Badge", + component: Badge, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + color: { + control: "select", + options: [ + "default", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + ], + }, + variant: { control: "select", options: ["standard", "dot"] }, + badgeContent: { control: "number" }, + max: { control: "number" }, + invisible: { control: "boolean" }, + showZero: { control: "boolean" }, + overlap: { control: "select", options: ["rectangular", "circular"] }, + anchorOrigin: { control: false }, + children: { + name: "child", + control: "select", + options: Object.keys(childMap), + mapping: childMap, + }, + }, + args: { + color: "primary", + variant: "standard", + badgeContent: 4, + max: 99, + invisible: false, + showZero: false, + overlap: "circular", + children: "mail", + }, +}; +export default meta; +type Story = StoryObj; + +export const Basic: Story = { render: (args) => }; + +export const Dot: Story = { + args: { variant: "dot", color: "secondary" }, + render: (args) => , +}; + +export const Colors: Story = { + args: { badgeContent: 7 }, + render: (args) => ( + <> + + + + + + + + ), +}; diff --git a/src/components/MUI/DataDisplay/Badge.tsx b/src/components/MUI/DataDisplay/Badge.tsx new file mode 100644 index 0000000..aa686af --- /dev/null +++ b/src/components/MUI/DataDisplay/Badge.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiBadge, { BadgeProps as MuiBadgeProps } from "@mui/material/Badge"; + +export type BadgeProps = MuiBadgeProps; + +export const Badge = React.forwardRef( + (props, ref) => , +); + +Badge.displayName = "Badge"; diff --git a/src/components/MUI/DataDisplay/Chip.stories.tsx b/src/components/MUI/DataDisplay/Chip.stories.tsx new file mode 100644 index 0000000..31060d4 --- /dev/null +++ b/src/components/MUI/DataDisplay/Chip.stories.tsx @@ -0,0 +1,140 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Chip } from "./Chip"; +import SaveIcon from "@mui/icons-material/Save"; +import SendIcon from "@mui/icons-material/Send"; +import DeleteIcon from "@mui/icons-material/Delete"; +import AddIcon from "@mui/icons-material/Add"; +import { Stack } from "../Layout/Stack"; + +const iconMap = { + none: undefined, + save: , + send: , + delete: , + add: , +} as const; + +const meta: Meta = { + title: "MUI/Data Display/Chip", + component: Chip, + tags: ["autodocs"], + parameters: { + controls: { expanded: true }, + layout: "padded", + }, + argTypes: { + label: { control: "text" }, + variant: { control: { type: "select" }, options: ["filled", "outlined"] }, + color: { + control: { type: "select" }, + options: [ + "default", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + ], + }, + size: { control: { type: "select" }, options: ["small", "medium"] }, + clickable: { control: "boolean" }, + disabled: { control: "boolean" }, + + icon: { + control: { type: "select" }, + options: Object.keys(iconMap), + mapping: iconMap, + }, + deleteIcon: { + control: { type: "select" }, + options: Object.keys(iconMap), + mapping: iconMap, + }, + + onDelete: { + control: { type: "select" }, + options: ["undefined", "deletable"], + mapping: { + undefined: undefined, + deletable: () => console.log("delete clicked"), + }, + }, + + sx: { control: "object" }, + }, + args: { + label: "Chip", + variant: "filled", + color: "primary", + size: "medium", + clickable: false, + disabled: false, + icon: undefined, + deleteIcon: undefined, + sx: { width: 80 }, + onDelete: undefined, + }, +}; +export default meta; + +type Story = StoryObj; + +export const Basic: Story = { + render: (args) => , +}; + +export const Variants: Story = { + render: (args) => ( + + + + + ), +}; + +export const Colors: Story = { + args: { variant: "filled" }, + render: (args) => ( + + + + + + + + + + ), +}; + +export const WithIcons: Story = { + args: { color: "primary" }, + render: (args) => ( + + + + + + + ), +}; + +export const Deletable: Story = { + render: (args) => ( + + console.log("delete clicked")} + /> + console.log("delete clicked")} + /> + + ), +}; diff --git a/src/components/MUI/DataDisplay/Chip.tsx b/src/components/MUI/DataDisplay/Chip.tsx new file mode 100644 index 0000000..c62561c --- /dev/null +++ b/src/components/MUI/DataDisplay/Chip.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiChip, { ChipProps as MuiChipProps } from "@mui/material/Chip"; + +export type ChipProps = MuiChipProps; + +export const Chip = React.forwardRef( + (props, ref) => , +); + +Chip.displayName = "Chip"; diff --git a/src/components/MUI/DataDisplay/Divider.stories.tsx b/src/components/MUI/DataDisplay/Divider.stories.tsx new file mode 100644 index 0000000..f1d56b8 --- /dev/null +++ b/src/components/MUI/DataDisplay/Divider.stories.tsx @@ -0,0 +1,51 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Divider } from "./Divider"; + +const meta: Meta = { + title: "MUI/Data Display/Divider", + component: Divider, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + variant: { control: "select", options: ["fullWidth", "inset", "middle"] }, + orientation: { control: "select", options: ["horizontal", "vertical"] }, + textAlign: { control: "select", options: ["center", "left", "right"] }, + flexItem: { control: "boolean" }, + children: { name: "label", control: "text" }, + }, + args: { + variant: "fullWidth", + orientation: "horizontal", + textAlign: "center", + flexItem: false, + children: "", + }, +}; +export default meta; +type Story = StoryObj; + +export const Basic: Story = { render: (args) => }; + +export const WithLabel: Story = { + args: { children: "Section" }, + render: (args) => , +}; + +export const Vertical: Story = { + args: { orientation: "vertical", flexItem: true }, + render: (args) => ( +
+ +
+ ), +}; + +export const Variants: Story = { + render: (args) => ( +
+ + + +
+ ), +}; diff --git a/src/components/MUI/DataDisplay/Divider.tsx b/src/components/MUI/DataDisplay/Divider.tsx new file mode 100644 index 0000000..9b2a1a4 --- /dev/null +++ b/src/components/MUI/DataDisplay/Divider.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiDivider, { + DividerProps as MuiDividerProps, +} from "@mui/material/Divider"; + +export type DividerProps = MuiDividerProps; + +export const Divider = React.forwardRef( + (props, ref) => , +); + +Divider.displayName = "Divider"; diff --git a/src/components/MUI/DataDisplay/Icon.stories.tsx b/src/components/MUI/DataDisplay/Icon.stories.tsx new file mode 100644 index 0000000..ca488b7 --- /dev/null +++ b/src/components/MUI/DataDisplay/Icon.stories.tsx @@ -0,0 +1,74 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Icon } from "./Icon"; +import HomeIcon from "@mui/icons-material/Home"; +import FavoriteIcon from "@mui/icons-material/Favorite"; +import SearchIcon from "@mui/icons-material/Search"; +import SettingsIcon from "@mui/icons-material/Settings"; + +const iconChildrenMap = { + home: , + favorite: , + search: , + settings: , +} as const; + +const meta: Meta = { + title: "MUI/Data Display/Icon", + component: Icon, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + color: { + control: "select", + options: [ + "inherit", + "primary", + "secondary", + "action", + "disabled", + "error", + "info", + "success", + "warning", + "red", + "blue", + "green", + ], + }, + fontSize: { + control: "select", + options: ["inherit", "small", "medium", "large"], + }, + children: { + name: "icon", + control: "select", + options: Object.keys(iconChildrenMap), + mapping: iconChildrenMap, + }, + baseClassName: { control: false }, + }, + args: { + color: "primary", + fontSize: "medium", + children: "home", + }, +}; +export default meta; +type Story = StoryObj; + +export const Basic: Story = { render: (args) => }; + +export const Colors: Story = { + render: (args) => ( + <> + + + + + + + + + + ), +}; diff --git a/src/components/MUI/DataDisplay/Icon.tsx b/src/components/MUI/DataDisplay/Icon.tsx new file mode 100644 index 0000000..8b76d08 --- /dev/null +++ b/src/components/MUI/DataDisplay/Icon.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiIcon, { IconProps as MuiIconProps } from "@mui/material/Icon"; + +export type IconProps = MuiIconProps; + +export const Icon = React.forwardRef( + (props, ref) => , +); + +Icon.displayName = "Icon"; diff --git a/src/components/MUI/DataDisplay/IconButton.stories.tsx b/src/components/MUI/DataDisplay/IconButton.stories.tsx new file mode 100644 index 0000000..a611d3f --- /dev/null +++ b/src/components/MUI/DataDisplay/IconButton.stories.tsx @@ -0,0 +1,178 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { IconButton } from "./IconButton"; +import { SvgIcon } from "./SvgIcon"; +import { Stack } from "../Layout/Stack"; + +const ArrowDownPath = ( + + + +); + +const meta: Meta = { + title: "MUI/Data Display/IconButton", + component: IconButton, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + color: { + control: "select", + options: [ + "inherit", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + ], + description: + "Applies theme color to the IconButton (icon inherits via context).", + }, + size: { + control: "select", + options: ["small", "medium", "large"], + description: "IconButton size. Icon inside can also set fontSize.", + }, + edge: { + control: "select", + options: [false, "start", "end"], + description: "Move the button to the edge of a container for alignment.", + }, + disabled: { control: "boolean" }, + "aria-label": { + control: "text", + name: "aria-label", + description: "Accessible label for screen readers.", + }, + sx: { control: "object", description: "MUI `sx` prop for ad‑hoc styling." }, + + children: { control: false }, + }, + args: { + color: "inherit", + size: "medium", + edge: false, + disabled: false, + "aria-label": "arrow down", + sx: undefined, + }, +}; +export default meta; + +type Story = StoryObj; + +export const Basic: Story = { + render: (args) => {ArrowDownPath}, +}; + +export const Sizes: Story = { + render: (args) => ( + + + {ArrowDownPath} + + + {ArrowDownPath} + + + {ArrowDownPath} + + + ), +}; + +export const Colors: Story = { + render: (args) => ( + + + {ArrowDownPath} + + + {ArrowDownPath} + + + {ArrowDownPath} + + + {ArrowDownPath} + + + {ArrowDownPath} + + + {ArrowDownPath} + + + {ArrowDownPath} + + + ), +}; + +export const Disabled: Story = { + args: { disabled: true }, + render: (args) => {ArrowDownPath}, +}; + +export const EdgeAlignment: Story = { + render: (args) => ( + + + {ArrowDownPath} + +
+ + {ArrowDownPath} + + + ), +}; + +export const WithCustomSvgIcon: Story = { + render: (args) => ( + + + + + + + + + + + + + +
+ + + + + +
+
+ ), +}; + +export const StyledViaSx: Story = { + args: { + sx: { "& svg": { fontSize: 40 } }, + }, + render: (args) => ( + + + {ArrowDownPath} + + + {ArrowDownPath} + + + ), +}; +``; diff --git a/src/components/MUI/DataDisplay/IconButton.tsx b/src/components/MUI/DataDisplay/IconButton.tsx new file mode 100644 index 0000000..52db5ef --- /dev/null +++ b/src/components/MUI/DataDisplay/IconButton.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiIconButton, { + IconButtonProps as MuiIconButtonProps, +} from "@mui/material/IconButton"; + +export type IconButtonProps = MuiIconButtonProps; + +export const IconButton = React.forwardRef( + (props, ref) => , +); + +IconButton.displayName = "IconButton"; diff --git a/src/components/MUI/DataDisplay/List.stories.tsx b/src/components/MUI/DataDisplay/List.stories.tsx new file mode 100644 index 0000000..786e635 --- /dev/null +++ b/src/components/MUI/DataDisplay/List.stories.tsx @@ -0,0 +1,49 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import InboxIcon from "@mui/icons-material/MoveToInbox"; +import MailIcon from "@mui/icons-material/Mail"; +import { List } from "./List"; +import { ListItem } from "./ListItem"; +import { ListItemIcon } from "./ListItemIcon"; +import { ListItemText } from "./ListItemText"; +import { Divider } from "./Divider"; + +const meta: Meta = { + title: "MUI/Data Display/List/List", + component: List, + parameters: { layout: "padded" }, + argTypes: { + dense: { control: "boolean" }, + disablePadding: { control: "boolean" }, + subheader: { control: "text" }, + }, + args: { + dense: false, + disablePadding: false, + subheader: "", + }, +}; +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + render: (args) => ( + + + + + + + + + + + + + + + + + + + ), +}; diff --git a/src/components/MUI/DataDisplay/List.tsx b/src/components/MUI/DataDisplay/List.tsx new file mode 100644 index 0000000..c80ba89 --- /dev/null +++ b/src/components/MUI/DataDisplay/List.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiList, { ListProps as MuiListProps } from "@mui/material/List"; + +export type ListProps = MuiListProps; + +export const List = React.forwardRef( + (props, ref) => , +); + +List.displayName = "List"; diff --git a/src/components/MUI/DataDisplay/ListItem.stories.tsx b/src/components/MUI/DataDisplay/ListItem.stories.tsx new file mode 100644 index 0000000..bd23923 --- /dev/null +++ b/src/components/MUI/DataDisplay/ListItem.stories.tsx @@ -0,0 +1,75 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { ListItem } from "./ListItem"; +import { ListItemText } from "./ListItemText"; +import { List } from "./List"; +import { ListItemIcon } from "./ListItemIcon"; +import diamond from "../../../public/images/diamond.jpg"; +import soleil from "../../../public/images/soleil.jpg"; + +import InboxIcon from "@mui/icons-material/MoveToInbox"; +import MailIcon from "@mui/icons-material/Mail"; +import { ListItemAvatar } from "./ListItemAvatar"; +import { Avatar } from "./Avatar"; + +const meta: Meta = { + title: "MUI/Data Display/List/ListItem", + component: ListItem, + parameters: { layout: "padded" }, + argTypes: { + dense: { control: "boolean" }, + disableGutters: { control: "boolean" }, + disablePadding: { control: "boolean" }, + divider: { control: "boolean" }, + }, + args: { + dense: false, + disableGutters: false, + disablePadding: false, + divider: true, + }, +}; +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + render: (args) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ), +}; diff --git a/src/components/MUI/DataDisplay/ListItem.tsx b/src/components/MUI/DataDisplay/ListItem.tsx new file mode 100644 index 0000000..f3dda62 --- /dev/null +++ b/src/components/MUI/DataDisplay/ListItem.tsx @@ -0,0 +1,13 @@ +import * as React from "react"; +import MuiListItem, { + ListItemProps as MuiListItemProps, +} from "@mui/material/ListItem"; + +export type ListItemProps = MuiListItemProps; + +export const ListItem = React.forwardRef( + function ListItem(props, ref) { + return ; + }, +); +ListItem.displayName = "ListItem"; diff --git a/src/components/MUI/DataDisplay/ListItemAvatar.tsx b/src/components/MUI/DataDisplay/ListItemAvatar.tsx new file mode 100644 index 0000000..c84c43d --- /dev/null +++ b/src/components/MUI/DataDisplay/ListItemAvatar.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +import MuiListItemAvatar, { + ListItemAvatarProps as MuiListItemAvatarProps, +} from "@mui/material/ListItemAvatar"; + +export type ListItemAvatarProps = MuiListItemAvatarProps; + +export const ListItemAvatar = React.forwardRef< + HTMLDivElement, + ListItemAvatarProps +>(function ListItemAvatar(props, ref) { + return ; +}); + +ListItemAvatar.displayName = "ListItemAvatar"; diff --git a/src/components/MUI/DataDisplay/ListItemButton.stories.tsx b/src/components/MUI/DataDisplay/ListItemButton.stories.tsx new file mode 100644 index 0000000..fcb4755 --- /dev/null +++ b/src/components/MUI/DataDisplay/ListItemButton.stories.tsx @@ -0,0 +1,38 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { ListItemButton } from "./ListItemButton"; +import { List } from "./List"; +import { ListItem } from "./ListItem"; +import { ListItemText } from "./ListItemText"; + +const meta: Meta = { + title: "MUI/Data Display/List/ListItemButton", + component: ListItemButton, + parameters: { layout: "padded" }, + argTypes: { + selected: { control: "boolean" }, + disabled: { control: "boolean" }, + }, + args: { + selected: false, + disabled: false, + }, +}; +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + render: (args) => ( + + + + + + + + + + + + + ), +}; diff --git a/src/components/MUI/DataDisplay/ListItemButton.tsx b/src/components/MUI/DataDisplay/ListItemButton.tsx new file mode 100644 index 0000000..52893e9 --- /dev/null +++ b/src/components/MUI/DataDisplay/ListItemButton.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +import MuiListItemButton, { + ListItemButtonProps as MuiListItemButtonProps, +} from "@mui/material/ListItemButton"; + +export type ListItemButtonProps = MuiListItemButtonProps; + +export const ListItemButton = React.forwardRef< + HTMLDivElement, + ListItemButtonProps +>(function ListItemButton(props, ref) { + return ; +}); + +ListItemButton.displayName = "ListItemButton"; diff --git a/src/components/MUI/DataDisplay/ListItemIcon.stories.tsx b/src/components/MUI/DataDisplay/ListItemIcon.stories.tsx new file mode 100644 index 0000000..dd90220 --- /dev/null +++ b/src/components/MUI/DataDisplay/ListItemIcon.stories.tsx @@ -0,0 +1,34 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { ListItemIcon } from "./ListItemIcon"; +import { ListItem } from "./ListItem"; +import { List } from "./List"; +import { ListItemText } from "./ListItemText"; +import InboxIcon from "@mui/icons-material/MoveToInbox"; +import MailIcon from "@mui/icons-material/Mail"; + +const meta: Meta = { + title: "MUI/Data Display/List/ListItemIcon", + component: ListItemIcon, + parameters: { layout: "padded" }, +}; +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + render: () => ( + + + + + + + + + + + + + + + ), +}; diff --git a/src/components/MUI/DataDisplay/ListItemIcon.tsx b/src/components/MUI/DataDisplay/ListItemIcon.tsx new file mode 100644 index 0000000..2c4f2a7 --- /dev/null +++ b/src/components/MUI/DataDisplay/ListItemIcon.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import MuiListItemIcon, { + ListItemIconProps as MuiListItemIconProps, +} from "@mui/material/ListItemIcon"; + +export type ListItemIconProps = MuiListItemIconProps; + +export const ListItemIcon = React.forwardRef( + function ListItemIcon(props, ref) { + return ; + }, +); + +ListItemIcon.displayName = "ListItemIcon"; diff --git a/src/components/MUI/DataDisplay/ListItemText.stories.tsx b/src/components/MUI/DataDisplay/ListItemText.stories.tsx new file mode 100644 index 0000000..7f43637 --- /dev/null +++ b/src/components/MUI/DataDisplay/ListItemText.stories.tsx @@ -0,0 +1,35 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { ListItemText } from "./ListItemText"; +import { ListItem } from "./ListItem"; +import { List } from "./List"; + +const meta: Meta = { + title: "MUI/Data Display/List/ListItemText", + component: ListItemText, + parameters: { layout: "padded" }, + argTypes: { + primary: { control: "text" }, + secondary: { control: "text" }, + inset: { control: "boolean" }, + }, + args: { + primary: "Primary text", + secondary: "Secondary text", + inset: false, + }, +}; +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + render: (args) => ( + + + + + + + + + ), +}; diff --git a/src/components/MUI/DataDisplay/ListItemText.tsx b/src/components/MUI/DataDisplay/ListItemText.tsx new file mode 100644 index 0000000..6157671 --- /dev/null +++ b/src/components/MUI/DataDisplay/ListItemText.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +import MuiListItemText, { + ListItemTextProps as MuiListItemTextProps, +} from "@mui/material/ListItemText"; + +export type ListItemTextProps = MuiListItemTextProps; + +export const ListItemText = React.forwardRef< + HTMLSpanElement, + ListItemTextProps +>(function ListItemText(props, ref) { + return ; +}); + +ListItemText.displayName = "ListItemText"; diff --git a/src/components/MUI/DataDisplay/ListSubheader.stories.tsx b/src/components/MUI/DataDisplay/ListSubheader.stories.tsx new file mode 100644 index 0000000..effd66f --- /dev/null +++ b/src/components/MUI/DataDisplay/ListSubheader.stories.tsx @@ -0,0 +1,44 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { ListSubheader } from "./ListSubheader"; +import { List } from "./List"; +import { ListItem } from "./ListItem"; +import { ListItemText } from "./ListItemText"; + +const meta: Meta = { + title: "MUI/Data Display/List/ListSubheader", + component: ListSubheader, + parameters: { layout: "padded" }, + argTypes: { + color: { + control: { type: "radio" }, + options: ["default", "inherit", "primary"], + }, + disableGutters: { control: "boolean" }, + disableSticky: { control: "boolean" }, + inset: { control: "boolean" }, + }, + args: { + color: "default", + disableGutters: false, + disableSticky: false, + inset: false, + }, +}; +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + render: (args) => ( + Folders}> + + + + + + + + + + + ), +}; diff --git a/src/components/MUI/DataDisplay/ListSubheader.tsx b/src/components/MUI/DataDisplay/ListSubheader.tsx new file mode 100644 index 0000000..18213bc --- /dev/null +++ b/src/components/MUI/DataDisplay/ListSubheader.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import MuiListSubheader, { + ListSubheaderProps as MuiListSubheaderProps, +} from "@mui/material/ListSubheader"; + +export type ListSubheaderProps = MuiListSubheaderProps; + +export const ListSubheader = React.forwardRef< + HTMLLIElement, + ListSubheaderProps +>(function ListSubheader(props, ref) { + return ; +}); +ListSubheader.displayName = "ListSubheader"; diff --git a/src/components/MUI/DataDisplay/SvgIcon.stories.tsx b/src/components/MUI/DataDisplay/SvgIcon.stories.tsx new file mode 100644 index 0000000..c3931df --- /dev/null +++ b/src/components/MUI/DataDisplay/SvgIcon.stories.tsx @@ -0,0 +1,163 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { SvgIcon } from "./SvgIcon"; +import { IconButton } from "./IconButton"; +import { Stack } from "../Layout/Stack"; + +const meta: Meta = { + title: "MUI/Data Display/SvgIcon", + component: SvgIcon, + tags: ["autodocs"], + parameters: { + controls: { expanded: true }, + layout: "padded", + }, + argTypes: { + color: { + control: "select", + options: [ + "inherit", + "primary", + "secondary", + "action", + "disabled", + "error", + "info", + "success", + "warning", + ], + description: "Applies theme color", + }, + fontSize: { + control: "select", + options: ["inherit", "small", "medium", "large"], + description: "Applies theme size preset", + }, + viewBox: { + control: "text", + description: "ViewBox for the SVG; default is '0 0 24 24'", + }, + inheritViewBox: { + control: "boolean", + description: + "If true, use the viewBox of the child SVG element rather than the default", + }, + titleAccess: { + control: "text", + description: + "Adds a element for accessibility (sets role='img' if provided)", + }, + sx: { + control: "object", + description: "MUI `sx` prop", + }, + }, + args: { + color: "primary", + fontSize: "medium", + viewBox: "0 0 24 24", + inheritViewBox: false, + titleAccess: "Down arrow", + sx: undefined, + }, +}; +export default meta; + +type Story = StoryObj<typeof meta>; + +const d = "M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"; + +export const Basic: Story = { + render: (args) => <SvgIcon {...args}>{<path d={d} />}</SvgIcon>, +}; + +export const Sizes: Story = { + render: (args) => ( + <Stack direction="row" spacing={2} alignItems="center"> + <SvgIcon {...args} fontSize="small"> + {<path d={d} />} + </SvgIcon> + <SvgIcon {...args} fontSize="medium"> + {<path d={d} />} + </SvgIcon> + <SvgIcon {...args} fontSize="large"> + {<path d={d} />} + </SvgIcon> + <div style={{ fontSize: 32, display: "flex", alignItems: "center" }}> + <SvgIcon {...args} fontSize="inherit"> + {<path d={d} />} + </SvgIcon> + </div> + </Stack> + ), +}; + +export const Colors: Story = { + render: (args) => ( + <Stack direction="row" spacing={2} alignItems="center"> + <SvgIcon {...args} color="inherit"> + {<path d={d} />} + </SvgIcon> + <SvgIcon {...args} color="primary"> + {<path d={d} />} + </SvgIcon> + <SvgIcon {...args} color="secondary"> + {<path d={d} />} + </SvgIcon> + <SvgIcon {...args} color="error"> + {<path d={d} />} + </SvgIcon> + <SvgIcon {...args} color="warning"> + {<path d={d} />} + </SvgIcon> + <SvgIcon {...args} color="info"> + {<path d={d} />} + </SvgIcon> + <SvgIcon {...args} color="success"> + {<path d={d} />} + </SvgIcon> + <SvgIcon {...args} color="action"> + {<path d={d} />} + </SvgIcon> + <SvgIcon {...args} color="disabled"> + {<path d={d} />} + </SvgIcon> + </Stack> + ), +}; + +export const CustomViewBoxAndInherit: Story = { + args: { + viewBox: "0 0 48 48", + inheritViewBox: false, + titleAccess: "Custom viewBox icon", + pathD: "M24 4L12 20h8v16h8V20h8L24 4z", + }, + render: (args) => ( + <Stack direction="row" spacing={4} alignItems="center"> + <SvgIcon {...args}>{<path d={d} />}</SvgIcon> + <SvgIcon {...args} inheritViewBox> + <svg viewBox="0 0 32 32"> + <path d="M16 2l-6 10h4v8h4v-8h4L16 2z" /> + </svg> + </SvgIcon> + </Stack> + ), +}; + +export const InIconButton: Story = { + args: { color: "primary" }, + render: (args) => ( + <Stack direction="row" spacing={2}> + <IconButton color="primary" aria-label="download"> + <SvgIcon viewBox="0 0 24 24"> + <path d="M5 20h14v-2H5v2zm7-18v12l4-4 1.41 1.41L12 18l-5.41-5.59L8 10l4 4V2h2z" /> + </SvgIcon> + </IconButton> + <IconButton color="secondary" aria-label="arrow down"> + <SvgIcon> + <path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z" /> + </SvgIcon> + </IconButton> + </Stack> + ), +}; diff --git a/src/components/MUI/DataDisplay/SvgIcon.tsx b/src/components/MUI/DataDisplay/SvgIcon.tsx new file mode 100644 index 0000000..84dc6ec --- /dev/null +++ b/src/components/MUI/DataDisplay/SvgIcon.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiSvgIcon, { + SvgIconProps as MuiSvgIconProps, +} from "@mui/material/SvgIcon"; + +export type SvgIconProps = MuiSvgIconProps; + +export const SvgIcon = React.forwardRef<SVGSVGElement, SvgIconProps>( + (props, ref) => <MuiSvgIcon ref={ref} {...props} />, +); + +SvgIcon.displayName = "SvgIcon"; diff --git a/src/components/MUI/DataDisplay/Table.stories.tsx b/src/components/MUI/DataDisplay/Table.stories.tsx new file mode 100644 index 0000000..50e78ac --- /dev/null +++ b/src/components/MUI/DataDisplay/Table.stories.tsx @@ -0,0 +1,82 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Table } from "./Table"; +import { TableContainer } from "./TableContainer"; +import { TableRow } from "./TableRow"; +import { TableCell } from "./TableCell"; +import { TableHead } from "./TableHead"; +import { TableBody } from "./TableBody"; +import { Paper } from "../Surfaces/Paper"; + +type Dessert = { + name: string; + calories: number; + fat: number; + carbs: number; + protein: number; +}; +const rows: Dessert[] = [ + { name: "Frozen yoghurt", calories: 159, fat: 6, carbs: 24, protein: 4 }, + { + name: "Ice cream sandwich", + calories: 237, + fat: 9, + carbs: 37, + protein: 4.3, + }, + { name: "Eclair", calories: 262, fat: 16, carbs: 24, protein: 6 }, +]; + +const meta: Meta<typeof Table> = { + title: "MUI/Data Display/Table/Table", + component: Table, + parameters: { layout: "padded" }, + argTypes: { + size: { control: { type: "radio" }, options: ["small", "medium"] }, + padding: { + control: { type: "radio" }, + options: ["normal", "none", "checkbox"], + }, + stickyHeader: { control: "boolean" }, + }, + args: { + size: "medium", + padding: "normal", + stickyHeader: false, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Playground: Story = { + render: (args) => ( + <TableContainer + component={Paper} + sx={{ maxHeight: args.stickyHeader ? 320 : "auto" }} + > + <Table {...args} aria-label="desserts"> + <TableHead> + <TableRow> + <TableCell>Dessert</TableCell> + <TableCell align="right">Calories</TableCell> + <TableCell align="right">Fat (g)</TableCell> + <TableCell align="right">Carbs (g)</TableCell> + <TableCell align="right">Protein (g)</TableCell> + </TableRow> + </TableHead> + <TableBody> + {rows.map((row) => ( + <TableRow key={row.name}> + <TableCell component="th" scope="row"> + {row.name} + </TableCell> + <TableCell align="right">{row.calories}</TableCell> + <TableCell align="right">{row.fat}</TableCell> + <TableCell align="right">{row.carbs}</TableCell> + <TableCell align="right">{row.protein}</TableCell> + </TableRow> + ))} + </TableBody> + </Table> + </TableContainer> + ), +}; diff --git a/src/components/MUI/DataDisplay/Table.tsx b/src/components/MUI/DataDisplay/Table.tsx new file mode 100644 index 0000000..a0a96c2 --- /dev/null +++ b/src/components/MUI/DataDisplay/Table.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiTable, { TableProps as MuiTableProps } from "@mui/material/Table"; + +export type TableProps = MuiTableProps; + +export const Table = React.forwardRef<HTMLTableElement, TableProps>( + (props, ref) => <MuiTable ref={ref} {...props} />, +); + +Table.displayName = "Table"; diff --git a/src/components/MUI/DataDisplay/TableBody.stories.tsx b/src/components/MUI/DataDisplay/TableBody.stories.tsx new file mode 100644 index 0000000..8e56290 --- /dev/null +++ b/src/components/MUI/DataDisplay/TableBody.stories.tsx @@ -0,0 +1,41 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { TableContainer } from "./TableContainer"; +import { Table } from "./Table"; +import { TableHead } from "./TableHead"; +import { TableCell } from "./TableCell"; +import { TableRow } from "./TableRow"; +import { TableBody } from "./TableBody"; +import { Paper } from "../Surfaces/Paper"; + +const meta: Meta<typeof TableBody> = { + title: "MUI/Data Display/Table/TableBody", + component: TableBody, + parameters: { layout: "padded" }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Playground: Story = { + render: () => ( + <TableContainer component={Paper}> + <Table aria-label="body demo"> + <TableHead> + <TableRow> + <TableCell>Item</TableCell> + <TableCell align="right">Qty</TableCell> + </TableRow> + </TableHead> + <TableBody> + <TableRow> + <TableCell>Apples</TableCell> + <TableCell align="right">5</TableCell> + </TableRow> + <TableRow> + <TableCell>Oranges</TableCell> + <TableCell align="right">3</TableCell> + </TableRow> + </TableBody> + </Table> + </TableContainer> + ), +}; diff --git a/src/components/MUI/DataDisplay/TableBody.tsx b/src/components/MUI/DataDisplay/TableBody.tsx new file mode 100644 index 0000000..02fefb9 --- /dev/null +++ b/src/components/MUI/DataDisplay/TableBody.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +import MuiTableBody, { + TableBodyProps as MuiTableBodyProps, +} from "@mui/material/TableBody"; + +export type TableBodyProps = MuiTableBodyProps; + +export const TableBody = React.forwardRef< + HTMLTableSectionElement, + TableBodyProps +>(function TableBody(props, ref) { + return <MuiTableBody ref={ref} {...props} />; +}); + +TableBody.displayName = "TableBody"; diff --git a/src/components/MUI/DataDisplay/TableCell.stories.tsx b/src/components/MUI/DataDisplay/TableCell.stories.tsx new file mode 100644 index 0000000..77b3e24 --- /dev/null +++ b/src/components/MUI/DataDisplay/TableCell.stories.tsx @@ -0,0 +1,50 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { TableContainer } from "./TableContainer"; +import { Table } from "./Table"; +import { TableHead } from "./TableHead"; +import { TableCell } from "./TableCell"; +import { TableRow } from "./TableRow"; +import { TableBody } from "./TableBody"; +import { Paper } from "../Surfaces/Paper"; + +const meta: Meta<typeof TableCell> = { + title: "MUI/Data Display/Table/TableCell", + component: TableCell, + parameters: { layout: "padded" }, + argTypes: { + align: { + control: { type: "radio" }, + options: ["inherit", "left", "center", "right", "justify"], + }, + padding: { control: { type: "radio" }, options: ["normal", "none"] }, + scope: { control: "text" }, + }, + args: { + align: "left", + padding: "normal", + scope: "row", + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Playground: Story = { + render: (args) => ( + <TableContainer component={Paper}> + <Table aria-label="cell demo"> + <TableHead> + <TableRow> + <TableCell>Item</TableCell> + <TableCell align="right">Qty</TableCell> + </TableRow> + </TableHead> + <TableBody> + <TableRow> + <TableCell {...args}>Apples</TableCell> + <TableCell align="right">5</TableCell> + </TableRow> + </TableBody> + </Table> + </TableContainer> + ), +}; diff --git a/src/components/MUI/DataDisplay/TableCell.tsx b/src/components/MUI/DataDisplay/TableCell.tsx new file mode 100644 index 0000000..a412200 --- /dev/null +++ b/src/components/MUI/DataDisplay/TableCell.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import MuiTableCell, { + TableCellProps as MuiTableCellProps, +} from "@mui/material/TableCell"; + +export type TableCellProps = MuiTableCellProps; + +export const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>( + function TableCell(props, ref) { + return <MuiTableCell ref={ref} {...props} />; + }, +); + +TableCell.displayName = "TableCell"; diff --git a/src/components/MUI/DataDisplay/TableContainer.stories.tsx b/src/components/MUI/DataDisplay/TableContainer.stories.tsx new file mode 100644 index 0000000..8ea451a --- /dev/null +++ b/src/components/MUI/DataDisplay/TableContainer.stories.tsx @@ -0,0 +1,45 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { TableContainer } from "./TableContainer"; +import { Table } from "./Table"; +import { TableHead } from "./TableHead"; +import { TableCell } from "./TableCell"; +import { TableRow } from "./TableRow"; +import { TableBody } from "./TableBody"; +import { Paper } from "../Surfaces/Paper"; + +const meta: Meta<typeof TableContainer> = { + title: "MUI/Data Display/Table/TableContainer", + component: TableContainer, + parameters: { layout: "padded" }, + argTypes: { + component: { control: "text" }, + }, + args: { + component: "div", + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Playground: Story = { + render: (args) => ( + <TableContainer {...args} component={Paper} sx={{ maxHeight: 280 }}> + <Table stickyHeader> + <TableHead> + <TableRow> + <TableCell>Header A</TableCell> + <TableCell>Header B</TableCell> + </TableRow> + </TableHead> + <TableBody> + {Array.from({ length: 12 }).map((_, i) => ( + <TableRow key={i}> + <TableCell>Row {i + 1} A</TableCell> + <TableCell>Row {i + 1} B</TableCell> + </TableRow> + ))} + </TableBody> + </Table> + </TableContainer> + ), +}; diff --git a/src/components/MUI/DataDisplay/TableContainer.tsx b/src/components/MUI/DataDisplay/TableContainer.tsx new file mode 100644 index 0000000..a100e56 --- /dev/null +++ b/src/components/MUI/DataDisplay/TableContainer.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +import MuiTableContainer, { + TableContainerProps as MuiTableContainerProps, +} from "@mui/material/TableContainer"; + +export type TableContainerProps = MuiTableContainerProps; + +export const TableContainer = React.forwardRef< + HTMLDivElement, + TableContainerProps +>(function TableContainer(props, ref) { + return <MuiTableContainer ref={ref} {...props} />; +}); + +TableContainer.displayName = "TableContainer"; diff --git a/src/components/MUI/DataDisplay/TableFooter.stories.tsx b/src/components/MUI/DataDisplay/TableFooter.stories.tsx new file mode 100644 index 0000000..73fcec2 --- /dev/null +++ b/src/components/MUI/DataDisplay/TableFooter.stories.tsx @@ -0,0 +1,49 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { TableContainer } from "./TableContainer"; +import { Table } from "./Table"; +import { TableHead } from "./TableHead"; +import { TableCell } from "./TableCell"; +import { TableRow } from "./TableRow"; +import { TableBody } from "./TableBody"; +import { Paper } from "../Surfaces/Paper"; +import { TableFooter } from "./TableFooter"; + +const meta: Meta<typeof TableFooter> = { + title: "MUI/Data Display/Table/TableFooter", + component: TableFooter, + parameters: { layout: "padded" }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Playground: Story = { + render: () => ( + <TableContainer component={Paper}> + <Table aria-label="footer demo"> + <TableHead> + <TableRow> + <TableCell>Item</TableCell> + <TableCell>Qty</TableCell> + </TableRow> + </TableHead> + <TableBody> + <TableRow> + <TableCell>Apples</TableCell> + <TableCell>5</TableCell> + </TableRow> + <TableRow> + <TableCell>Oranges</TableCell> + <TableCell>3</TableCell> + </TableRow> + </TableBody> + <TableFooter> + <TableRow> + <TableCell>Totals</TableCell> + <TableCell>8</TableCell> + </TableRow> + </TableFooter> + </Table> + </TableContainer> + ), +}; +``; diff --git a/src/components/MUI/DataDisplay/TableFooter.tsx b/src/components/MUI/DataDisplay/TableFooter.tsx new file mode 100644 index 0000000..e8db5f4 --- /dev/null +++ b/src/components/MUI/DataDisplay/TableFooter.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +import MuiTableFooter, { + TableFooterProps as MuiTableFooterProps, +} from "@mui/material/TableFooter"; + +export type TableFooterProps = MuiTableFooterProps; + +export const TableFooter = React.forwardRef< + HTMLTableSectionElement, + TableFooterProps +>(function TableFooter(props, ref) { + return <MuiTableFooter ref={ref} {...props} />; +}); + +TableFooter.displayName = "TableFooter"; diff --git a/src/components/MUI/DataDisplay/TableHead.stories.tsx b/src/components/MUI/DataDisplay/TableHead.stories.tsx new file mode 100644 index 0000000..111a76c --- /dev/null +++ b/src/components/MUI/DataDisplay/TableHead.stories.tsx @@ -0,0 +1,41 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { TableContainer } from "./TableContainer"; +import { Table } from "./Table"; +import { TableHead } from "./TableHead"; +import { TableCell } from "./TableCell"; +import { TableRow } from "./TableRow"; +import { TableBody } from "./TableBody"; +import { Paper } from "../Surfaces/Paper"; + +const meta: Meta<typeof TableHead> = { + title: "MUI/Data Display/Table/TableHead", + component: TableHead, + parameters: { layout: "padded" }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Playground: Story = { + render: () => ( + <TableContainer component={Paper}> + <Table aria-label="head demo"> + <TableHead> + <TableRow> + <TableCell>Column A</TableCell> + <TableCell>Column B</TableCell> + </TableRow> + </TableHead> + <TableBody> + <TableRow> + <TableCell>A1</TableCell> + <TableCell>B1</TableCell> + </TableRow> + <TableRow> + <TableCell>A2</TableCell> + <TableCell>B2</TableCell> + </TableRow> + </TableBody> + </Table> + </TableContainer> + ), +}; diff --git a/src/components/MUI/DataDisplay/TableHead.tsx b/src/components/MUI/DataDisplay/TableHead.tsx new file mode 100644 index 0000000..765e047 --- /dev/null +++ b/src/components/MUI/DataDisplay/TableHead.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +import MuiTableHead, { + TableHeadProps as MuiTableHeadProps, +} from "@mui/material/TableHead"; + +export type TableHeadProps = MuiTableHeadProps; + +export const TableHead = React.forwardRef< + HTMLTableSectionElement, + TableHeadProps +>(function TableHead(props, ref) { + return <MuiTableHead ref={ref} {...props} />; +}); + +TableHead.displayName = "TableHead"; diff --git a/src/components/MUI/DataDisplay/TablePagination.stories.tsx b/src/components/MUI/DataDisplay/TablePagination.stories.tsx new file mode 100644 index 0000000..f80e3dc --- /dev/null +++ b/src/components/MUI/DataDisplay/TablePagination.stories.tsx @@ -0,0 +1,72 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { TableContainer } from "./TableContainer"; +import { Table } from "./Table"; +import { TableHead } from "./TableHead"; +import { TableCell } from "./TableCell"; +import { TableRow } from "./TableRow"; +import { TableBody } from "./TableBody"; +import { Paper } from "../Surfaces/Paper"; +import { TablePagination } from "./TablePagination"; +import React from "react"; +import { TableFooter } from "./TableFooter"; + +type Row = { id: number; name: string }; +const rows: Row[] = Array.from({ length: 23 }).map((_, i) => ({ + id: i + 1, + name: `Row ${i + 1}`, +})); + +const meta: Meta<typeof TablePagination> = { + title: "MUI/Data Display/Table/TablePagination", + component: TablePagination, + parameters: { layout: "padded" }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Playground: Story = { + render: () => { + const [page, setPage] = React.useState(0); + const [rowsPerPage, setRowsPerPage] = React.useState(5); + const slice = rows.slice( + page * rowsPerPage, + page * rowsPerPage + rowsPerPage, + ); + + return ( + <TableContainer component={Paper}> + <Table aria-label="pagination demo"> + <TableHead> + <TableRow> + <TableCell>ID</TableCell> + <TableCell>Name</TableCell> + </TableRow> + </TableHead> + <TableBody> + {slice.map((row) => ( + <TableRow key={row.id}> + <TableCell>{row.id}</TableCell> + <TableCell>{row.name}</TableCell> + </TableRow> + ))} + </TableBody> + <TableFooter> + <TableRow> + <TablePagination + count={rows.length} + page={page} + rowsPerPage={rowsPerPage} + onPageChange={(_, newPage) => setPage(newPage)} + onRowsPerPageChange={(e) => { + setRowsPerPage(parseInt(e.target.value, 10)); + setPage(0); + }} + rowsPerPageOptions={[5, 10, 25]} + /> + </TableRow> + </TableFooter> + </Table> + </TableContainer> + ); + }, +}; diff --git a/src/components/MUI/DataDisplay/TablePagination.tsx b/src/components/MUI/DataDisplay/TablePagination.tsx new file mode 100644 index 0000000..29bbbab --- /dev/null +++ b/src/components/MUI/DataDisplay/TablePagination.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +import MuiTablePagination, { + TablePaginationProps as MuiTablePaginationProps, +} from "@mui/material/TablePagination"; + +export type TablePaginationProps = MuiTablePaginationProps; + +export const TablePagination = React.forwardRef< + HTMLDivElement, + TablePaginationProps +>(function TablePagination(props, ref) { + return <MuiTablePagination ref={ref} {...props} />; +}); + +TablePagination.displayName = "TablePagination"; diff --git a/src/components/MUI/DataDisplay/TableRow.stories.tsx b/src/components/MUI/DataDisplay/TableRow.stories.tsx new file mode 100644 index 0000000..7489a34 --- /dev/null +++ b/src/components/MUI/DataDisplay/TableRow.stories.tsx @@ -0,0 +1,49 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { TableContainer } from "./TableContainer"; +import { Table } from "./Table"; +import { TableHead } from "./TableHead"; +import { TableCell } from "./TableCell"; +import { TableRow } from "./TableRow"; +import { TableBody } from "./TableBody"; +import { Paper } from "../Surfaces/Paper"; + +const meta: Meta<typeof TableRow> = { + title: "MUI/Data Display/Table/TableRow", + component: TableRow, + parameters: { layout: "padded" }, + argTypes: { + hover: { control: "boolean" }, + selected: { control: "boolean" }, + }, + args: { + hover: true, + selected: false, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Playground: Story = { + render: (args) => ( + <TableContainer component={Paper}> + <Table aria-label="row demo"> + <TableHead> + <TableRow> + <TableCell>Item</TableCell> + <TableCell>Qty</TableCell> + </TableRow> + </TableHead> + <TableBody> + <TableRow {...args}> + <TableCell>Apples</TableCell> + <TableCell>5</TableCell> + </TableRow> + <TableRow {...args}> + <TableCell>Oranges</TableCell> + <TableCell>3</TableCell> + </TableRow> + </TableBody> + </Table> + </TableContainer> + ), +}; diff --git a/src/components/MUI/DataDisplay/TableRow.tsx b/src/components/MUI/DataDisplay/TableRow.tsx new file mode 100644 index 0000000..a05de11 --- /dev/null +++ b/src/components/MUI/DataDisplay/TableRow.tsx @@ -0,0 +1,13 @@ +import * as React from "react"; +import MuiTableRow, { + TableRowProps as MuiTableRowProps, +} from "@mui/material/TableRow"; + +export type TableRowProps = MuiTableRowProps; + +export const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>( + function TableRow(props, ref) { + return <MuiTableRow ref={ref} {...props} />; + }, +); +TableRow.displayName = "TableRow"; diff --git a/src/components/MUI/DataDisplay/TableSortLabel.stories.tsx b/src/components/MUI/DataDisplay/TableSortLabel.stories.tsx new file mode 100644 index 0000000..4599262 --- /dev/null +++ b/src/components/MUI/DataDisplay/TableSortLabel.stories.tsx @@ -0,0 +1,80 @@ +import React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; +import { TableContainer } from "./TableContainer"; +import { Table } from "./Table"; +import { TableHead } from "./TableHead"; +import { TableCell } from "./TableCell"; +import { TableRow } from "./TableRow"; +import { TableBody } from "./TableBody"; +import { Paper } from "../Surfaces/Paper"; +import { TableSortLabel } from "./TableSortLabel"; + +type Row = { name: string; calories: number }; +const rows: Row[] = [ + { name: "Frozen yoghurt", calories: 159 }, + { name: "Ice cream sandwich", calories: 237 }, + { name: "Eclair", calories: 262 }, +]; + +const meta: Meta<typeof TableSortLabel> = { + title: "MUI/Data Display/Table/TableSortLabel", + component: TableSortLabel, + parameters: { layout: "padded" }, + argTypes: { + active: { control: "boolean" }, + direction: { control: { type: "radio" }, options: ["asc", "desc"] }, + disabled: { control: "boolean" }, + }, + args: { + active: true, + direction: "asc", + disabled: false, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Playground: Story = { + render: (args) => { + const [orderAsc, setOrderAsc] = React.useState(args.direction === "asc"); + const [active, setActive] = React.useState(args.active); + + const sorted = [...rows].sort((a, b) => + orderAsc ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name), + ); + + return ( + <TableContainer component={Paper}> + <Table aria-label="sort label demo"> + <TableHead> + <TableRow> + <TableCell sortDirection={orderAsc ? "asc" : "desc"}> + <TableSortLabel + {...args} + active={active} + direction={orderAsc ? "asc" : "desc"} + onClick={() => { + setOrderAsc(!orderAsc); + setActive(true); + }} + > + Dessert (100g serving) + </TableSortLabel> + </TableCell> + <TableCell align="right">Calories</TableCell> + </TableRow> + </TableHead> + <TableBody> + {sorted.map((row) => ( + <TableRow key={row.name}> + <TableCell>{row.name}</TableCell> + <TableCell align="right">{row.calories}</TableCell> + </TableRow> + ))} + </TableBody> + </Table> + </TableContainer> + ); + }, +}; +``; diff --git a/src/components/MUI/DataDisplay/TableSortLabel.tsx b/src/components/MUI/DataDisplay/TableSortLabel.tsx new file mode 100644 index 0000000..11ddad9 --- /dev/null +++ b/src/components/MUI/DataDisplay/TableSortLabel.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +import MuiTableSortLabel, { + TableSortLabelProps as MuiTableSortLabelProps, +} from "@mui/material/TableSortLabel"; + +export type TableSortLabelProps = MuiTableSortLabelProps; + +export const TableSortLabel = React.forwardRef< + HTMLSpanElement, + TableSortLabelProps +>(function TableSortLabel(props, ref) { + return <MuiTableSortLabel ref={ref} {...props} />; +}); + +TableSortLabel.displayName = "TableSortLabel"; diff --git a/src/components/MUI/DataDisplay/Typography.stories.tsx b/src/components/MUI/DataDisplay/Typography.stories.tsx new file mode 100644 index 0000000..b0e319a --- /dev/null +++ b/src/components/MUI/DataDisplay/Typography.stories.tsx @@ -0,0 +1,155 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Typography } from "./Typography"; +import { Stack } from "../Layout/Stack"; + +const meta: Meta<typeof Typography> = { + title: "MUI/Data Display/Typography", + component: Typography, + tags: ["autodocs"], + parameters: { + controls: { expanded: true }, + layout: "padded", + }, + argTypes: { + variant: { + control: { type: "select" }, + options: [ + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "subtitle1", + "subtitle2", + "body1", + "body2", + "caption", + "button", + "overline", + ], + }, + color: { + control: { type: "select" }, + options: [ + "inherit", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + "textPrimary", + "textSecondary", + ], + }, + align: { + control: { type: "select" }, + options: ["inherit", "left", "center", "right", "justify"], + }, + gutterBottom: { control: "boolean" }, + noWrap: { control: "boolean" }, + paragraph: { control: "boolean" }, + children: { name: "text", control: "text" }, + sx: { control: false }, + }, + args: { + variant: "body1", + color: "inherit", + align: "inherit", + gutterBottom: false, + noWrap: false, + paragraph: false, + children: "The quick brown fox jumps over the lazy dog.", + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => <Typography {...args} />, +}; + +export const Variants: Story = { + render: (args) => ( + <Stack spacing={1}> + <Typography {...args} variant="h4"> + Heading (h4) + </Typography> + <Typography {...args} variant="subtitle1"> + Subtitle 1 + </Typography> + <Typography {...args} variant="body1"> + Body 1 + </Typography> + <Typography {...args} variant="body2"> + Body 2 + </Typography> + <Typography {...args} variant="caption"> + Caption + </Typography> + <Typography {...args} variant="overline"> + OVERLINE + </Typography> + <Typography {...args} variant="button"> + Button text + </Typography> + </Stack> + ), +}; + +export const AlignmentAndWrap: Story = { + render: (args) => ( + <Stack spacing={1}> + <Typography {...args} align="left"> + Left aligned + </Typography> + <Typography {...args} align="center"> + Center aligned + </Typography> + <Typography {...args} align="right"> + Right aligned + </Typography> + <Typography {...args} noWrap sx={{ maxWidth: 240 }}> + This is a very very very long line that will be truncated when noWrap is + true. + </Typography> + <Typography {...args} paragraph> + Paragraph renders with bottom margin to separate blocks in content + layouts. + </Typography> + </Stack> + ), +}; + +export const Colors: Story = { + args: { variant: "body1" }, + render: (args) => ( + <Stack spacing={1}> + <Typography {...args} color="primary"> + Primary + </Typography> + <Typography {...args} color="secondary"> + Secondary + </Typography> + <Typography {...args} color="success"> + Success + </Typography> + <Typography {...args} color="error"> + Error + </Typography> + <Typography {...args} color="info"> + Info + </Typography> + <Typography {...args} color="warning"> + Warning + </Typography> + <Typography {...args} color="textPrimary"> + textPrimary + </Typography> + <Typography {...args} color="textSecondary"> + textSecondary + </Typography> + </Stack> + ), +}; diff --git a/src/components/MUI/DataDisplay/Typography.tsx b/src/components/MUI/DataDisplay/Typography.tsx new file mode 100644 index 0000000..581ab8e --- /dev/null +++ b/src/components/MUI/DataDisplay/Typography.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiTypography, { + TypographyProps as MuiTypographyProps, +} from "@mui/material/Typography"; + +export type TypographyProps = MuiTypographyProps; + +export const Typography = React.forwardRef<HTMLSpanElement, TypographyProps>( + (props, ref) => <MuiTypography ref={ref} {...props} />, +); + +Typography.displayName = "Typography"; diff --git a/src/components/MUI/Feedback/Alert.stories.tsx b/src/components/MUI/Feedback/Alert.stories.tsx new file mode 100644 index 0000000..4668c09 --- /dev/null +++ b/src/components/MUI/Feedback/Alert.stories.tsx @@ -0,0 +1,65 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Alert } from "./Alert"; +import { Button } from "../Inputs/Button"; + +const meta: Meta<typeof Alert> = { + title: "MUI/Feedback/Alert", + component: Alert, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + severity: { + control: "select", + options: ["success", "info", "warning", "error"], + }, + variant: { control: "select", options: ["standard", "outlined", "filled"] }, + children: { name: "message", control: "text" }, + icon: { control: false }, + action: { control: false }, + onClose: { control: false }, + }, + args: { + severity: "info", + variant: "standard", + children: "This is an info alert", + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { render: (args) => <Alert {...args} /> }; + +export const Variants: Story = { + render: (args) => ( + <> + <Alert {...args} variant="standard"> + Standard + </Alert> + <Alert {...args} variant="outlined"> + Outlined + </Alert> + <Alert {...args} variant="filled"> + Filled + </Alert> + </> + ), +}; + +export const WithActionAndClose: Story = { + render: (args) => ( + <> + <Alert + {...args} + severity="warning" + action={ + <Button color="inherit" size="small"> + UNDO + </Button> + } + onClose={() => console.log("alert close")} + > + Warning with action + </Alert> + </> + ), +}; diff --git a/src/components/MUI/Feedback/Alert.tsx b/src/components/MUI/Feedback/Alert.tsx new file mode 100644 index 0000000..3760b7d --- /dev/null +++ b/src/components/MUI/Feedback/Alert.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiAlert, { AlertProps as MuiAlertProps } from "@mui/material/Alert"; + +export type AlertProps = MuiAlertProps; + +export const Alert = React.forwardRef<HTMLDivElement, AlertProps>( + (props, ref) => <MuiAlert ref={ref} {...props} />, +); + +Alert.displayName = "Alert"; diff --git a/src/components/MUI/Feedback/Backdrop.stories.tsx b/src/components/MUI/Feedback/Backdrop.stories.tsx new file mode 100644 index 0000000..6e64453 --- /dev/null +++ b/src/components/MUI/Feedback/Backdrop.stories.tsx @@ -0,0 +1,38 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import * as React from "react"; +import { Backdrop } from "./Backdrop"; +import { CircularProgress } from "./CircularProgress"; +import { Button } from "../Inputs/Button"; + +const meta: Meta<typeof Backdrop> = { + title: "MUI/Feedback/Backdrop", + component: Backdrop, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + open: { control: "boolean" }, + invisible: { control: "boolean" }, + }, + args: { open: false, invisible: false }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Controlled: Story = { + render: (args) => { + const [open, setOpen] = React.useState(false); + return ( + <div style={{ display: "flex", gap: 12, alignItems: "center" }}> + <Button onClick={() => setOpen(true)}>Show</Button> + <Backdrop + {...args} + open={open} + onClick={() => setOpen(false)} + sx={{ color: "#fff", zIndex: (t) => t.zIndex.drawer + 1 }} + > + <CircularProgress color="inherit" /> + </Backdrop> + </div> + ); + }, +}; diff --git a/src/components/MUI/Feedback/Backdrop.tsx b/src/components/MUI/Feedback/Backdrop.tsx new file mode 100644 index 0000000..3686d04 --- /dev/null +++ b/src/components/MUI/Feedback/Backdrop.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiBackdrop, { + BackdropProps as MuiBackdropProps, +} from "@mui/material/Backdrop"; + +export type BackdropProps = MuiBackdropProps; + +export const Backdrop = React.forwardRef<HTMLDivElement, BackdropProps>( + (props, ref) => <MuiBackdrop ref={ref} {...props} />, +); + +Backdrop.displayName = "Backdrop"; diff --git a/src/components/MUI/Feedback/CircularProgress.stories.tsx b/src/components/MUI/Feedback/CircularProgress.stories.tsx new file mode 100644 index 0000000..61871b1 --- /dev/null +++ b/src/components/MUI/Feedback/CircularProgress.stories.tsx @@ -0,0 +1,45 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { CircularProgress } from "./CircularProgress"; + +const meta: Meta<typeof CircularProgress> = { + title: "MUI/Feedback/CircularProgress", + component: CircularProgress, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + color: { + control: "select", + options: [ + "primary", + "secondary", + "success", + "error", + "info", + "warning", + "inherit", + ], + }, + variant: { control: "select", options: ["indeterminate", "determinate"] }, + value: { control: { type: "number", min: 0, max: 100, step: 1 } }, + size: { control: { type: "number", min: 8, max: 200, step: 2 } }, + thickness: { control: { type: "number", min: 1, max: 10, step: 0.5 } }, + }, + args: { + color: "primary", + variant: "indeterminate", + value: 40, + size: 40, + thickness: 3.6, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => <CircularProgress {...args} />, +}; + +export const Determinate: Story = { + args: { variant: "determinate", value: 70 }, + render: (args) => <CircularProgress {...args} />, +}; diff --git a/src/components/MUI/Feedback/CircularProgress.tsx b/src/components/MUI/Feedback/CircularProgress.tsx new file mode 100644 index 0000000..5a2aa25 --- /dev/null +++ b/src/components/MUI/Feedback/CircularProgress.tsx @@ -0,0 +1,13 @@ +import * as React from "react"; +import MuiCircularProgress, { + CircularProgressProps as MuiCircularProgressProps, +} from "@mui/material/CircularProgress"; + +export type CircularProgressProps = MuiCircularProgressProps; + +export const CircularProgress = React.forwardRef< + HTMLSpanElement, + CircularProgressProps +>((props, ref) => <MuiCircularProgress ref={ref} {...props} />); + +CircularProgress.displayName = "CircularProgress"; diff --git a/src/components/MUI/Feedback/Dialog.stories.tsx b/src/components/MUI/Feedback/Dialog.stories.tsx new file mode 100644 index 0000000..ac660c8 --- /dev/null +++ b/src/components/MUI/Feedback/Dialog.stories.tsx @@ -0,0 +1,69 @@ +import React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; +import { Dialog } from "./Dialog"; +import DialogTitle from "@mui/material/DialogTitle"; +import DialogContent from "@mui/material/DialogContent"; +import DialogActions from "@mui/material/DialogActions"; +import { Typography } from "../DataDisplay/Typography"; +import { Button } from "../Inputs/Button"; + +const meta: Meta<typeof Dialog> = { + title: "MUI/Feedback/Dialog", + component: Dialog, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + fullWidth: { control: "boolean" }, + maxWidth: { + control: "select", + options: ["xs", "sm", "md", "lg", "xl", false], + }, + fullScreen: { control: "boolean" }, + scroll: { control: "select", options: ["paper", "body"] }, + }, + args: { fullWidth: true, maxWidth: "sm", fullScreen: false, scroll: "paper" }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => { + const [open, setOpen] = React.useState(false); + return ( + <div style={{ display: "flex", gap: 12 }}> + <Button onClick={() => setOpen(true)}>Open dialog</Button> + <Dialog {...args} open={open} onClose={() => setOpen(false)}> + <DialogTitle>Title</DialogTitle> + <DialogContent dividers> + <Typography variant="body2">Content goes here.</Typography> + </DialogContent> + <DialogActions> + <Button onClick={() => setOpen(false)}>Close</Button> + <Button variant="contained">Action</Button> + </DialogActions> + </Dialog> + </div> + ); + }, +}; + +export const FullScreen: Story = { + args: { fullScreen: true }, + render: (args) => { + const [open, setOpen] = React.useState(false); + return ( + <div style={{ display: "flex", gap: 12 }}> + <Button onClick={() => setOpen(true)}>Open full-screen</Button> + <Dialog {...args} open={open} onClose={() => setOpen(false)}> + <DialogTitle>Full Screen</DialogTitle> + <DialogContent dividers> + <Typography>Full-screen content.</Typography> + </DialogContent> + <DialogActions> + <Button onClick={() => setOpen(false)}>Close</Button> + </DialogActions> + </Dialog> + </div> + ); + }, +}; diff --git a/src/components/MUI/Feedback/Dialog.tsx b/src/components/MUI/Feedback/Dialog.tsx new file mode 100644 index 0000000..88c2811 --- /dev/null +++ b/src/components/MUI/Feedback/Dialog.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiDialog, { DialogProps as MuiDialogProps } from "@mui/material/Dialog"; + +export type DialogProps = MuiDialogProps; + +export const Dialog = React.forwardRef<HTMLDivElement, DialogProps>( + (props, ref) => <MuiDialog ref={ref} {...props} />, +); + +Dialog.displayName = "Dialog"; diff --git a/src/components/MUI/Feedback/LinearProgress.stories.tsx b/src/components/MUI/Feedback/LinearProgress.stories.tsx new file mode 100644 index 0000000..691b52d --- /dev/null +++ b/src/components/MUI/Feedback/LinearProgress.stories.tsx @@ -0,0 +1,49 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { LinearProgress } from "./LinearProgress"; + +const meta: Meta<typeof LinearProgress> = { + title: "MUI/Feedback/LinearProgress", + component: LinearProgress, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + color: { + control: "select", + options: [ + "primary", + "secondary", + "success", + "error", + "info", + "warning", + "inherit", + ], + }, + variant: { + control: "select", + options: ["indeterminate", "determinate", "buffer", "query"], + }, + value: { control: { type: "number", min: 0, max: 100, step: 1 } }, + valueBuffer: { control: { type: "number", min: 0, max: 100, step: 1 } }, + }, + args: { + color: "primary", + variant: "indeterminate", + value: 40, + valueBuffer: 60, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { render: (args) => <LinearProgress {...args} /> }; + +export const Determinate: Story = { + args: { variant: "determinate", value: 50 }, + render: (args) => <LinearProgress {...args} />, +}; + +export const Buffer: Story = { + args: { variant: "buffer", value: 30, valueBuffer: 60 }, + render: (args) => <LinearProgress {...args} />, +}; diff --git a/src/components/MUI/Feedback/LinearProgress.tsx b/src/components/MUI/Feedback/LinearProgress.tsx new file mode 100644 index 0000000..d21d8df --- /dev/null +++ b/src/components/MUI/Feedback/LinearProgress.tsx @@ -0,0 +1,13 @@ +import * as React from "react"; +import MuiLinearProgress, { + LinearProgressProps as MuiLinearProgressProps, +} from "@mui/material/LinearProgress"; + +export type LinearProgressProps = MuiLinearProgressProps; + +export const LinearProgress = React.forwardRef< + HTMLDivElement, + LinearProgressProps +>((props, ref) => <MuiLinearProgress ref={ref} {...props} />); + +LinearProgress.displayName = "LinearProgress"; diff --git a/src/components/MUI/Feedback/Skeleton.stories.tsx b/src/components/MUI/Feedback/Skeleton.stories.tsx new file mode 100644 index 0000000..012e7a5 --- /dev/null +++ b/src/components/MUI/Feedback/Skeleton.stories.tsx @@ -0,0 +1,23 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Skeleton } from "./Skeleton"; + +const meta: Meta<typeof Skeleton> = { + title: "MUI/Feedback/Skeleton", + component: Skeleton, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + variant: { + control: "select", + options: ["text", "rectangular", "circular"], + }, + animation: { control: "select", options: ["pulse", "wave", false] }, + width: { control: { type: "number", min: 16, max: 600, step: 4 } }, + height: { control: { type: "number", min: 16, max: 600, step: 4 } }, + }, + args: { variant: "text", animation: "pulse", width: 240, height: 24 }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { render: (args) => <Skeleton {...args} /> }; diff --git a/src/components/MUI/Feedback/Skeleton.tsx b/src/components/MUI/Feedback/Skeleton.tsx new file mode 100644 index 0000000..dd7b5ea --- /dev/null +++ b/src/components/MUI/Feedback/Skeleton.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiSkeleton, { + SkeletonProps as MuiSkeletonProps, +} from "@mui/material/Skeleton"; + +export type SkeletonProps = MuiSkeletonProps; + +export const Skeleton = React.forwardRef<HTMLSpanElement, SkeletonProps>( + (props, ref) => <MuiSkeleton ref={ref} {...props} />, +); + +Skeleton.displayName = "Skeleton"; diff --git a/src/components/MUI/Feedback/Snackbar.stories.tsx b/src/components/MUI/Feedback/Snackbar.stories.tsx new file mode 100644 index 0000000..706600c --- /dev/null +++ b/src/components/MUI/Feedback/Snackbar.stories.tsx @@ -0,0 +1,96 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import React from "react"; +import { Snackbar } from "./Snackbar"; +import { Button } from "../Inputs/Button"; + +const anchorMap = { + "top-left": { vertical: "top", horizontal: "left" }, + "top-center": { vertical: "top", horizontal: "center" }, + "top-right": { vertical: "top", horizontal: "right" }, + "bottom-left": { vertical: "bottom", horizontal: "left" }, + "bottom-center": { vertical: "bottom", horizontal: "center" }, + "bottom-right": { vertical: "bottom", horizontal: "right" }, +} as const; + +const meta: Meta<typeof Snackbar> = { + title: "MUI/Feedback/Snackbar", + component: Snackbar, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + message: { control: "text" }, + autoHideDuration: { + control: { type: "number", min: 1000, max: 10000, step: 500 }, + }, + anchorOrigin: { + control: { type: "select" }, + options: Object.keys(anchorMap), + mapping: anchorMap, + }, + }, + args: { + message: "Saved", + autoHideDuration: 3000, + anchorOrigin: { vertical: "bottom", horizontal: "left" }, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Controlled: Story = { + render: (args) => { + const [open, setOpen] = React.useState(false); + return ( + <div style={{ display: "flex", gap: 12, alignItems: "center" }}> + <Button onClick={() => setOpen(true)}>Show</Button> + <Snackbar {...args} open={open} onClose={() => setOpen(false)} /> + </div> + ); + }, +}; + +export const Positions: Story = { + render: (args) => { + const [open, setOpen] = React.useState(true); + return ( + <div style={{ display: "grid", gap: 12 }}> + <Snackbar + {...args} + anchorOrigin={anchorMap["top-left"]} + open={open} + onClose={() => setOpen(false)} + /> + <Snackbar + {...args} + anchorOrigin={anchorMap["top-center"]} + open={open} + onClose={() => setOpen(false)} + /> + <Snackbar + {...args} + anchorOrigin={anchorMap["top-right"]} + open={open} + onClose={() => setOpen(false)} + /> + <Snackbar + {...args} + anchorOrigin={anchorMap["bottom-left"]} + open={open} + onClose={() => setOpen(false)} + /> + <Snackbar + {...args} + anchorOrigin={anchorMap["bottom-center"]} + open={open} + onClose={() => setOpen(false)} + /> + <Snackbar + {...args} + anchorOrigin={anchorMap["bottom-right"]} + open={open} + onClose={() => setOpen(false)} + /> + </div> + ); + }, +}; diff --git a/src/components/MUI/Feedback/Snackbar.tsx b/src/components/MUI/Feedback/Snackbar.tsx new file mode 100644 index 0000000..c72a864 --- /dev/null +++ b/src/components/MUI/Feedback/Snackbar.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiSnackbar, { + SnackbarProps as MuiSnackbarProps, +} from "@mui/material/Snackbar"; + +export type SnackbarProps = MuiSnackbarProps; + +export const Snackbar = React.forwardRef<HTMLDivElement, SnackbarProps>( + (props, ref) => <MuiSnackbar ref={ref} {...props} />, +); + +Snackbar.displayName = "Snackbar"; diff --git a/src/components/MUI/Feedback/Tooltip.stories.tsx b/src/components/MUI/Feedback/Tooltip.stories.tsx new file mode 100644 index 0000000..4fa3ec4 --- /dev/null +++ b/src/components/MUI/Feedback/Tooltip.stories.tsx @@ -0,0 +1,94 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Tooltip } from "./Tooltip"; +import InfoIcon from "@mui/icons-material/Info"; +import { IconButton } from "../DataDisplay/IconButton"; + +const meta: Meta<typeof Tooltip> = { + title: "MUI/Feedback/Tooltip", + component: Tooltip, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + title: { control: "text" }, + placement: { + control: "select", + options: [ + "bottom", + "bottom-start", + "bottom-end", + "top", + "top-start", + "top-end", + "left", + "left-start", + "left-end", + "right", + "right-start", + "right-end", + ], + }, + arrow: { control: "boolean" }, + disableInteractive: { control: "boolean" }, + }, + args: { + title: "Tooltip", + placement: "top", + arrow: true, + disableInteractive: false, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <Tooltip {...args} title={args.title!}> + <IconButton aria-label="info"> + <InfoIcon /> + </IconButton> + </Tooltip> + ), +}; + +export const Placements: Story = { + render: (args) => ( + <div + style={{ + display: "grid", + gap: 12, + gridTemplateColumns: "repeat(3, minmax(0, 1fr))", + }} + > + <Tooltip {...args} title={args.title!} placement="top"> + <IconButton> + <InfoIcon /> + </IconButton> + </Tooltip> + <Tooltip {...args} title={args.title!} placement="right"> + <IconButton> + <InfoIcon /> + </IconButton> + </Tooltip> + <Tooltip {...args} title={args.title!} placement="bottom"> + <IconButton> + <InfoIcon /> + </IconButton> + </Tooltip> + <Tooltip {...args} title={args.title!} placement="left"> + <IconButton> + <InfoIcon /> + </IconButton> + </Tooltip> + <Tooltip {...args} title={args.title!} placement="top-start"> + <IconButton> + <InfoIcon /> + </IconButton> + </Tooltip> + <Tooltip {...args} title={args.title!} placement="top-end"> + <IconButton> + <InfoIcon /> + </IconButton> + </Tooltip> + </div> + ), +}; diff --git a/src/components/MUI/Feedback/Tooltip.tsx b/src/components/MUI/Feedback/Tooltip.tsx new file mode 100644 index 0000000..536fc0c --- /dev/null +++ b/src/components/MUI/Feedback/Tooltip.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiTooltip, { + TooltipProps as MuiTooltipProps, +} from "@mui/material/Tooltip"; + +export type TooltipProps = MuiTooltipProps; + +export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>( + (props, ref) => <MuiTooltip ref={ref as any} {...props} />, +); + +Tooltip.displayName = "Tooltip"; diff --git a/src/components/MUI/Inputs/Autocomplete.stories.tsx b/src/components/MUI/Inputs/Autocomplete.stories.tsx new file mode 100644 index 0000000..32ebe4d --- /dev/null +++ b/src/components/MUI/Inputs/Autocomplete.stories.tsx @@ -0,0 +1,189 @@ +import * as React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; +import { Autocomplete } from "./Autocomplete"; +import { Chip } from "../DataDisplay/Chip"; +import { TextField } from "./TextField"; + +const options = [ + "Apple", + "Apricot", + "Banana", + "Blueberry", + "Cherry", + "Date", + "Fig", + "Grape", + "Kiwi", + "Lime", + "Mango", + "Orange", + "Papaya", + "Pear", + "Plum", + "Raspberry", + "Strawberry", +]; + +type ExtraArgs = { + label: string; + placeholder?: string; + tfVariant: "outlined" | "filled" | "standard"; + tfColor: "primary" | "secondary" | "success" | "error" | "info" | "warning"; + defaultValue?: string[] | string | null; +}; +type AutoArgs = React.ComponentProps<typeof Autocomplete> & ExtraArgs; + +const meta: Meta<AutoArgs> = { + title: "MUI/Inputs/Autocomplete", + component: Autocomplete, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + multiple: { control: "boolean" }, + freeSolo: { control: "boolean" }, + disableClearable: { control: "boolean" }, + autoHighlight: { control: "boolean" }, + autoSelect: { control: "boolean" }, + filterSelectedOptions: { control: "boolean" }, + size: { control: { type: "select" }, options: ["small", "medium"] }, + options: { control: { type: "object" } }, + tfVariant: { + name: "TextField variant", + control: { type: "select" }, + options: ["outlined", "filled", "standard"], + }, + tfColor: { + name: "TextField color", + control: { type: "select" }, + options: ["primary", "secondary", "success", "error", "info", "warning"], + }, + label: { control: "text" }, + placeholder: { control: "text" }, + renderInput: { control: false }, + renderTags: { control: false }, + value: { control: false }, + onChange: { control: false }, + defaultValue: { control: false }, + }, + args: { + options, + multiple: false, + freeSolo: false, + disableClearable: false, + autoHighlight: true, + autoSelect: false, + filterSelectedOptions: true, + size: "medium", + tfVariant: "outlined", + tfColor: "primary", + label: "Choose a fruit", + placeholder: "Type to search…", + limitTags: -1, + defaultValue: null, + }, +}; +export default meta; +type Story = StoryObj<AutoArgs>; + +const withTF = (args: AutoArgs) => ({ + ...args, + renderInput: (params: any) => ( + <TextField + {...params} + label={args.label} + variant={args.tfVariant} + color={args.tfColor} + placeholder={args.placeholder} + /> + ), +}); + +export const Basic: Story = { + render: (args) => <Autocomplete {...withTF(args)} />, +}; + +export const FreeSolo: Story = { + args: { freeSolo: true, disableClearable: true }, + render: (args) => <Autocomplete {...withTF(args)} />, +}; + +export const MultipleChips: Story = { + args: { + multiple: true, + filterSelectedOptions: true, + size: "small", + defaultValue: [], + }, + render: (args) => { + const initial = Array.isArray(args.defaultValue) + ? (args.defaultValue as string[]) + : []; + const [value, setValue] = React.useState<string[]>(initial); + return ( + <Autocomplete + {...withTF(args)} + multiple + value={value} + onChange={(_, newValue) => setValue((newValue ?? []) as string[])} + options={options} + renderTags={(selected = [], getTagProps) => + selected.map((option, index) => ( + <Chip + {...getTagProps({ index })} + key={String(option)} + label={String(option)} + size="small" + /> + )) + } + /> + ); + }, +}; + +export const ToggleMultipleSafely: Story = { + args: { + multiple: false, + filterSelectedOptions: true, + size: "medium", + defaultValue: null, + }, + render: (args) => { + const [value, setValue] = React.useState<string[] | string | null>( + args.defaultValue ?? null, + ); + React.useEffect(() => { + setValue((prev) => { + if (args.multiple) { + if (prev == null) return []; + return Array.isArray(prev) ? prev : prev ? [prev] : []; + } else { + if (prev == null) return null; + return Array.isArray(prev) ? (prev[0] ?? null) : prev; + } + }); + }, [args.multiple]); + return ( + <Autocomplete + {...withTF(args)} + multiple={args.multiple} + value={value as any} + onChange={(_, newValue) => { + if (args.multiple) setValue((newValue ?? []) as string[]); + else setValue((newValue as string) ?? null); + }} + options={options} + renderTags={(selected = [], getTagProps) => + selected.map((option, index) => ( + <Chip + {...getTagProps({ index })} + key={String(option)} + label={String(option)} + size="small" + /> + )) + } + /> + ); + }, +}; diff --git a/src/components/MUI/Inputs/Autocomplete.tsx b/src/components/MUI/Inputs/Autocomplete.tsx new file mode 100644 index 0000000..af995a3 --- /dev/null +++ b/src/components/MUI/Inputs/Autocomplete.tsx @@ -0,0 +1,18 @@ +import * as React from "react"; +import MuiAutocomplete, { + AutocompleteProps as MuiAutocompleteProps, +} from "@mui/material/Autocomplete"; + +export type AutocompleteProps<T = any> = MuiAutocompleteProps< + T, + boolean | undefined, + boolean | undefined, + boolean | undefined +>; + +export const Autocomplete = React.forwardRef< + HTMLDivElement, + AutocompleteProps<any> +>((props, ref) => <MuiAutocomplete ref={ref} {...props} />); + +Autocomplete.displayName = "Autocomplete"; diff --git a/src/components/MUI/Inputs/Button.stories.tsx b/src/components/MUI/Inputs/Button.stories.tsx new file mode 100644 index 0000000..01a2d35 --- /dev/null +++ b/src/components/MUI/Inputs/Button.stories.tsx @@ -0,0 +1,231 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Button } from "./Button"; +import SaveIcon from "@mui/icons-material/Save"; +import SendIcon from "@mui/icons-material/Send"; +import DeleteIcon from "@mui/icons-material/Delete"; +import AddIcon from "@mui/icons-material/Add"; +import { Box } from "../Layout/Box"; +import { Stack } from "../Layout/Stack"; + +const iconMap = { + none: undefined, + save: <SaveIcon />, + send: <SendIcon />, + delete: <DeleteIcon />, + add: <AddIcon />, +} as const; +type IconKey = keyof typeof iconMap; + +const applyIconArgs = (args: any) => { + const { startIconName, endIconName, ...rest } = args; + return { + ...rest, + startIcon: iconMap[startIconName as IconKey], + endIcon: iconMap[endIconName as IconKey], + }; +}; + +const meta: Meta<typeof Button> = { + title: "MUI/Inputs/Button", + component: Button, + tags: ["autodocs"], + parameters: { + controls: { expanded: true }, + layout: "padded", + }, + + argTypes: { + variant: { + control: { type: "select" }, + options: ["text", "contained", "outlined"], + }, + color: { + control: { type: "select" }, + options: [ + "inherit", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + ], + }, + size: { + control: { type: "select" }, + options: ["small", "medium", "large"], + }, + + startIconName: { + name: "startIcon", + control: { type: "select" }, + options: Object.keys(iconMap), + }, + endIconName: { + name: "endIcon", + control: { type: "select" }, + options: Object.keys(iconMap), + }, + + href: { control: "text" }, + target: { control: { type: "select" }, options: ["", "_self", "_blank"] }, + rel: { control: "text" }, + ariaLabel: { name: "aria-label", control: "text" }, + + component: { control: false }, + children: { name: "label", control: "text" }, + } as any, + args: { + children: "Button", + variant: "contained", + color: "primary", + size: "medium", + disableElevation: false, + disabled: false, + disableFocusRipple: false, + disableRipple: false, + fullWidth: false, + startIcon: "none" as IconKey, + endIcon: "none" as IconKey, + href: "", + rel: "", + }, +}; + +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <Button + {...applyIconArgs(args)} + aria-label={args.ariaLabel || undefined} + href={args.href || undefined} + target={args.target || undefined} + rel={args.rel || undefined} + > + {args.children} + </Button> + ), +}; + +export const Variants: Story = { + render: (args) => ( + <Stack direction="row" spacing={1}> + <Button {...applyIconArgs(args)} variant="text"> + Text + </Button> + <Button {...applyIconArgs(args)} variant="contained"> + Contained + </Button> + <Button {...applyIconArgs(args)} variant="outlined"> + Outlined + </Button> + </Stack> + ), + args: { color: "primary" }, +}; + +export const Sizes: Story = { + render: (args) => ( + <Stack direction="row" spacing={1}> + <Button {...applyIconArgs(args)} size="small"> + Small + </Button> + <Button {...applyIconArgs(args)} size="medium"> + Medium + </Button> + <Button {...applyIconArgs(args)} size="large"> + Large + </Button> + </Stack> + ), +}; + +export const Colors: Story = { + render: (args) => ( + <Stack direction="row" spacing={1}> + <Button {...applyIconArgs(args)} color="primary"> + Primary + </Button> + <Button {...applyIconArgs(args)} color="secondary"> + Secondary + </Button> + <Button {...applyIconArgs(args)} color="success"> + Success + </Button> + <Button {...applyIconArgs(args)} color="error"> + Error + </Button> + <Button {...applyIconArgs(args)} color="info"> + Info + </Button> + <Button {...applyIconArgs(args)} color="warning"> + Warning + </Button> + </Stack> + ), + args: { variant: "contained" }, +}; + +export const WithIcons: Story = { + render: (args) => ( + <Stack direction="row" spacing={1}> + <Button {...applyIconArgs({ ...args, startIconName: "save" })}> + Save + </Button> + + <Button + {...applyIconArgs({ ...args, startIconName: "add" })} + variant="contained" + color="success" + > + Add + </Button> + <Button + {...applyIconArgs({ ...args, endIconName: "send" })} + variant="outlined" + color="info" + > + Send + </Button> + <Button + {...applyIconArgs({ ...args, endIconName: "delete" })} + variant="text" + color="error" + > + Delete + </Button> + </Stack> + ), +}; + +export const States: Story = { + render: (args) => ( + <Stack spacing={1} sx={{ maxWidth: 480 }}> + <Box sx={{ display: "inline-block" }}> + <Button {...applyIconArgs(args)} disabled> + Disabled + </Button> + </Box> + <Box sx={{ display: "inline-block" }}> + <Button {...applyIconArgs(args)} variant="contained" disableElevation> + No Elevation + </Button> + </Box> + <Box sx={{ display: "inline-block" }}> + <Button + {...applyIconArgs(args)} + variant="outlined" + color="primary" + href={args.href || "https://mui.com/"} + > + Link example + </Button> + </Box> + <Button {...applyIconArgs(args)} variant="contained" fullWidth> + Full width + </Button> + </Stack> + ), +}; diff --git a/src/components/MUI/Inputs/Button.tsx b/src/components/MUI/Inputs/Button.tsx new file mode 100644 index 0000000..7a61ef8 --- /dev/null +++ b/src/components/MUI/Inputs/Button.tsx @@ -0,0 +1,14 @@ +import React from "react"; +import MuiButton, { ButtonProps as MuiButtonProps } from "@mui/material/Button"; + +export type ButtonProps = MuiButtonProps; + +export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( + ({ children, ...rest }, ref) => ( + <MuiButton ref={ref} {...rest}> + {children} + </MuiButton> + ), +); + +Button.displayName = "Button"; diff --git a/src/components/MUI/Inputs/ButtonGroup.stories.tsx b/src/components/MUI/Inputs/ButtonGroup.stories.tsx new file mode 100644 index 0000000..c9a2465 --- /dev/null +++ b/src/components/MUI/Inputs/ButtonGroup.stories.tsx @@ -0,0 +1,60 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { ButtonGroup } from "./ButtonGroup"; +import { Button } from "./Button"; + +const meta: Meta<typeof ButtonGroup> = { + title: "MUI/Inputs/ButtonGroup", + component: ButtonGroup, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + variant: { control: "select", options: ["text", "outlined", "contained"] }, + color: { + control: "select", + options: [ + "inherit", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + ], + }, + size: { control: "select", options: ["small", "medium", "large"] }, + orientation: { control: "select", options: ["horizontal", "vertical"] }, + disabled: { control: "boolean" }, + fullWidth: { control: "boolean" }, + }, + args: { + variant: "outlined", + color: "primary", + size: "medium", + orientation: "horizontal", + disabled: false, + fullWidth: false, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <ButtonGroup {...args}> + <Button>One</Button> + <Button>Two</Button> + <Button>Three</Button> + </ButtonGroup> + ), +}; + +export const Vertical: Story = { + args: { orientation: "vertical" }, + render: (args) => ( + <ButtonGroup {...args}> + <Button>Top</Button> + <Button>Middle</Button> + <Button>Bottom</Button> + </ButtonGroup> + ), +}; diff --git a/src/components/MUI/Inputs/ButtonGroup.tsx b/src/components/MUI/Inputs/ButtonGroup.tsx new file mode 100644 index 0000000..40d7ce6 --- /dev/null +++ b/src/components/MUI/Inputs/ButtonGroup.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiButtonGroup, { + ButtonGroupProps as MuiButtonGroupProps, +} from "@mui/material/ButtonGroup"; + +export type ButtonGroupProps = MuiButtonGroupProps; + +export const ButtonGroup = React.forwardRef<HTMLDivElement, ButtonGroupProps>( + (props, ref) => <MuiButtonGroup ref={ref} {...props} />, +); diff --git a/src/components/MUI/Inputs/Checkbox.stories.tsx b/src/components/MUI/Inputs/Checkbox.stories.tsx new file mode 100644 index 0000000..f364c80 --- /dev/null +++ b/src/components/MUI/Inputs/Checkbox.stories.tsx @@ -0,0 +1,70 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import * as React from "react"; +import { Checkbox } from "./Checkbox"; + +type CBArgs = React.ComponentProps<typeof Checkbox>; + +const meta: Meta<CBArgs> = { + title: "MUI/Inputs/Checkbox", + component: Checkbox, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + color: { + control: "select", + options: [ + "default", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + ], + }, + size: { control: "select", options: ["small", "medium"] }, + disabled: { control: "boolean" }, + indeterminate: { control: "boolean" }, + + checked: { control: false }, + onChange: { control: false }, + }, + args: { + color: "primary", + size: "medium", + disabled: false, + indeterminate: false, + }, +}; +export default meta; +type Story = StoryObj<CBArgs>; + +export const Basic: Story = { + render: (args) => <Checkbox {...args} />, +}; + +export const Controlled: Story = { + render: (args) => { + const [checked, setChecked] = React.useState(true); + return ( + <Checkbox + {...args} + checked={checked} + onChange={(e) => setChecked(e.target.checked)} + /> + ); + }, +}; + +export const ColorsAndSizes: Story = { + render: (args) => ( + <div style={{ display: "flex", gap: 8, alignItems: "center" }}> + <Checkbox {...args} color="primary" /> + <Checkbox {...args} color="secondary" /> + <Checkbox {...args} color="success" /> + <Checkbox {...args} color="error" /> + <Checkbox {...args} size="small" color="info" /> + <Checkbox {...args} size="small" color="warning" /> + </div> + ), +}; diff --git a/src/components/MUI/Inputs/Checkbox.tsx b/src/components/MUI/Inputs/Checkbox.tsx new file mode 100644 index 0000000..6b7fc2d --- /dev/null +++ b/src/components/MUI/Inputs/Checkbox.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiCheckbox, { + CheckboxProps as MuiCheckboxProps, +} from "@mui/material/Checkbox"; + +export type CheckboxProps = MuiCheckboxProps; + +export const Checkbox = React.forwardRef<HTMLButtonElement, CheckboxProps>( + (props, ref) => <MuiCheckbox ref={ref} {...props} />, +); diff --git a/src/components/MUI/Inputs/Fab.stories.tsx b/src/components/MUI/Inputs/Fab.stories.tsx new file mode 100644 index 0000000..f1a5060 --- /dev/null +++ b/src/components/MUI/Inputs/Fab.stories.tsx @@ -0,0 +1,87 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Fab } from "./Fab"; +import AddIcon from "@mui/icons-material/Add"; +import EditIcon from "@mui/icons-material/Edit"; +import NavigationIcon from "@mui/icons-material/Navigation"; + +const meta: Meta<typeof Fab> = { + title: "MUI/Inputs/Fab", + component: Fab, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + color: { + control: "select", + options: [ + "default", + "inherit", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + ], + }, + size: { control: "select", options: ["small", "medium", "large"] }, + variant: { control: "select", options: ["circular", "extended"] }, + disabled: { control: "boolean" }, + }, + args: { + color: "primary", + size: "medium", + variant: "circular", + disabled: false, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <Fab {...args}> + <AddIcon /> + </Fab> + ), +}; + +export const Colors: Story = { + render: (args) => ( + <div style={{ display: "flex", gap: 12, alignItems: "center" }}> + <Fab {...args} color="primary"> + <AddIcon /> + </Fab> + <Fab {...args} color="secondary"> + <EditIcon /> + </Fab> + <Fab {...args} color="success"> + <AddIcon /> + </Fab> + <Fab {...args} color="error"> + <AddIcon /> + </Fab> + <Fab {...args} color="info"> + <AddIcon /> + </Fab> + <Fab {...args} color="warning"> + <AddIcon /> + </Fab> + </div> + ), +}; + +export const Extended: Story = { + args: { variant: "extended" }, + render: (args) => ( + <div style={{ display: "flex", gap: 12, alignItems: "center" }}> + <Fab {...args}> + <NavigationIcon sx={{ mr: 1 }} /> + Navigate + </Fab> + <Fab {...args} color="secondary"> + <EditIcon sx={{ mr: 1 }} /> + Edit + </Fab> + </div> + ), +}; diff --git a/src/components/MUI/Inputs/Fab.tsx b/src/components/MUI/Inputs/Fab.tsx new file mode 100644 index 0000000..e463057 --- /dev/null +++ b/src/components/MUI/Inputs/Fab.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiFab, { FabProps as MuiFabProps } from "@mui/material/Fab"; + +export type FabProps = MuiFabProps; + +export const Fab = React.forwardRef<HTMLButtonElement, FabProps>( + (props, ref) => <MuiFab ref={ref} {...props} />, +); + +Fab.displayName = "Fab"; diff --git a/src/components/MUI/Inputs/Radio.stories.tsx b/src/components/MUI/Inputs/Radio.stories.tsx new file mode 100644 index 0000000..e65bbc3 --- /dev/null +++ b/src/components/MUI/Inputs/Radio.stories.tsx @@ -0,0 +1,70 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import * as React from "react"; +import { Radio } from "./Radio"; +import { RadioGroup } from "./RadioGroup"; +import FormControlLabel from "@mui/material/FormControlLabel"; + +type RArgs = React.ComponentProps<typeof Radio>; + +const meta: Meta<RArgs> = { + title: "MUI/Inputs/Radio", + component: Radio, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + color: { + control: "select", + options: [ + "default", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + ], + }, + size: { control: "select", options: ["small", "medium"] }, + disabled: { control: "boolean" }, + checked: { control: false }, + onChange: { control: false }, + }, + args: { + color: "primary", + size: "medium", + disabled: false, + }, +}; +export default meta; +type Story = StoryObj<RArgs>; + +export const Basic: Story = { render: (args) => <Radio {...args} /> }; + +export const GroupControlled: Story = { + render: (args) => { + const [value, setValue] = React.useState("a"); + return ( + <RadioGroup + value={value} + onChange={(e) => setValue((e.target as HTMLInputElement).value)} + row + > + <FormControlLabel + value="a" + control={<Radio {...args} />} + label="Option A" + /> + <FormControlLabel + value="b" + control={<Radio {...args} />} + label="Option B" + /> + <FormControlLabel + value="c" + control={<Radio {...args} />} + label="Option C" + /> + </RadioGroup> + ); + }, +}; diff --git a/src/components/MUI/Inputs/Radio.tsx b/src/components/MUI/Inputs/Radio.tsx new file mode 100644 index 0000000..ca5799c --- /dev/null +++ b/src/components/MUI/Inputs/Radio.tsx @@ -0,0 +1,8 @@ +import * as React from "react"; +import MuiRadio, { RadioProps as MuiRadioProps } from "@mui/material/Radio"; + +export type RadioProps = MuiRadioProps; + +export const Radio = React.forwardRef<HTMLButtonElement, RadioProps>( + (props, ref) => <MuiRadio ref={ref} {...props} />, +); diff --git a/src/components/MUI/Inputs/RadioGroup.stories.tsx b/src/components/MUI/Inputs/RadioGroup.stories.tsx new file mode 100644 index 0000000..40ec1a0 --- /dev/null +++ b/src/components/MUI/Inputs/RadioGroup.stories.tsx @@ -0,0 +1,39 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { RadioGroup } from "./RadioGroup"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import { Radio } from "./Radio"; + +const meta: Meta<typeof RadioGroup> = { + title: "MUI/Inputs/RadioGroup", + component: RadioGroup, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + row: { control: "boolean" }, + name: { control: "text" }, + }, + args: { row: true, name: "choices" }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <RadioGroup {...args} defaultValue="a"> + <FormControlLabel value="a" control={<Radio />} label="Option A" /> + <FormControlLabel value="b" control={<Radio />} label="Option B" /> + <FormControlLabel value="c" control={<Radio />} label="Option C" /> + </RadioGroup> + ), +}; + +export const Vertical: Story = { + args: { row: false }, + render: (args) => ( + <RadioGroup {...args} defaultValue="b"> + <FormControlLabel value="a" control={<Radio />} label="Alpha" /> + <FormControlLabel value="b" control={<Radio />} label="Beta" /> + <FormControlLabel value="c" control={<Radio />} label="Gamma" /> + </RadioGroup> + ), +}; diff --git a/src/components/MUI/Inputs/RadioGroup.tsx b/src/components/MUI/Inputs/RadioGroup.tsx new file mode 100644 index 0000000..c859ec5 --- /dev/null +++ b/src/components/MUI/Inputs/RadioGroup.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiRadioGroup, { + RadioGroupProps as MuiRadioGroupProps, +} from "@mui/material/RadioGroup"; + +export type RadioGroupProps = MuiRadioGroupProps; + +export const RadioGroup = React.forwardRef<HTMLDivElement, RadioGroupProps>( + (props, ref) => <MuiRadioGroup ref={ref} {...props} />, +); + +RadioGroup.displayName = "RadioGroup"; diff --git a/src/components/MUI/Inputs/Rating.stories.tsx b/src/components/MUI/Inputs/Rating.stories.tsx new file mode 100644 index 0000000..7590f59 --- /dev/null +++ b/src/components/MUI/Inputs/Rating.stories.tsx @@ -0,0 +1,47 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import * as React from "react"; +import { Rating } from "./Rating"; + +type RatingArgs = React.ComponentProps<typeof Rating>; + +const meta: Meta<RatingArgs> = { + title: "MUI/Inputs/Rating", + component: Rating, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + value: { control: { type: "number", min: 0, max: 5, step: 0.5 } }, + precision: { control: { type: "number", min: 0.1, max: 1, step: 0.1 } }, + max: { control: { type: "number", min: 1, max: 10, step: 1 } }, + readOnly: { control: "boolean" }, + disabled: { control: "boolean" }, + size: { control: "select", options: ["small", "medium", "large"] }, + icon: { control: false }, + emptyIcon: { control: false }, + onChange: { control: false }, + }, + args: { + value: 3.5, + precision: 0.5, + max: 5, + readOnly: false, + disabled: false, + size: "medium", + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => { + const [value, setValue] = React.useState(args.value ?? 3.5); + return ( + <Rating {...args} value={value} onChange={(_, v) => setValue(v ?? 0)} /> + ); + }, +}; + +export const ReadOnly: Story = { + args: { readOnly: true, value: 4 }, + render: (args) => <Rating {...args} />, +}; diff --git a/src/components/MUI/Inputs/Rating.tsx b/src/components/MUI/Inputs/Rating.tsx new file mode 100644 index 0000000..dc7a0b7 --- /dev/null +++ b/src/components/MUI/Inputs/Rating.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiRating, { RatingProps as MuiRatingProps } from "@mui/material/Rating"; + +export type RatingProps = MuiRatingProps; + +export const Rating = React.forwardRef<HTMLSpanElement, RatingProps>( + (props, ref) => <MuiRating ref={ref} {...props} />, +); + +Rating.displayName = "Rating"; diff --git a/src/components/MUI/Inputs/Select.stories.tsx b/src/components/MUI/Inputs/Select.stories.tsx new file mode 100644 index 0000000..c3ff1c8 --- /dev/null +++ b/src/components/MUI/Inputs/Select.stories.tsx @@ -0,0 +1,81 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Select } from "./Select"; +import { FormControl, InputLabel, MenuItem } from "@mui/material"; + +const cityOptions = ["London", "Paris", "Berlin", "Rome", "Madrid"]; + +type ExtraArgs = { + label?: string; + items?: string[]; +}; +type SelectArgs = React.ComponentProps<typeof Select> & ExtraArgs; + +const meta: Meta<SelectArgs> = { + title: "MUI/Inputs/Select", + component: Select, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + variant: { control: "select", options: ["outlined", "filled", "standard"] }, + color: { + control: "select", + options: ["primary", "secondary", "success", "error", "info", "warning"], + }, + size: { control: "select", options: ["small", "medium"] }, + multiple: { control: "boolean" }, + displayEmpty: { control: "boolean" }, + value: { control: false }, + onChange: { control: false }, + + label: { control: "text" }, + items: { control: { type: "object" } }, + }, + args: { + variant: "outlined", + color: "primary", + size: "medium", + multiple: false, + displayEmpty: false, + label: "City", + items: cityOptions, + defaultValue: cityOptions[0], + }, +}; +export default meta; +type Story = StoryObj<SelectArgs>; + +const renderSelectWithLabel = (args: SelectArgs) => ( + <FormControl + variant={args.variant} + color={args.color} + size={args.size} + sx={{ minWidth: 200 }} + > + {args.label && <InputLabel id="demo-select-label">{args.label}</InputLabel>} + <Select {...args} labelId="demo-select-label" label={args.label}> + {(args.items || []).map((item) => ( + <MenuItem key={item} value={item}> + {item} + </MenuItem> + ))} + </Select> + </FormControl> +); + +export const Basic: Story = { + render: (args: SelectArgs) => renderSelectWithLabel(args), +}; + +export const Multiple: Story = { + args: { multiple: true, defaultValue: [cityOptions[0], cityOptions[2]] }, + render: (args: SelectArgs) => renderSelectWithLabel(args), +}; + +export const FilledAndStandard: Story = { + render: (args: SelectArgs) => ( + <div style={{ display: "grid", gap: 12 }}> + {renderSelectWithLabel({ ...args, variant: "filled" })} + {renderSelectWithLabel({ ...args, variant: "standard" })} + </div> + ), +}; diff --git a/src/components/MUI/Inputs/Select.tsx b/src/components/MUI/Inputs/Select.tsx new file mode 100644 index 0000000..5c80077 --- /dev/null +++ b/src/components/MUI/Inputs/Select.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiSelect, { SelectProps as MuiSelectProps } from "@mui/material/Select"; + +export type SelectProps = MuiSelectProps; + +export const Select = React.forwardRef<HTMLDivElement, SelectProps>( + (props, ref) => <MuiSelect ref={ref} {...props} />, +); + +Select.displayName = "Select"; diff --git a/src/components/MUI/Inputs/Slider.stories.tsx b/src/components/MUI/Inputs/Slider.stories.tsx new file mode 100644 index 0000000..bba946a --- /dev/null +++ b/src/components/MUI/Inputs/Slider.stories.tsx @@ -0,0 +1,78 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import * as React from "react"; +import { Slider } from "./Slider"; + +type SliderArgs = React.ComponentProps<typeof Slider>; + +const meta: Meta<SliderArgs> = { + title: "MUI/Inputs/Slider", + component: Slider, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + color: { + control: "select", + options: ["primary", "secondary", "success", "error", "info", "warning"], + }, + size: { control: "select", options: ["small", "medium"] }, + orientation: { control: "select", options: ["horizontal", "vertical"] }, + min: { control: { type: "number", min: 0, max: 100, step: 1 } }, + max: { control: { type: "number", min: 0, max: 100, step: 1 } }, + step: { control: { type: "number", min: 1, max: 20, step: 1 } }, + marks: { control: "boolean" }, + valueLabelDisplay: { control: "select", options: ["off", "auto", "on"] }, + disabled: { control: "boolean" }, + value: { control: false }, + onChange: { control: false }, + }, + args: { + color: "primary", + size: "medium", + orientation: "horizontal", + min: 0, + max: 100, + step: 1, + marks: false, + valueLabelDisplay: "off", + disabled: false, + }, +}; +export default meta; +type Story = StoryObj<SliderArgs>; + +export const Basic: Story = { render: (args) => <Slider {...args} /> }; + +export const DiscreteWithMarks: Story = { + args: { step: 10, marks: true, valueLabelDisplay: "auto" }, + render: (args) => <Slider {...args} />, +}; + +export const Range: Story = { + render: (args) => { + const [value, setValue] = React.useState<number[]>([20, 80]); + return ( + <Slider + {...args} + value={value} + onChange={(_, v) => setValue(v as number[])} + valueLabelDisplay="auto" + /> + ); + }, +}; + +export const Vertical: Story = { + args: { + orientation: "vertical", + min: 0, + max: 100, + step: 5, + marks: true, + valueLabelDisplay: "auto", + }, + render: (args) => ( + <div style={{ height: 200 }}> + <Slider {...args} /> + </div> + ), +}; diff --git a/src/components/MUI/Inputs/Slider.tsx b/src/components/MUI/Inputs/Slider.tsx new file mode 100644 index 0000000..6f24ce4 --- /dev/null +++ b/src/components/MUI/Inputs/Slider.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiSlider, { SliderProps as MuiSliderProps } from "@mui/material/Slider"; + +export type SliderProps = MuiSliderProps; + +export const Slider = React.forwardRef<HTMLSpanElement, SliderProps>( + (props, ref) => <MuiSlider ref={ref} {...props} />, +); + +Slider.displayName = "Slider"; diff --git a/src/components/MUI/Inputs/SpeedDial.stories.tsx b/src/components/MUI/Inputs/SpeedDial.stories.tsx new file mode 100644 index 0000000..9f02c5a --- /dev/null +++ b/src/components/MUI/Inputs/SpeedDial.stories.tsx @@ -0,0 +1,44 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { SpeedDial } from "./SpeedDial"; +import SpeedDialIcon from "@mui/material/SpeedDialIcon"; +import SpeedDialAction from "@mui/material/SpeedDialAction"; +import FileCopyIcon from "@mui/icons-material/FileCopy"; +import SaveIcon from "@mui/icons-material/Save"; +import PrintIcon from "@mui/icons-material/Print"; +import ShareIcon from "@mui/icons-material/Share"; + +const meta: Meta<typeof SpeedDial> = { + title: "MUI/Inputs/SpeedDial", + component: SpeedDial, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + ariaLabel: { control: "text" }, + direction: { control: "select", options: ["up", "down", "left", "right"] }, + FabProps: { control: false }, + open: { control: "boolean" }, + onClose: { control: false }, + onOpen: { control: false }, + }, + args: { ariaLabel: "SpeedDial", direction: "up", open: true }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <div style={{ height: 240 }}> + <SpeedDial + {...args} + icon={<SpeedDialIcon />} + sx={{ position: "absolute", bottom: 16, right: 16 }} + ariaLabel="" + > + <SpeedDialAction icon={<FileCopyIcon />} tooltipTitle="Copy" /> + <SpeedDialAction icon={<SaveIcon />} tooltipTitle="Save" /> + <SpeedDialAction icon={<PrintIcon />} tooltipTitle="Print" /> + <SpeedDialAction icon={<ShareIcon />} tooltipTitle="Share" /> + </SpeedDial> + </div> + ), +}; diff --git a/src/components/MUI/Inputs/SpeedDial.tsx b/src/components/MUI/Inputs/SpeedDial.tsx new file mode 100644 index 0000000..abacb73 --- /dev/null +++ b/src/components/MUI/Inputs/SpeedDial.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiSpeedDial, { + SpeedDialProps as MuiSpeedDialProps, +} from "@mui/material/SpeedDial"; + +export type SpeedDialProps = MuiSpeedDialProps; + +export const SpeedDial = React.forwardRef<HTMLDivElement, SpeedDialProps>( + (props, ref) => <MuiSpeedDial ref={ref} {...props} />, +); + +SpeedDial.displayName = "SpeedDial"; diff --git a/src/components/MUI/Inputs/Switch.stories.tsx b/src/components/MUI/Inputs/Switch.stories.tsx new file mode 100644 index 0000000..0c07115 --- /dev/null +++ b/src/components/MUI/Inputs/Switch.stories.tsx @@ -0,0 +1,68 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import * as React from "react"; +import { Switch } from "./Switch"; + +type SWArgs = React.ComponentProps<typeof Switch>; + +const meta: Meta<SWArgs> = { + title: "MUI/Inputs/Switch", + component: Switch, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + color: { + control: "select", + options: [ + "default", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + ], + }, + size: { control: "select", options: ["small", "medium"] }, + disabled: { control: "boolean" }, + edge: { control: "select", options: [false, "start", "end"] }, + + checked: { control: false }, + onChange: { control: false }, + }, + args: { + color: "primary", + size: "medium", + disabled: false, + edge: false, + }, +}; +export default meta; +type Story = StoryObj<SWArgs>; + +export const Basic: Story = { render: (args) => <Switch {...args} /> }; + +export const Controlled: Story = { + render: (args) => { + const [checked, setChecked] = React.useState(true); + return ( + <Switch + {...args} + checked={checked} + onChange={(e) => setChecked(e.target.checked)} + /> + ); + }, +}; + +export const ColorsAndSizes: Story = { + render: (args) => ( + <div style={{ display: "flex", gap: 8, alignItems: "center" }}> + <Switch {...args} color="primary" /> + <Switch {...args} color="secondary" /> + <Switch {...args} color="success" /> + <Switch {...args} color="error" /> + <Switch {...args} size="small" color="info" /> + <Switch {...args} size="small" color="warning" /> + </div> + ), +}; diff --git a/src/components/MUI/Inputs/Switch.tsx b/src/components/MUI/Inputs/Switch.tsx new file mode 100644 index 0000000..567b57e --- /dev/null +++ b/src/components/MUI/Inputs/Switch.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiSwitch, { SwitchProps as MuiSwitchProps } from "@mui/material/Switch"; + +export type SwitchProps = MuiSwitchProps; + +export const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>( + (props, ref) => <MuiSwitch ref={ref} {...props} />, +); + +Switch.displayName = "Switch"; diff --git a/src/components/MUI/Inputs/TextField.stories.tsx b/src/components/MUI/Inputs/TextField.stories.tsx new file mode 100644 index 0000000..154c571 --- /dev/null +++ b/src/components/MUI/Inputs/TextField.stories.tsx @@ -0,0 +1,169 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { TextField } from "./TextField"; + +type TFArgs = React.ComponentProps<typeof TextField>; + +const meta: Meta<TFArgs> = { + title: "MUI/Inputs/TextField", + component: TextField, + tags: ["autodocs"], + parameters: { + controls: { expanded: true }, + layout: "padded", + }, + argTypes: { + variant: { + control: { type: "select" }, + options: ["outlined", "filled,", "standard"].map((s) => + s.replace(",", ""), + ), + }, + color: { + control: { type: "select" }, + options: ["primary", "secondary", "success", "error", "info", "warning"], + }, + size: { control: { type: "select" }, options: ["small", "medium"] }, + margin: { + control: { type: "select" }, + options: ["none", "dense", "normal"], + }, + type: { control: "text" }, + label: { control: "text" }, + placeholder: { control: "text" }, + helperText: { control: "text" }, + error: { control: "boolean" }, + required: { control: "boolean" }, + disabled: { control: "boolean" }, + fullWidth: { control: "boolean" }, + multiline: { control: "boolean" }, + rows: { control: { type: "number", min: 1, max: 12, step: 1 } }, + value: { control: false }, + onChange: { control: false }, + InputProps: { control: false }, + InputLabelProps: { control: false }, + FormHelperTextProps: { control: false }, + sx: { control: false }, + }, + args: { + variant: "outlined", + color: "primary", + size: "medium", + margin: "none", + type: "text", + label: "Your name", + placeholder: "Type here…", + helperText: "", + error: false, + required: false, + disabled: false, + fullWidth: false, + multiline: false, + rows: 1, + }, +}; + +export default meta; +type Story = StoryObj<TFArgs>; + +export const Basic: Story = { + render: (args) => <TextField {...args} />, +}; + +export const Variants: Story = { + render: (args) => ( + <div style={{ display: "grid", gap: 12 }}> + <TextField {...args} variant="outlined" label="Outlined" /> + <TextField {...args} variant="filled" label="Filled" /> + <TextField {...args} variant="standard" label="Standard" /> + </div> + ), + args: { color: "primary", helperText: "" }, +}; + +export const SizesAndColors: Story = { + render: (args) => ( + <div style={{ display: "grid", gap: 12 }}> + <div style={{ display: "flex", gap: 12 }}> + <TextField + {...args} + size="small" + color="primary" + label="Small / primary" + /> + <TextField + {...args} + size="small" + color="secondary" + label="Small / secondary" + /> + </div> + <div style={{ display: "flex", gap: 12 }}> + <TextField + {...args} + size="medium" + color="success" + label="Medium / success" + /> + <TextField + {...args} + size="medium" + color="error" + label="Medium / error" + /> + </div> + </div> + ), + args: { variant: "outlined", helperText: "" }, +}; + +export const States: Story = { + render: (args) => ( + <div style={{ display: "grid", gap: 12 }}> + <TextField {...args} required label="Required" helperText="* Required" /> + <TextField {...args} error label="Error" helperText="Invalid value" /> + <TextField {...args} disabled label="Disabled" placeholder="Disabled" /> + <div style={{ maxWidth: 420 }}> + <TextField + {...args} + fullWidth + label="Full width" + placeholder="Expands to container width" + /> + </div> + </div> + ), + args: { variant: "outlined", color: "primary" }, +}; + +export const Multiline: Story = { + args: { + multiline: true, + rows: 4, + label: "Message", + placeholder: "Write a few lines…", + }, + render: (args) => <TextField {...args} />, +}; + +export const InputTypes: Story = { + render: (args) => ( + <div style={{ display: "grid", gap: 12 }}> + <TextField {...args} type="text" label="Text" placeholder="Text…" /> + <TextField + {...args} + type="password" + label="Password" + placeholder="••••••••" + /> + <TextField {...args} type="number" label="Number" placeholder="0" /> + <TextField + {...args} + type="email" + label="Email" + placeholder="name@example.com" + /> + <TextField {...args} type="search" label="Search" placeholder="Find…" /> + </div> + ), + args: { variant: "outlined", helperText: "" }, +}; diff --git a/src/components/MUI/Inputs/TextField.tsx b/src/components/MUI/Inputs/TextField.tsx new file mode 100644 index 0000000..aa104ee --- /dev/null +++ b/src/components/MUI/Inputs/TextField.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiTextField, { + TextFieldProps as MuiTextFieldProps, +} from "@mui/material/TextField"; + +export type TextFieldProps = MuiTextFieldProps; + +export const TextField = React.forwardRef<HTMLDivElement, TextFieldProps>( + (props, ref) => <MuiTextField ref={ref} {...props} />, +); + +TextField.displayName = "TextField"; diff --git a/src/components/MUI/Inputs/ToggleButtonGroup.stories.tsx b/src/components/MUI/Inputs/ToggleButtonGroup.stories.tsx new file mode 100644 index 0000000..5b4284e --- /dev/null +++ b/src/components/MUI/Inputs/ToggleButtonGroup.stories.tsx @@ -0,0 +1,78 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import * as React from "react"; +import { ToggleButtonGroup } from "./ToggleButtonGroup"; +import ToggleButton from "@mui/material/ToggleButton"; + +type TBGArgs = React.ComponentProps<typeof ToggleButtonGroup>; + +const meta: Meta<TBGArgs> = { + title: "MUI/Inputs/ToggleButtonGroup", + component: ToggleButtonGroup, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + color: { + control: "select", + options: [ + "standard", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + ], + }, + size: { control: "select", options: ["small", "medium", "large"] }, + exclusive: { control: "boolean" }, + disabled: { control: "boolean" }, + + value: { control: false }, + onChange: { control: false }, + orientation: { control: "select", options: ["horizontal", "vertical"] }, + }, + args: { + color: "primary", + size: "medium", + exclusive: true, + disabled: false, + orientation: "horizontal", + }, +}; +export default meta; +type Story = StoryObj<TBGArgs>; + +export const ExclusiveControlled: Story = { + render: (args) => { + const [value, setValue] = React.useState<string | null>("left"); + return ( + <ToggleButtonGroup + {...args} + value={value} + onChange={(_, next) => setValue(next)} + > + <ToggleButton value="left">Left</ToggleButton> + <ToggleButton value="center">Center</ToggleButton> + <ToggleButton value="right">Right</ToggleButton> + </ToggleButtonGroup> + ); + }, +}; + +export const MultipleControlled: Story = { + args: { exclusive: false }, + render: (args) => { + const [value, setValue] = React.useState<string[]>(["bold"]); + return ( + <ToggleButtonGroup + {...args} + value={value} + onChange={(_, next) => setValue(next)} + > + <ToggleButton value="bold">Bold</ToggleButton> + <ToggleButton value="italic">Italic</ToggleButton> + <ToggleButton value="underline">Underline</ToggleButton> + </ToggleButtonGroup> + ); + }, +}; diff --git a/src/components/MUI/Inputs/ToggleButtonGroup.tsx b/src/components/MUI/Inputs/ToggleButtonGroup.tsx new file mode 100644 index 0000000..0423f64 --- /dev/null +++ b/src/components/MUI/Inputs/ToggleButtonGroup.tsx @@ -0,0 +1,13 @@ +import * as React from "react"; +import MuiToggleButtonGroup, { + ToggleButtonGroupProps as MuiToggleButtonGroupProps, +} from "@mui/material/ToggleButtonGroup"; + +export type ToggleButtonGroupProps = MuiToggleButtonGroupProps; + +export const ToggleButtonGroup = React.forwardRef< + HTMLDivElement, + ToggleButtonGroupProps +>((props, ref) => <MuiToggleButtonGroup ref={ref} {...props} />); + +ToggleButtonGroup.displayName = "ToggleButtonGroup"; diff --git a/src/components/MUI/Inputs/TransferList.stories.tsx b/src/components/MUI/Inputs/TransferList.stories.tsx new file mode 100644 index 0000000..11c5da9 --- /dev/null +++ b/src/components/MUI/Inputs/TransferList.stories.tsx @@ -0,0 +1,48 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { TransferList } from "./TransferList"; +// Vite raw import +import transferListSource from "./TransferList.tsx?raw"; + +const meta: Meta<typeof TransferList> = { + title: "MUI/Inputs/TransferList", + component: TransferList, + tags: ["autodocs"], + parameters: { + controls: { expanded: true }, + layout: "padded", + }, + args: { + left: [ + "Apple", + "Banana", + "Cherry", + "Date", + "Fig", + "Grape", + "Kiwi", + "Lemon", + "Mango", + "Orange", + "Pear", + "Plum", + ], + right: ["Blueberry", "Raspberry", "Strawberry"], + titleLeft: "Available", + titleRight: "Chosen", + }, +}; +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => <TransferList left={[]} right={[]} {...args} />, + parameters: { + docs: { + source: { + code: transferListSource, + language: "tsx", + }, + }, + }, +}; diff --git a/src/components/MUI/Inputs/TransferList.tsx b/src/components/MUI/Inputs/TransferList.tsx new file mode 100644 index 0000000..0436e79 --- /dev/null +++ b/src/components/MUI/Inputs/TransferList.tsx @@ -0,0 +1,105 @@ +import * as React from "react"; +import List from "@mui/material/List"; +import ListItem from "@mui/material/ListItem"; +import ListItemButton from "@mui/material/ListItemButton"; +import ListItemText from "@mui/material/ListItemText"; +import Checkbox from "@mui/material/Checkbox"; +import Button from "@mui/material/Button"; +import Paper from "@mui/material/Paper"; + +export type TransferListProps = { + left: string[]; + right: string[]; + onChange?: (left: string[], right: string[]) => void; + titleLeft?: string; + titleRight?: string; +}; + +export const TransferList: React.FC<TransferListProps> = ({ + left, + right, + onChange, + titleLeft = "Available", + titleRight = "Selected", +}) => { + const [leftItems, setLeftItems] = React.useState(left); + const [rightItems, setRightItems] = React.useState(right); + const [checked, setChecked] = React.useState<string[]>([]); + + const leftChecked = checked.filter((v) => leftItems.includes(v)); + const rightChecked = checked.filter((v) => rightItems.includes(v)); + + const toggle = (value: string) => { + setChecked((prev) => + prev.includes(value) + ? prev.filter((v) => v !== value) + : prev.concat(value), + ); + }; + + const moveRight = () => { + const nextRight = rightItems.concat(leftChecked); + const nextLeft = leftItems.filter((v) => !leftChecked.includes(v)); + setRightItems(nextRight); + setLeftItems(nextLeft); + setChecked((prev) => prev.filter((v) => !leftChecked.includes(v))); + onChange?.(nextLeft, nextRight); + }; + + const moveLeft = () => { + const nextLeft = leftItems.concat(rightChecked); + const nextRight = rightItems.filter((v) => !rightChecked.includes(v)); + setLeftItems(nextLeft); + setRightItems(nextRight); + setChecked((prev) => prev.filter((v) => !rightChecked.includes(v))); + onChange?.(nextLeft, nextRight); + }; + + const renderList = (title: string, items: string[]) => ( + <Paper + sx={{ width: 240, height: 260, display: "flex", flexDirection: "column" }} + > + <div style={{ fontSize: 14, fontWeight: 600, padding: "8px 12px" }}> + {title} + </div> + <List dense disablePadding sx={{ overflow: "auto", flex: 1 }}> + {items.map((value) => { + const checkedItem = checked.includes(value); + return ( + <ListItem key={value} disablePadding> + <ListItemButton onClick={() => toggle(value)} dense> + <Checkbox tabIndex={-1} checked={checkedItem} disableRipple /> + <ListItemText primary={value} /> + </ListItemButton> + </ListItem> + ); + })} + </List> + </Paper> + ); + + return ( + <div style={{ display: "flex", gap: 12, alignItems: "center" }}> + {renderList(titleLeft, leftItems)} + <div style={{ display: "grid", gap: 8 }}> + <Button + variant="outlined" + onClick={moveRight} + disabled={leftChecked.length === 0} + > + {">"} + </Button> + <Button + variant="outlined" + onClick={moveLeft} + disabled={rightChecked.length === 0} + > + {"<"} + </Button> + </div> + {renderList(titleRight, rightItems)} + </div> + ); +}; + +TransferList.displayName = "TransferList"; diff --git a/src/components/MUI/Layout/Box.stories.tsx b/src/components/MUI/Layout/Box.stories.tsx new file mode 100644 index 0000000..f9a72e8 --- /dev/null +++ b/src/components/MUI/Layout/Box.stories.tsx @@ -0,0 +1,70 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Box } from "./Box"; + +const meta: Meta<typeof Box> = { + title: "MUI/Layout/Box", + component: Box, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + component: { control: "text" }, + p: { control: { type: "number", min: 0, max: 10, step: 0.5 } }, + m: { control: { type: "number", min: 0, max: 10, step: 0.5 } }, + bgcolor: { control: "text" }, + color: { control: "text" }, + borderRadius: { control: { type: "number", min: 0, max: 24, step: 1 } }, + }, + args: { + component: "div", + p: 2, + m: 0, + bgcolor: "background.paper", + color: "text.primary", + borderRadius: 1, + }, +}; +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <Box + component={args.component as any} + sx={{ + p: args.p, + m: args.m, + bgcolor: args.bgcolor, + color: args.color, + borderRadius: args.borderRadius, + width: 320, + }} + > + Box content + </Box> + ), +}; + +export const Variants: Story = { + render: (args) => ( + <div style={{ display: "grid", gap: 12 }}> + <Box + sx={{ p: 2, bgcolor: "primary.main", color: "primary.contrastText" }} + > + Primary + </Box> + <Box + sx={{ + p: 2, + bgcolor: "secondary.main", + color: "secondary.contrastText", + }} + > + Secondary + </Box> + <Box sx={{ p: 2, bgcolor: "success.main", color: "common.white" }}> + Success + </Box> + </div> + ), +}; diff --git a/src/components/MUI/Layout/Box.tsx b/src/components/MUI/Layout/Box.tsx new file mode 100644 index 0000000..eaa781d --- /dev/null +++ b/src/components/MUI/Layout/Box.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiBox, { BoxProps as MuiBoxProps } from "@mui/material/Box"; + +export type BoxProps = MuiBoxProps; + +export const Box = React.forwardRef<HTMLDivElement, BoxProps>((props, ref) => ( + <MuiBox ref={ref} {...props} /> +)); + +Box.displayName = "Box"; diff --git a/src/components/MUI/Layout/Container.stories.tsx b/src/components/MUI/Layout/Container.stories.tsx new file mode 100644 index 0000000..471b62f --- /dev/null +++ b/src/components/MUI/Layout/Container.stories.tsx @@ -0,0 +1,55 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Container } from "./Container"; +import { Box } from "./Box"; + +const meta: Meta<typeof Container> = { + title: "MUI/Layout/Container", + component: Container, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + maxWidth: { + control: "select", + options: [false, "xs", "sm", "md", "lg", "xl"], + }, + fixed: { control: "boolean" }, + disableGutters: { control: "boolean" }, + }, + args: { maxWidth: "md", fixed: false, disableGutters: false }, +}; +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <Container {...args}> + <Box + sx={{ + bgcolor: "primary.main", + color: "primary.contrastText", + p: 2, + borderRadius: 1, + }} + > + Content inside Container + </Box> + </Container> + ), +}; + +export const Sizes: Story = { + render: (args) => ( + <div style={{ display: "grid", gap: 12 }}> + <Container {...args} maxWidth="sm"> + <Box sx={{ p: 2, bgcolor: "background.paper" }}>sm</Box> + </Container> + <Container {...args} maxWidth="md"> + <Box sx={{ p: 2, bgcolor: "background.paper" }}>md</Box> + </Container> + <Container {...args} maxWidth="lg"> + <Box sx={{ p: 2, bgcolor: "background.paper" }}>lg</Box> + </Container> + </div> + ), +}; diff --git a/src/components/MUI/Layout/Container.tsx b/src/components/MUI/Layout/Container.tsx new file mode 100644 index 0000000..75a8c47 --- /dev/null +++ b/src/components/MUI/Layout/Container.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiContainer, { + ContainerProps as MuiContainerProps, +} from "@mui/material/Container"; + +export type ContainerProps = MuiContainerProps; + +export const Container = React.forwardRef<HTMLDivElement, ContainerProps>( + (props, ref) => <MuiContainer ref={ref} {...props} />, +); + +Container.displayName = "Container"; diff --git a/src/components/MUI/Layout/Grid2.stories.tsx b/src/components/MUI/Layout/Grid2.stories.tsx new file mode 100644 index 0000000..2f862db --- /dev/null +++ b/src/components/MUI/Layout/Grid2.stories.tsx @@ -0,0 +1,64 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { GridV2 } from "./Grid2"; +import { Box } from "./Box"; + +const meta: Meta<typeof GridV2> = { + title: "MUI/Layout/Grid v2", + component: GridV2, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + spacing: { control: { type: "number", min: 0, max: 10, step: 0.5 } }, + columns: { control: { type: "number", min: 1, max: 24, step: 1 } }, + }, + args: { spacing: 2, columns: 12 }, +}; +export default meta; + +type Story = StoryObj<typeof meta>; + +const Item = ({ children }: { children: React.ReactNode }) => ( + <Box + sx={{ + bgcolor: "primary.main", + color: "primary.contrastText", + p: 1, + textAlign: "center", + borderRadius: 1, + }} + > + {children} + </Box> +); + +export const Basic: Story = { + render: (args) => ( + <GridV2 container spacing={args.spacing} columns={args.columns}> + <GridV2 size={{ xs: 4 }}> + <Item>xs=4</Item> + </GridV2> + <GridV2 size={{ xs: 4 }}> + <Item>xs=4</Item> + </GridV2> + <GridV2 size={{ xs: 4 }}> + <Item>xs=4</Item> + </GridV2> + </GridV2> + ), +}; + +export const Responsive: Story = { + render: (args) => ( + <GridV2 container spacing={args.spacing} columns={12}> + <GridV2 size={{ xs: 12, sm: 12, md: 4 }}> + <Item>xs=12 sm=6 md=4</Item> + </GridV2> + <GridV2 size={{ xs: 12, sm: 12, md: 4 }}> + <Item>xs=12 sm=6 md=4</Item> + </GridV2> + <GridV2 size={{ xs: 12, sm: 12, md: 4 }}> + <Item>xs=12 sm=12 md=4</Item> + </GridV2> + </GridV2> + ), +}; diff --git a/src/components/MUI/Layout/Grid2.tsx b/src/components/MUI/Layout/Grid2.tsx new file mode 100644 index 0000000..e2e6197 --- /dev/null +++ b/src/components/MUI/Layout/Grid2.tsx @@ -0,0 +1,10 @@ +import Grid2, { Grid2Props } from "@mui/material/Grid2/Grid2"; +import React from "react"; + +export type GridV2Props = Grid2Props; + +export const GridV2 = React.forwardRef<HTMLDivElement, Grid2Props>( + (props, ref) => <Grid2 ref={ref} {...props} />, +); + +GridV2.displayName = "GridV2"; diff --git a/src/components/MUI/Layout/ImageList.stories.tsx b/src/components/MUI/Layout/ImageList.stories.tsx new file mode 100644 index 0000000..b060224 --- /dev/null +++ b/src/components/MUI/Layout/ImageList.stories.tsx @@ -0,0 +1,82 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { ImageList } from "./ImageList"; + +import diamond from "../../../public/images/diamond.jpg"; +import bessy from "../../../public/images/bessy.jpg"; +import soleil from "../../../public/images/soleil.jpg"; +import shanghai from "../../../public/images/shanghai.jpg"; +import ImageListItemBar from "@mui/material/ImageListItemBar"; +import ImageListItem from "@mui/material/ImageListItem"; + +const items = [ + { + img: shanghai, + title: "Shanghai", + }, + { + img: diamond, + title: "Diamond", + }, + { + img: soleil, + title: "Soleil", + }, + { + img: bessy, + title: "Bessy", + }, +]; + +const meta: Meta<typeof ImageList> = { + title: "MUI/Layout/ImageList", + component: ImageList, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + cols: { control: { type: "number", min: 1, max: 6, step: 1 } }, + rowHeight: { control: { type: "number", min: 80, max: 400, step: 10 } }, + gap: { control: { type: "number", min: 0, max: 32, step: 1 } }, + variant: { + control: "select", + options: ["masonry", "quilted", "standard", "woven"], + }, + }, + args: { cols: 3, rowHeight: 164, gap: 8, variant: "standard" }, +}; +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <ImageList {...args}> + {items.map((it) => ( + <ImageListItem key={it.img}> + <img + src={`${it.img}?w=248&fit=crop&auto=format`} + alt={it.title} + loading="lazy" + /> + <ImageListItemBar title={it.title} /> + </ImageListItem> + ))} + </ImageList> + ), +}; + +export const Masonry: Story = { + args: { variant: "masonry", cols: 3, gap: 8 }, + render: (args) => ( + <ImageList {...args}> + {items.map((it) => ( + <ImageListItem key={it.img}> + <img + src={`${it.img}?w=248&fit=crop&auto=format`} + alt={it.title} + loading="lazy" + /> + </ImageListItem> + ))} + </ImageList> + ), +}; diff --git a/src/components/MUI/Layout/ImageList.tsx b/src/components/MUI/Layout/ImageList.tsx new file mode 100644 index 0000000..094c5c3 --- /dev/null +++ b/src/components/MUI/Layout/ImageList.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiImageList, { + ImageListProps as MuiImageListProps, +} from "@mui/material/ImageList"; + +export type ImageListProps = MuiImageListProps; + +export const ImageList = React.forwardRef<HTMLUListElement, ImageListProps>( + (props, ref) => <MuiImageList ref={ref} {...props} />, +); + +ImageList.displayName = "ImageList"; diff --git a/src/components/MUI/Layout/Stack.stories.tsx b/src/components/MUI/Layout/Stack.stories.tsx new file mode 100644 index 0000000..d3b7518 --- /dev/null +++ b/src/components/MUI/Layout/Stack.stories.tsx @@ -0,0 +1,77 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Stack } from "./Stack"; +import { Box } from "./Box"; + +const meta: Meta<typeof Stack> = { + title: "MUI/Layout/Stack", + component: Stack, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + direction: { + control: "select", + options: ["row", "row-reverse", "column", "column-reverse"], + }, + spacing: { control: { type: "number", min: 0, max: 10, step: 0.5 } }, + divider: { control: false }, + alignItems: { + control: "select", + options: ["stretch", "flex-start", "center", "flex-end", "baseline"], + }, + justifyContent: { + control: "select", + options: [ + "flex-start", + "center", + "flex-end", + "space-between", + "space-around", + "space-evenly", + ], + }, + }, + args: { + direction: "row", + spacing: 2, + alignItems: "center", + justifyContent: "flex-start", + }, +}; +export default meta; + +type Story = StoryObj<typeof meta>; + +const Item = ({ children }: { children: React.ReactNode }) => ( + <Box + sx={{ + bgcolor: "primary.main", + color: "primary.contrastText", + px: 2, + py: 1, + borderRadius: 1, + }} + > + {children} + </Box> +); + +export const Basic: Story = { + render: (args) => ( + <Stack {...args}> + <Item>One</Item> + <Item>Two</Item> + <Item>Three</Item> + </Stack> + ), +}; + +export const Vertical: Story = { + args: { direction: "column" }, + render: (args) => ( + <Stack {...args}> + <Item>A</Item> + <Item>B</Item> + <Item>C</Item> + </Stack> + ), +}; diff --git a/src/components/MUI/Layout/Stack.tsx b/src/components/MUI/Layout/Stack.tsx new file mode 100644 index 0000000..2006df5 --- /dev/null +++ b/src/components/MUI/Layout/Stack.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiStack, { StackProps as MuiStackProps } from "@mui/material/Stack"; + +export type StackProps = MuiStackProps; + +export const Stack = React.forwardRef<HTMLDivElement, StackProps>( + (props, ref) => <MuiStack ref={ref} {...props} />, +); + +Stack.displayName = "Stack"; diff --git a/src/components/MUI/Navigation/AppBar.stories.tsx b/src/components/MUI/Navigation/AppBar.stories.tsx new file mode 100644 index 0000000..30b90be --- /dev/null +++ b/src/components/MUI/Navigation/AppBar.stories.tsx @@ -0,0 +1,58 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { AppBar } from "./AppBar"; +import MenuIcon from "@mui/icons-material/Menu"; +import { IconButton } from "../DataDisplay/IconButton"; +import Toolbar from "@mui/material/Toolbar"; +import { Typography } from "../DataDisplay/Typography"; +import { Button } from "../Inputs/Button"; + +const meta: Meta<typeof AppBar> = { + title: "MUI/Navigation/AppBar", + component: AppBar, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "fullscreen" }, + argTypes: { + color: { + control: "select", + options: [ + "default", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + "transparent", + "inherit", + ], + }, + position: { + control: "select", + options: ["fixed", "absolute", "sticky", "static", "relative"], + }, + }, + args: { color: "primary", position: "static" }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <AppBar {...args}> + <Toolbar> + <IconButton + edge="start" + color="inherit" + aria-label="menu" + sx={{ mr: 2 }} + > + <MenuIcon /> + </IconButton> + <Typography variant="h6" sx={{ flexGrow: 1 }}> + Title + </Typography> + <Button color="inherit">Login</Button> + </Toolbar> + </AppBar> + ), +}; diff --git a/src/components/MUI/Navigation/AppBar.tsx b/src/components/MUI/Navigation/AppBar.tsx new file mode 100644 index 0000000..99b3971 --- /dev/null +++ b/src/components/MUI/Navigation/AppBar.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiAppBar, { AppBarProps as MuiAppBarProps } from "@mui/material/AppBar"; + +export type AppBarProps = MuiAppBarProps; + +export const AppBar = React.forwardRef<HTMLDivElement, AppBarProps>( + (props, ref) => <MuiAppBar ref={ref} {...props} />, +); + +AppBar.displayName = "AppBar"; diff --git a/src/components/MUI/Navigation/BottomNavigation.stories.tsx b/src/components/MUI/Navigation/BottomNavigation.stories.tsx new file mode 100644 index 0000000..9b6c04f --- /dev/null +++ b/src/components/MUI/Navigation/BottomNavigation.stories.tsx @@ -0,0 +1,39 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import * as React from "react"; +import { BottomNavigation } from "./BottomNavigation"; +import RestoreIcon from "@mui/icons-material/Restore"; +import FavoriteIcon from "@mui/icons-material/Favorite"; +import LocationOnIcon from "@mui/icons-material/LocationOn"; +import BottomNavigationAction from "@mui/material/BottomNavigationAction"; + +const meta: Meta<typeof BottomNavigation> = { + title: "MUI/Navigation/BottomNavigation", + component: BottomNavigation, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + showLabels: { control: "boolean" }, + value: { control: false }, + onChange: { control: false }, + }, + args: { showLabels: true }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Controlled: Story = { + render: (args) => { + const [value, setValue] = React.useState(0); + return ( + <BottomNavigation + {...args} + value={value} + onChange={(_, v) => setValue(v)} + > + <BottomNavigationAction label="Recents" icon={<RestoreIcon />} /> + <BottomNavigationAction label="Favorites" icon={<FavoriteIcon />} /> + <BottomNavigationAction label="Nearby" icon={<LocationOnIcon />} /> + </BottomNavigation> + ); + }, +}; diff --git a/src/components/MUI/Navigation/BottomNavigation.tsx b/src/components/MUI/Navigation/BottomNavigation.tsx new file mode 100644 index 0000000..8030005 --- /dev/null +++ b/src/components/MUI/Navigation/BottomNavigation.tsx @@ -0,0 +1,13 @@ +import * as React from "react"; +import MuiBottomNavigation, { + BottomNavigationProps as MuiBottomNavigationProps, +} from "@mui/material/BottomNavigation"; + +export type BottomNavigationProps = MuiBottomNavigationProps; + +export const BottomNavigation = React.forwardRef< + HTMLDivElement, + BottomNavigationProps +>((props, ref) => <MuiBottomNavigation ref={ref} {...props} />); + +BottomNavigation.displayName = "BottomNavigation"; diff --git a/src/components/MUI/Navigation/Breadcrumbs.stories.tsx b/src/components/MUI/Navigation/Breadcrumbs.stories.tsx new file mode 100644 index 0000000..2f3e1c4 --- /dev/null +++ b/src/components/MUI/Navigation/Breadcrumbs.stories.tsx @@ -0,0 +1,95 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Breadcrumbs } from "./Breadcrumbs"; +import HomeIcon from "@mui/icons-material/Home"; +import WhatshotIcon from "@mui/icons-material/Whatshot"; +import GrainIcon from "@mui/icons-material/Grain"; +import { Link } from "./Link"; +import { Typography } from "../DataDisplay/Typography"; + +const meta: Meta<typeof Breadcrumbs> = { + title: "MUI/Navigation/Breadcrumbs", + component: Breadcrumbs, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + separator: { control: "text" }, + maxItems: { control: { type: "number", min: 2, max: 10, step: 1 } }, + itemsBeforeCollapse: { + control: { type: "number", min: 0, max: 5, step: 1 }, + }, + itemsAfterCollapse: { + control: { type: "number", min: 0, max: 5, step: 1 }, + }, + }, + args: { + separator: "/", + maxItems: 8, + itemsBeforeCollapse: 1, + itemsAfterCollapse: 1, + }, +}; +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <Breadcrumbs {...args}> + <Link>Home</Link> + <Link>Library</Link> + <Typography color="text.primary">Data</Typography> + </Breadcrumbs> + ), +}; + +export const CustomSeparator: Story = { + args: { separator: "›" }, + render: (args) => ( + <Breadcrumbs {...args}> + <Link>#Home</Link> + <Link>#Catalog</Link> + <Link>#Accessories</Link> + <Typography color="text.primary">Cables</Typography> + </Breadcrumbs> + ), +}; + +export const WithIcons: Story = { + render: (args) => ( + <Breadcrumbs {...args} separator="›"> + <Link> + <HomeIcon fontSize="inherit" /> + Home + </Link> + <Link> + <WhatshotIcon fontSize="inherit" /> + Trending + </Link> + <Typography + color="text.primary" + sx={{ display: "inline-flex", alignItems: "center", gap: 0.5 }} + > + <GrainIcon fontSize="inherit" /> + Details + </Typography> + </Breadcrumbs> + ), +}; + +export const Collapsed: Story = { + args: { + maxItems: 3, + itemsBeforeCollapse: 1, + itemsAfterCollapse: 1, + separator: "/", + }, + render: (args) => ( + <Breadcrumbs {...args}> + <Link>Home</Link> + <Link>Section</Link> + <Link>Category</Link> + <Link>Subcategory</Link> + <Typography color="text.primary">Item</Typography> + </Breadcrumbs> + ), +}; diff --git a/src/components/MUI/Navigation/Breadcrumbs.tsx b/src/components/MUI/Navigation/Breadcrumbs.tsx new file mode 100644 index 0000000..10b4e5f --- /dev/null +++ b/src/components/MUI/Navigation/Breadcrumbs.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiBreadcrumbs, { + BreadcrumbsProps as MuiBreadcrumbsProps, +} from "@mui/material/Breadcrumbs"; + +export type BreadcrumbsProps = MuiBreadcrumbsProps; + +export const Breadcrumbs = React.forwardRef<HTMLDivElement, BreadcrumbsProps>( + (props, ref) => <MuiBreadcrumbs ref={ref} {...props} />, +); + +Breadcrumbs.displayName = "Breadcrumbs"; diff --git a/src/components/MUI/Navigation/Drawer.stories.tsx b/src/components/MUI/Navigation/Drawer.stories.tsx new file mode 100644 index 0000000..837c216 --- /dev/null +++ b/src/components/MUI/Navigation/Drawer.stories.tsx @@ -0,0 +1,54 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import * as React from "react"; +import { Drawer } from "./Drawer"; +import { Button } from "../Inputs/Button"; +import { List } from "../DataDisplay/List"; +import { ListItem } from "../DataDisplay/ListItem"; +import { ListItemText } from "../DataDisplay/ListItemText"; + +const meta: Meta<typeof Drawer> = { + title: "MUI/Navigation/Drawer", + component: Drawer, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + anchor: { control: "select", options: ["left", "right", "top", "bottom"] }, + }, + args: { anchor: "left" }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Temporary: Story = { + render: (args) => { + const [open, setOpen] = React.useState(false); + return ( + <div style={{ display: "flex", gap: 12 }}> + <Button onClick={() => setOpen(true)}>Open drawer</Button> + <Drawer {...args} open={open} onClose={() => setOpen(false)}> + <div + role="presentation" + style={{ + width: + args.anchor === "top" || args.anchor === "bottom" + ? "100%" + : 250, + }} + > + <List> + <ListItem> + <ListItemText primary="Item 1" /> + </ListItem> + <ListItem> + <ListItemText primary="Item 2" /> + </ListItem> + <ListItem> + <ListItemText primary="Item 3" /> + </ListItem> + </List> + </div> + </Drawer> + </div> + ); + }, +}; diff --git a/src/components/MUI/Navigation/Drawer.tsx b/src/components/MUI/Navigation/Drawer.tsx new file mode 100644 index 0000000..a32fc00 --- /dev/null +++ b/src/components/MUI/Navigation/Drawer.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiDrawer, { DrawerProps as MuiDrawerProps } from "@mui/material/Drawer"; + +export type DrawerProps = MuiDrawerProps; + +export const Drawer = React.forwardRef<HTMLDivElement, DrawerProps>( + (props, ref) => <MuiDrawer ref={ref} {...props} />, +); + +Drawer.displayName = "Drawer"; diff --git a/src/components/MUI/Navigation/Link.stories.tsx b/src/components/MUI/Navigation/Link.stories.tsx new file mode 100644 index 0000000..dcc0658 --- /dev/null +++ b/src/components/MUI/Navigation/Link.stories.tsx @@ -0,0 +1,40 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Link } from "./Link"; + +const meta: Meta<typeof Link> = { + title: "MUI/Navigation/Link", + component: Link, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + underline: { control: "select", options: ["none", "hover", "always"] }, + color: { + control: "select", + options: [ + "inherit", + "primary", + "secondary", + "success", + "error", + "info", + "warning", + ], + }, + href: { control: "text" }, + target: { control: "select", options: ["", "_self", "_blank"] }, + rel: { control: "text" }, + children: { name: "text", control: "text" }, + }, + args: { + underline: "hover", + color: "primary", + href: "https://mui.com/", + target: "_blank", + rel: "noopener noreferrer", + children: "MUI docs", + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { render: (args) => <Link {...args} /> }; diff --git a/src/components/MUI/Navigation/Link.tsx b/src/components/MUI/Navigation/Link.tsx new file mode 100644 index 0000000..62ac326 --- /dev/null +++ b/src/components/MUI/Navigation/Link.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiLink, { LinkProps as MuiLinkProps } from "@mui/material/Link"; + +export type LinkProps = MuiLinkProps; + +export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>( + (props, ref) => <MuiLink ref={ref} {...props} />, +); + +Link.displayName = "Link"; diff --git a/src/components/MUI/Navigation/Menu.stories.tsx b/src/components/MUI/Navigation/Menu.stories.tsx new file mode 100644 index 0000000..5913d58 --- /dev/null +++ b/src/components/MUI/Navigation/Menu.stories.tsx @@ -0,0 +1,99 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Menu } from "./Menu"; +import SaveIcon from "@mui/icons-material/Save"; +import SendIcon from "@mui/icons-material/Send"; +import React from "react"; +import { Button } from "../Inputs/Button"; +import { ListItemIcon } from "../DataDisplay/ListItemIcon"; +import MenuItem from "@mui/material/MenuItem"; + +const originMap = { + tl: { vertical: "top", horizontal: "left" }, + tc: { vertical: "top", horizontal: "center" }, + tr: { vertical: "top", horizontal: "right" }, + bl: { vertical: "bottom", horizontal: "left" }, + bc: { vertical: "bottom", horizontal: "center" }, + br: { vertical: "bottom", horizontal: "right" }, +} as const; + +const meta: Meta<typeof Menu> = { + title: "MUI/Navigation/Menu", + component: Menu, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + anchorOrigin: { + control: "select", + options: Object.keys(originMap), + mapping: originMap, + }, + transformOrigin: { + control: "select", + options: Object.keys(originMap), + mapping: originMap, + }, + keepMounted: { control: "boolean" }, + variant: { control: "select", options: ["selectedMenu", "menu"] }, + }, + args: { + anchorOrigin: { vertical: "bottom", horizontal: "left" }, + transformOrigin: { vertical: "top", horizontal: "left" }, + keepMounted: false, + variant: "menu", + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => { + const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); + const open = Boolean(anchorEl); + return ( + <div style={{ display: "flex", gap: 12 }}> + <Button onClick={(e) => setAnchorEl(e.currentTarget)}>Open menu</Button> + <Menu + {...args} + anchorEl={anchorEl} + open={open} + onClose={() => setAnchorEl(null)} + > + <MenuItem onClick={() => setAnchorEl(null)}>Profile</MenuItem> + <MenuItem onClick={() => setAnchorEl(null)}>My account</MenuItem> + <MenuItem onClick={() => setAnchorEl(null)}>Logout</MenuItem> + </Menu> + </div> + ); + }, +}; + +export const WithIcons: Story = { + render: (args) => { + const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); + const open = Boolean(anchorEl); + return ( + <div style={{ display: "flex", gap: 12 }}> + <Button onClick={(e) => setAnchorEl(e.currentTarget)}>Open menu</Button> + <Menu + {...args} + anchorEl={anchorEl} + open={open} + onClose={() => setAnchorEl(null)} + > + <MenuItem onClick={() => setAnchorEl(null)}> + <ListItemIcon> + <SaveIcon /> + </ListItemIcon> + Save + </MenuItem> + <MenuItem onClick={() => setAnchorEl(null)}> + <ListItemIcon> + <SendIcon /> + </ListItemIcon> + Send + </MenuItem> + </Menu> + </div> + ); + }, +}; diff --git a/src/components/MUI/Navigation/Menu.tsx b/src/components/MUI/Navigation/Menu.tsx new file mode 100644 index 0000000..3d95d69 --- /dev/null +++ b/src/components/MUI/Navigation/Menu.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiMenu, { MenuProps as MuiMenuProps } from "@mui/material/Menu"; + +export type MenuProps = MuiMenuProps; + +export const Menu = React.forwardRef<HTMLDivElement, MenuProps>( + (props, ref) => <MuiMenu ref={ref} {...props} />, +); + +Menu.displayName = "Menu"; diff --git a/src/components/MUI/Navigation/Pagination.stories.tsx b/src/components/MUI/Navigation/Pagination.stories.tsx new file mode 100644 index 0000000..c49e1de --- /dev/null +++ b/src/components/MUI/Navigation/Pagination.stories.tsx @@ -0,0 +1,41 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Pagination } from "./Pagination"; +import React from "react"; + +const meta: Meta<typeof Pagination> = { + title: "MUI/Navigation/Pagination", + component: Pagination, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + count: { control: { type: "number", min: 1, max: 20, step: 1 } }, + page: { control: false }, + onChange: { control: false }, + color: { control: "select", options: ["primary", "secondary", "standard"] }, + variant: { control: "select", options: ["text", "outlined"] }, + shape: { control: "select", options: ["rounded", "circular"] }, + size: { control: "select", options: ["small", "medium", "large"] }, + showFirstButton: { control: "boolean" }, + showLastButton: { control: "boolean" }, + disabled: { control: "boolean" }, + }, + args: { + count: 10, + color: "primary", + variant: "outlined", + shape: "rounded", + size: "medium", + showFirstButton: false, + showLastButton: false, + disabled: false, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Controlled: Story = { + render: (args) => { + const [page, setPage] = React.useState(1); + return <Pagination {...args} page={page} onChange={(_, p) => setPage(p)} />; + }, +}; diff --git a/src/components/MUI/Navigation/Pagination.tsx b/src/components/MUI/Navigation/Pagination.tsx new file mode 100644 index 0000000..40d9dd0 --- /dev/null +++ b/src/components/MUI/Navigation/Pagination.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiPagination, { + PaginationProps as MuiPaginationProps, +} from "@mui/material/Pagination"; + +export type PaginationProps = MuiPaginationProps; + +export const Pagination = React.forwardRef<HTMLDivElement, PaginationProps>( + (props, ref) => <MuiPagination ref={ref} {...props} />, +); + +Pagination.displayName = "Pagination"; diff --git a/src/components/MUI/Navigation/Stepper.stories.tsx b/src/components/MUI/Navigation/Stepper.stories.tsx new file mode 100644 index 0000000..e8597a7 --- /dev/null +++ b/src/components/MUI/Navigation/Stepper.stories.tsx @@ -0,0 +1,104 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Stepper } from "./Stepper"; +import React from "react"; +import StepLabel from "@mui/material/StepLabel"; +import Step from "@mui/material/Step"; +import { Button } from "../Inputs/Button"; +import StepContent from "@mui/material/StepContent"; + +const steps = [ + "Select campaign settings", + "Create an ad group", + "Create an ad", +]; + +const meta: Meta<typeof Stepper> = { + title: "MUI/Navigation/Stepper", + component: Stepper, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + orientation: { control: "select", options: ["horizontal", "vertical"] }, + alternativeLabel: { control: "boolean" }, + activeStep: { + control: { type: "number", min: 0, max: steps.length - 1, step: 1 }, + }, + }, + args: { orientation: "horizontal", alternativeLabel: false, activeStep: 0 }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Controlled: Story = { + render: (args) => { + const [active, setActive] = React.useState(0); + return ( + <div style={{ display: "grid", gap: 12 }}> + <Stepper {...args} activeStep={active}> + {steps.map((label) => ( + <Step key={label}> + <StepLabel>{label}</StepLabel> + </Step> + ))} + </Stepper> + <div style={{ display: "flex", gap: 8 }}> + <Button onClick={() => setActive((a) => Math.max(a - 1, 0))}> + Back + </Button> + <Button + variant="contained" + onClick={() => setActive((a) => Math.min(a + 1, steps.length - 1))} + > + Next + </Button> + </div> + </div> + ); + }, +}; + +export const Vertical: Story = { + args: { orientation: "vertical" }, + render: (args) => { + const [active, setActive] = React.useState(0); + return ( + <div style={{ display: "grid", gap: 12 }}> + <Stepper {...args} activeStep={active}> + {steps.map((label, idx) => ( + <Step key={label}> + <StepLabel>{label}</StepLabel> + <StepContent> + <div style={{ display: "flex", gap: 8 }}> + <Button onClick={() => setActive((a) => Math.max(a - 1, 0))}> + Back + </Button> + <Button + variant="contained" + onClick={() => + setActive((a) => Math.min(a + 1, steps.length - 1)) + } + > + Next + </Button> + </div> + </StepContent> + </Step> + ))} + </Stepper> + </div> + ); + }, +}; + +export const AlternativeLabel: Story = { + args: { alternativeLabel: true }, + render: (args) => ( + <Stepper {...args}> + {steps.map((label) => ( + <Step key={label}> + <StepLabel>{label}</StepLabel> + </Step> + ))} + </Stepper> + ), +}; diff --git a/src/components/MUI/Navigation/Stepper.tsx b/src/components/MUI/Navigation/Stepper.tsx new file mode 100644 index 0000000..68c7fe2 --- /dev/null +++ b/src/components/MUI/Navigation/Stepper.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiStepper, { + StepperProps as MuiStepperProps, +} from "@mui/material/Stepper"; + +export type StepperProps = MuiStepperProps; + +export const Stepper = React.forwardRef<HTMLDivElement, StepperProps>( + (props, ref) => <MuiStepper ref={ref} {...props} />, +); + +Stepper.displayName = "Stepper"; diff --git a/src/components/MUI/Navigation/Tabs.stories.tsx b/src/components/MUI/Navigation/Tabs.stories.tsx new file mode 100644 index 0000000..d1756a8 --- /dev/null +++ b/src/components/MUI/Navigation/Tabs.stories.tsx @@ -0,0 +1,64 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Tabs } from "./Tabs"; +import React from "react"; +import Tab from "@mui/material/Tab"; + +const meta: Meta<typeof Tabs> = { + title: "MUI/Navigation/Tabs", + component: Tabs, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + orientation: { control: "select", options: ["horizontal", "vertical"] }, + variant: { + control: "select", + options: ["standard", "scrollable", "fullWidth"], + }, + textColor: { + control: "select", + options: ["inherit", "primary", "secondary"], + }, + indicatorColor: { control: "select", options: ["primary", "secondary"] }, + value: { control: false }, + onChange: { control: false }, + }, + args: { + orientation: "horizontal", + variant: "standard", + textColor: "primary", + indicatorColor: "primary", + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Controlled: Story = { + render: (args) => { + const [value, setValue] = React.useState(0); + return ( + <div style={{ display: "flex", gap: 12 }}> + <Tabs {...args} value={value} onChange={(_, v) => setValue(v)}> + <Tab label="Tab One" /> + <Tab label="Tab Two" /> + <Tab label="Tab Three" /> + </Tabs> + </div> + ); + }, +}; + +export const Vertical: Story = { + args: { orientation: "vertical" }, + render: (args) => { + const [value, setValue] = React.useState(0); + return ( + <div style={{ display: "flex", height: 160 }}> + <Tabs {...args} value={value} onChange={(_, v) => setValue(v)}> + <Tab label="Item A" /> + <Tab label="Item B" /> + <Tab label="Item C" /> + </Tabs> + </div> + ); + }, +}; diff --git a/src/components/MUI/Navigation/Tabs.tsx b/src/components/MUI/Navigation/Tabs.tsx new file mode 100644 index 0000000..6573bb0 --- /dev/null +++ b/src/components/MUI/Navigation/Tabs.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiTabs, { TabsProps as MuiTabsProps } from "@mui/material/Tabs"; + +export type TabsProps = MuiTabsProps; + +export const Tabs = React.forwardRef<HTMLDivElement, TabsProps>( + (props, ref) => <MuiTabs ref={ref} {...props} />, +); + +Tabs.displayName = "Tabs"; diff --git a/src/components/MUI/Surfaces/Accordion.stories.tsx b/src/components/MUI/Surfaces/Accordion.stories.tsx new file mode 100644 index 0000000..0543466 --- /dev/null +++ b/src/components/MUI/Surfaces/Accordion.stories.tsx @@ -0,0 +1,78 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import AccordionSummary from "@mui/material/AccordionSummary"; +import AccordionDetails from "@mui/material/AccordionDetails"; +import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; +import { Accordion } from "./Accordion"; +import { Typography } from "../DataDisplay/Typography"; + +const meta: Meta<typeof Accordion> = { + title: "MUI/Surfaces/Accordion", + component: Accordion, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + disabled: { control: "boolean" }, + disableGutters: { control: "boolean" }, + square: { control: "boolean" }, + expanded: { control: false }, + defaultExpanded: { control: "boolean" }, + }, + args: { + disabled: false, + disableGutters: false, + square: false, + defaultExpanded: false, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <Accordion {...args}> + <AccordionSummary expandIcon={<ExpandMoreIcon />}> + <Typography>Summary</Typography> + </AccordionSummary> + <AccordionDetails> + <Typography>Details</Typography> + </AccordionDetails> + </Accordion> + ), +}; + +export const Multiple: Story = { + render: (args: any) => ( + <div style={{ display: "grid", gap: 12 }}> + <Accordion {...args}> + <AccordionSummary expandIcon={<ExpandMoreIcon />}> + <Typography>Item 1</Typography> + </AccordionSummary> + <AccordionDetails> + <Typography>Content 1</Typography> + </AccordionDetails> + </Accordion> + <Accordion {...args}> + <AccordionSummary expandIcon={<ExpandMoreIcon />}> + <Typography>Item 2</Typography> + </AccordionSummary> + <AccordionDetails> + <Typography>Content 2</Typography> + </AccordionDetails> + </Accordion> + </div> + ), +}; + +export const Disabled: Story = { + args: { disabled: true }, + render: (args) => ( + <Accordion {...args}> + <AccordionSummary expandIcon={<ExpandMoreIcon />}> + <Typography>Disabled</Typography> + </AccordionSummary> + <AccordionDetails> + <Typography>Cannot expand</Typography> + </AccordionDetails> + </Accordion> + ), +}; diff --git a/src/components/MUI/Surfaces/Accordion.tsx b/src/components/MUI/Surfaces/Accordion.tsx new file mode 100644 index 0000000..56649a6 --- /dev/null +++ b/src/components/MUI/Surfaces/Accordion.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiAccordion, { + AccordionProps as MuiAccordionProps, +} from "@mui/material/Accordion"; + +export type AccordionProps = MuiAccordionProps; + +export const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>( + (props, ref) => <MuiAccordion ref={ref} {...props} />, +); + +Accordion.displayName = "Accordion"; diff --git a/src/components/MUI/Surfaces/Card.stories.tsx b/src/components/MUI/Surfaces/Card.stories.tsx new file mode 100644 index 0000000..3d42bc2 --- /dev/null +++ b/src/components/MUI/Surfaces/Card.stories.tsx @@ -0,0 +1,65 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Card } from "./Card"; +import Diamond from "../../../public/images/diamond.jpg"; +import { Typography } from "../DataDisplay/Typography"; +import { Button } from "../Inputs/Button"; +import CardContent from "@mui/material/CardContent"; +import CardActions from "@mui/material/CardActions"; +import CardMedia from "@mui/material/CardMedia"; + +const meta: Meta<typeof Card> = { + title: "MUI/Surfaces/Card", + component: Card, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + variant: { control: "select", options: ["elevation", "outlined"] }, + raised: { control: "boolean" }, + elevation: { control: { type: "number", min: 0, max: 24, step: 1 } }, + sx: { control: false }, + }, + args: { + variant: "elevation", + raised: false, + elevation: 1, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <Card {...args} sx={{ maxWidth: 345 }}> + <CardMedia component="img" height="140" image={Diamond} alt="Random" /> + <CardContent> + <Typography gutterBottom variant="h6" component="div"> + Card title + </Typography> + <Typography variant="body2" color="text.secondary"> + Some descriptive text to show typical card content area sizing. + </Typography> + </CardContent> + <CardActions> + <Button size="small">Share</Button> + <Button size="small">Learn More</Button> + </CardActions> + </Card> + ), +}; + +export const Outlined: Story = { + args: { variant: "outlined", elevation: 0 }, + render: (args) => ( + <Card {...args} sx={{ maxWidth: 345 }}> + <CardContent> + <Typography variant="h6">Outlined card</Typography> + <Typography variant="body2" color="text.secondary"> + Uses the outlined variant with zero elevation. + </Typography> + </CardContent> + <CardActions> + <Button size="small">Action</Button> + </CardActions> + </Card> + ), +}; diff --git a/src/components/MUI/Surfaces/Card.tsx b/src/components/MUI/Surfaces/Card.tsx new file mode 100644 index 0000000..ab1ee4a --- /dev/null +++ b/src/components/MUI/Surfaces/Card.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiCard, { CardProps as MuiCardProps } from "@mui/material/Card"; + +export type CardProps = MuiCardProps; + +export const Card = React.forwardRef<HTMLDivElement, CardProps>( + (props, ref) => <MuiCard ref={ref} {...props} />, +); + +Card.displayName = "Card"; diff --git a/src/components/MUI/Surfaces/Paper.stories.tsx b/src/components/MUI/Surfaces/Paper.stories.tsx new file mode 100644 index 0000000..43f4d7c --- /dev/null +++ b/src/components/MUI/Surfaces/Paper.stories.tsx @@ -0,0 +1,44 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Paper } from "./Paper"; + +const meta: Meta<typeof Paper> = { + title: "MUI/Surfaces/Paper", + component: Paper, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + variant: { control: "select", options: ["elevation", "outlined"] }, + elevation: { control: { type: "number", min: 0, max: 24, step: 1 } }, + square: { control: "boolean" }, + }, + args: { variant: "elevation", elevation: 1, square: false }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => ( + <Paper {...args} sx={{ p: 2, maxWidth: 360 }}> + Paper content + </Paper> + ), +}; + +export const Elevations: Story = { + render: (args) => ( + <div style={{ display: "flex", gap: 12 }}> + <Paper {...args} elevation={0} sx={{ p: 2 }}> + elevation 0 + </Paper> + <Paper {...args} elevation={3} sx={{ p: 2 }}> + elevation 3 + </Paper> + <Paper {...args} elevation={8} sx={{ p: 2 }}> + elevation 8 + </Paper> + <Paper {...args} elevation={16} sx={{ p: 2 }}> + elevation 16 + </Paper> + </div> + ), +}; diff --git a/src/components/MUI/Surfaces/Paper.tsx b/src/components/MUI/Surfaces/Paper.tsx new file mode 100644 index 0000000..ce0e7a6 --- /dev/null +++ b/src/components/MUI/Surfaces/Paper.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiPaper, { PaperProps as MuiPaperProps } from "@mui/material/Paper"; + +export type PaperProps = MuiPaperProps; + +export const Paper = React.forwardRef<HTMLDivElement, PaperProps>( + (props, ref) => <MuiPaper ref={ref} {...props} />, +); + +Paper.displayName = "Paper"; diff --git a/src/components/MUI/Utils/ClickAwayListener.stories.tsx b/src/components/MUI/Utils/ClickAwayListener.stories.tsx new file mode 100644 index 0000000..7c0e088 --- /dev/null +++ b/src/components/MUI/Utils/ClickAwayListener.stories.tsx @@ -0,0 +1,81 @@ +import * as React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; +import { ClickAwayListener } from "./ClickAwayListener"; +import { Box } from "../Layout/Box"; +import { Button } from "../Inputs/Button"; + +type ExtraArgs = { + content?: string; +}; +type Args = React.ComponentProps<typeof ClickAwayListener> & ExtraArgs; + +const meta: Meta<Args> = { + title: "MUI/Utils/ClickAwayListener", + component: ClickAwayListener, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + disableReactTree: { control: "boolean" }, + mouseEvent: { + control: "select", + options: [ + "onClick", + "onMouseDown", + "onMouseUp", + "onPointerDown", + "onPointerUp", + false, + ], + }, + touchEvent: { + control: "select", + options: ["onTouchEnd", "onTouchStart", false], + }, + onClickAway: { control: false }, + children: { control: false }, + content: { control: "text" }, + }, + args: { + disableReactTree: false, + mouseEvent: "onClick", + touchEvent: "onTouchEnd", + content: "Click me, I will stay visible until you click outside.", + }, +}; +export default meta; +type Story = StoryObj<Args>; + +export const Basic: Story = { + render: (args: Args) => { + const [open, setOpen] = React.useState(false); + const handleClick = () => setOpen((p) => !p); + const handleClickAway = () => setOpen(false); + return ( + <ClickAwayListener + onClickAway={handleClickAway} + disableReactTree={args.disableReactTree} + mouseEvent={args.mouseEvent} + touchEvent={args.touchEvent} + > + <Box sx={{ position: "relative" }}> + <Button onClick={handleClick}>Toggle</Button> + {open && ( + <Box + sx={{ + border: 1, + p: 2, + bgcolor: "background.paper", + position: "absolute", + top: 44, + left: 0, + minWidth: 260, + }} + > + {args.content} + </Box> + )} + </Box> + </ClickAwayListener> + ); + }, +}; diff --git a/src/components/MUI/Utils/ClickAwayListener.tsx b/src/components/MUI/Utils/ClickAwayListener.tsx new file mode 100644 index 0000000..5640c88 --- /dev/null +++ b/src/components/MUI/Utils/ClickAwayListener.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiClickAwayListener from "@mui/material/ClickAwayListener"; + +export type ClickAwayListenerProps = React.ComponentProps< + typeof MuiClickAwayListener +>; + +export const ClickAwayListener = (props: ClickAwayListenerProps) => ( + <MuiClickAwayListener {...props} /> +); + +ClickAwayListener.displayName = "ClickAwayListener"; diff --git a/src/components/MUI/Utils/CssBaseline.stories.tsx b/src/components/MUI/Utils/CssBaseline.stories.tsx new file mode 100644 index 0000000..e705c98 --- /dev/null +++ b/src/components/MUI/Utils/CssBaseline.stories.tsx @@ -0,0 +1,37 @@ +import * as React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; +import { Typography } from "../DataDisplay/Typography"; +import { Box } from "../Layout/Box"; +import { CssBaseline } from "./CssBaseline"; + +type Args = React.ComponentProps<typeof CssBaseline>; + +const meta: Meta<Args> = { + title: "MUI/Utils/CssBaseline", + component: CssBaseline, + tags: ["autodocs"], + parameters: { layout: "padded" }, + argTypes: { + enableColorScheme: { control: "boolean" }, + children: { control: false }, + }, + args: { + enableColorScheme: false, + }, +}; +export default meta; +type Story = StoryObj<Args>; + +export const Basic: Story = { + render: (args: Args) => ( + <> + <CssBaseline {...args} /> + <Box sx={{ p: 2, bgcolor: "background.default", color: "text.primary" }}> + <Typography variant="h6">CssBaseline applied</Typography> + <Typography variant="body2"> + This area reflects baseline styles. + </Typography> + </Box> + </> + ), +}; diff --git a/src/components/MUI/Utils/CssBaseline.tsx b/src/components/MUI/Utils/CssBaseline.tsx new file mode 100644 index 0000000..9db7067 --- /dev/null +++ b/src/components/MUI/Utils/CssBaseline.tsx @@ -0,0 +1,8 @@ +import * as React from "react"; +import MuiCssBaseline from "@mui/material/CssBaseline"; + +export type CssBaselineProps = React.ComponentProps<typeof MuiCssBaseline>; + +export const CssBaseline = (props: CssBaselineProps) => ( + <MuiCssBaseline {...props} /> +); diff --git a/src/components/MUI/Utils/Modal.stories.tsx b/src/components/MUI/Utils/Modal.stories.tsx new file mode 100644 index 0000000..5ae4375 --- /dev/null +++ b/src/components/MUI/Utils/Modal.stories.tsx @@ -0,0 +1,76 @@ +import * as React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; +import { Modal } from "./Modal"; +import { Box } from "../Layout/Box"; +import { Typography } from "../DataDisplay/Typography"; +import { Button } from "../Inputs/Button"; + +type Args = React.ComponentProps<typeof Modal> & { + title?: string; + content?: string; +}; + +const meta: Meta<Args> = { + title: "MUI/Utils/Modal", + component: Modal, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + open: { control: false }, + onClose: { control: false }, + title: { control: "text" }, + content: { control: "text" }, + keepMounted: { control: "boolean" }, + hideBackdrop: { control: "boolean" }, + closeAfterTransition: { control: "boolean" }, + }, + args: { + title: "Text in a modal", + content: "Duis mollis, est non commodo luctus, nisi erat porttitor ligula.", + keepMounted: false, + hideBackdrop: false, + closeAfterTransition: false, + }, +}; +export default meta; +type Story = StoryObj<Args>; + +export const Basic: Story = { + render: (args: Args) => { + const [open, setOpen] = React.useState(false); + const style = { + position: "absolute", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)", + minWidth: 320, + bgcolor: "background.paper", + border: "1px solid", + boxShadow: 24, + p: 3, + }; + return ( + <> + <Button onClick={() => setOpen(true)}>Open modal</Button> + <Modal + open={open} + onClose={() => setOpen(false)} + keepMounted={args.keepMounted} + hideBackdrop={args.hideBackdrop} + closeAfterTransition={args.closeAfterTransition} + aria-labelledby="modal-title" + aria-describedby="modal-description" + > + <Box sx={style}> + <Typography id="modal-title" variant="h6"> + {args.title} + </Typography> + <Typography id="modal-description" sx={{ mt: 2 }}> + {args.content} + </Typography> + </Box> + </Modal> + </> + ); + }, +}; diff --git a/src/components/MUI/Utils/Modal.tsx b/src/components/MUI/Utils/Modal.tsx new file mode 100644 index 0000000..83a7fdb --- /dev/null +++ b/src/components/MUI/Utils/Modal.tsx @@ -0,0 +1,8 @@ +import * as React from "react"; +import MuiModal from "@mui/material/Modal"; + +export type ModalProps = React.ComponentProps<typeof MuiModal>; + +export const Modal = React.forwardRef<HTMLDivElement, ModalProps>( + (props, ref) => <MuiModal ref={ref} {...props} />, +); diff --git a/src/components/MUI/Utils/NoSsr.stories.tsx b/src/components/MUI/Utils/NoSsr.stories.tsx new file mode 100644 index 0000000..2301044 --- /dev/null +++ b/src/components/MUI/Utils/NoSsr.stories.tsx @@ -0,0 +1,53 @@ +import * as React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; +import { NoSsr } from "./NoSsr"; +import { Box } from "../Layout/Box"; + +type Args = React.ComponentProps<typeof NoSsr> & { + serverContent?: string; + clientContent?: string; +}; + +const meta: Meta<Args> = { + title: "MUI/Utils/NoSsr", + component: NoSsr, + tags: ["autodocs"], + parameters: { layout: "padded" }, + argTypes: { + defer: { control: "boolean" }, + fallback: { control: "text" }, + serverContent: { control: "text" }, + clientContent: { control: "text" }, + }, + args: { + defer: false, + fallback: null, + serverContent: "Server and Client", + clientContent: "Client only", + }, +}; +export default meta; +type Story = StoryObj<Args>; + +export const Basic: Story = { + render: (args: Args) => ( + <div> + <Box + sx={{ p: 2, bgcolor: "primary.main", color: "primary.contrastText" }} + > + {args.serverContent} + </Box> + <NoSsr defer={args.defer} fallback={args.fallback}> + <Box + sx={{ + p: 2, + bgcolor: "secondary.main", + color: "secondary.contrastText", + }} + > + {args.clientContent} + </Box> + </NoSsr> + </div> + ), +}; diff --git a/src/components/MUI/Utils/NoSsr.tsx b/src/components/MUI/Utils/NoSsr.tsx new file mode 100644 index 0000000..29f349b --- /dev/null +++ b/src/components/MUI/Utils/NoSsr.tsx @@ -0,0 +1,8 @@ +import * as React from "react"; +import MuiNoSsr from "@mui/material/NoSsr"; + +export type NoSsrProps = React.ComponentProps<typeof MuiNoSsr>; + +export const NoSsr = (props: NoSsrProps) => <MuiNoSsr {...props} />; + +NoSsr.displayName = "NoSsr"; diff --git a/src/components/MUI/Utils/Popover.stories.tsx b/src/components/MUI/Utils/Popover.stories.tsx new file mode 100644 index 0000000..49213bf --- /dev/null +++ b/src/components/MUI/Utils/Popover.stories.tsx @@ -0,0 +1,62 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import React from "react"; +import { Popover } from "./Popover"; +import { Button } from "../Inputs/Button"; + +const originMap = { + tl: { vertical: "top", horizontal: "left" }, + tc: { vertical: "top", horizontal: "center" }, + tr: { vertical: "top", horizontal: "right" }, + bl: { vertical: "bottom", horizontal: "left" }, + bc: { vertical: "bottom", horizontal: "center" }, + br: { vertical: "bottom", horizontal: "right" }, +} as const; + +const meta: Meta<typeof Popover> = { + title: "MUI/Utils/Popover", + component: Popover, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + anchorOrigin: { + control: "select", + options: Object.keys(originMap), + mapping: originMap, + }, + transformOrigin: { + control: "select", + options: Object.keys(originMap), + mapping: originMap, + }, + disablePortal: { control: "boolean" }, + }, + args: { + anchorOrigin: { vertical: "bottom", horizontal: "left" }, + transformOrigin: { vertical: "top", horizontal: "left" }, + disablePortal: false, + }, +}; +export default meta; +type Story = StoryObj<typeof meta>; + +export const Basic: Story = { + render: (args) => { + const [anchorEl, setAnchorEl] = React.useState<HTMLElement | null>(null); + const open = Boolean(anchorEl); + return ( + <div style={{ display: "flex", gap: 12 }}> + <Button onClick={(e) => setAnchorEl(e.currentTarget)}> + Open popover + </Button> + <Popover + {...args} + open={open} + anchorEl={anchorEl} + onClose={() => setAnchorEl(null)} + > + <div style={{ padding: 16 }}>Popover content</div> + </Popover> + </div> + ); + }, +}; diff --git a/src/components/MUI/Utils/Popover.tsx b/src/components/MUI/Utils/Popover.tsx new file mode 100644 index 0000000..35b52f7 --- /dev/null +++ b/src/components/MUI/Utils/Popover.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import MuiPopover, { + PopoverProps as MuiPopoverProps, +} from "@mui/material/Popover"; + +export type PopoverProps = MuiPopoverProps; + +export const Popover = React.forwardRef<HTMLDivElement, PopoverProps>( + (props, ref) => <MuiPopover ref={ref} {...props} />, +); + +Popover.displayName = "Popover"; diff --git a/src/components/MUI/Utils/Popper.stories.tsx b/src/components/MUI/Utils/Popper.stories.tsx new file mode 100644 index 0000000..b953b05 --- /dev/null +++ b/src/components/MUI/Utils/Popper.stories.tsx @@ -0,0 +1,87 @@ +import * as React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; +import { Popper, PopperProps } from "./Popper"; +import { Button } from "../Inputs/Button"; +import { Fade } from "./Transitions"; +import { Box } from "../Layout/Box"; + +type Args = { + placement?: PopperProps["placement"]; + disablePortal?: boolean; + keepMounted?: boolean; + transition?: boolean; + content?: string; +}; + +const meta: Meta<Args> = { + title: "MUI/Utils/Popper", + component: Popper, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + placement: { + control: "select", + options: [ + "bottom", + "top", + "right", + "left", + "bottom-start", + "bottom-end", + "top-start", + "top-end", + "right-start", + "right-end", + "left-start", + "left-end", + ], + }, + disablePortal: { control: "boolean" }, + keepMounted: { control: "boolean" }, + transition: { control: "boolean" }, + content: { control: "text" }, + }, + args: { + placement: "bottom", + disablePortal: false, + keepMounted: false, + transition: true, + content: "The content of the Popper.", + }, +}; +export default meta; +type Story = StoryObj<Args>; + +export const Basic: Story = { + render: (args: Args) => { + const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); + const open = Boolean(anchorEl); + const id = open ? "demo-popper" : undefined; + const handleClick = (event: React.MouseEvent<HTMLElement>) => + setAnchorEl(anchorEl ? null : event.currentTarget); + return ( + <> + <Button aria-describedby={id} type="button" onClick={handleClick}> + Toggle Popper + </Button> + <Popper + id={id} + open={open} + anchorEl={anchorEl} + placement={args.placement} + disablePortal={args.disablePortal} + keepMounted={args.keepMounted} + transition={args.transition} + > + {({ TransitionProps }) => ( + <Fade {...TransitionProps} timeout={250}> + <Box sx={{ border: 1, p: 1, bgcolor: "background.paper" }}> + {args.content} + </Box> + </Fade> + )} + </Popper> + </> + ); + }, +}; diff --git a/src/components/MUI/Utils/Popper.tsx b/src/components/MUI/Utils/Popper.tsx new file mode 100644 index 0000000..f0f477a --- /dev/null +++ b/src/components/MUI/Utils/Popper.tsx @@ -0,0 +1,8 @@ +import * as React from "react"; +import MuiPopper from "@mui/material/Popper"; + +export type PopperProps = React.ComponentProps<typeof MuiPopper>; + +export const Popper = React.forwardRef<HTMLDivElement, PopperProps>( + (props, ref) => <MuiPopper ref={ref} {...props} />, +); diff --git a/src/components/MUI/Utils/Portal.stories.tsx b/src/components/MUI/Utils/Portal.stories.tsx new file mode 100644 index 0000000..1d88069 --- /dev/null +++ b/src/components/MUI/Utils/Portal.stories.tsx @@ -0,0 +1,52 @@ +import * as React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; +import { Portal } from "./Portal"; +import { Button } from "../Inputs/Button"; +import { Box } from "../Layout/Box"; + +type Args = React.ComponentProps<typeof Portal> & { text?: string }; + +const meta: Meta<Args> = { + title: "MUI/Utils/Portal", + component: Portal, + tags: ["autodocs"], + parameters: { layout: "padded" }, + argTypes: { + disablePortal: { control: "boolean" }, + container: { control: false }, + children: { control: false }, + text: { control: "text" }, + }, + args: { + disablePortal: false, + text: "But I actually render here!", + }, +}; +export default meta; +type Story = StoryObj<Args>; + +export const Basic: Story = { + render: (args: Args) => { + const container = React.useRef<HTMLDivElement | null>(null); + const [show, setShow] = React.useState(false); + return ( + <> + <Button onClick={() => setShow((p) => !p)}> + {show ? "Unmount children" : "Mount children"} + </Button> + <Box sx={{ p: 1, my: 1, border: "1px solid" }}> + It looks like I will render here. + {show ? ( + <Portal + container={() => container.current!} + disablePortal={args.disablePortal} + > + <span>{args.text}</span> + </Portal> + ) : null} + </Box> + <Box sx={{ p: 1, my: 1, border: "1px solid" }} ref={container} /> + </> + ); + }, +}; diff --git a/src/components/MUI/Utils/Portal.tsx b/src/components/MUI/Utils/Portal.tsx new file mode 100644 index 0000000..1bc3ad5 --- /dev/null +++ b/src/components/MUI/Utils/Portal.tsx @@ -0,0 +1,8 @@ +import * as React from "react"; +import MuiPortal from "@mui/material/Portal"; + +export type PortalProps = React.ComponentProps<typeof MuiPortal>; + +export const Portal = (props: PortalProps) => <MuiPortal {...props} />; + +Portal.displayName = "Portal"; diff --git a/src/components/MUI/Utils/TextareaAutosize.stories.tsx b/src/components/MUI/Utils/TextareaAutosize.stories.tsx new file mode 100644 index 0000000..4001c01 --- /dev/null +++ b/src/components/MUI/Utils/TextareaAutosize.stories.tsx @@ -0,0 +1,30 @@ +import * as React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; +import { TextareaAutosize } from "./TextareaAutosize"; + +type Args = React.ComponentProps<typeof TextareaAutosize>; + +const meta: Meta<Args> = { + title: "MUI/Utils/TextareaAutosize", + component: TextareaAutosize, + tags: ["autodocs"], + parameters: { controls: { expanded: true }, layout: "padded" }, + argTypes: { + minRows: { control: { type: "number", min: 1 } }, + maxRows: { control: { type: "number", min: 1 } }, + placeholder: { control: "text" }, + defaultValue: { control: "text" }, + }, + args: { + minRows: 3, + maxRows: 6, + placeholder: "Type here...", + defaultValue: "", + }, +}; +export default meta; +type Story = StoryObj<Args>; + +export const Basic: Story = { + render: (args: Args) => <TextareaAutosize {...args} style={{ width: 260 }} />, +}; diff --git a/src/components/MUI/Utils/TextareaAutosize.tsx b/src/components/MUI/Utils/TextareaAutosize.tsx new file mode 100644 index 0000000..7faa77a --- /dev/null +++ b/src/components/MUI/Utils/TextareaAutosize.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import MuiTextareaAutosize from "@mui/material/TextareaAutosize"; + +export type TextareaAutosizeProps = React.ComponentProps< + typeof MuiTextareaAutosize +>; + +export const TextareaAutosize = (props: TextareaAutosizeProps) => ( + <MuiTextareaAutosize {...props} /> +); diff --git a/src/components/MUI/Utils/Transitions.stories.tsx b/src/components/MUI/Utils/Transitions.stories.tsx new file mode 100644 index 0000000..b2a3dba --- /dev/null +++ b/src/components/MUI/Utils/Transitions.stories.tsx @@ -0,0 +1,81 @@ +import * as React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; +import { Fade, Grow, Slide, Collapse, Zoom } from "./Transitions"; + +import FormControlLabel from "@mui/material/FormControlLabel"; +import { Box } from "../Layout/Box"; +import { Switch } from "../Inputs/Switch"; + +type ExtraArgs = { + show?: boolean; + text?: string; + direction?: "left" | "right" | "up" | "down"; +}; +type Args = ExtraArgs; + +const meta: Meta<Args> = { + title: "MUI/Utils/Transitions", + tags: ["autodocs"], + parameters: { layout: "padded" }, + argTypes: { + show: { control: "boolean" }, + text: { control: "text" }, + direction: { control: "select", options: ["left", "right", "up", "down"] }, + }, + args: { + show: true, + text: "Transition content", + direction: "up", + }, +}; +export default meta; +type Story = StoryObj<Args>; + +const Icon = (text: string) => ( + <Box + sx={{ + width: 120, + height: 60, + border: 1, + display: "flex", + alignItems: "center", + justifyContent: "center", + bgcolor: "background.paper", + }} + > + {text} + </Box> +); + +export const All: Story = { + render: (args: Args) => { + const [checked, setChecked] = React.useState<boolean>(args.show ?? true); + return ( + <Box sx={{ display: "grid", gap: 2 }}> + <FormControlLabel + control={ + <Switch + checked={checked} + onChange={(e) => setChecked(e.target.checked)} + /> + } + label="Show" + /> + <Box sx={{ display: "flex", gap: 2, flexWrap: "wrap" }}> + <Fade in={checked}>{Icon("Fade")}</Fade> + <Grow in={checked}>{Icon("Grow")}</Grow> + <Slide + in={checked} + direction={args.direction} + mountOnEnter + unmountOnExit + > + {Icon("Slide")} + </Slide> + <Collapse in={checked}>{Icon("Collapse")}</Collapse> + <Zoom in={checked}>{Icon("Zoom")}</Zoom> + </Box> + </Box> + ); + }, +}; diff --git a/src/components/MUI/Utils/Transitions.tsx b/src/components/MUI/Utils/Transitions.tsx new file mode 100644 index 0000000..1b89be2 --- /dev/null +++ b/src/components/MUI/Utils/Transitions.tsx @@ -0,0 +1,24 @@ +import * as React from "react"; +import MuiFade from "@mui/material/Fade"; +import MuiGrow from "@mui/material/Grow"; +import MuiSlide from "@mui/material/Slide"; +import MuiCollapse from "@mui/material/Collapse"; +import MuiZoom from "@mui/material/Zoom"; + +export type FadeProps = React.ComponentProps<typeof MuiFade>; +export type GrowProps = React.ComponentProps<typeof MuiGrow>; +export type SlideProps = React.ComponentProps<typeof MuiSlide>; +export type CollapseProps = React.ComponentProps<typeof MuiCollapse>; +export type ZoomProps = React.ComponentProps<typeof MuiZoom>; + +export const Fade = (props: FadeProps) => <MuiFade {...props} />; +export const Grow = (props: GrowProps) => <MuiGrow {...props} />; +export const Slide = (props: SlideProps) => <MuiSlide {...props} />; +export const Collapse = (props: CollapseProps) => <MuiCollapse {...props} />; +export const Zoom = (props: ZoomProps) => <MuiZoom {...props} />; + +Fade.displayName = "Fade"; +Grow.displayName = "Grow"; +Slide.displayName = "Slide"; +Collapse.displayName = "Collapse"; +Zoom.displayName = "Zoom"; diff --git a/src/components/MUI/Utils/UseMediaQuery.stories.tsx b/src/components/MUI/Utils/UseMediaQuery.stories.tsx new file mode 100644 index 0000000..54d5b88 --- /dev/null +++ b/src/components/MUI/Utils/UseMediaQuery.stories.tsx @@ -0,0 +1,43 @@ +import * as React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; +import { UseMediaQuery } from "./UseMediaQuery"; +import { useTheme } from "@mui/material/styles"; +import { Box } from "../Layout/Box"; + +type Args = React.ComponentProps<typeof UseMediaQuery> & { + useThemeBreakpoint?: boolean; + breakpoint?: "xs" | "sm" | "md" | "lg" | "xl"; +}; + +const meta: Meta<Args> = { + title: "MUI/Utils/useMediaQuery", + component: UseMediaQuery, + tags: ["autodocs"], + parameters: { layout: "padded" }, + argTypes: { + query: { control: "text" }, + useThemeBreakpoint: { control: "boolean" }, + breakpoint: { control: "select", options: ["xs", "sm", "md", "lg", "xl"] }, + }, + args: { + query: "(min-width:600px)", + useThemeBreakpoint: false, + breakpoint: "sm", + }, +}; +export default meta; +type Story = StoryObj<Args>; + +export const Basic: Story = { + render: (args: Args) => { + const theme = useTheme(); + const query = args.useThemeBreakpoint + ? theme.breakpoints.up(args.breakpoint || "sm") + : args.query; + return ( + <Box sx={{ display: "grid", gap: 1 }}> + <UseMediaQuery query={query} /> + </Box> + ); + }, +}; diff --git a/src/components/MUI/Utils/UseMediaQuery.tsx b/src/components/MUI/Utils/UseMediaQuery.tsx new file mode 100644 index 0000000..dbae50a --- /dev/null +++ b/src/components/MUI/Utils/UseMediaQuery.tsx @@ -0,0 +1,8 @@ +import useMediaQueryHook from "@mui/material/useMediaQuery"; + +export type UseMediaQueryProps = { query: string }; + +export const UseMediaQuery = ({ query }: UseMediaQueryProps) => { + const matches = useMediaQueryHook(query); + return <span>{`${query} matches: ${matches}`}</span>; +}; diff --git a/src/index.ts b/src/index.ts index 8277145..4c2c45a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,6 +22,7 @@ export * from "./components/helpers/jsonforms"; // themes export * from "./themes/BaseTheme"; export * from "./themes/DiamondTheme"; +export * from "./themes/DiamondDSTheme"; export * from "./themes/GenericTheme"; export * from "./themes/ThemeProvider"; export * from "./themes/ThemeManager"; diff --git a/src/storybook/Introduction.mdx b/src/storybook/Installation.mdx similarity index 98% rename from src/storybook/Introduction.mdx rename to src/storybook/Installation.mdx index 7113771..770c475 100644 --- a/src/storybook/Introduction.mdx +++ b/src/storybook/Installation.mdx @@ -1,7 +1,7 @@ -import packageJson from "../../package.json" +import packageJson from "../../package.json"; import { Meta } from "@storybook/blocks"; -<Meta title="Introduction" /> +<Meta title="Installation" /> <div className="sb-container"> <div className='sb-section-title'> @@ -14,6 +14,7 @@ import { Meta } from "@storybook/blocks"; Check out the list of components on the left. To use them, follow the instructions below. </div> + </div> <div className="sb-container"> @@ -111,8 +112,8 @@ import { Meta } from "@storybook/blocks"; } ``` </div> -</div> +</div> <div className="sb-container"> <div className='sb-section-title'> @@ -151,4 +152,5 @@ import { Meta } from "@storybook/blocks"; on GitHub. </div> + </div> diff --git a/src/storybook/about.mdx b/src/storybook/about.mdx new file mode 100644 index 0000000..c02e3b4 --- /dev/null +++ b/src/storybook/about.mdx @@ -0,0 +1,119 @@ +import { Meta } from "@storybook/blocks"; + +<Meta title="About" /> + +<div> + <h1>Scientific design system for Diamond</h1> + <p><strong>Version: Scientific React UI - v0.3.1-alpha.3</strong></p> + +{" "} +<p> + Diamond II brings major upgrades to our scientific capabilities, and with that + comes a growing ecosystem of tools used across beamlines, data acquisition, + analysis, and scientific support. +</p> + +{" "} +<p> + This design system gives us a shared foundation of components, patterns, and + visual rules so that every tool at Diamond feels coherent, predictable, and + efficient, in service of better science and smoother operations across the + facility. +</p> + +{" "} +<h2>Why we need a design system</h2> +<ul> + <li> + <strong>Modernise for Diamond II</strong>: redesign interfaces with clarity, + safety, and efficiency at the core. + </li> + <li> + <strong>Unify legacy systems</strong>: reduce inconsistent patterns, + behaviours, and visual languages across tools. + </li> + <li> + <strong>Reduce cognitive load</strong>: scientists and engineers move + between multiple systems; familiarity helps. + </li> + <li> + <strong>Accelerate delivery</strong>: shared components and patterns reduce + repeated work. + </li> + <li> + <strong>Future-proof</strong>: new tools start coherent and stay coherent. + </li> +</ul> + +{" "} +<h2>What the design system includes</h2> +<h3>Design assets</h3> +<ul> + <li> + <strong>Foundations</strong>: colour, typography, spacing, grid, interaction + states + </li> + <li> + <strong>Components</strong>: buttons, inputs, tables, tabs + </li> + <li> + <strong>Patterns</strong>: panels, configuration, monitoring, data browsing + </li> + <li> + <strong>Templates</strong>: pages, dashboards, details views + </li> +</ul> + +{" "} +<h3>Plus</h3> +<ul> + <li>Accessibility guidance</li> + <li>Processes and documentation</li> + <li>UX strategy and interaction principles</li> +</ul> + +{" "} +<h2>Where truth lives</h2> +<ul> + <li> + <strong>Figma</strong> is the design source of truth. + </li> + <li> + <strong>Storybook</strong> is the code source of truth. + </li> + <li> + We build on <strong>Material UI (MUI)</strong> in React, customised for + Diamond workflows. + </li> +</ul> + +{" "} +<h2>What’s different about scientific controls</h2> +<ul> + <li> + <strong>Time is scarce</strong> on beamlines; interruptions are costly. + </li> + <li> + <strong>Experiments are stateful</strong>; the UI must make state and + progress obvious. + </li> + <li> + <strong>Users may be visiting</strong> and working under pressure. + </li> + <li> + <strong>High-density data</strong> is normal: tables, logs, dashboards. + </li> + <li> + <strong>Safety-critical actions</strong> need clear signifiers, + confirmation, and recovery paths. + </li> +</ul> + + <h2>How to use this documentation</h2> + <ol> + <li>Start with Foundations to understand the rules.</li> + <li>Use Components for building blocks.</li> + <li>Use Patterns for repeatable workflows.</li> + <li>Treat docs as the shared contract: what we build, how it behaves, and why.</li> + </ol> +</div> diff --git a/src/storybook/accessibility/00-overview.mdx b/src/storybook/accessibility/00-overview.mdx new file mode 100644 index 0000000..7af1d45 --- /dev/null +++ b/src/storybook/accessibility/00-overview.mdx @@ -0,0 +1,99 @@ +import { Meta } from "@storybook/blocks"; + +<Meta title="Accessibility/Overview" /> + +<div> + <h1>Accessibility</h1> + +{" "} +<p> + Accessibility in the Diamond design system is not a checklist or a separate + mode. It’s a baseline for quality, clarity, and usability in complex + scientific tools. +</p> + +{" "} +<p> + Our goal is to make interfaces that are understandable, predictable, and + usable across a wide range of abilities, environments, and levels of fatigue. +</p> + +{" "} +<h2>Core principles</h2> +<ul> + <li> + <strong>Clarity over cleverness</strong>: interfaces should explain + themselves. + </li> + <li> + <strong>Predictable behaviour</strong>: similar things behave in similar + ways. + </li> + <li> + <strong>Multiple ways to perceive information</strong>: never rely on one + signal alone. + </li> + <li> + <strong>Low cognitive effort by default</strong>: minimise mental overhead. + </li> +</ul> + +{" "} +<h2>Do</h2> + +{" "} +<h3>Interactive elements</h3> +<ul> + <li>Ensure every interactive control has an accessible name.</li> + <li>Provide this via a visible label, `aria-label`, or `aria-labelledby`.</li> + <li>Make keyboard focus clearly visible at all times.</li> + <li> + Ensure disabled states are clearly distinguishable from enabled and default. + </li> +</ul> + +{" "} +<h3>Forms and inputs</h3> +<ul> + <li>Always associate inputs with labels (even if visually hidden).</li> + <li>Make error messages clear, specific, and actionable.</li> + <li>Associate errors programmatically with the relevant field.</li> +</ul> + +{" "} +<h3>Content and layout</h3> +<ul> + <li>Do not rely on colour alone to convey meaning.</li> + <li>Support icons with text or accessible names.</li> + <li>Use a logical, predictable reading order.</li> +</ul> + +{" "} +<h2>Don’t</h2> +<ul> + <li>Don’t use placeholder text as a replacement for labels.</li> + <li>Don’t hide important information in faint or decorative text.</li> + <li>Don’t introduce unexpected interaction patterns.</li> + <li>Don’t create dense, unbroken blocks of content.</li> +</ul> + +{" "} +<h2>Storybook guidance</h2> +<ul> + <li> + Simple component stories may be visually minimal, but they must still expose + an accessible name, or be explicitly documented as intentionally incomplete. + </li> + <li> + Accessibility warnings in Storybook are signals, not noise. Either resolve + them or document why they exist. + </li> +</ul> + + <h2>Quick sense check</h2> + <ul> + <li>Can this be used with a keyboard only?</li> + <li>Is its purpose clear without colour?</li> + <li>Would it still make sense when someone is tired or distracted?</li> + </ul> +</div> diff --git a/src/storybook/accessibility/01-colour-contrast.mdx b/src/storybook/accessibility/01-colour-contrast.mdx new file mode 100644 index 0000000..204f208 --- /dev/null +++ b/src/storybook/accessibility/01-colour-contrast.mdx @@ -0,0 +1,400 @@ +import { Meta } from "@storybook/blocks"; + +<Meta title="Accessibility/Colour contrast" /> + +<div> + <h1>Colour contrast</h1> + +<p> + Colour contrast affects readability, accuracy, and fatigue. In data-heavy + scientific tools, poor contrast slows users down and increases errors. +</p> + +<p> + We use both WCAG contrast ratios and APCA to balance compliance with + real-world readability. +</p> + +<h2>WCAG contrast</h2> + +<p> + WCAG 2.x contrast ratios provide a clear, widely accepted compliance baseline. +</p> + +<ul> + <li>Used to define minimum acceptable contrast.</li> + <li>Acts as a hard “do not go below” threshold.</li> + <li>Especially important for small text and critical UI.</li> +</ul> + +<h2>APCA contrast</h2> + +<p> + APCA (Advanced Perceptual Contrast Algorithm) models human perception more + closely. It accounts for font size, weight, and polarity (light-on-dark vs + dark-on-light). +</p> + +<ul> + <li>Used to tune readability in light and dark themes.</li> + <li>Helps avoid over-contrast that causes eye strain.</li> + <li>Works better for large text and dense information.</li> +</ul> + +<h2>How we use them together</h2> + +<p> + All text should meet WCAG minimums. APCA is then used to refine token values + for comfort and hierarchy. +</p> + + <div> + <h2>Colour-specific considerations (green, orange, and red)</h2> + + <p> + Some hues behave poorly for perceived contrast, even when WCAG 2 contrast ratios pass. + </p> + + <p> + Green, orange, and red are common examples because perceived contrast is affected by luminance, + surrounding colours, polarity (light-on-dark vs dark-on-light), and colour vision differences. + </p> + + <p> + A practical issue we see in real interfaces: WCAG 2 ratios can sometimes indicate that black + text on a saturated green, orange, or red background is “high contrast”, but in practice it + can feel low-contrast, vibrating, or tiring to read — especially for small text, thinner + fonts, or dense data. This gap between numeric ratios and human perception is one of the + problems APCA is designed to address. + </p> + + <ul> + <li> + <strong>Green</strong>: may appear muddy or unstable with dark text, and can be difficult + for users with common colour vision differences. + </li> + <li> + <strong>Orange</strong>: often looks washed out on light backgrounds or overly bright on + dark backgrounds, reducing legibility. + </li> + <li> + <strong>Red</strong>: can appear low-contrast or “vibrating” with dark text, and is + particularly problematic for error or alert states if not handled carefully. + </li> + </ul> + + <p> + When using these colours for status, emphasis, or meaning: + </p> + + <ul> + <li>Never rely on colour alone — pair with text, icons, or labels.</li> + <li>Test in both light and dark modes, at realistic sizes and weights.</li> + <li>Use APCA to assess perceived readability, not just WCAG 2 ratios.</li> + </ul> + + <p> + The examples below illustrate combinations that may pass WCAG 2 but still feel hard to read + in practice. + </p> + + <p><strong>WCAG 2 vs APCA: why “passes” can still look wrong</strong></p> + <p> + WCAG 2 contrast ratio is a useful baseline, but it can recommend text colours that feel + low-contrast in practice (especially on saturated greens/oranges/reds). APCA is designed + to better reflect perceived contrast and readability. + </p> + +{/* START EXAMPLE */} + +<style>{` /* Scoped demo styles so Storybook/theme doesn't interfere */ + .ds-a11y-demo, .ds-a11y-demo * { + box-sizing: border-box; + } + /* Reset common typography overrides that can change perceived contrast */ + .ds-a11y-demo p, + .ds-a11y-demo span, + .ds-a11y-demo strong, + .ds-a11y-demo li, + .ds-a11y-demo h3 { + margin: 0; + color: inherit; + letter-spacing: normal; + text-transform: none; + } + .ds-a11y-demo p { margin-bottom: 8px; } + .ds-a11y-demo ul { margin: 0; padding-left: 18px; } + .ds-a11y-grid { + display: grid; + gap: 16px; + max-width: 920px; + margin-top: 12px; + } + .ds-a11y-panels { + display: grid; + gap: 16px; + grid-template-columns: 1fr 1fr; + } + .ds-a11y-panel { + border-radius: 10px; + padding: 14px; + border: 1px solid rgba(0,0,0,0.12); + } + .ds-a11y-panel--light { + background: #ffffff; + color: #111111; + } + .ds-a11y-panel--dark { + background: #0b0f14; /* "inverse" surface */ + color: #f3f5f7; + border: 1px solid rgba(255,255,255,0.14); + } + .ds-a11y-row { + display: grid; + gap: 8px; + margin-top: 10px; + } + .ds-a11y-rowTitle { + font-weight: 700; + margin-bottom: 2px; + } + .ds-chipRow { + display: grid; + gap: 10px; + } + .ds-chipLabel { + font-size: 13px; + opacity: 0.9; + } + .ds-chip { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 10px 12px; + border-radius: 8px; + line-height: 1.2; + border: 1px solid rgba(0,0,0,0.12); + width: fit-content; + max-width: 100%; + } + .ds-a11y-panel--dark .ds-chip { + border: 1px solid rgba(255,255,255,0.14); + } + .ds-chipText { + font-size: 14px; + font-weight: 650; + } + /* Use CSS vars + !important so theme styles can’t override demo colours */ + .ds-chip[data-bg] { background: var(--bg) !important; } + .ds-chip[data-fg] { color: var(--fg) !important; } + .ds-note { + border-radius: 10px; + padding: 12px 14px; + border: 1px solid rgba(0,0,0,0.10); + } + .ds-a11y-panel--dark + .ds-note, + .ds-a11y-panel--dark .ds-note { + border: 1px solid rgba(255,255,255,0.14); + } + `}</style> + +<div className="ds-a11y-demo ds-a11y-grid"> + + <div className="ds-a11y-panels"> + {/* Light */} + <div className="ds-a11y-panel ds-a11y-panel--light"> + <p className="ds-a11y-rowTitle">Light surface</p> + + <div className="ds-a11y-row"> + <p><strong>Green</strong> bg `--ds-green-9` `#4CA65A`</p> + <div className="ds-chipRow"> + <div> + <p className="ds-chipLabel"><strong>WCAG 2 candidate</strong></p> + <div + className="ds-chip" + data-bg + data-fg + style={{ ['--bg']: '#4CA65A', ['--fg']: '#000000' }} + > + <span className="ds-chipText">Experiment complete · 12 files processed</span> + </div> + </div> + + <div> + <p className="ds-chipLabel"><strong>APCA candidate</strong> ✅</p> + <div + className="ds-chip" + data-bg + data-fg + style={{ ['--bg']: '#4CA65A', ['--fg']: '#FFFFFF' }} + > + <span className="ds-chipText">Experiment complete · 12 files processed</span> + </div> + </div> + </div> + </div> + + <div className="ds-a11y-row"> + <p><strong>Orange</strong> bg `--ds-orange-9` `#FF780A`</p> + <div className="ds-chipRow"> + <div> + <p className="ds-chipLabel"><strong>WCAG 2 candidate</strong></p> + <div className="ds-chip" data-bg data-fg style={{ ['--bg']: '#FF780A', ['--fg']: '#000000' }}> + <span className="ds-chipText">Beamline temperature near limit</span> + </div> + </div> + + <div> + <p className="ds-chipLabel"><strong>APCA candidate</strong> ✅</p> + <div className="ds-chip" data-bg data-fg style={{ ['--bg']: '#FF780A', ['--fg']: '#FFFFFF' }}> + <span className="ds-chipText">Beamline temperature near limit</span> + </div> + </div> + </div> + </div> + + <div className="ds-a11y-row"> + <p><strong>Red</strong> bg `--ds-red-9` `#E54D2E`</p> + <div className="ds-chipRow"> + <div> + <p className="ds-chipLabel"><strong>WCAG 2 candidate</strong></p> + <div className="ds-chip" data-bg data-fg style={{ ['--bg']: '#E54D2E', ['--fg']: '#000000' }}> + <span className="ds-chipText">Connection failed · retry required</span> + </div> + </div> + + <div> + <p className="ds-chipLabel"><strong>APCA candidate</strong> ✅</p> + <div className="ds-chip" data-bg data-fg style={{ ['--bg']: '#E54D2E', ['--fg']: '#FFFFFF' }}> + <span className="ds-chipText">Connection failed · retry required</span> + </div> + </div> + </div> + </div> + </div> + + {/* Dark / inverse */} + <div className="ds-a11y-panel ds-a11y-panel--dark"> + <p className="ds-a11y-rowTitle">Dark (inverse) surface</p> + + <div className="ds-a11y-row"> + <p><strong>Green</strong> bg `--ds-green-9` `#30A46C`</p> + <div className="ds-chipRow"> + <div> + <p className="ds-chipLabel"><strong>WCAG 2 candidate</strong></p> + <div className="ds-chip" data-bg data-fg style={{ ['--bg']: '#30A46C', ['--fg']: '#FFFFFF' }}> + <span className="ds-chipText">Experiment complete · 12 files processed</span> + </div> + </div> + + <div> + <p className="ds-chipLabel"><strong>APCA candidate</strong> ✅</p> + <div className="ds-chip" data-bg data-fg style={{ ['--bg']: '#30A46C', ['--fg']: '#000000' }}> + <span className="ds-chipText">Experiment complete · 12 files processed</span> + </div> + </div> + </div> + </div> + + <div className="ds-a11y-row"> + <p><strong>Orange</strong> bg `--ds-orange-9` `#F76B15`</p> + <div className="ds-chipRow"> + <div> + <p className="ds-chipLabel"><strong>WCAG 2 candidate</strong></p> + <div className="ds-chip" data-bg data-fg style={{ ['--bg']: '#F76B15', ['--fg']: '#000000' }}> + <span className="ds-chipText">Beamline temperature near limit</span> + </div> + </div> + + <div> + <p className="ds-chipLabel"><strong>APCA candidate</strong> ✅</p> + <div className="ds-chip" data-bg data-fg style={{ ['--bg']: '#F76B15', ['--fg']: '#FFFFFF' }}> + <span className="ds-chipText">Beamline temperature near limit</span> + </div> + </div> + </div> + </div> + + <div className="ds-a11y-row"> + <p><strong>Red</strong> bg `--ds-red-9` `#E54D2E`</p> + <div className="ds-chipRow"> + <div> + <p className="ds-chipLabel"><strong>WCAG 2 candidate</strong></p> + <div className="ds-chip" data-bg data-fg style={{ ['--bg']: '#E54D2E', ['--fg']: '#000000' }}> + <span className="ds-chipText">Connection failed · retry required</span> + </div> + </div> + + <div> + <p className="ds-chipLabel"><strong>APCA candidate</strong> ✅</p> + <div className="ds-chip" data-bg data-fg style={{ ['--bg']: '#E54D2E', ['--fg']: '#FFFFFF' }}> + <span className="ds-chipText">Connection failed · retry required</span> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + + <div className="ds-note"> + <p style={{ marginBottom: 6 }}><strong>How to use this</strong></p> + <ul> + <li>Use WCAG 2 as the baseline check, especially for small text.</li> + <li>Use APCA to validate perceived readability and comfort (particularly for saturated status colours).</li> + <li>Always pair colour with icons/text — never rely on colour alone for meaning.</li> + </ul> + </div> + </div> + +{/* END EXAMPLE */} + +<h2>Practical guidance</h2> +<ul> + <li> + <strong>Body text</strong>: prioritise APCA readability while meeting WCAG. + </li> + <li> + <strong>UI chrome</strong>: prioritise WCAG clarity and consistency. + </li> + <li> + <strong>Subtle text</strong>: only for non-essential information. + </li> + <li> + <strong>Disabled states</strong>: visually distinct but still readable where + meaning matters. + </li> +</ul> + +<h2>Common pitfalls</h2> +<ul> + <li>Reducing contrast to “de-emphasise” text that still carries meaning.</li> + <li>Relying on colour alone for status or validation.</li> + <li>Forgetting that contrast behaves differently in dark mode.</li> +</ul> + +<h2>When WCAG and APCA disagree</h2> +<ul> + <li>If WCAG fails, the colour must change.</li> + <li> + If WCAG passes but APCA indicates poor readability, adjust for comfort. + </li> + <li>For critical UI, readability always wins over subtlety.</li> +</ul> + +<h2>Future: WCAG 3 and APCA</h2> + +<p> + APCA is being developed as part of WCAG 3, which is still in progress. While + WCAG 2.x remains the formal standard today, WCAG 3 reflects a shift towards + perceptual models of contrast and readability. +</p> + +<p>Our approach reflects this transition:</p> + +<ul> + <li>WCAG 2.x is treated as the compliance baseline.</li> + <li>APCA is used to improve real-world readability and comfort.</li> + <li>This positions us closer to where accessibility standards are heading.</li> +</ul> +</div> diff --git a/src/storybook/accessibility/02-cognitive-and-learning.mdx b/src/storybook/accessibility/02-cognitive-and-learning.mdx new file mode 100644 index 0000000..91ed4b9 --- /dev/null +++ b/src/storybook/accessibility/02-cognitive-and-learning.mdx @@ -0,0 +1,151 @@ +import { Meta } from "@storybook/blocks"; + +<Meta title="Accessibility/Cognitive and learning" /> + +<div> + <h1>Cognitive and learning accessibility</h1> + +<p> + Accessibility is not only about vision or motor input. People differ in how + they process information, maintain focus, remember things, and recover from + errors. +</p> + +<p> + In complex scientific tools, these differences matter. Our responsibility is + to design systems that are usable, understandable, and forgiving across a wide + range of abilities and conditions. +</p> + +<h2>Experience, usability, and accessibility by design</h2> + +<p> + Improving accessibility is not just about adding new features. It also means + continuously improving the core experience: making it more intuitive, more + inclusive, and easier to use. +</p> + +<p> + Our users include people with different processing capabilities and + disabilities. We should consider these differences when designing interfaces, + interactions, and content — not as edge cases, but as part of normal usage. +</p> + +<h2>User processing capabilities to consider</h2> +<ul> + <li>Reading, skimming, and scanning content</li> + <li>Focus and sustained attention</li> + <li>Different memory types and memorisation strategies</li> +</ul> + +<h2>Types of disabilities and conditions</h2> +<p>Users may experience one or more of the following:</p> +<ul> + <li>Cognitive disabilities</li> + <li>Learning disabilities</li> + <li>Intellectual disability</li> + <li>Vision impairment (including colour blindness)</li> + <li>Deaf or hard of hearing</li> + <li>Physical disabilities</li> + <li>Mental health conditions</li> + <li>Acquired brain injury</li> + <li>Neurodiversity</li> +</ul> + +{" "} + +<p> + With this in mind, usability and accessibility should be treated as + foundational design qualities, not optional enhancements. +</p> + +{" "} + +<h2>Design objectives</h2> + +{" "} + +<p> + The W3C guidance on cognitive and learning disabilities is useful not only for + people with disabilities, but for most users. The objectives below are adapted + from that guidance and reflect how we aim to design Diamond tools. +</p> + +{" "} + +<h3>Help users understand what things are and how to use them</h3> +<ul> + <li>Use icons, symbols, terms, and patterns that are already familiar.</li> + <li> + Avoid inventing new interaction patterns without strong justification. + </li> + <li>Make purpose and behaviour obvious at first glance.</li> +</ul> + +<h3>Help users find what they need</h3> +<ul> + <li>Use clear structure, headings, and visual boundaries.</li> + <li>Keep navigation predictable and consistent.</li> + <li>Use layout and grouping to signal relationships.</li> +</ul> + +<h3>Use clear content</h3> +<ul> + <li>Prefer simple words and short sentences.</li> + <li>Break text into small, readable blocks.</li> + <li>Use clear images and diagrams where they add meaning.</li> +</ul> + +<h3>Help users avoid mistakes</h3> +<ul> + <li>Ask only for information that is genuinely required.</li> + <li>Prevent errors where possible, rather than reacting to them.</li> + <li>When errors occur, make recovery easy and explicit.</li> +</ul> + +<h3>Help users focus</h3> +<ul> + <li>Avoid unnecessary distractions.</li> + <li> + Use headings and structure to help users re-orient if context is lost. + </li> + <li>Provide breadcrumbs or clear navigation paths where appropriate.</li> +</ul> + +<h3>Provide help and support</h3> +<ul> + <li>Make it easy to access human help or support.</li> + <li>Offer multiple ways to understand content (text, visuals, summaries).</li> + <li>Use icons and visual cues to reinforce meaning, not replace it.</li> +</ul> + +<h3>Support adaptation and personalisation</h3> +<ul> + <li>Allow users to adjust preferences when possible.</li> + <li>Design so assistive technologies and extensions can work effectively.</li> + <li>Avoid blocking browser or OS-level accessibility features.</li> +</ul> + +<h3>Test with real users</h3> +<ul> + <li>Involve people with different disabilities in research and testing.</li> + <li>Include them in usability testing and design validation.</li> + <li>Treat their feedback as expert input.</li> +</ul> + +<h2>Applying this in Storybook</h2> +<ul> + <li>Is the component understandable without prior knowledge?</li> + <li>Does it rely on memory or hidden rules?</li> + <li>Is error recovery clear and forgiving?</li> + <li>Would this still make sense at the end of a long day?</li> +</ul> + + <h2>Further reading</h2> + <ul> + <li><a href="https://www.w3.org/TR/coga-usable/" target="_blank" rel="noopener noreferrer">Making Content Usable for People with Cognitive and Learning Disabilities</a></li> + <li><a href="https://www.w3.org/WAI/fundamentals/accessibility-usability-inclusion/" target="_blank" rel="noopener noreferrer">W3C: Accessibility, Usability, and Inclusion</a></li> + <li><a href="https://www.w3.org/TR/coga-usable/" target="_blank" rel="noopener noreferrer">Making Content Usable for People with Cognitive and Learning Disabilities</a></li> + <li><a href="https://uxplanet.org/how-human-memory-works-tips-for-ux-designers-12b14071bdf9" target="_blank" rel="noopener noreferrer">How Human Memory Works: Tips for UX Designers</a></li> + </ul> +</div> diff --git a/src/storybook/foundation/colours.mdx b/src/storybook/foundation/colours.mdx new file mode 100644 index 0000000..e03d3fd --- /dev/null +++ b/src/storybook/foundation/colours.mdx @@ -0,0 +1,642 @@ +import { Meta } from "@storybook/blocks"; + +<Meta title="Foundation/Colour" /> + +<style>{` + .ds-note { + margin: 12px 0 20px; + padding: 12px 14px; + border: 1px solid var(--ds-border-subtle, var(--ds-olive-6)); + background: var(--ds-bg-surface-1, var(--ds-olive-2)); + border-radius: 12px; + } + + .ds-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 14px; + margin: 14px 0 24px; + } + + .ds-swatch { + border: 1px solid var(--ds-border-subtle, var(--ds-olive-6)); + border-radius: 14px; + background: var(--ds-bg-paper, var(--ds-olive-1)); + overflow: hidden; + } + + .ds-swatch__chip { + height: 56px; + background: var(--swatch); + border-bottom: 1px solid var(--ds-border-subtle, var(--ds-olive-6)); + } + + .ds-swatch__body { + padding: 12px 12px 10px; + } + + .ds-swatch__name { + font-weight: 600; + margin: 0 0 6px; + color: var(--ds-olive-12); + } + + .ds-swatch__meta { + margin: 0; + padding-left: 16px; + color: var(--ds-olive-11); + font-size: 14px; + line-height: 20px; + } + + .ds-swatch__meta li { + margin: 2px 0; + list-style-type: none; + } + + .ds-row { + display: flex; + gap: 10px; + flex-wrap: wrap; + margin: 10px 0 0; + } + + .ds-pill { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 6px 10px; + border-radius: 999px; + border: 1px solid var(--ds-border-subtle, var(--ds-olive-6)); + background: var(--ds-bg-paper, var(--ds-olive-1)); + color: var(--ds-olive-12); + font-size: 13px; + line-height: 18px; + } + + .text-inverse { + color: var(--ds-olive-1); + } + + .ds-dot { + width: 12px; + height: 12px; + border-radius: 999px; + background: var(--dot); + border: 1px solid rgba(0,0,0,0.12); + display: inline-block; + } + + li .ds-dot { + margin-left: -16px; + margin-right: 8px; + } + + .ds-surface-demo { + border: 1px solid var(--ds-border-subtle, var(--ds-olive-6)); + border-radius: 14px; + background: var(--ds-bg-paper, var(--ds-olive-1)); + padding: 14px; + margin: 14px 0 24px; + } + + .ds-surface-card { + border: 1px solid var(--ds-border-subtle, var(--ds-olive-6)); + background: var(--ds-bg-surface-1, var(--ds-olive-2)); + border-radius: 12px; + padding: 12px; + } + + .ds-divider { + height: 1px; + background: var(--ds-border-subtle, var(--ds-olive-6)); + margin: 12px 0; + } + + .ds-text-demo p { + margin: 8px 0; + } + + .ds-overlay-demo { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + gap: 12px; + margin-top: 12px; + } + + .ds-overlay-tile { + border: 1px solid var(--ds-border-subtle, var(--ds-olive-6)); + border-radius: 12px; + background: var(--ds-bg-surface-1, var(--ds-olive-2)); + overflow: hidden; + } + + .ds-overlay-tile__top { + height: 56px; + background: var(--ds-bg-surface-1, var(--ds-olive-2)); + position: relative; + } + + .ds-overlay-tile__overlay { + position: absolute; + inset: 0; + background: var(--overlay); + } + + .ds-overlay-tile__body { + padding: 10px 12px; + color: var(--ds-olive-12); + font-size: 13px; + } + + .ds-guidelines h3 code { + font-weight: 500; + border: 1px solid rgb(236, 244, 249); + color: rgba(46, 52, 56, 0.9); + background-color: rgb(255, 255, 255); + margin: 0 2px; + padding: 3px 5px; + white-space: nowrap; + border-radius: 6px; + } +`}</style> + +<div> + <h1>Colour</h1> + +{" "} + +<p> + Our colour system is role-based and implemented through MUI theme tokens. + Values are provided as CSS variables (primitives + semantic “on-colour” + + overlays) so light/dark mode and future refinement remain consistent. The + current primitives and semantic variables live in + `diamond-colors-primitives.css`. +</p> + +<section className="ds-guidelines"> + <h2>How to use colour roles</h2> + <div className="ds-note"> + <h3><code>light</code> / <code>main</code></h3> + <p><strong>Role:</strong> Solid backgrounds and emphasis.</p> + <p><strong>Use for:</strong></p> + <ul> + <li>Buttons and primary actions</li> + <li>Active states (selected tabs, toggles, current step)</li> + <li>Strong accents and highlights</li> + </ul> + <p> + <strong>Rule:</strong> + If it feels like a control or an action, use <code>main</code> + (or <code>light</code> for calmer emphasis). + </p> + </div> + <div className="ds-note"> + <h3><code>bgCanvas</code> / <code>bgSurface*</code></h3> + <p><strong>Role:</strong> Light backgrounds and layout surfaces.</p> + <p><strong>Use for:</strong></p> + <ul> + <li>Page backgrounds (<code>bgCanvas</code>)</li> + <li>Panels, cards, grouped sections (<code>bgSurface1</code>, <code>bgSurface2</code>)</li> + <li>Containers behind inputs or tables</li> + </ul> + <p> + <strong>Rule:</strong> + If it feels like a surface you place things on, use <code>bg*</code>. + </p> + </div> + <div className="ds-note"> + <h3><code>dark</code> / <code>darker</code></h3> + <p><strong>Role:</strong> High-contrast foregrounds on light surfaces.</p> + <p><strong>Use for:</strong></p> + <ul> + <li>Primary and secondary text</li> + <li>Icons and glyphs</li> + <li>High-contrast borders on light backgrounds</li> + </ul> + <p> + <strong>Rule:</strong> + If it communicates meaning or information, use <code>dark</code> or <code>darker</code>. + </p> + </div> + <div className="ds-note"> + <p> + <strong>Heuristic:</strong><br /> + Background → <code>bg*</code><br /> + Control or action → <code>main</code> / <code>light</code><br /> + Text or icon → <code>dark</code> / <code>darker</code> + </p> + </div> + + <h2>How to use dividers and borders</h2> + <div className="ds-note"> + <h3><code>divider</code></h3> + <p><strong>Role:</strong> Framework-level structural separator (MUI).</p> + <p><strong>Use for:</strong></p> + <ul> + <li>MUI <code><Divider /></code></li> + <li>Table row separators</li> + <li>List separators</li> + <li>Menu separators</li> + <li>Default MUI table borders</li> + </ul> + <p> + <strong>Rule:</strong> + Use when MUI needs a neutral separator by default. + </p> + </div> + <div className="ds-note"> + <h3><code>border.subtle</code></h3> + <p><strong>Role:</strong> Structural, non-interactive boundaries.</p> + <p><strong>Use for:</strong></p> + <ul> + <li>Card edges</li> + <li>Panel outlines</li> + <li>Table grid lines</li> + <li>Section boundaries</li> + <li>Non-interactive containers</li> + </ul> + <p> + <strong>Rule:</strong> + If it structures space but should not attract attention, use <code>border.subtle</code>. + </p> + <h3><code>border.strong</code></h3> + <p><strong>Role:</strong> Interactive baseline.</p> + <p><strong>Use for:</strong></p> + <ul> + <li>Input outlines (resting)</li> + <li>Outlined buttons (resting)</li> + <li>Selectable cards</li> + <li>Interactive panels</li> + </ul> + <p> + <strong>Rule:</strong> + If something can be interacted with, its resting border should be <code>strong</code>. + </p> + <h3><code>border.emphasis</code></h3> + <p><strong>Role:</strong> Interactive emphasis and discovery.</p> + <p><strong>Use for:</strong></p> + <ul> + <li>Hover state for inputs and outlined controls</li> + <li>Drag targets</li> + <li>Drop zones</li> + <li>Highlighted or previewed containers</li> + </ul> + <p> + <strong>Rule:</strong> + If the UI is signalling “you’re about to interact with this”, use <code>border.emphasis</code>. + </p> + </div> + <div className="ds-note"> + <h3>Key principles</h3> + <ul> + <li> + <code>divider</code> maps to <code>border.subtle</code>, but they are not the same concept: + <ul> + <li><code>divider</code> = framework behaviour</li> + <li><code>border.subtle</code> = design intent</li> + </ul> + </li> + <li> + Borders communicate affordance: + <ul> + <li>Structure → <code>subtle</code></li> + <li>Interactivity → <code>strong</code></li> + <li>Intent / discovery → <code>emphasis</code></li> + </ul> + </li> + <li> + Focus should not rely on border strength alone — + use semantic colour (primary, error, etc.) and/or thickness. + </li> + </ul> + + <p> + <strong>DiamondDS rule:</strong><br /> + <em>Surfaces hold content, colours express meaning, dividers structure space, and borders signal interactivity.</em> + </p> + </div> +</section> + +{" "} + +<div className="ds-note"> + <strong>What changed:</strong> the palette now exposes more layers per intent + colour: ` lighter → light → main → dark → darker`, plus `*Channel` tokens for + alpha-based overlays. Also added `brand` colour scheme, fixed background colours +</div> + +{" "} + +<h2>MUI palette mapping (current)</h2> +<p> + These are the current top-level palette decisions used in our MUI theme. We + also define explicit `action.*` overlays to avoid Material’s default overlay + behaviour and keep interaction states consistent with our primitives. +</p> + + <div className="ds-grid"> + {/* Primary */} + <div className="ds-swatch" style={{ ['--swatch']: 'var(--ds-indigo-9)' }}> + <div className="ds-swatch__chip" /> + <div className="ds-swatch__body"> + <p className="ds-swatch__name">Primary</p> + <ul className="ds-swatch__meta"> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-indigo-7)' }} /> <strong>lighter</strong>: `--ds-indigo-7`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-indigo-8)' }} /> <strong>light</strong>: `--ds-indigo-8`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-indigo-9)' }} /> <strong>main</strong>: `--ds-indigo-9`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-indigo-10)' }} /> <strong>dark</strong>: `--ds-indigo-10`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-indigo-11)' }} /> <strong>darker</strong>: `--ds-indigo-11`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-indigo-12)' }} /> <strong>darkest</strong>: `--ds-indigo-12`</li> + <li><strong>contrast text</strong>: `--ds-fg-fixed-white`</li> + <li><strong>mainChannel</strong>: `--ds-indigo-9Channel`</li> + <li><strong>lightChannel</strong>: `--ds-indigo-8Channel`</li> + <li><strong>darkChannel</strong>: `--ds-indigo-10Channel`</li> + <li><strong>bgCanvas</strong>: <code>--ds-indigo-1</code></li> + <li><strong>bgSurface1</strong>: <code>--ds-indigo-2</code></li> + <li><strong>bgSurface2</strong>: <code>--ds-indigo-3</code></li> + </ul> + <div className="ds-row"> + <span className="ds-pill text-inverse" style={{ ['background']: 'var(--ds-indigo-9)' }} > main</span> + <span className="ds-pill text-inverse" style={{ ['background']: 'var(--ds-indigo-10)' }} > dark</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-indigo-1)' }} > canvas</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-indigo-2)' }} > surface1</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-indigo-3)' }} > surface2</span> + </div> + </div> + </div> + + {/* Secondary */} + <div className="ds-swatch" style={{ ['--swatch']: 'var(--ds-navy-9)' }}> + <div className="ds-swatch__chip" /> + <div className="ds-swatch__body"> + <p className="ds-swatch__name">Secondary</p> + <ul className="ds-swatch__meta"> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-navy-7)' }} /> <strong>lighter</strong>: `--ds-navy-7`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-navy-8)' }} /> <strong>light</strong>: `--ds-navy-8`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-navy-9)' }} /> <strong>main</strong>: `--ds-navy-9`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-navy-10)' }} /> <strong>dark</strong>: `--ds-navy-10`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-navy-11)' }} /> <strong>darker</strong>: `--ds-navy-11`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-navy-12)' }} /> <strong>darkest</strong>: `--ds-navy-12`</li> + <li><strong>contrast text</strong>: `--ds-fg-fixed-white`</li> + <li><strong>mainChannel</strong>: `--ds-navy-9Channel`</li> + <li><strong>lightChannel</strong>: `--ds-navy-8Channel`</li> + <li><strong>darkChannel</strong>: `--ds-navy-10Channel`</li> + <li><strong>bgCanvas</strong>: <code>--ds-navy-1</code></li> + <li><strong>bgSurface1</strong>: <code>--ds-navy-2</code></li> + <li><strong>bgSurface2</strong>: <code>--ds-navy-3</code></li> + </ul> + <div className="ds-row"> + <span className="ds-pill text-inverse" style={{ ['background']: 'var(--ds-navy-9)' }} > main</span> + <span className="ds-pill text-inverse" style={{ ['background']: 'var(--ds-navy-10)' }} > dark</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-navy-1)' }} > canvas</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-navy-2)' }} > surface1</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-navy-3)' }} > surface2</span> + </div> + </div> + </div> + + {/* Brand */} + <div className="ds-swatch" style={{ ['--swatch']: 'var(--ds-navy-10)' }}> + <div className="ds-swatch__chip" /> + <div className="ds-swatch__body"> + <p className="ds-swatch__name">Brand</p> + <ul className="ds-swatch__meta"> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-navy-10)' }} /> <strong>main</strong>: `--ds-navy-10`</li> + <li><strong>contrast text</strong>: `--ds-fg-fixed-white`</li> + </ul> + <div className="ds-row"> + <span className="ds-pill text-inverse" style={{ ['background']: 'var(--ds-navy-10)' }} > main</span> + </div> + </div> + </div> + + {/* Success */} + <div className="ds-swatch" style={{ ['--swatch']: 'var(--ds-green-9)' }}> + <div className="ds-swatch__chip" /> + <div className="ds-swatch__body"> + <p className="ds-swatch__name">Success</p> + <ul className="ds-swatch__meta"> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-green-7)' }} /> <strong>lighter</strong>: `--ds-green-7`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-green-8)' }} /> <strong>light</strong>: `--ds-green-8`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-green-9)' }} /> <strong>main</strong>: `--ds-green-9`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-green-10)' }} /> <strong>dark</strong>: `--ds-green-10`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-green-11)' }} /> <strong>darker</strong>: `--ds-green-11`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-green-12)' }} /> <strong>darkest</strong>: `--ds-green-12`</li> + <li><strong>contrast text</strong>: `--ds-fg-fixed-white`</li> + <li><strong>mainChannel</strong>: `--ds-green-9Channel`</li> + <li><strong>bgCanvas</strong>: <code>--ds-green-1</code></li> + <li><strong>bgSurface1</strong>: <code>--ds-green-2</code></li> + <li><strong>bgSurface2</strong>: <code>--ds-green-3</code></li> + </ul> + <div className="ds-row"> + <span className="ds-pill text-inverse" style={{ ['background']: 'var(--ds-green-9)' }} > main</span> + <span className="ds-pill text-inverse" style={{ ['background']: 'var(--ds-green-10)' }} > dark</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-green-1)' }} > canvas</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-green-2)' }} > surface1</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-green-3)' }} > surface2</span> + </div> + </div> + </div> + + {/* Warning */} + <div className="ds-swatch" style={{ ['--swatch']: 'var(--ds-orange-9)' }}> + <div className="ds-swatch__chip" /> + <div className="ds-swatch__body"> + <p className="ds-swatch__name">Warning</p> + <ul className="ds-swatch__meta"> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-orange-7)' }} /> <strong>lighter</strong>: `--ds-orange-7`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-orange-8)' }} /> <strong>light</strong>: `--ds-orange-8`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-orange-9)' }} /> <strong>main</strong>: `--ds-orange-9`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-orange-10)' }} /> <strong>dark</strong>: `--ds-orange-10`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-orange-11)' }} /> <strong>darker</strong>: `--ds-orange-11`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-orange-12)' }} /> <strong>darkest</strong>: `--ds-orange-12`</li> + <li><strong>contrast text</strong>: `--ds-fg-fixed-white`</li> + <li><strong>mainChannel</strong>: `--ds-orange-9Channel`</li> + <li><strong>bgCanvas</strong>: <code>--ds-orange-1</code></li> + <li><strong>bgSurface1</strong>: <code>--ds-orange-2</code></li> + <li><strong>bgSurface2</strong>: <code>--ds-orange-3</code></li> + </ul> + <div className="ds-row"> + <span className="ds-pill" style={{ ['background']: 'var(--ds-orange-9)' }} > main</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-orange-10)' }} > dark</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-orange-1)' }} > canvas</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-orange-2)' }} > surface1</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-orange-3)' }} > surface2</span> + </div> + </div> + </div> + + {/* Error */} + <div className="ds-swatch" style={{ ['--swatch']: 'var(--ds-red-9)' }}> + <div className="ds-swatch__chip" /> + <div className="ds-swatch__body"> + <p className="ds-swatch__name">Error</p> + <ul className="ds-swatch__meta"> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-red-7)' }} /> <strong>lighter</strong>: `--ds-red-7`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-red-8)' }} /> <strong>light</strong>: `--ds-red-8`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-red-9)' }} /> <strong>main</strong>: `--ds-red-9`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-red-10)' }} /> <strong>dark</strong>: `--ds-red-10`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-red-11)' }} /> <strong>darker</strong>: `--ds-red-11`</li> + <li><span className="ds-dot" style={{ ['--dot']: 'var(--ds-red-12)' }} /> <strong>darkest</strong>: `--ds-red-12`</li> + <li><strong>contrast text</strong>: `--ds-fg-fixed-white`</li> + <li><strong>mainChannel</strong>: `--ds-red-9Channel`</li> + <li><strong>bgCanvas</strong>: <code>--ds-red-1</code></li> + <li><strong>bgSurface1</strong>: <code>--ds-red-2</code></li> + <li><strong>bgSurface2</strong>: <code>--ds-red-3</code></li> + </ul> + <div className="ds-row"> + <span className="ds-pill text-inverse" style={{ ['background']: 'var(--ds-red-9)' }} > main</span> + <span className="ds-pill text-inverse" style={{ ['background']: 'var(--ds-red-10)' }} > dark</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-red-1)' }} > canvas</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-red-2)' }} > surface1</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-red-3)' }} > surface2</span> + </div> + </div> + </div> + +{/* Background surfaces */} + +<div className="ds-swatch" style={{ ["--swatch"]: "var(--ds-bg-paper)" }}> + <div className="ds-swatch__chip" /> + <div className="ds-swatch__body"> + <p className="ds-swatch__name">Background surfaces</p> + <ul className="ds-swatch__meta"> + <li> + <strong>default</strong>: <code>--ds-bg-canvas</code> + </li> + <li> + <strong>paper</strong>: <code>--ds-bg-paper</code> + </li> + <li> + <strong>surface1</strong>: <code>--ds-bg-surface-1</code> + </li> + <li> + <strong>surface2</strong>: <code>--ds-bg-surface-2</code> + </li> + <li> + <strong>outlinedBg</strong>: <code>--ds-bg-surface-2</code> + </li> + </ul> + <div className="ds-row"> + <span className="ds-pill" style={{ ['background']: 'var(--ds-bg-canvas)' }} > canvas</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-bg-paper)' }} > paper</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-bg-surface-1)' }} > surface1</span> + <span className="ds-pill" style={{ ['background']: 'var(--ds-bg-surface-2)' }} > surface2</span> + </div> + </div> +</div> + + {/* Divider and borders */} + <div className="ds-swatch" style={{ ['--swatch']: 'var(--ds-olive-6)' }}> + <div className="ds-swatch__chip" /> + <div className="ds-swatch__body"> + <p className="ds-swatch__name">Divider and borders</p> + <ul className="ds-swatch__meta"> + <li><strong>divider</strong>: `--ds-olive-6`</li> + <li><strong>Border subtle</strong>: `--ds-olive-6`</li> + <li><strong>Border strong</strong>: `--ds-olive-7`</li> + <li><strong>Border emphasis</strong>: `--ds-olive-8`</li> + </ul> + </div> + </div> + + </div> + +<h2>Surfaces, text, and dividers (quick visual check)</h2> +<div className="ds-surface-demo"> + <div className="ds-surface-card"> + <div className="ds-text-demo"> + <p style={{ color: "var(--ds-olive-12)" }}> + <strong>Text primary</strong> → `--ds-olive-12` + </p> + <p style={{ color: "var(--ds-olive-11)" }}> + Text secondary → `--ds-olive-11` + </p> + <p style={{ color: "var(--ds-olive-8)" }}>Text disabled → `--ds-olive-8`</p> + </div> + <div className="ds-divider" /> + <p style={{ margin: 0, color: "var(--ds-olive-11)" }}> + Canvas uses `--ds-olive-1` and surfaces use `--ds-olive-2`. Divider uses + `--ds-olive-6`. + </p> + </div> +</div> + +{" "} + +<h2>Interaction overlays (MUI action tokens)</h2> +<p> + We define `action.hover`, `action.selected`, `action.focus`, + `action.disabled`, and `action.disabledBackground` as explicit overlays + (`--ds-overlay-*`) so interaction states remain consistent across themes. +</p> + + <div className="ds-overlay-demo"> + <div className="ds-overlay-tile"> + <div className="ds-overlay-tile__top"> + <div className="ds-overlay-tile__overlay" style={{ ['--overlay']: 'var(--ds-overlay-hover)' }} /> + </div> + <div className="ds-overlay-tile__body"> + <ul className="ds-swatch__meta"> + <li><strong>hover</strong>: `--ds-overlay-hover`</li> + </ul> + </div> + </div> + + <div className="ds-overlay-tile"> + <div className="ds-overlay-tile__top"> + <div className="ds-overlay-tile__overlay" style={{ ['--overlay']: 'var(--ds-overlay-selected)' }} /> + </div> + <div className="ds-overlay-tile__body"> + <ul className="ds-swatch__meta"> + <li><strong>selected</strong>: `--ds-overlay-selected`</li> + </ul> + </div> + </div> + + <div className="ds-overlay-tile"> + <div className="ds-overlay-tile__top"> + <div className="ds-overlay-tile__overlay" style={{ ['--overlay']: 'var(--ds-overlay-focus)' }} /> + </div> + <div className="ds-overlay-tile__body"> + <ul className="ds-swatch__meta"> + <li><strong>focus</strong>: `--ds-overlay-focus`</li> + </ul> + </div> + </div> + + <div className="ds-overlay-tile"> + <div className="ds-overlay-tile__top"> + <div className="ds-overlay-tile__overlay" style={{ ['--overlay']: 'var(--ds-overlay-disabled)' }} /> + </div> + <div className="ds-overlay-tile__body"> + <ul className="ds-swatch__meta"> + <li><strong>disabled</strong>: `--ds-overlay-disabled`</li> + </ul> + </div> + </div> + + <div className="ds-overlay-tile"> + <div className="ds-overlay-tile__top"> + <div className="ds-overlay-tile__overlay" style={{ ['--overlay']: 'var(--ds-overlay-disabled-bg)' }} /> + </div> + <div className="ds-overlay-tile__body"> + <ul className="ds-swatch__meta"> + <li><strong>disabled background</strong>: `--ds-overlay-disabled-bg`</li> + </ul> + </div> + </div> + + </div> + +<h2>Component style example</h2> +<p> + Components can override specific behaviour where needed. For example, we set + `MuiButton` to use sentence case (no automatic uppercase). +</p> + + <div className="ds-note"> + <strong>MUI Button:</strong> `textTransform: none` + </div> +</div> diff --git a/src/storybook/foundation/typography.mdx b/src/storybook/foundation/typography.mdx new file mode 100644 index 0000000..45aa78a --- /dev/null +++ b/src/storybook/foundation/typography.mdx @@ -0,0 +1,77 @@ +import { Meta } from "@storybook/blocks"; + +<Meta title="Foundation/Typography" /> + +<div> + <h1>Typography</h1> + +<p> + Typography is a functional tool, not decoration. In scientific software, type + choices affect speed, accuracy, and confidence. +</p> + +{" "} + +<h2>Why it matters in Diamond tools</h2> +<ul> + <li> + <strong>Readability and legibility</strong>: clear at small sizes and on + imperfect displays. + </li> + <li> + <strong>Hierarchy</strong>: predictable structure for scanning data-heavy + screens. + </li> + <li> + <strong>Accessibility</strong>: legible sizing and contrast across contexts. + </li> + <li> + <strong>Reduced cognitive load</strong>: less visual noise, faster + decisions. + </li> + <li> + <strong>Works for dense data</strong>: tables, logs, dashboards, forms, + documentation. + </li> +</ul> + +{" "} + +<h2>Font roles</h2> +<ul> + <li> + <strong>Outfit</strong>: brand-forward headings and hero text. + </li> + <li> + <strong>Inter</strong>: default UI font for functional work (body, labels, + tables). + </li> + <li> + <strong>IBM Plex Mono</strong>: code, identifiers, aligned technical values. + </li> +</ul> + +<h2>Practical guidance</h2> + +<h3>Do</h3> +<ul> + <li>Keep hierarchy consistent across products and screens.</li> + <li>Prefer short, clear labels in controls and tables.</li> + <li>Make numbers and units easy to scan (alignment matters).</li> +</ul> + +{" "} + +<h3>Don’t</h3> +<ul> + <li>Don’t use brand typography for dense operational content.</li> + <li>Don’t “style your way” out of hierarchy problems.</li> + <li>Don’t hide important info in faint secondary text.</li> +</ul> + + <h2>Tokens (to be defined)</h2> + <p> + We’ll define tokens for display, body, and mono usage (e.g. `typography.display.*`, + `typography.body.*`, `typography.mono.*`) and reference them consistently. + </p> +</div> diff --git a/src/styles/diamondDS/diamond-colors-primitives.css b/src/styles/diamondDS/diamond-colors-primitives.css new file mode 100644 index 0000000..8975a93 --- /dev/null +++ b/src/styles/diamondDS/diamond-colors-primitives.css @@ -0,0 +1,830 @@ +:root { + --ds-black: #000000; + --ds-black-a1: #0000000d; + --ds-black-a2: #0000001a; + --ds-black-a3: #00000026; + --ds-black-a4: #0003; + --ds-black-a5: #0000004d; + --ds-black-a6: #0006; + --ds-black-a7: #00000080; + --ds-black-a8: #0009; + --ds-black-a9: #000000b3; + --ds-black-a10: #000c; + --ds-black-a11: #000000e6; + --ds-black-a12: #000000f2; + --ds-blackChannel: 0 0 0; + --ds-white: #ffffff; + --ds-white-a1: #ffffff0d; + --ds-white-a2: #ffffff1a; + --ds-white-a3: #ffffff26; + --ds-white-a4: #fff3; + --ds-white-a5: #ffffff4d; + --ds-white-a6: #fff6; + --ds-white-a7: #ffffff80; + --ds-white-a8: #fff9; + --ds-white-a9: #ffffffb3; + --ds-white-a10: #fffc; + --ds-white-a11: #ffffffe6; + --ds-white-a12: #fffffff2; + --ds-whiteChannel: 255 255 255; + } + + :root, .light, :root[data-mode="light"] { /*LIGHT MODE */ + /* Radix based colours */ + --ds-gray-1:#fcfcfc; + --ds-gray-2:#f9f9f9; + --ds-gray-3:#f0f0f0; + --ds-gray-4:#e8e8e8; + --ds-gray-5:#e0e0e0; + --ds-gray-6:#d9d9d9; + --ds-gray-7:#cecece; + --ds-gray-8:#bbb; + --ds-gray-9:#8d8d8d; + --ds-gray-10:#838383; + --ds-gray-11:#646464; + --ds-gray-12:#202020; + --ds-gray-a1:#00000003; + --ds-gray-a2:#00000006; + --ds-gray-a3:#0000000f; + --ds-gray-a4:#00000017; + --ds-gray-a5:#0000001f; + --ds-gray-a6:#00000026; + --ds-gray-a7:#00000031; + --ds-gray-a8:#00000044; + --ds-gray-a9:#00000072; + --ds-gray-a10:#0000007c; + --ds-gray-a11:#0000009b; + --ds-gray-a12:#000000df; + --ds-gray-1Channel: 252 252 252; + --ds-gray-2Channel: 249 249 249; + --ds-gray-3Channel: 240 240 240; + --ds-gray-4Channel: 232 232 232; + --ds-gray-5Channel: 224 224 224; + --ds-gray-6Channel: 217 217 217; + --ds-gray-7Channel: 206 206 206; + --ds-gray-8Channel: 187 187 187; + --ds-gray-9Channel: 141 141 141; + --ds-gray-10Channel: 131 131 131; + --ds-gray-11Channel: 100 100 100; + --ds-gray-12Channel: 32 32 32; + --ds-olive-1:#fcfdfc; + --ds-olive-2:#f8faf8; + --ds-olive-3:#eff1ef; + --ds-olive-4:#e7e9e7; + --ds-olive-5:#dfe2df; + --ds-olive-6:#d7dad7; + --ds-olive-7:#cccfcc; + --ds-olive-8:#b9bcb8; + --ds-olive-9:#898e87; + --ds-olive-10:#7f847d; + --ds-olive-11:#60655f; + --ds-olive-12:#1d211c; + --ds-olive-a1:#00550003; + --ds-olive-a2:#00490007; + --ds-olive-a3:#00200010; + --ds-olive-a4:#00160018; + --ds-olive-a5:#00180020; + --ds-olive-a6:#00140028; + --ds-olive-a7:#000f0033; + --ds-olive-a8:#040f0047; + --ds-olive-a9:#050f0078; + --ds-olive-a10:#040e0082; + --ds-olive-a11:#020a00a0; + --ds-olive-a12:#010600e3; + --ds-olive-1Channel: 252 253 252; + --ds-olive-2Channel: 248 250 248; + --ds-olive-3Channel: 239 241 239; + --ds-olive-4Channel: 231 233 231; + --ds-olive-5Channel: 223 226 223; + --ds-olive-6Channel: 215 218 215; + --ds-olive-7Channel: 204 207 204; + --ds-olive-8Channel: 185 188 184; + --ds-olive-9Channel: 137 142 135; + --ds-olive-10Channel: 127 132 125; + --ds-olive-11Channel: 96 101 95; + --ds-olive-12Channel: 29 33 28; + --ds-cyan-1: #FAFEFF; + --ds-cyan-2: #F1FBFC; + --ds-cyan-3: #E3F6F8; + --ds-cyan-4: #D4EFF3; + --ds-cyan-5: #C2E6EB; + --ds-cyan-6: #ACDBE1; + --ds-cyan-7: #8CCCD3; + --ds-cyan-8: #64BAC3; + --ds-cyan-9: #3A9FAC; + --ds-cyan-10: #009CA6; /* brand */ + --ds-cyan-11: #006873; + --ds-cyan-12: #003A40; + --ds-cyan-a1: #3A9FAC05; + --ds-cyan-a2: #3A9FAC0A; + --ds-cyan-a3: #3A9FAC10; + --ds-cyan-a4: #3A9FAC17; + --ds-cyan-a5: #3A9FAC1F; + --ds-cyan-a6: #3A9FAC27; + --ds-cyan-a7: #3A9FAC33; + --ds-cyan-a8: #3A9FAC47; + --ds-cyan-a9: #3A9FAC63; + --ds-cyan-a10: #3A9FAC7D; + --ds-cyan-a11: #3A9FACA2; + --ds-cyan-a12: #3A9FACDE; + --ds-cyan-1Channel: 250 254 255; + --ds-cyan-2Channel: 241 251 252; + --ds-cyan-3Channel: 227 246 248; + --ds-cyan-4Channel: 212 239 243; + --ds-cyan-5Channel: 194 230 235; + --ds-cyan-6Channel: 172 219 225; + --ds-cyan-7Channel: 140 204 211; + --ds-cyan-8Channel: 100 186 195; + --ds-cyan-9Channel: 58 159 172; + --ds-cyan-10Channel: 0 156 166; + --ds-cyan-11Channel: 0 104 115; + --ds-cyan-12Channel: 0 58 64; + --ds-green-1: #FBFEFB; + --ds-green-2: #F3FBF4; + --ds-green-3: #E6F6E8; + --ds-green-4: #D8F0DB; + --ds-green-5: #C9E9CC; + --ds-green-6: #B4DEB8; + --ds-green-7: #95CF9B; + --ds-green-8: #70BE78; + --ds-green-9: #4CA65A; + --ds-green-10: #008C15; /* brand */ + --ds-green-11: #00620F; + --ds-green-12: #003708; + --ds-green-a1: #4CA65A05; + --ds-green-a2: #4CA65A0A; + --ds-green-a3: #4CA65A10; + --ds-green-a4: #4CA65A17; + --ds-green-a5: #4CA65A1F; + --ds-green-a6: #4CA65A27; + --ds-green-a7: #4CA65A33; + --ds-green-a8: #4CA65A47; + --ds-green-a9: #4CA65A63; + --ds-green-a10: #4CA65A7D; + --ds-green-a11: #4CA65AA2; + --ds-green-a12: #4CA65ADE; + --ds-green-1Channel: 251 254 251; + --ds-green-2Channel: 243 251 244; + --ds-green-3Channel: 230 246 232; + --ds-green-4Channel: 216 240 219; + --ds-green-5Channel: 201 233 204; + --ds-green-6Channel: 180 222 184; + --ds-green-7Channel: 149 207 155; + --ds-green-8Channel: 112 190 120; + --ds-green-9Channel: 76 166 90; + --ds-green-10Channel: 0 140 21; + --ds-green-11Channel: 0 98 15; + --ds-green-12Channel: 0 55 8; + --ds-indigo-1:#fdfdfe; + --ds-indigo-2:#f7f9ff; + --ds-indigo-3:#edf2fe; + --ds-indigo-4:#e1e9ff; + --ds-indigo-5:#d2deff; + --ds-indigo-6:#c1d0ff; + --ds-indigo-7:#abbdf9; + --ds-indigo-8:#8da4ef; + --ds-indigo-9:#3e63dd; + --ds-indigo-10:#3358d4; + --ds-indigo-11:#3a5bc7; + --ds-indigo-12:#1f2d5c; + --ds-indigo-a1:#00008002; + --ds-indigo-a2:#0040ff08; + --ds-indigo-a3:#0047f112; + --ds-indigo-a4:#0044ff1e; + --ds-indigo-a5:#0044ff2d; + --ds-indigo-a6:#003eff3e; + --ds-indigo-a7:#0037ed54; + --ds-indigo-a8:#0034dc72; + --ds-indigo-a9:#0031d2c1; + --ds-indigo-a10:#002ec9cc; + --ds-indigo-a11:#002bb7c5; + --ds-indigo-a12:#001046e0; + --ds-indigo-1Channel: 253 253 254; + --ds-indigo-2Channel: 247 249 255; + --ds-indigo-3Channel: 237 242 254; + --ds-indigo-4Channel: 225 233 255; + --ds-indigo-5Channel: 210 222 255; + --ds-indigo-6Channel: 193 208 255; + --ds-indigo-7Channel: 171 189 249; + --ds-indigo-8Channel: 141 164 239; + --ds-indigo-9Channel: 62 99 221; + --ds-indigo-10Channel: 51 88 212; + --ds-indigo-11Channel: 58 91 199; + --ds-indigo-12Channel: 31 45 92; + --ds-lime-1:#fcfdfa; + --ds-lime-2:#f8faf3; + --ds-lime-3:#eef6d6; + --ds-lime-4:#e2f0bd; + --ds-lime-5:#d3e7a6; + --ds-lime-6:#c2da91; + --ds-lime-7:#abc978; + --ds-lime-8:#8db654; + --ds-lime-9:#bdee63; + --ds-lime-10:#b0e64c; + --ds-lime-11:#5c7c2f; + --ds-lime-12:#37401c; + --ds-lime-a1:#66990005; + --ds-lime-a2:#6b95000c; + --ds-lime-a3:#96c80029; + --ds-lime-a4:#8fc60042; + --ds-lime-a5:#81bb0059; + --ds-lime-a6:#72aa006e; + --ds-lime-a7:#61990087; + --ds-lime-a8:#559200ab; + --ds-lime-a9:#93e4009c; + --ds-lime-a10:#8fdc00b3; + --ds-lime-a11:#375f00d0; + --ds-lime-a12:#1e2900e3; + --ds-lime-1Channel: 252 253 250; + --ds-lime-2Channel: 248 250 243; + --ds-lime-3Channel: 238 246 214; + --ds-lime-4Channel: 226 240 189; + --ds-lime-5Channel: 211 231 166; + --ds-lime-6Channel: 194 218 145; + --ds-lime-7Channel: 171 201 120; + --ds-lime-8Channel: 141 182 84; + --ds-lime-9Channel: 189 238 99; + --ds-lime-10Channel: 176 230 76; + --ds-lime-11Channel: 92 124 47; + --ds-lime-12Channel: 55 64 28; + --ds-violet-1: #FEFBFF; + --ds-violet-2: #FCF4FD; + --ds-violet-3: #F9E7FB; + --ds-violet-4: #F5D9F7; + --ds-violet-5: #F0C9F1; + --ds-violet-6: #E7B2E8; + --ds-violet-7: #DA98DC; + --ds-violet-8: #C978CE; + --ds-violet-9: #C91FA8; + --ds-violet-10: #B0008E; /* brand */ + --ds-violet-11: #9A007A; + --ds-violet-12: #640055; + --ds-violet-a1: #B952BF05; + --ds-violet-a2: #B952BF0A; + --ds-violet-a3: #B952BF10; + --ds-violet-a4: #B952BF17; + --ds-violet-a5: #B952BF1F; + --ds-violet-a6: #B952BF27; + --ds-violet-a7: #B952BF33; + --ds-violet-a8: #B952BF47; + --ds-violet-a9: #B952BF63; + --ds-violet-a10: #B952BF7D; + --ds-violet-a11: #B952BFA2; + --ds-violet-a12: #B952BFDE; + --ds-violet-1Channel: 254 251 255; + --ds-violet-2Channel: 252 244 253; + --ds-violet-3Channel: 249 231 251; + --ds-violet-4Channel: 245 217 247; + --ds-violet-5Channel: 240 201 241; + --ds-violet-6Channel: 231 178 232; + --ds-violet-7Channel: 218 152 220; + --ds-violet-8Channel: 201 120 206; + --ds-violet-9Channel: 201 31 168; + --ds-violet-10Channel: 176 0 142; + --ds-violet-11Channel: 154 0 122; + --ds-violet-12Channel: 100 0 85; + --ds-orange-1: #FFF9F3; + --ds-orange-2: #FFF1E3; + --ds-orange-3: #FFE4CC; + --ds-orange-4: #FFD6B3; + --ds-orange-5: #FFC796; + --ds-orange-6: #FFB777; + --ds-orange-7: #FFA457; + --ds-orange-8: #FF8B2F; + --ds-orange-9: #FF780A; + --ds-orange-10: #FF6900; /* brand */ + --ds-orange-11: #A24600; + --ds-orange-12: #552300; + --ds-orange-a1: #FF780A05; + --ds-orange-a2: #FF780A0A; + --ds-orange-a3: #FF780A10; + --ds-orange-a4: #FF780A17; + --ds-orange-a5: #FF780A1F; + --ds-orange-a6: #FF780A27; + --ds-orange-a7: #FF780A33; + --ds-orange-a8: #FF780A47; + --ds-orange-a9: #FF780A63; + --ds-orange-a10: #FF780A7D; + --ds-orange-a11: #FF780AA2; + --ds-orange-a12: #FF780ADE; + --ds-orange-1Channel: 255 249 243; + --ds-orange-2Channel: 255 241 227; + --ds-orange-3Channel: 255 228 204; + --ds-orange-4Channel: 255 214 179; + --ds-orange-5Channel: 255 199 150; + --ds-orange-6Channel: 255 183 119; + --ds-orange-7Channel: 255 164 87; + --ds-orange-8Channel: 255 139 47; + --ds-orange-9Channel: 255 120 10; + --ds-orange-10Channel: 255 105 0; + --ds-orange-11Channel: 162 70 0; + --ds-orange-12Channel: 85 35 0; + --ds-red-1: #fffcfc; + --ds-red-2: #fff8f7; + --ds-red-3: #feebe7; + --ds-red-4: #ffdcd3; + --ds-red-5: #ffcdc2; + --ds-red-6: #fdbdaf; + --ds-red-7: #f5a898; + --ds-red-8: #ec8e7b; + --ds-red-9: #e54d2e; + --ds-red-10: #E10600; /* brand */ + --ds-red-11: #d13415; + --ds-red-12: #5c271f; + --ds-red-a1: #ff000003; + --ds-red-a2: #ff200008; + --ds-red-a3: #f52b0018; + --ds-red-a4: #ff35002c; + --ds-red-a5: #ff2e003d; + --ds-red-a6: #f92d0050; + --ds-red-a7: #e7280067; + --ds-red-a8: #db250084; + --ds-red-a9: #df2600d1; + --ds-red-a10: #d72400da; + --ds-red-a11: #cd2200ea; + --ds-red-a12: #460900e0; + --ds-red-1Channel: 255 252 252; + --ds-red-2Channel: 255 239 239; + --ds-red-3Channel: 255 226 225; + --ds-red-4Channel: 255 212 210; + --ds-red-5Channel: 255 195 193; + --ds-red-6Channel: 255 174 171; + --ds-red-7Channel: 255 144 141; + --ds-red-8Channel: 247 111 106; + --ds-red-9Channel: 229 75 69; + --ds-red-10Channel: 225 6 0; + --ds-red-11Channel: 150 4 0; + --ds-red-12Channel: 75 2 0; + --ds-yellow-1:#fdfdf9; + --ds-yellow-2:#fefce9; + --ds-yellow-3:#fffab8; + --ds-yellow-4:#fff394; + --ds-yellow-5:#ffe770; + --ds-yellow-6:#f3d768; + --ds-yellow-7:#e4c767; + --ds-yellow-8:#d5ae39; + --ds-yellow-9:#ffe629; + --ds-yellow-10:#FCD021; /* brand */ + --ds-yellow-11:#9e6c00; + --ds-yellow-12:#473b1f; + --ds-yellow-a1:#aaaa0006; + --ds-yellow-a2:#f4dd0016; + --ds-yellow-a3:#ffee0047; + --ds-yellow-a4:#ffe3016b; + --ds-yellow-a5:#ffd5008f; + --ds-yellow-a6:#ebbc0097; + --ds-yellow-a7:#d2a10098; + --ds-yellow-a8:#c99700c6; + --ds-yellow-a9:#ffe100d6; + --ds-yellow-a10:#FCD021; + --ds-yellow-a11:#9e6c00; + --ds-yellow-a12:#2e2000e0; + --ds-yellow-1Channel: 253 253 249; + --ds-yellow-2Channel: 254 252 233; + --ds-yellow-3Channel: 255 250 184; + --ds-yellow-4Channel: 255 243 148; + --ds-yellow-5Channel: 255 231 112; + --ds-yellow-6Channel: 243 215 104; + --ds-yellow-7Channel: 228 199 103; + --ds-yellow-8Channel: 213 174 57; + --ds-yellow-9Channel: 255 230 41; + --ds-yellow-10Channel: 255 220 0; + --ds-yellow-11Channel: 158 108 0; + --ds-yellow-12Channel: 71 59 31; + /* Diamond Brand Blue */ + --ds-navy-1: #F9FAFD; + --ds-navy-2: #EFF1F7; + --ds-navy-3: #E0E2ED; + --ds-navy-4: #D0D4E2; + --ds-navy-5: #BEC3D4; + --ds-navy-6: #A9AFC3; + --ds-navy-7: #9196AF; + --ds-navy-8: #777C98; + --ds-navy-9: #586084; + --ds-navy-10: #202945; /* brand */ + --ds-navy-11: #586084; + --ds-navy-12: #202945; /* brand */ + --ds-navy-a1: #58608405; + --ds-navy-a2: #5860840A; + --ds-navy-a3: #58608410; + --ds-navy-a4: #58608417; + --ds-navy-a5: #5860841F; + --ds-navy-a6: #58608427; + --ds-navy-a7: #58608433; + --ds-navy-a8: #58608447; + --ds-navy-a9: #58608463; + --ds-navy-a10: #5860847D; + --ds-navy-a11: #58608463; + --ds-navy-a12: #5860847D; + --ds-navy-1Channel: 249 250 253; + --ds-navy-2Channel: 239 241 247; + --ds-navy-3Channel: 224 226 237; + --ds-navy-4Channel: 208 212 226; + --ds-navy-5Channel: 190 195 212; + --ds-navy-6Channel: 169 175 195; + --ds-navy-7Channel: 145 150 175; + --ds-navy-8Channel: 119 124 152; + --ds-navy-9Channel: 88 96 132; + --ds-navy-10Channel: 32 41 69; + --ds-navy-11Channel: 88 96 132; + --ds-navy-12Channel: 32 41 69; + } + .dark, :root[data-mode="dark"] { /* Dark Mode */ + /* Radix based colours */ + --ds-gray-1:#111; + --ds-gray-2:#191919; + --ds-gray-3:#222; + --ds-gray-4:#2a2a2a; + --ds-gray-5:#313131; + --ds-gray-6:#3a3a3a; + --ds-gray-7:#484848; + --ds-gray-8:#606060; + --ds-gray-9:#6e6e6e; + --ds-gray-10:#7b7b7b; + --ds-gray-11:#b4b4b4; + --ds-gray-12:#eee; + --ds-gray-a1:#0000; + --ds-gray-a2:#ffffff09; + --ds-gray-a3:#ffffff12; + --ds-gray-a4:#ffffff1b; + --ds-gray-a5:#ffffff22; + --ds-gray-a6:#ffffff2c; + --ds-gray-a7:#ffffff3b; + --ds-gray-a8:#ffffff55; + --ds-gray-a9:#ffffff64; + --ds-gray-a10:#ffffff72; + --ds-gray-a11:#ffffffaf; + --ds-gray-a12:#ffffffed; + --ds-gray-1Channel: 17 17 17; + --ds-gray-2Channel: 25 25 25; + --ds-gray-3Channel: 34 34 34; + --ds-gray-4Channel: 42 42 42; + --ds-gray-5Channel: 49 49 49; + --ds-gray-6Channel: 58 58 58; + --ds-gray-7Channel: 72 72 72; + --ds-gray-8Channel: 96 96 96; + --ds-gray-9Channel: 110 110 110; + --ds-gray-10Channel: 123 123 123; + --ds-gray-11Channel: 180 180 180; + --ds-gray-12Channel: 238 238 238; + --ds-olive-1:#111210; + --ds-olive-2:#181917; + --ds-olive-3:#212220; + --ds-olive-4:#282a27; + --ds-olive-5:#2f312e; + --ds-olive-6:#383a36; + --ds-olive-7:#454843; + --ds-olive-8:#5c625b; + --ds-olive-9:#687066; + --ds-olive-10:#767d74; + --ds-olive-11:#afb5ad; + --ds-olive-12:#eceeec; + --ds-olive-a1:#0000; + --ds-olive-a2:#f1f2f008; + --ds-olive-a3:#f4f5f312; + --ds-olive-a4:#f3fef21a; + --ds-olive-a5:#f2fbf122; + --ds-olive-a6:#f4faed2c; + --ds-olive-a7:#f2fced3b; + --ds-olive-a8:#edfdeb57; + --ds-olive-a9:#ebfde766; + --ds-olive-a10:#f0fdec74; + --ds-olive-a11:#f6fef4b0; + --ds-olive-a12:#fdfffded; + --ds-olive-1Channel: 17 18 16; + --ds-olive-2Channel: 24 25 23; + --ds-olive-3Channel: 33 34 32; + --ds-olive-4Channel: 40 42 39; + --ds-olive-5Channel: 47 49 46; + --ds-olive-6Channel: 56 58 54; + --ds-olive-7Channel: 69 72 67; + --ds-olive-8Channel: 92 98 91; + --ds-olive-9Channel: 104 112 102; + --ds-olive-10Channel: 118 125 116; + --ds-olive-11Channel: 175 181 173; + --ds-olive-12Channel: 236 238 236; + --ds-cyan-1:#0b161a; + --ds-cyan-2:#101b20; + --ds-cyan-3:#082c36; + --ds-cyan-4:#003848; + --ds-cyan-5:#004558; + --ds-cyan-6:#045468; + --ds-cyan-7:#12677e; + --ds-cyan-8:#11809c; + --ds-cyan-9:#00a2c7; + --ds-cyan-10:#23afd0; + --ds-cyan-11:#4ccce6; + --ds-cyan-12:#b6ecf7; + --ds-cyan-a1:#0091f70a; + --ds-cyan-a2:#02a7f211; + --ds-cyan-a3:#00befd28; + --ds-cyan-a4:#00baff3b; + --ds-cyan-a5:#00befd4d; + --ds-cyan-a6:#00c7fd5e; + --ds-cyan-a7:#14cdff75; + --ds-cyan-a8:#11cfff95; + --ds-cyan-a9:#00cfffc3; + --ds-cyan-a10:#28d6ffcd; + --ds-cyan-a11:#52e1fee5; + --ds-cyan-a12:#bbf3fef7; + --ds-cyan-1Channel: 11 22 26; + --ds-cyan-2Channel: 16 27 32; + --ds-cyan-3Channel: 8 44 54; + --ds-cyan-4Channel: 0 56 72; + --ds-cyan-5Channel: 0 69 88; + --ds-cyan-6Channel: 4 84 104; + --ds-cyan-7Channel: 18 103 126; + --ds-cyan-8Channel: 17 128 156; + --ds-cyan-9Channel: 0 162 199; + --ds-cyan-10Channel: 35 175 208; + --ds-cyan-11Channel: 76 204 230; + --ds-cyan-12Channel: 182 236 247; + --ds-green-1:#0e1512; + --ds-green-2:#121b17; + --ds-green-3:#132d21; + --ds-green-4:#113b29; + --ds-green-5:#174933; + --ds-green-6:#20573e; + --ds-green-7:#28684a; + --ds-green-8:#2f7c57; + --ds-green-9:#30a46c; + --ds-green-10:#33b074; + --ds-green-11:#3dd68c; + --ds-green-12:#b1f1cb; + --ds-green-a1:#00de4505; + --ds-green-a2:#29f99d0b; + --ds-green-a3:#22ff991e; + --ds-green-a4:#11ff992d; + --ds-green-a5:#2bffa23c; + --ds-green-a6:#44ffaa4b; + --ds-green-a7:#50fdac5e; + --ds-green-a8:#54ffad73; + --ds-green-a9:#44ffa49e; + --ds-green-a10:#43fea4ab; + --ds-green-a11:#46fea5d4; + --ds-green-a12:#bbffd7f0; + --ds-green-1Channel: 14 21 18; + --ds-green-2Channel: 18 27 23; + --ds-green-3Channel: 19 45 33; + --ds-green-4Channel: 17 59 41; + --ds-green-5Channel: 23 73 51; + --ds-green-6Channel: 32 87 62; + --ds-green-7Channel: 40 104 74; + --ds-green-8Channel: 47 124 87; + --ds-green-9Channel: 48 164 108; + --ds-green-10Channel: 51 176 116; + --ds-green-11Channel: 61 214 140; + --ds-green-12Channel: 177 241 203; + --ds-indigo-1:#11131f; + --ds-indigo-2:#141726; + --ds-indigo-3:#182449; + --ds-indigo-4:#1d2e62; + --ds-indigo-5:#253974; + --ds-indigo-6:#304384; + --ds-indigo-7:#3a4f97; + --ds-indigo-8:#435db1; + --ds-indigo-9:#3e63dd; + --ds-indigo-10:#5472e4; + --ds-indigo-11:#9eb1ff; + --ds-indigo-12:#d6e1ff; + --ds-indigo-a1:#1133ff0f; + --ds-indigo-a2:#3354fa17; + --ds-indigo-a3:#2f62ff3c; + --ds-indigo-a4:#3566ff57; + --ds-indigo-a5:#4171fd6b; + --ds-indigo-a6:#5178fd7c; + --ds-indigo-a7:#5a7fff90; + --ds-indigo-a8:#5b81feac; + --ds-indigo-a9:#4671ffdb; + --ds-indigo-a10:#5c7efee3; + --ds-indigo-a11:#9eb1ff; + --ds-indigo-a12:#d6e1ff; + --ds-indigo-1Channel: 17 19 31; + --ds-indigo-2Channel: 20 23 38; + --ds-indigo-3Channel: 24 36 73; + --ds-indigo-4Channel: 29 46 98; + --ds-indigo-5Channel: 37 57 116; + --ds-indigo-6Channel: 48 67 132; + --ds-indigo-7Channel: 58 79 151; + --ds-indigo-8Channel: 67 93 177; + --ds-indigo-9Channel: 62 99 221; + --ds-indigo-10Channel: 84 114 228; + --ds-indigo-11Channel: 158 177 255; + --ds-indigo-12Channel: 214 225 255; + --ds-lime-1:#11130c; + --ds-lime-2:#151a10; + --ds-lime-3:#1f2917; + --ds-lime-4:#29371d; + --ds-lime-5:#334423; + --ds-lime-6:#3d522a; + --ds-lime-7:#496231; + --ds-lime-8:#577538; + --ds-lime-9:#bdee63; + --ds-lime-10:#d4ff70; + --ds-lime-11:#bde56c; + --ds-lime-12:#e3f7ba; + --ds-lime-a1:#11bb0003; + --ds-lime-a2:#78f7000a; + --ds-lime-a3:#9bfd4c1a; + --ds-lime-a4:#a7fe5c29; + --ds-lime-a5:#affe6537; + --ds-lime-a6:#b2fe6d46; + --ds-lime-a7:#b6ff6f57; + --ds-lime-a8:#b6fd6d6c; + --ds-lime-a9:#caff69ed; + --ds-lime-a10:#d4ff70; + --ds-lime-a11:#d1fe77e4; + --ds-lime-a12:#e9febff7; + --ds-lime-1Channel: 17 19 12; + --ds-lime-2Channel: 21 26 16; + --ds-lime-3Channel: 31 41 23; + --ds-lime-4Channel: 41 55 29; + --ds-lime-5Channel: 51 68 35; + --ds-lime-6Channel: 61 82 42; + --ds-lime-7Channel: 73 98 49; + --ds-lime-8Channel: 87 117 56; + --ds-lime-9Channel: 189 238 99; + --ds-lime-10Channel: 212 255 112; + --ds-lime-11Channel: 189 229 108; + --ds-lime-12Channel: 227 247 186; + --ds-orange-1:#17120e; + --ds-orange-2:#1e160f; + --ds-orange-3:#331e0b; + --ds-orange-4:#462100; + --ds-orange-5:#562800; + --ds-orange-6:#66350c; + --ds-orange-7:#7e451d; + --ds-orange-8:#a35829; + --ds-orange-9:#f76b15; + --ds-orange-10:#ff801f; + --ds-orange-11:#ffa057; + --ds-orange-12:#ffe0c2; + --ds-orange-a1:#ec360007; + --ds-orange-a2:#fe6d000e; + --ds-orange-a3:#fb6a0025; + --ds-orange-a4:#ff590039; + --ds-orange-a5:#ff61004a; + --ds-orange-a6:#fd75045c; + --ds-orange-a7:#ff832c75; + --ds-orange-a8:#fe84389d; + --ds-orange-a9:#fe6d15f7; + --ds-orange-a10:#ff801f; + --ds-orange-a11:#ffa057; + --ds-orange-a12:#ffe0c2; + --ds-orange-1Channel: 23 18 14; + --ds-orange-2Channel: 30 22 15; + --ds-orange-3Channel: 51 30 11; + --ds-orange-4Channel: 70 33 0; + --ds-orange-5Channel: 86 40 0; + --ds-orange-6Channel: 102 53 12; + --ds-orange-7Channel: 126 69 29; + --ds-orange-8Channel: 163 88 41; + --ds-orange-9Channel: 247 107 21; + --ds-orange-10Channel: 255 128 31; + --ds-orange-11Channel: 255 160 87; + --ds-orange-12Channel: 255 224 194; + --ds-violet-1:#181118; + --ds-violet-2:#201320; + --ds-violet-3:#351a35; + --ds-violet-4:#451d47; + --ds-violet-5:#512454; + --ds-violet-6:#5e3061; + --ds-violet-7:#734079; + --ds-violet-8:#92549c; + --ds-violet-9:#ab4aba; + --ds-violet-10:#b658c4; + --ds-violet-11:#e796f3; + --ds-violet-12:#f4d4f4; + --ds-violet-a1:#f112f108; + --ds-violet-a2:#f22ff211; + --ds-violet-a3:#fd4cfd27; + --ds-violet-a4:#f646ff3a; + --ds-violet-a5:#f455ff48; + --ds-violet-a6:#f66dff56; + --ds-violet-a7:#f07cfd70; + --ds-violet-a8:#ee84ff95; + --ds-violet-a9:#e961feb6; + --ds-violet-a10:#ed70ffc0; + --ds-violet-a11:#f19cfef3; + --ds-violet-a12:#feddfef4; + --ds-violet-1Channel: 24 17 24; + --ds-violet-2Channel: 32 19 32; + --ds-violet-3Channel: 53 26 53; + --ds-violet-4Channel: 69 29 71; + --ds-violet-5Channel: 81 36 84; + --ds-violet-6Channel: 94 48 97; + --ds-violet-7Channel: 115 64 121; + --ds-violet-8Channel: 146 84 156; + --ds-violet-9Channel: 171 74 186; + --ds-violet-10Channel: 182 88 196; + --ds-violet-11Channel: 231 150 243; + --ds-violet-12Channel: 244 212 244; + --ds-red-1: #181111; + --ds-red-2: #1f1513; + --ds-red-3: #391714; + --ds-red-4: #4e1511; + --ds-red-5: #5e1c16; + --ds-red-6: #6e2920; + --ds-red-7: #853a2d; + --ds-red-8: #ac4d39; + --ds-red-10: #ec6142; + --ds-red-11: #ff977d; + --ds-red-12: #fbd3cb; + --ds-red-a1: #f1121208; + --ds-red-a2: #ff55330f; + --ds-red-a3: #ff35232b; + --ds-red-a4: #fd201142; + --ds-red-a5: #fe332153; + --ds-red-a6: #ff4f3864; + --ds-red-a7: #fd644a7d; + --ds-red-a8: #fe6d4ea7; + --ds-red-a9: #fe5431e4; + --ds-red-a10: #ff6847eb; + --ds-red-a11: #ff977d; + --ds-red-a12: #ffd6cefb; + --ds-red-1Channel: 25 17 17; + --ds-red-2Channel: 32 19 20; + --ds-red-3Channel: 59 18 25; + --ds-red-4Channel: 80 15 28; + --ds-red-5Channel: 97 22 35; + --ds-red-6Channel: 114 35 45; + --ds-red-7Channel: 140 51 58; + --ds-red-8Channel: 181 69 72; + --ds-red-9Channel: 229 72 77; + --ds-red-10Channel: 236 93 94; + --ds-red-11Channel: 255 149 146; + --ds-red-12Channel: 255 209 217; + --ds-yellow-1:#14120b; + --ds-yellow-2:#1b180f; + --ds-yellow-3:#2d2305; + --ds-yellow-4:#362b00; + --ds-yellow-5:#433500; + --ds-yellow-6:#524202; + --ds-yellow-7:#665417; + --ds-yellow-8:#836a21; + --ds-yellow-9:#ffe629; + --ds-yellow-10:#ffff57; + --ds-yellow-11:#f5e147; + --ds-yellow-12:#f6eeb4; + --ds-yellow-a1:#d1510004; + --ds-yellow-a2:#f9b4000b; + --ds-yellow-a3:#ffaa001e; + --ds-yellow-a4:#fdb70028; + --ds-yellow-a5:#febb0036; + --ds-yellow-a6:#fec40046; + --ds-yellow-a7:#fdcb225c; + --ds-yellow-a8:#fdca327b; + --ds-yellow-a9:#ffe629; + --ds-yellow-a10:#ffff57; + --ds-yellow-a11:#fee949f5; + --ds-yellow-a12:#fef6baf6; + --ds-yellow-1Channel: 20 18 11; + --ds-yellow-2Channel: 27 24 15; + --ds-yellow-3Channel: 45 35 5; + --ds-yellow-4Channel: 54 43 0; + --ds-yellow-5Channel: 67 53 0; + --ds-yellow-6Channel: 82 66 2; + --ds-yellow-7Channel: 102 84 23; + --ds-yellow-8Channel: 131 106 33; + --ds-yellow-9Channel: 255 230 41; + --ds-yellow-10Channel: 255 255 87; + --ds-yellow-11Channel: 245 225 71; + --ds-yellow-12Channel: 246 238 180; + /* Diamond Brand Blue */ + --ds-navy-1: #070910; + --ds-navy-2: #0B0E17; + --ds-navy-3: #101521; + --ds-navy-4: #141A2B; + --ds-navy-5: #192034; + --ds-navy-6: #1D263F; + --ds-navy-7: #202945; /* brand sits here in dark ramp */ + --ds-navy-8: #273352; + --ds-navy-9: #5F678D; + --ds-navy-10: #7983AF; + --ds-navy-11: #9ca9ce; + --ds-navy-12: #d5ddf0; + --ds-navy-a1: #32406405; + --ds-navy-a2: #3240640A; + --ds-navy-a3: #32406410; + --ds-navy-a4: #32406417; + --ds-navy-a5: #3240641F; + --ds-navy-a6: #32406427; + --ds-navy-a7: #32406433; + --ds-navy-a8: #32406447; + --ds-navy-a9: #32406463; + --ds-navy-a10: #3240647D; + --ds-navy-a11: #324064A2; + --ds-navy-a12: #324064DE; + --ds-navy-1Channel: 7 9 16; /* #070910 */ + --ds-navy-2Channel: 11 14 23; /* #0b0e17 */ + --ds-navy-3Channel: 16 21 33; /* #101521 */ + --ds-navy-4Channel: 20 26 43; /* #141a2b */ + --ds-navy-5Channel: 25 32 52; /* #192034 */ + --ds-navy-6Channel: 29 38 63; /* #1d263f */ + --ds-navy-7Channel: 32 41 69; /* #202945 (brand) */ + --ds-navy-8Channel: 39 51 82; /* #273352 */ + --ds-navy-9Channel: 95 103 141; /* #324064 */ + --ds-navy-10Channel: 121 131 175; + --ds-navy-11Channel: 156 169 206; /* #9ca9ce */ + --ds-navy-12Channel: 213 221 240; /* #d5ddf0 */ + } \ No newline at end of file diff --git a/src/styles/diamondDS/diamond-tokens-semantic.css b/src/styles/diamondDS/diamond-tokens-semantic.css new file mode 100644 index 0000000..416fc4b --- /dev/null +++ b/src/styles/diamondDS/diamond-tokens-semantic.css @@ -0,0 +1,74 @@ +:root { /* Semantic tokens that can be defined once */ + /* Borders */ + --ds-border-subtle: var(--ds-olive-6); /* Structural, non-interactive */ + --ds-border-emphasis: var(--ds-olive-7); /* Interactive baseline */ + --ds-border-strong: var(--ds-olive-8); /* Interactive emphasis */ + /* Borders for intent states */ + --ds-border-emphasis-primary: var(--ds-indigo-7); + --ds-border-emphasis-secondary: var(--ds-navy-7); + --ds-border-emphasis-success: var(--ds-green-7); + --ds-border-emphasis-warning: var(--ds-orange-7); + --ds-border-emphasis-error: var(--ds-red-7); + --ds-border-emphasis-info: var(--ds-indigo-7); + --ds-border-strong-primary: var(--ds-indigo-8); + --ds-border-strong-secondary: var(--ds-navy-8); + --ds-border-strong-success: var(--ds-green-8); + --ds-border-strong-warning: var(--ds-orange-8); + --ds-border-strong-error: var(--ds-red-8); + --ds-border-strong-info: var(--ds-indigo-8); + + /* Background tokens */ + --ds-bg-canvas: var(--ds-olive-1); + --ds-bg-paper: var(--ds-white); + --ds-bg-surface-1: var(--ds-olive-2); + --ds-bg-surface-2: var(--ds-olive-3); + + --ds-bg-interactive-rest: var(--ds-olive-3); + --ds-bg-interactive-hover: var(--ds-olive-4); + + /* Text hierarchy tokens */ + --ds-fg-primary: var(--ds-olive-12); + --ds-fg-secondary: var(--ds-olive-11); + --ds-fg-tertiary: var(--ds-olive-10); + + /* Disabled tokens */ + --ds-fg-disabled: var(--ds-olive-8); + --ds-border-disabled: var(--ds-olive-6); + --ds-bg-disabled: var(--ds-olive-a3); +} + +:root, .light, :root[data-mode="light"] { /* Light mode */ + /* On-colour tokens */ + --ds-fg-fixed-white: var(--ds-white); /* Always white */ + --ds-fg-fixed-black: var(--ds-black); /* Always black */ + --ds-fg-inverse: var(--ds-white); /* White (light) → Black (dark) */ + --ds-fg-default: var(--ds-black); /* Black (light) → White (dark) */ + + --ds-overlay-hover: rgba(0, 0, 0, 0.06); + --ds-overlay-selected: rgba(0, 0, 0, 0.10); + --ds-overlay-focus: rgba(0, 0, 0, 0.12); + --ds-overlay-disabled: rgba(0, 0, 0, 0.26); + --ds-overlay-disabled-bg: rgba(0, 0, 0, 0.06); + + --ds-bg-brand: var(--ds-navy-10); /* Diamond Brand Blue */ +} + +.dark, :root[data-mode="dark"] { /* dark mode semantic overrides */ + /* On-colour tokens */ + --ds-fg-fixed-white: var(--ds-white); /* Always white */ + --ds-fg-fixed-black: var(--ds-black); /* Always black */ + --ds-fg-inverse: var(--ds-black); /* White (light) → Black (dark) */ + --ds-fg-default: var(--ds-white); /* Black (light) → White (dark) */ + + --ds-bg-brand: var(--ds-navy-7); /* Diamond Brand Blue */ + + --ds-overlay-hover: rgba(255, 255, 255, 0.06); + --ds-overlay-selected: rgba(255, 255, 255, 0.10); + --ds-overlay-focus: rgba(255, 255, 255, 0.12); + --ds-overlay-disabled: rgba(255, 255, 255, 0.30); + --ds-overlay-disabled-bg: rgba(255, 255, 255, 0.08); + + /* Paper (main surface override) */ + --ds-bg-paper: var(--ds-olive-2); + +} \ No newline at end of file diff --git a/src/themes/DiamondDSTheme.ts b/src/themes/DiamondDSTheme.ts new file mode 100644 index 0000000..4ccf7cd --- /dev/null +++ b/src/themes/DiamondDSTheme.ts @@ -0,0 +1,776 @@ +import "../styles/diamondDS/diamond-colors-primitives.css"; +import "../styles/diamondDS/diamond-tokens-semantic.css"; + +import type {} from "@mui/material/themeCssVarsAugmentation"; +import { createTheme } from "@mui/material/styles"; +import type { Theme } from "@mui/material/styles"; +import type { CSSObject } from "@mui/material/styles"; + +import type { ButtonProps } from "@mui/material/Button"; +import type { ChipProps } from "@mui/material/Chip"; +import type { CheckboxProps } from "@mui/material/Checkbox"; +import type { InputProps } from "@mui/material/Input"; +import type { FilledInputProps } from "@mui/material/FilledInput"; +import type { OutlinedInputProps } from "@mui/material/OutlinedInput"; + +import { mergeThemeOptions } from "./ThemeManager"; + +import logoImageLight from "../public/diamond/logo-light.svg"; +import logoImageDark from "../public/diamond/logo-dark.svg"; +import logoShort from "../public/diamond/logo-short.svg"; + +import React from "react"; +import { + DsCheckboxBlankIcon, + DsCheckboxCheckedIcon, + DsCheckboxIndeterminateIcon, +} from "./icons"; +import { light } from "@mui/material/styles/createPalette"; + +type OverrideArgs<OwnerState = unknown> = { + ownerState: OwnerState; + theme: Theme; +}; +type ThemeOnlyArgs = { theme: Theme }; + +/** MUI module augmentation for custom properties */ +declare module "@mui/material/styles" { + interface TypeBackground { + default: string; + paper: string; + surface1?: string; + surface2?: string; + } + + interface Palette { + brand?: PaletteColor; + + border: { + subtle: string; + emphasis: string; + strong: string; + }; + } + + interface PaletteOptions { + brand?: SimplePaletteColorOptions; + + border?: { + subtle?: string; + emphasis?: string; + strong?: string; + }; + } + + interface PaletteColor { + lighter?: string; + darkest?: string; + darker?: string; + mainChannel?: string; + lightChannel?: string; + darkChannel?: string; + + bgCanvas?: string; + bgSurface1?: string; + bgSurface2?: string; + } + + interface SimplePaletteColorOptions { + lighter?: string; + darkest?: string; + darker?: string; + mainChannel?: string; + lightChannel?: string; + darkChannel?: string; + + bgCanvas?: string; + bgSurface1?: string; + bgSurface2?: string; + } + + interface TypeText { + placeholder?: string; + placeholderFocus?: string; + } +} + +export type DSMode = "light" | "dark"; + +/** + * Prefer vars-backed palette (CSS variables) when present, otherwise fall back to palette. + * This prevents “default MUI hex” leaking into overrides when vars are available. + */ +type MuiIntent = "primary" | "secondary" | "error" | "warning" | "info" | "success"; +function resolveIntentPalette(theme: Theme, colour: MuiIntent) { + const t = theme as any; + return t.vars?.palette?.[colour] ?? (theme.palette as any)[colour]; +} + +export const createMuiTheme = (mode: DSMode): Theme => { + const DiamondDSThemeOptions = mergeThemeOptions({ + typography: { + fontFamily: [ + "Inter Variable", + "Inter", + "system-ui", + "-apple-system", + '"Segoe UI"', + "Roboto", + "Helvetica", + "Arial", + "sans-serif", + ].join(","), + }, + + logos: { + normal: { + src: mode === "dark" ? (logoImageDark ?? logoImageLight) : logoImageLight, + srcDark: logoImageDark ?? logoImageLight, + alt: "Diamond Light Source Logo", + width: "100", + }, + short: { + src: logoShort, + alt: "Diamond Light Source Logo", + width: "35", + }, + }, + + palette: { + mode, + + // Prevent "Material dark overlays" by defining action tokens from primitives + action: { + hover: "var(--ds-overlay-hover)", + selected: "var(--ds-overlay-selected)", + focus: "var(--ds-overlay-focus)", + disabled: "var(--ds-overlay-disabled)", + disabledBackground: "var(--ds-overlay-disabled-bg)", + + selectedChannel: undefined, + + hoverOpacity: 0.12, + selectedOpacity: 0.16, + disabledOpacity: 0.38, + focusOpacity: 0.16, + }, + + text: { + primary: "var(--ds-olive-12)", // main text, input value + secondary: "var(--ds-olive-11)", // secondary text, helper text, labels + disabled: "var(--ds-olive-9)", // disabled text + + primaryChannel: "var(--ds-olive-12Channel)", + secondaryChannel: "var(--ds-olive-11Channel)", + + placeholder: "var(--ds-olive-10)", // default hint text (if not secondary) + placeholderFocus: "var(--ds-olive-9)", // optional, calmer on focus + }, + + background: { + default: "var(--ds-bg-canvas)", // page background + paper: "var(--ds-bg-paper)", // cards, sheets, menus, etc. + surface1: "var(--ds-bg-surface-1)", // e.g. cards + surface2: "var(--ds-bg-surface-2)", // e.g. inputs, outlined containers + + defaultChannel: "var(--ds-olive-1Channel)", // for calculating hover/active states in components like Button + paperChannel: "var(--ds-whiteChannel)", // for overlays on paper (e.g. popover backdrop) + }, + + primaryChannel: "var(--ds-indigo-9Channel)", // for calculating hover/active states in components like Button + + divider: "var(--ds-border-subtle)", // Framework-level structural separator + dividerInverse: "var(--ds-white-a4)", + dividerChannel: "var(--ds-olive-6Channel)", + + border: { + subtle: "var(--ds-border-subtle)", // Structural, non-interactive boundaries + emphasis: "var(--ds-border-emphasis)", // Interactive baseline + strong: "var(--ds-border-strong)", // Interactive hover + }, + + primary: { + lighter: "var(--ds-indigo-7)", + light: "var(--ds-indigo-8)", + main: "var(--ds-indigo-9)", + dark: "var(--ds-indigo-10)", + darker: "var(--ds-indigo-11)", + darkest: "var(--ds-indigo-12)", + contrastText: "var(--ds-fg-fixed-white)", + + mainChannel: "var(--ds-indigo-9Channel)", + lightChannel: "var(--ds-indigo-8Channel)", + darkChannel: "var(--ds-indigo-10Channel)", + + bgCanvas: "var(--ds-indigo-1)", + bgSurface1: "var(--ds-indigo-2)", + bgSurface2: "var(--ds-indigo-3)", + }, + + secondary: { + lighter: "var(--ds-navy-7)", + light: "var(--ds-navy-8)", + main: "var(--ds-navy-9)", + dark: "var(--ds-navy-10)", + darker: "var(--ds-navy-11)", + darkest: "var(--ds-navy-12)", + contrastText: "var(--ds-fg-fixed-white)", + + mainChannel: "var(--ds-navy-9Channel)", + lightChannel: "var(--ds-navy-8Channel)", + darkChannel: "var(--ds-navy-10Channel)", + + bgCanvas: "var(--ds-navy-1)", + bgSurface1: "var(--ds-navy-2)", + bgSurface2: "var(--ds-navy-3)", + }, + + brand: { + main: "var(--ds-bg-brand)", // navy-10 Stays the same on light/dark modes + light: "var(--ds-navy-9)", + contrastText: "var(--ds-fg-fixed-white)", + }, + + error: { + lighter: "var(--ds-red-7)", + light: "var(--ds-red-8)", + main: "var(--ds-red-9)", + dark: "var(--ds-red-10)", + darker: "var(--ds-red-11)", + darkest: "var(--ds-red-12)", + contrastText: "var(--ds-fg-fixed-white)", + + mainChannel: "var(--ds-red-9Channel)", + lightChannel: "var(--ds-red-8Channel)", + darkChannel: "var(--ds-red-10Channel)", + + bgCanvas: "var(--ds-red-1)", + bgSurface1: "var(--ds-red-2)", + bgSurface2: "var(--ds-red-3)", + }, + + warning: { + lighter: "var(--ds-orange-7)", + light: "var(--ds-orange-8)", + main: "var(--ds-orange-9)", + dark: "var(--ds-orange-10)", + darker: "var(--ds-orange-11)", + darkest: "var(--ds-orange-12)", + contrastText: "var(--ds-fg-fixed-white)", + + mainChannel: "var(--ds-orange-9Channel)", + lightChannel: "var(--ds-orange-8Channel)", + darkChannel: "var(--ds-orange-10Channel)", + + bgCanvas: "var(--ds-orange-1)", + bgSurface1: "var(--ds-orange-2)", + bgSurface2: "var(--ds-orange-3)", + }, + + success: { + lighter: "var(--ds-green-7)", + light: "var(--ds-green-8)", + main: "var(--ds-green-9)", + dark: "var(--ds-green-10)", + darker: "var(--ds-green-11)", + darkest: "var(--ds-green-12)", + contrastText: "var(--ds-fg-fixed-white)", + + mainChannel: "var(--ds-green-9Channel)", + lightChannel: "var(--ds-green-8Channel)", + darkChannel: "var(--ds-green-10Channel)", + + bgCanvas: "var(--ds-green-1)", + bgSurface1: "var(--ds-green-2)", + bgSurface2: "var(--ds-green-3)", + }, + + info: { + main: "var(--ds-indigo-9)", + light: "var(--ds-indigo-8)", + dark: "var(--ds-indigo-10)", + darker: "var(--ds-indigo-11)", + darkest: "var(--ds-indigo-12)", + contrastText: "var(--ds-fg-fixed-white)", + + mainChannel: "var(--ds-indigo-9Channel)", + lightChannel: "var(--ds-indigo-8Channel)", + darkChannel: "var(--ds-indigo-10Channel)", + + bgCanvas: "var(--ds-indigo-1)", + bgSurface1: "var(--ds-indigo-2)", + bgSurface2: "var(--ds-indigo-3)", + }, + + grey: { + 50: "var(--ds-olive-2)", + 100: "var(--ds-olive-3)", + 200: "var(--ds-olive-4)", + 300: "var(--ds-olive-5)", + 400: "var(--ds-olive-7)", + 500: "var(--ds-olive-8)", + 600: "var(--ds-olive-9)", + 700: "var(--ds-olive-11)", + 800: "var(--ds-olive-10)", + 900: "var(--ds-olive-12)", + }, + }, + + components: { + MuiButton: { + styleOverrides: { + root: ( + { ownerState, theme }: { ownerState: ButtonProps; theme: Theme } + ): CSSObject => { + const base: CSSObject = { textTransform: "none" }; + + const variant = ownerState.variant ?? "text"; + + const rawColour = ownerState.color ?? "primary"; + if (rawColour === "inherit") return base; + + const colour = rawColour as MuiIntent; + + const varsPalette = (theme as any).vars?.palette?.[colour]; + const fallbackPalette = (theme.palette as any)[colour]; + + const darker = + varsPalette?.darker ?? + fallbackPalette?.darker ?? + varsPalette?.dark ?? + fallbackPalette?.dark; + + const mainChannel = + varsPalette?.mainChannel ?? fallbackPalette?.mainChannel; + + if (variant === "outlined") { + return { + ...base, + ...(darker && { + "--variant-outlinedColor": darker, + color: darker, + }), + ...(mainChannel && { + "--variant-outlinedBorder": `rgba(${mainChannel} / 0.7)`, + borderColor: `rgba(${mainChannel} / 0.7)`, + }), + } as CSSObject; + } + + if (variant === "text") { + return { + ...base, + ...(darker && { "--variant-textColor": darker, color: darker }), + } as CSSObject; + } + + return base; + }, + }, + }, + + MuiChip: { + styleOverrides: { + root: ({ ownerState }: { ownerState: ChipProps }): CSSObject => { + const base: CSSObject = { + "& .MuiChip-icon, & .MuiChip-deleteIcon": { color: "currentColor" }, + }; + + const isDefault = (ownerState.color ?? "default") === "default"; + const isOutlined = ownerState.variant === "outlined"; + const isInteractive = !!(ownerState.clickable || ownerState.onDelete); + + if (isDefault) { + return { + ...base, + color: "var(--ds-olive-12)", + borderColor: "var(--ds-border-emphasis)", + backgroundColor: isOutlined ? "transparent" : "var(--ds-olive-4)", + + ...(isInteractive && { + "&:hover": { + backgroundColor: isOutlined + ? "var(--ds-overlay-hover)" + : "var(--ds-olive-5)", + }, + }), + } as CSSObject; + } + + return base; + }, + + outlinedPrimary: ({ theme }: { theme: Theme }): CSSObject => { + const p = resolveIntentPalette(theme, "primary"); + return { + color: p.darker ?? p.dark, + borderColor: `rgba(${p.darkChannel ?? p.mainChannel} / 0.7)`, + }; + }, + + outlinedSecondary: ({ theme }: { theme: Theme }): CSSObject => { + const p = resolveIntentPalette(theme, "secondary"); + return { + color: p.darker ?? p.dark, + borderColor: `rgba(${p.darkChannel ?? p.mainChannel} / 0.7)`, + }; + }, + + outlinedError: ({ theme }: { theme: Theme }): CSSObject => { + const p = resolveIntentPalette(theme, "error"); + return { + color: p.darker ?? p.dark, + borderColor: `rgba(${p.darkChannel ?? p.mainChannel} / 0.7)`, + }; + }, + + outlinedWarning: ({ theme }: { theme: Theme }): CSSObject => { + const p = resolveIntentPalette(theme, "warning"); + return { + color: p.darker ?? p.dark, + borderColor: `rgba(${p.darkChannel ?? p.mainChannel} / 0.7)`, + }; + }, + + outlinedInfo: ({ theme }: { theme: Theme }): CSSObject => { + const p = resolveIntentPalette(theme, "info"); + return { + color: p.darker ?? p.dark, + borderColor: `rgba(${p.darkChannel ?? p.mainChannel} / 0.7)`, + }; + }, + + outlinedSuccess: ({ theme }: { theme: Theme }): CSSObject => { + const p = resolveIntentPalette(theme, "success"); + return { + color: p.darker ?? p.dark, + borderColor: `rgba(${p.darkChannel ?? p.mainChannel} / 0.7)`, + }; + }, + + }, + }, + + MuiCheckbox: { + defaultProps: { + icon: React.createElement(DsCheckboxBlankIcon), + checkedIcon: React.createElement(DsCheckboxCheckedIcon), + indeterminateIcon: React.createElement(DsCheckboxIndeterminateIcon), + }, + styleOverrides: { + root: ( + { ownerState, theme }: { ownerState: CheckboxProps; theme: Theme } + ): CSSObject => { + const base: CSSObject = { + "&:hover, &.Mui-focusVisible": { backgroundColor: "transparent" }, + }; + + // Disabled wins over everything + if (ownerState.disabled) { + return { + ...base, + color: "var(--ds-fg-disabled)", + + "--ds-checkbox-box-fill": "none", + "--ds-checkbox-box-stroke": "var(--ds-fg-disabled)", + "--ds-checkbox-box-strokeWidth": "2", + "--ds-checkbox-glyph": "var(--ds-fg-disabled)", + } as unknown as CSSObject; + } + + const raw = (ownerState.color ?? "default") as + | "default" + | MuiIntent; + + const isDefault = raw === "default"; + const colour = raw as Exclude<typeof raw, "default">; + + const varsPalette = !isDefault ? (theme as any).vars?.palette?.[colour] : null; + const fallbackPalette = !isDefault ? (theme.palette as any)[colour] : null; + + const selectedMain = isDefault + ? "var(--ds-olive-9)" + : (varsPalette?.main ?? fallbackPalette?.main); + + const selectedMainChannel = isDefault + ? null + : (varsPalette?.mainChannel ?? fallbackPalette?.mainChannel); + + const uncheckedOutline = "var(--ds-olive-9)"; + + return { + ...base, + + "&:not(.Mui-checked):not(.MuiCheckbox-indeterminate)": { + color: uncheckedOutline, + "--ds-checkbox-box-fill": "none", + "--ds-checkbox-box-stroke": uncheckedOutline, + "--ds-checkbox-box-strokeWidth": "2", + }, + + "&.Mui-checked": { + color: selectedMain, + "--ds-checkbox-box-fill": "currentColor", + "--ds-checkbox-box-stroke": "none", + "--ds-checkbox-box-strokeWidth": "0", + "--ds-checkbox-glyph": "var(--ds-white)", + }, + + "&.MuiCheckbox-indeterminate": { + color: selectedMain, + "--ds-checkbox-box-fill": "none", + "--ds-checkbox-box-stroke": "currentColor", + "--ds-checkbox-box-strokeWidth": "2", + "--ds-checkbox-glyph": "currentColor", + }, + + ...(selectedMainChannel && { + "&.Mui-checked:hover, &.MuiCheckbox-indeterminate:hover": { + backgroundColor: `rgba(${selectedMainChannel} / ${theme.palette.action.hoverOpacity})`, + }, + }), + } as unknown as CSSObject; + }, + }, + }, + + // MUI Input focus colour overrides + MuiInput: { + styleOverrides: { + root: ({ ownerState, theme }: OverrideArgs<InputProps>) => { + const colour = (ownerState.color ?? "primary") as MuiIntent; + const p = resolveIntentPalette(theme, colour); + + return { + // REST (interactive baseline) + "&:before": { + borderBottomColor: theme.palette.border.emphasis, + }, + + // HOVER (neutral hover strong) + "&:hover:not(.Mui-disabled):not(.Mui-error):before": { + borderBottomColor: theme.palette.border.strong, + }, + + // FOCUS (semantic colour + weight) + "&.Mui-focused:not(.Mui-error):after": { + borderBottomColor: "var(--ds-border-focus-primary)", + borderBottomWidth: 2, + }, + + // ERROR (rest) + "&.Mui-error:before": { + borderColor: theme.palette.error.lighter ?? theme.palette.error.light, + }, + + // ERROR hover + "&.Mui-error:hover:not(.Mui-disabled):before": { + borderBottomColor: theme.palette.error.light, + }, + + // ERROR + FOCUS (semantic colour + weight) + "&.Mui-error.Mui-focused:after": { + borderBottomColor: theme.palette.error.light, + borderBottomWidth: 2, + }, + + // DISABLED wins + "&.Mui-disabled:before": { + borderBottomStyle: "solid", + borderBottomColor: "var(--ds-border-disabled)", + }, + }; + }, + + input: ({ theme }: ThemeOnlyArgs) => ({ + "&::placeholder": { color: theme.palette.text.placeholder, opacity: 1 }, + "&:focus::placeholder": { color: theme.palette.text.placeholderFocus }, + }), + }, + }, + + MuiInputBase: { + styleOverrides: { + input: ({ theme }: ThemeOnlyArgs) => ({ + "&::placeholder": { color: theme.palette.text.placeholder, opacity: 1 }, + "&::-webkit-input-placeholder": { color: theme.palette.text.placeholder, opacity: 1 }, + "&::-moz-placeholder": { color: theme.palette.text.placeholder, opacity: 1 }, + + "&:focus::placeholder": { color: theme.palette.text.placeholderFocus }, + "&:focus::-webkit-input-placeholder": { color: theme.palette.text.placeholderFocus }, + "&:focus::-moz-placeholder": { color: theme.palette.text.placeholderFocus }, + }), + + root: ({ theme }: ThemeOnlyArgs) => ({ + "&.Mui-error input::placeholder, &.Mui-error input::-webkit-input-placeholder, &.Mui-error input::-moz-placeholder": { + color: theme.palette.error.light, + opacity: 1, + }, + "&.Mui-disabled input::placeholder, &.Mui-disabled input::-webkit-input-placeholder, &.Mui-disabled input::-moz-placeholder": { + color: theme.palette.text.disabled, + opacity: 1, + }, + }), + }, + }, + + MuiFilledInput: { + styleOverrides: { + root: ({ ownerState, theme }: OverrideArgs<FilledInputProps>) => { + const colour = (ownerState.color ?? "primary") as MuiIntent; + const p = resolveIntentPalette(theme, colour); + + return { + backgroundColor: theme.palette.background.surface2, + + "&:hover:not(.Mui-disabled)": { + backgroundColor: "var(--ds-overlay-hover)", + }, + + // REST (interactive baseline) + "&:before": { + borderBottomColor: theme.palette.border.emphasis, + }, + + // HOVER (neutral hover strong) + "&:hover:not(.Mui-disabled):not(.Mui-error):before": { + borderBottomColor: theme.palette.border.strong, + }, + + // FOCUS (semantic colour + weight) + "&.Mui-focused:not(.Mui-error):after": { + borderBottomColor: "var(--ds-border-focus-primary)", + borderBottomWidth: 2, + }, + + // ERROR (rest) + "&.Mui-error:before": { + borderColor: theme.palette.error.lighter ?? theme.palette.error.light, + }, + + // ERROR hover + "&.Mui-error:hover:not(.Mui-disabled):before": { + borderBottomColor: theme.palette.error.light, + }, + + // ERROR + FOCUS + "&.Mui-error.Mui-focused:after": { + borderBottomColor: theme.palette.error.light, + borderBottomWidth: 2, + }, + + // DISABLED wins + "&.Mui-disabled": { + backgroundColor: "var(--ds-bg-disabled)", + color: "var(--ds-fg-disabled)", + borderColor: "var(--ds-border-disabled)", + }, + }; + }, + + input: ({ theme }: ThemeOnlyArgs) => ({ + "&::placeholder": { color: theme.palette.text.placeholder, opacity: 1 }, + "&:focus::placeholder": { color: theme.palette.text.placeholderFocus }, + }), + }, + }, + + MuiOutlinedInput: { + styleOverrides: { + root: ({ ownerState, theme }: OverrideArgs<OutlinedInputProps>) => { + const colour = (ownerState.color ?? "primary") as MuiIntent; + const p = resolveIntentPalette(theme, colour); + + return { + // REST (interactive baseline) + "& .MuiOutlinedInput-notchedOutline": { + borderColor: theme.palette.border.emphasis, + }, + + // HOVER (neutral affordance) — ONLY when not focused + not error + not disabled + "&:hover:not(.Mui-disabled):not(.Mui-error):not(.Mui-focused) .MuiOutlinedInput-notchedOutline": { + borderColor: theme.palette.border.strong, + }, + + // FOCUS (semantic colour + weight) + "&.Mui-focused:not(.Mui-disabled):not(.Mui-error) .MuiOutlinedInput-notchedOutline": { + borderColor: p.light, + borderWidth: 2, + }, + + // ERROR (rest) + "&.Mui-error .MuiOutlinedInput-notchedOutline": { + borderColor: theme.palette.error.lighter ?? theme.palette.error.light, + }, + + // ERROR hover + "&.Mui-error:hover:not(.Mui-disabled):not(.Mui-focused) .MuiOutlinedInput-notchedOutline": { + borderColor: theme.palette.error.light, + }, + + // ERROR focus + "&.Mui-error.Mui-focused .MuiOutlinedInput-notchedOutline": { + borderColor: theme.palette.error.light, + borderWidth: 2, + }, + + // DISABLED wins + "&.Mui-disabled": { + backgroundColor: "var(--ds-bg-disabled)", + "& .MuiOutlinedInput-notchedOutline": { + borderColor: "var(--ds-border-disabled)", + }, + }, + }; + }, + }, + }, + + MuiInputLabel: { + styleOverrides: { + root: ({ theme }: ThemeOnlyArgs) => ({ + "&:not(.MuiInputLabel-shrink)": { + color: theme.palette.text.secondary, + }, + "&.Mui-disabled:not(.MuiInputLabel-shrink)": { + color: theme.palette.text.disabled, + }, + + "&.Mui-focused": { + color: theme.palette.primary.darker ?? theme.palette.primary.dark, + }, + + "&.Mui-focused.MuiFormLabel-colorSecondary": { + color: theme.palette.secondary.darker ?? theme.palette.secondary.dark, + }, + "&.Mui-focused.MuiFormLabel-colorSuccess": { + color: theme.palette.success.darker ?? theme.palette.success.dark, + }, + "&.Mui-focused.MuiFormLabel-colorWarning": { + color: theme.palette.warning.darker ?? theme.palette.warning.dark, + }, + "&.Mui-focused.MuiFormLabel-colorError": { + color: theme.palette.error.darker ?? theme.palette.error.dark, + }, + "&.Mui-focused.MuiFormLabel-colorInfo": { + color: theme.palette.info.darker ?? theme.palette.info.dark, + }, + + "&.Mui-focused.Mui-error": { + color: theme.palette.error.darker ?? theme.palette.error.dark, + }, + + "&.Mui-disabled": { + color: theme.palette.text.disabled, + }, + }), + }, + }, + }, + }); + + return createTheme(DiamondDSThemeOptions); +}; + +export const DiamondDSTheme = createMuiTheme("light"); +export const DiamondDSThemeDark = createMuiTheme("dark"); diff --git a/src/themes/DiamondTheme.ts b/src/themes/DiamondTheme.ts index be9ebc5..11ad5ee 100644 --- a/src/themes/DiamondTheme.ts +++ b/src/themes/DiamondTheme.ts @@ -10,6 +10,20 @@ const dlsLogoBlue = "#202740"; const dlsLogoYellow = "#facf07"; const DiamondThemeOptions = mergeThemeOptions({ + typography: { + fontFamily: [ + "Inter Variable", + "Inter", + "system-ui", + "-apple-system", + '"Segoe UI"', + "Roboto", + "Helvetica", + "Arial", + "sans-serif", + ].join(","), + }, + logos: { normal: { src: logoImageLight, diff --git a/src/themes/ThemeProvider.tsx b/src/themes/ThemeProvider.tsx index d4328d3..dd9c1e9 100644 --- a/src/themes/ThemeProvider.tsx +++ b/src/themes/ThemeProvider.tsx @@ -1,26 +1,48 @@ -import { ThemeProvider as Mui_ThemeProvider } from "@mui/material/styles"; +import React, { useLayoutEffect, useMemo } from "react"; import { CssBaseline } from "@mui/material"; -import { GenericTheme } from "./GenericTheme"; -import { ThemeProviderProps as Mui_ThemeProviderProps } from "@mui/material/styles/ThemeProvider"; +import { ThemeProvider as MuiThemeProvider } from "@mui/material/styles"; +import type { ThemeProviderProps as MuiThemeProviderProps } from "@mui/material/styles/ThemeProvider"; +import { createMuiTheme } from "./DiamondDSTheme"; +import type { DSMode } from "./DiamondDSTheme"; -interface ThemeProviderProps extends Partial<Mui_ThemeProviderProps> { +interface ThemeProviderProps extends Partial<MuiThemeProviderProps> { baseline?: boolean; + mode?: DSMode | "system"; } -const ThemeProvider = function ({ +function resolveMode(mode: DSMode | "system"): DSMode { + if (mode !== "system") return mode; + return window.matchMedia?.("(prefers-color-scheme: dark)")?.matches ? "dark" : "light"; +} + +export function ThemeProvider({ children, - theme = GenericTheme, baseline = true, defaultMode = "system", + mode = "light", ...props }: ThemeProviderProps) { + const resolvedMode = useMemo(() => resolveMode(mode), [mode]); + + useLayoutEffect(() => { + const root = document.documentElement; + + root.setAttribute("data-mode", resolvedMode); + + // compatibility classes + root.classList.toggle("dark", resolvedMode === "dark"); + root.classList.toggle("light", resolvedMode === "light"); + + // browser-native UI (scrollbars, form controls) + root.style.colorScheme = resolvedMode; + }, [resolvedMode]); + + const theme = useMemo(() => createMuiTheme(resolvedMode), [resolvedMode]); + return ( - <Mui_ThemeProvider theme={theme} defaultMode={defaultMode} {...props}> + <MuiThemeProvider theme={theme} defaultMode={defaultMode} {...props}> {baseline && <CssBaseline />} {children} - </Mui_ThemeProvider> + </MuiThemeProvider> ); -}; - -export { ThemeProvider }; -export type { ThemeProviderProps }; +} diff --git a/src/themes/icons/CheckboxIcons.tsx b/src/themes/icons/CheckboxIcons.tsx new file mode 100644 index 0000000..2eb3412 --- /dev/null +++ b/src/themes/icons/CheckboxIcons.tsx @@ -0,0 +1,45 @@ +import * as React from "react"; +import SvgIcon, { SvgIconProps } from "@mui/material/SvgIcon"; + +const BoxPath = (props: React.SVGProps<SVGPathElement>) => ( + <path + d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2z" + fill="var(--ds-checkbox-box-fill, none)" + stroke="var(--ds-checkbox-box-stroke, currentColor)" + strokeWidth="var(--ds-checkbox-box-strokeWidth, 2)" + strokeLinejoin="round" + {...props} + /> +); + +/** Unchecked (outline only) */ +export function DsCheckboxBlankIcon(props: SvgIconProps) { + return ( + <SvgIcon {...props} viewBox="0 0 24 24"> + <BoxPath /> + </SvgIcon> + ); +} + +/** Checked (fill + tick) */ +export function DsCheckboxCheckedIcon(props: SvgIconProps) { + return ( + <SvgIcon {...props} viewBox="0 0 24 24"> + <BoxPath /> + <path + d="M10 14.17l-3.59-3.58L5 12l5 5 9-9-1.41-1.41z" + fill="var(--ds-checkbox-glyph, var(--ds-white))" + /> + </SvgIcon> + ); +} + +/** Indeterminate (outlined feel by default via vars, bar uses glyph var) */ +export function DsCheckboxIndeterminateIcon(props: SvgIconProps) { + return ( + <SvgIcon {...props} viewBox="0 0 24 24"> + <BoxPath /> + <path d="M7 11h10v2H7z" fill="var(--ds-checkbox-glyph, currentColor)" /> + </SvgIcon> + ); +} diff --git a/src/themes/icons/index.ts b/src/themes/icons/index.ts new file mode 100644 index 0000000..ab573c6 --- /dev/null +++ b/src/themes/icons/index.ts @@ -0,0 +1 @@ +export * from "./CheckboxIcons"; diff --git a/src/types/raw.d.ts b/src/types/raw.d.ts new file mode 100644 index 0000000..abae50b --- /dev/null +++ b/src/types/raw.d.ts @@ -0,0 +1,4 @@ +declare module "*.tsx?raw" { + const content: string; + export default content; +}