diff --git a/.changeset/color-token-fallback.md b/.changeset/color-token-fallback.md new file mode 100644 index 000000000..92759512b --- /dev/null +++ b/.changeset/color-token-fallback.md @@ -0,0 +1,6 @@ +--- +'@cube-dev/ui-kit': minor +--- + +Added color token fallback syntax `(#color, #fallback)` for robust color hierarchies. Supports nested fallbacks like `(#primary, (#secondary, #default))`. Automatically generates RGB variants for the entire fallback chain, ensuring proper color variable resolution at runtime. + diff --git a/.changeset/overlay-min-width-improvement.md b/.changeset/overlay-min-width-improvement.md new file mode 100644 index 000000000..622a5d9a3 --- /dev/null +++ b/.changeset/overlay-min-width-improvement.md @@ -0,0 +1,6 @@ +--- +'@cube-dev/ui-kit': patch +--- + +Improved overlay width behavior for Picker and FilterPicker components to match their trigger button width, ensuring better visual consistency. + diff --git a/.changeset/picker-is-button-prop.md b/.changeset/picker-is-button-prop.md new file mode 100644 index 000000000..f12187b37 --- /dev/null +++ b/.changeset/picker-is-button-prop.md @@ -0,0 +1,6 @@ +--- +'@cube-dev/ui-kit': minor +--- + +Add `isButton` prop support to `Picker`, `FilterPicker`, and `Select` components. The prop is now properly passed to their trigger components (`ItemButton` for Picker/FilterPicker, `Item` for Select), allowing control over button styling. Defaults to `false` to maintain existing behavior. + diff --git a/.changeset/pink-rivers-destroy.md b/.changeset/pink-rivers-destroy.md new file mode 100644 index 000000000..66dbbe1e7 --- /dev/null +++ b/.changeset/pink-rivers-destroy.md @@ -0,0 +1,5 @@ +--- +"@cube-dev/ui-kit": patch +--- + +Decrease containerPadding of all overlays 12px -> 8px. diff --git a/.changeset/remove-legacy-at-syntax.md b/.changeset/remove-legacy-at-syntax.md new file mode 100644 index 000000000..3764ba78c --- /dev/null +++ b/.changeset/remove-legacy-at-syntax.md @@ -0,0 +1,6 @@ +--- +'@cube-dev/ui-kit': minor +--- + +Removed legacy `@` prefix support for custom properties. Use `$` prefix instead (e.g., `$custom-color` instead of `@custom-color`). + diff --git a/.changeset/tidy-laws-repair.md b/.changeset/tidy-laws-repair.md new file mode 100644 index 000000000..eb498ac9d --- /dev/null +++ b/.changeset/tidy-laws-repair.md @@ -0,0 +1,5 @@ +--- +"@cube-dev/ui-kit": minor +--- + +Specify `data-input-type` attribute for each field component and improve `qa` prop handling in various field components for consistency. diff --git a/.cursor/rules/storybook.mdc b/.cursor/rules/storybook.mdc index e7d04ad5b..828edcc5d 100644 --- a/.cursor/rules/storybook.mdc +++ b/.cursor/rules/storybook.mdc @@ -7,7 +7,7 @@ alwaysApply: false ### Stories Files (.stories.tsx) - Import types: `import type { Meta, StoryObj } from '@storybook/react-vite';` - Import `StoryFn` for custom template functions -- For interactive tests: `import { userEvent, within } from '@storybook/test';` (NOT from `@testing-library/react`) +- For interactive tests: `import { userEvent, within } from 'storybook/test';` (NOT from `@testing-library/react`) ### Documentation Files (.docs.mdx) - `import { Meta, Canvas, Story, Controls } from '@storybook/addon-docs/blocks';` @@ -103,7 +103,7 @@ export const Interactive: StoryObj = { }; ``` -**Important:** Always import `userEvent` and `within` from `'@storybook/test'` in story files. This ensures they respect Storybook's configuration (e.g., `testIdAttribute: 'data-qa'` set in `.storybook/preview.jsx`). Do NOT use `@testing-library/react` imports in stories. +**Important:** Always import `userEvent` and `within` from `'storybook/test'` in story files. This ensures they respect Storybook's configuration (e.g., `testIdAttribute: 'data-qa'` set in `.storybook/preview.jsx`). Do NOT use `@testing-library/react` imports in stories. ## MDX Documentation Structure diff --git a/.size-limit.cjs b/.size-limit.cjs index 3482f2adf..9edc44a85 100644 --- a/.size-limit.cjs +++ b/.size-limit.cjs @@ -20,7 +20,7 @@ module.exports = [ }), ); }, - limit: '320kB', + limit: '310kB', }, { name: 'Tree shaking (just a Button)', diff --git a/.storybook/preview.jsx b/.storybook/preview.jsx index 2277aa1ae..5a91c78aa 100644 --- a/.storybook/preview.jsx +++ b/.storybook/preview.jsx @@ -1,6 +1,6 @@ -import { configure } from '@storybook/test'; import isChromatic from 'chromatic/isChromatic'; import { config } from 'react-transition-group'; +import { configure } from 'storybook/test'; import { Root } from '../src'; diff --git a/package.json b/package.json index 719a18da3..9916e04e0 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,6 @@ "@react-stately/utils": "^3.10.8", "@react-types/shared": "^3.31.0", "@sparticuz/chromium": "^137.0.1", - "@storybook/test": "^8.6.14", "@tabler/icons-react": "^3.31.0", "@tanstack/react-virtual": "^3.13.12", "@trivago/prettier-plugin-sort-imports": "^5.2.2", @@ -117,9 +116,9 @@ "@size-limit/webpack": "^8.2.4", "@size-limit/webpack-why": "^8.2.4", "@statoscope/cli": "^5.20.1", - "@storybook/addon-docs": "^10.0.0", - "@storybook/addon-links": "^10.0.0", - "@storybook/react-vite": "^10.0.0", + "@storybook/addon-docs": "^10.0.8", + "@storybook/addon-links": "^10.0.8", + "@storybook/react-vite": "^10.0.8", "@swc/core": "^1.3.36", "@swc/jest": "^0.2.36", "@testing-library/dom": "^10.4.1", @@ -148,7 +147,7 @@ "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-storybook": "^10.0.0", + "eslint-plugin-storybook": "^10.0.8", "husky": "^6.0.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", @@ -165,7 +164,7 @@ "react-test-renderer": "^19.1.1", "rimraf": "^6.0.1", "size-limit": "^8.2.6", - "storybook": "^10.0.0", + "storybook": "^10.0.8", "storybook-addon-turbo-build": "^2.0.1", "styled-components": "^6.1.19", "swc-loader": "^0.2.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2473f5b08..45a53e52b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,9 +44,6 @@ importers: '@sparticuz/chromium': specifier: ^137.0.1 version: 137.0.1 - '@storybook/test': - specifier: ^8.6.14 - version: 8.6.14(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))) '@tabler/icons-react': specifier: ^3.31.0 version: 3.31.0(react@19.1.1) @@ -166,14 +163,14 @@ importers: specifier: ^5.20.1 version: 5.20.1 '@storybook/addon-docs': - specifier: ^10.0.0 - version: 10.0.0(@types/react@19.1.10)(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9)) + specifier: ^10.0.8 + version: 10.0.8(@types/react@19.1.10)(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9)) '@storybook/addon-links': - specifier: ^10.0.0 - version: 10.0.0(react@19.1.1)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))) + specifier: ^10.0.8 + version: 10.0.8(react@19.1.1)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))) '@storybook/react-vite': - specifier: ^10.0.0 - version: 10.0.0(esbuild@0.25.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.46.4)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(typescript@5.6.3)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9)) + specifier: ^10.0.8 + version: 10.0.8(esbuild@0.25.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.46.4)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(typescript@5.6.3)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9)) '@swc/core': specifier: ^1.3.36 version: 1.3.36 @@ -259,8 +256,8 @@ importers: specifier: ^5.2.0 version: 5.2.0(eslint@9.25.1) eslint-plugin-storybook: - specifier: ^10.0.0 - version: 10.0.0(eslint@9.25.1)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(typescript@5.6.3) + specifier: ^10.0.8 + version: 10.0.8(eslint@9.25.1)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(typescript@5.6.3) husky: specifier: ^6.0.0 version: 6.0.0 @@ -310,8 +307,8 @@ importers: specifier: ^8.2.6 version: 8.2.6 storybook: - specifier: ^10.0.0 - version: 10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) + specifier: ^10.0.8 + version: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) storybook-addon-turbo-build: specifier: ^2.0.1 version: 2.0.1(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9)) @@ -2640,32 +2637,32 @@ packages: '@statoscope/webpack-ui@5.26.2': resolution: {integrity: sha512-01RYHyG2nrif9Y5i717EI6jUMqdypbrOMdqpNUBFlw2rmaEB5t21V35b5Vd0pZEgesKNijE3ULvP7EQ37jEbIg==} - '@storybook/addon-docs@10.0.0': - resolution: {integrity: sha512-mwEI/os48ncIQMrLFAI3rJf88Ge/2/7Pj+g6+MRYjWAz5x9zCLrOgRUJFRvuzVY4SJKsKuSPYplrbmj4L+YlRQ==} + '@storybook/addon-docs@10.0.8': + resolution: {integrity: sha512-PYuaGXGycsamK/7OrFoE4syHGy22mdqqArl67cfosRwmRxZEI9ManQK0jTjNQM9ZX14NpThMOSWNGoWLckkxog==} peerDependencies: - storybook: ^10.0.0 + storybook: ^10.0.8 - '@storybook/addon-links@10.0.0': - resolution: {integrity: sha512-HCMA2eLuUyAZVyoEAgROvrrpKQYMD3BsjG7cc6nNxVQQO9xw5vcC6uKp/o6Yim3iiT5A+Vy/jSH72Lj9v9E0qA==} + '@storybook/addon-links@10.0.8': + resolution: {integrity: sha512-LnakruogdN5ND0cF0SOKyhzbEeIGDe1njkufX2aR9LOXQ0mMj5S2P86TdP87dR5R9bJjYYPPg/F7sjsAiI1Lqg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.0.0 + storybook: ^10.0.8 peerDependenciesMeta: react: optional: true - '@storybook/builder-vite@10.0.0': - resolution: {integrity: sha512-D8rcLAJSKeAol/xFA+uB9YGKOzg/SZiSMw12DkrJGgJD7GGM9xPR7VwQVxPtMUewmQrPtYB7LZ3Eaa+7PlMQ4Q==} + '@storybook/builder-vite@10.0.8': + resolution: {integrity: sha512-kaf/pUENzXxYgQMHGGPNiIk1ieb+SOMuSeLKx8wAUOlQOrzhtSH+ItACW/l43t+O6YZ8jYHoNBMF1kdQ1+Y5+w==} peerDependencies: - storybook: ^10.0.0 + storybook: ^10.0.8 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - '@storybook/csf-plugin@10.0.0': - resolution: {integrity: sha512-PLmhyDOCD71gRiWI1sUhf515PNNopp9MxWPEFfXN7ijBYZA4WJwHz1DBXK2qif/cY+e+Z12Wirhf0wM2kkOBJg==} + '@storybook/csf-plugin@10.0.8': + resolution: {integrity: sha512-OtLUWHIm3SDGtclQn6Mdd/YsWizLBgdEBRAdekGtwI/TvICfT7gpWYIycP53v2t9ufu2MIXjsxtV2maZKs8sZg==} peerDependencies: esbuild: '*' rollup: '*' - storybook: ^10.0.0 + storybook: ^10.0.8 vite: '*' webpack: '*' peerDependenciesMeta: @@ -2688,42 +2685,32 @@ 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.6.14': - resolution: {integrity: sha512-iG4MlWCcz1L7Yu8AwgsnfVAmMbvyRSk700Mfy2g4c8y5O+Cv1ejshE1LBBsCwHgkuqU0H4R0qu4g23+6UnUemQ==} - peerDependencies: - storybook: ^8.6.14 - - '@storybook/react-dom-shim@10.0.0': - resolution: {integrity: sha512-A4+DCu9o1F0ONpJx5yHIZ37Q7h63zxHIhK1MfDpOLfwfrapUkc/uag3WZuhwXrQMUbgFUgNA1A+8TceU5W4czA==} + '@storybook/react-dom-shim@10.0.8': + resolution: {integrity: sha512-ojuH22MB9Sz6rWbhTmC5IErZr0ZADbZijtPteUdydezY7scORT00UtbNoBcG0V6iVjdChgDtSKw2KHUUfchKqg==} peerDependencies: 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: ^10.0.0 + storybook: ^10.0.8 - '@storybook/react-vite@10.0.0': - resolution: {integrity: sha512-2R9RHuZsPuuNZZMyL3R+h+FJ2mhkj34zIJRgWNFx+41RujOjNUBFEAxUZ7aKcmZvWLN5SRzmAwKR3g42JNtS+A==} + '@storybook/react-vite@10.0.8': + resolution: {integrity: sha512-HS2X4qlitrZr3/sN2+ollxAaNE813IasZRE8lOez1Ey1ISGBtYIb9rmJs82MK35+yDM0pHdiDjkFMD4SkNYh2g==} peerDependencies: 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: ^10.0.0 + storybook: ^10.0.8 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - '@storybook/react@10.0.0': - resolution: {integrity: sha512-9e0RMlMG1QJFbga258AchHQlpD9uF+uGALi63kVILm5OApVyc9sC1FGgHtVS7DrEIdW5wVCWAFLNzgSw2YFC2w==} + '@storybook/react@10.0.8': + resolution: {integrity: sha512-PkuPb8sAqmjjkowSzm3rutiSuETvZI2F8SnjbHE6FRqZWWK4iFoaUrQbrg5kpPAtX//xIrqkdFwlbmQ3skhiPA==} peerDependencies: 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: ^10.0.0 + storybook: ^10.0.8 typescript: '>= 4.9.x' peerDependenciesMeta: typescript: optional: true - '@storybook/test@8.6.14': - resolution: {integrity: sha512-GkPNBbbZmz+XRdrhMtkxPotCLOQ1BaGNp/gFZYdGDk2KmUWBKmvc5JxxOhtoXM2703IzNFlQHSSNnhrDZYuLlw==} - peerDependencies: - storybook: ^8.6.14 - '@swc/core-darwin-arm64@1.3.36': resolution: {integrity: sha512-lsP+C8p9cC/Vd9uAbtxpEnM8GoJI/MMnVuXak7OlxOtDH9/oTwmAcAQTfNGNaH19d2FAIRwf+5RbXCPnxa2Zjw==} engines: {node: '>=10'} @@ -2820,18 +2807,10 @@ packages: '@tanstack/virtual-core@3.13.12': resolution: {integrity: sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==} - '@testing-library/dom@10.4.0': - resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} - engines: {node: '>=18'} - '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} engines: {node: '>=18'} - '@testing-library/jest-dom@6.5.0': - resolution: {integrity: sha512-xGGHpBXYSHUUr6XsKBfs85TWlYKpTc37cSBBVrXcib2MkHLboWlkClhWF37JKlDb9KEq3dHs+f2xR7XJEWGBxA==} - engines: {node: '>=14', npm: '>=6', yarn: '>=1'} - '@testing-library/jest-dom@6.7.0': resolution: {integrity: sha512-RI2e97YZ7MRa+vxP4UUnMuMFL2buSsf0ollxUbTgrbPLKhMn8KVTx7raS6DYjC7v1NDVrioOvaShxsguLNISCA==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} @@ -2867,12 +2846,6 @@ packages: '@types/react-dom': optional: true - '@testing-library/user-event@14.5.2': - resolution: {integrity: sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==} - engines: {node: '>=12', npm: '>=6'} - peerDependencies: - '@testing-library/dom': '>=7.21.4' - '@testing-library/user-event@14.6.1': resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} engines: {node: '>=12', npm: '>=6'} @@ -3195,9 +3168,6 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 - '@vitest/expect@2.0.5': - resolution: {integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==} - '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} @@ -3212,27 +3182,12 @@ packages: vite: optional: true - '@vitest/pretty-format@2.0.5': - resolution: {integrity: sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==} - - '@vitest/pretty-format@2.1.9': - resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==} - '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/spy@2.0.5': - resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==} - '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - '@vitest/utils@2.0.5': - resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==} - - '@vitest/utils@2.1.9': - resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} - '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} @@ -4325,11 +4280,11 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - eslint-plugin-storybook@10.0.0: - resolution: {integrity: sha512-q2NdHr1cRSR+cZef02EQOwaKdQwO+cslaDUndqszIaitfjvR31BzvuU7DCSTSJNhhLUEa8svda/kARZhG/bn2Q==} + eslint-plugin-storybook@10.0.8: + resolution: {integrity: sha512-ZKEMFhF/z/HRVvIgnEIYG2uAqmuLbkebUdHH3DpGHE64GPgk+KozcpqnD6zNk5vJ407bFmcWsGinBc2zi74f0g==} peerDependencies: eslint: '>=8' - storybook: ^10.0.0 + storybook: ^10.0.8 eslint-plugin-testing-library@5.11.1: resolution: {integrity: sha512-5eX9e1Kc2PqVRed3taaLnAAqPZGEX75C+M/rXzUAI3wIg/ZxzUm1OVAwfe/O+vE+6YXOLetSe9g5GKD2ecXipw==} @@ -6438,8 +6393,8 @@ packages: storybook-addon-turbo-build@2.0.1: resolution: {integrity: sha512-NP9e42fOmhkRe93okDlmIJ+2m+j4c9HZSa8EQJPJiJBQiAZ6MrjL6v0jzMukcwhIlu91RtHSkjlACm3xbi9jWQ==} - storybook@10.0.0: - resolution: {integrity: sha512-lJfn3+4koKQW1kp3RotkAYlvV8C/3lnhXOJYm+4aD9CACoT48qEOLwEmvIho6u+KTlbDnGonP5697Jw6rZ2E9A==} + storybook@10.0.8: + resolution: {integrity: sha512-vQMufKKA9TxgoEDHJv3esrqUkjszuuRiDkThiHxENFPdQawHhm2Dei+iwNRwH5W671zTDy9iRT9P1KDjcU5Iyw==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -6652,18 +6607,10 @@ packages: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} - tinyrainbow@1.2.0: - resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} - engines: {node: '>=14.0.0'} - tinyrainbow@2.0.0: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} - tinyspy@3.0.2: - resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} - engines: {node: '>=14.0.0'} - tinyspy@4.0.3: resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} engines: {node: '>=14.0.0'} @@ -10284,15 +10231,15 @@ snapshots: dependencies: '@statoscope/types': 5.22.0 - '@storybook/addon-docs@10.0.0(@types/react@19.1.10)(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9))': + '@storybook/addon-docs@10.0.8(@types/react@19.1.10)(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9))': dependencies: '@mdx-js/react': 3.0.1(@types/react@19.1.10)(react@19.1.1) - '@storybook/csf-plugin': 10.0.0(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9)) + '@storybook/csf-plugin': 10.0.8(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9)) '@storybook/icons': 1.6.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@storybook/react-dom-shim': 10.0.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))) + '@storybook/react-dom-shim': 10.0.8(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))) react: 19.1.1 react-dom: 19.1.1(react@19.1.1) - storybook: 10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' @@ -10301,17 +10248,17 @@ snapshots: - vite - webpack - '@storybook/addon-links@10.0.0(react@19.1.1)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))': + '@storybook/addon-links@10.0.8(react@19.1.1)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))': dependencies: '@storybook/global': 5.0.0 - storybook: 10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) optionalDependencies: react: 19.1.1 - '@storybook/builder-vite@10.0.0(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9))': + '@storybook/builder-vite@10.0.8(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9))': dependencies: - '@storybook/csf-plugin': 10.0.0(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9)) - storybook: 10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) + '@storybook/csf-plugin': 10.0.8(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9)) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) ts-dedent: 2.2.0 vite: 7.1.3(@types/node@22.17.2)(terser@5.31.1) transitivePeerDependencies: @@ -10319,9 +10266,9 @@ snapshots: - rollup - webpack - '@storybook/csf-plugin@10.0.0(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9))': + '@storybook/csf-plugin@10.0.8(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9))': dependencies: - storybook: 10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) unplugin: 2.3.10 optionalDependencies: esbuild: 0.25.9 @@ -10336,31 +10283,25 @@ snapshots: react: 19.1.1 react-dom: 19.1.1(react@19.1.1) - '@storybook/instrumenter@8.6.14(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))': - dependencies: - '@storybook/global': 5.0.0 - '@vitest/utils': 2.1.9 - storybook: 10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) - - '@storybook/react-dom-shim@10.0.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))': + '@storybook/react-dom-shim@10.0.8(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))': dependencies: react: 19.1.1 react-dom: 19.1.1(react@19.1.1) - storybook: 10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) - '@storybook/react-vite@10.0.0(esbuild@0.25.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.46.4)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(typescript@5.6.3)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9))': + '@storybook/react-vite@10.0.8(esbuild@0.25.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.46.4)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(typescript@5.6.3)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.1(typescript@5.6.3)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) '@rollup/pluginutils': 5.1.0(rollup@4.46.4) - '@storybook/builder-vite': 10.0.0(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9)) - '@storybook/react': 10.0.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(typescript@5.6.3) + '@storybook/builder-vite': 10.0.8(esbuild@0.25.9)(rollup@4.46.4)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))(webpack@5.76.1(@swc/core@1.3.36)(esbuild@0.25.9)) + '@storybook/react': 10.0.8(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(typescript@5.6.3) empathic: 2.0.0 magic-string: 0.30.17 react: 19.1.1 react-docgen: 8.0.0 react-dom: 19.1.1(react@19.1.1) resolve: 1.22.8 - storybook: 10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) tsconfig-paths: 4.2.0 vite: 7.1.3(@types/node@22.17.2)(terser@5.31.1) transitivePeerDependencies: @@ -10370,27 +10311,16 @@ snapshots: - typescript - webpack - '@storybook/react@10.0.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(typescript@5.6.3)': + '@storybook/react@10.0.8(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(typescript@5.6.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.0.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))) + '@storybook/react-dom-shim': 10.0.8(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))) react: 19.1.1 react-dom: 19.1.1(react@19.1.1) - storybook: 10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) optionalDependencies: typescript: 5.6.3 - '@storybook/test@8.6.14(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))': - dependencies: - '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.6.14(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1))) - '@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: 10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) - '@swc/core-darwin-arm64@1.3.36': optional: true @@ -10466,17 +10396,6 @@ snapshots: '@tanstack/virtual-core@3.13.12': {} - '@testing-library/dom@10.4.0': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/runtime': 7.28.3 - '@types/aria-query': 5.0.4 - aria-query: 5.3.0 - chalk: 4.1.2 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - pretty-format: 27.5.1 - '@testing-library/dom@10.4.1': dependencies: '@babel/code-frame': 7.27.1 @@ -10488,16 +10407,6 @@ snapshots: picocolors: 1.1.1 pretty-format: 27.5.1 - '@testing-library/jest-dom@6.5.0': - dependencies: - '@adobe/css-tools': 4.4.4 - aria-query: 5.3.2 - chalk: 3.0.0 - css.escape: 1.5.1 - dom-accessibility-api: 0.6.3 - lodash: 4.17.21 - redent: 3.0.0 - '@testing-library/jest-dom@6.7.0': dependencies: '@adobe/css-tools': 4.4.4 @@ -10527,10 +10436,6 @@ snapshots: '@types/react': 19.1.10 '@types/react-dom': 19.1.7(@types/react@19.1.10) - '@testing-library/user-event@14.5.2(@testing-library/dom@10.4.0)': - dependencies: - '@testing-library/dom': 10.4.0 - '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': dependencies: '@testing-library/dom': 10.4.1 @@ -10918,13 +10823,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/expect@2.0.5': - dependencies: - '@vitest/spy': 2.0.5 - '@vitest/utils': 2.0.5 - chai: 5.2.0 - tinyrainbow: 1.2.0 - '@vitest/expect@3.2.4': dependencies: '@types/chai': 5.2.2 @@ -10941,39 +10839,14 @@ snapshots: optionalDependencies: vite: 7.1.3(@types/node@22.17.2)(terser@5.31.1) - '@vitest/pretty-format@2.0.5': - dependencies: - tinyrainbow: 1.2.0 - - '@vitest/pretty-format@2.1.9': - dependencies: - tinyrainbow: 1.2.0 - '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 - '@vitest/spy@2.0.5': - dependencies: - tinyspy: 3.0.2 - '@vitest/spy@3.2.4': dependencies: tinyspy: 4.0.3 - '@vitest/utils@2.0.5': - dependencies: - '@vitest/pretty-format': 2.0.5 - estree-walker: 3.0.3 - loupe: 3.2.0 - tinyrainbow: 1.2.0 - - '@vitest/utils@2.1.9': - dependencies: - '@vitest/pretty-format': 2.1.9 - loupe: 3.2.0 - tinyrainbow: 1.2.0 - '@vitest/utils@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 @@ -12299,11 +12172,11 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-storybook@10.0.0(eslint@9.25.1)(storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(typescript@5.6.3): + eslint-plugin-storybook@10.0.8(eslint@9.25.1)(storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)))(typescript@5.6.3): dependencies: '@typescript-eslint/utils': 8.31.0(eslint@9.25.1)(typescript@5.6.3) eslint: 9.25.1 - storybook: 10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) + storybook: 10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)) transitivePeerDependencies: - supports-color - typescript @@ -14962,7 +14835,7 @@ snapshots: transitivePeerDependencies: - webpack - storybook@10.0.0(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)): + storybook@10.0.8(@testing-library/dom@10.4.1)(prettier@3.2.5)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(vite@7.1.3(@types/node@22.17.2)(terser@5.31.1)): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 1.6.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -15231,12 +15104,8 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - tinyrainbow@1.2.0: {} - tinyrainbow@2.0.0: {} - tinyspy@3.0.2: {} - tinyspy@4.0.3: {} tmp@0.0.33: diff --git a/src/components/CollectionItem.docs.mdx b/src/components/CollectionItem.docs.mdx index 3b1a9978d..e5924f162 100644 --- a/src/components/CollectionItem.docs.mdx +++ b/src/components/CollectionItem.docs.mdx @@ -98,7 +98,7 @@ const items = [{ ## Properties -Extends all [Item component](/components/Item) props: +Extends all [Item component](/docs/content-item--docs) props: - `children` - Item content - `icon` / `rightIcon` - Icons @@ -296,8 +296,8 @@ const items: User[] = [ ## Related Components -- [Item](/components/Item) - Base item component -- [ListBox](/components/ListBox) - List with selection -- [Select](/components/Select) - Dropdown selector -- [ComboBox](/components/ComboBox) - Searchable input -- [Menu](/components/Menu) - Action menu +- [Item](/docs/content-item--docs) - Base item component +- [ListBox](/docs/forms-listbox--docs) - List with selection +- [Select](/docs/forms-select--docs) - Dropdown selector +- [ComboBox](/docs/forms-combobox--docs) - Searchable input +- [Menu](/docs/actions-menu--docs) - Action menu diff --git a/src/components/actions/CommandMenu/CommandMenu.stories.tsx b/src/components/actions/CommandMenu/CommandMenu.stories.tsx index ef069b937..131548c07 100644 --- a/src/components/actions/CommandMenu/CommandMenu.stories.tsx +++ b/src/components/actions/CommandMenu/CommandMenu.stories.tsx @@ -1,10 +1,3 @@ -import { - expect, - findByRole, - userEvent, - waitFor, - within, -} from '@storybook/test'; import { IconArrowBack, IconArrowForward, @@ -18,6 +11,7 @@ import { IconSelect, } from '@tabler/icons-react'; import React, { useState } from 'react'; +import { expect, findByRole, userEvent, waitFor, within } from 'storybook/test'; import { EditIcon, TrashIcon } from '../../../icons'; import { tasty } from '../../../tasty'; diff --git a/src/components/actions/ItemAction/ItemAction.stories.tsx b/src/components/actions/ItemAction/ItemAction.stories.tsx index a3fea0b57..379564099 100644 --- a/src/components/actions/ItemAction/ItemAction.stories.tsx +++ b/src/components/actions/ItemAction/ItemAction.stories.tsx @@ -1,4 +1,3 @@ -import { userEvent, within } from '@storybook/test'; import { IconCopy, IconEdit, @@ -8,6 +7,7 @@ import { IconStar, IconTrash, } from '@tabler/icons-react'; +import { userEvent, within } from 'storybook/test'; import { Item } from '../../content/Item'; import { Space } from '../../layout/Space'; diff --git a/src/components/actions/ItemButton/ItemButton.stories.tsx b/src/components/actions/ItemButton/ItemButton.stories.tsx index bec6b88be..92615aef1 100644 --- a/src/components/actions/ItemButton/ItemButton.stories.tsx +++ b/src/components/actions/ItemButton/ItemButton.stories.tsx @@ -1,10 +1,10 @@ -import { userEvent, within } from '@storybook/test'; import { IconEdit, IconExternalLink, IconFile, IconTrash, } from '@tabler/icons-react'; +import { userEvent, within } from 'storybook/test'; import { timeout } from '../../../utils/promise'; import { ItemAction } from '../ItemAction'; diff --git a/src/components/actions/Menu/Menu.stories.tsx b/src/components/actions/Menu/Menu.stories.tsx index 1155b5751..2e4cdb163 100644 --- a/src/components/actions/Menu/Menu.stories.tsx +++ b/src/components/actions/Menu/Menu.stories.tsx @@ -1,13 +1,6 @@ // @ts-nocheck // NOTE: Type checking is disabled in this Storybook file to prevent // noisy errors from complex generic typings that do not affect runtime behaviour. -import { - expect, - findByRole, - userEvent, - waitFor, - within, -} from '@storybook/test'; import { IconBook, IconBulb, @@ -17,6 +10,7 @@ import { IconReload, } from '@tabler/icons-react'; import { useState } from 'react'; +import { expect, findByRole, userEvent, waitFor, within } from 'storybook/test'; import { CheckIcon, diff --git a/src/components/content/Item/Item.stories.tsx b/src/components/content/Item/Item.stories.tsx index 47d757015..d7db2fa76 100644 --- a/src/components/content/Item/Item.stories.tsx +++ b/src/components/content/Item/Item.stories.tsx @@ -1,4 +1,3 @@ -import { expect, userEvent, waitFor, within } from '@storybook/test'; import { IconCoin, IconEdit, @@ -7,6 +6,7 @@ import { IconUser, } from '@tabler/icons-react'; import { useState } from 'react'; +import { expect, userEvent, waitFor, within } from 'storybook/test'; import { DirectionIcon } from '../../../icons'; import { baseProps } from '../../../stories/lists/baseProps'; diff --git a/src/components/content/Item/Item.tsx b/src/components/content/Item/Item.tsx index 6347526b0..7cbfab538 100644 --- a/src/components/content/Item/Item.tsx +++ b/src/components/content/Item/Item.tsx @@ -573,89 +573,77 @@ export function useAutoTooltip({ return props; }, [labelProps]); - const renderWithTooltip = useCallback( - ( - renderElement: ( - tooltipTriggerProps?: HTMLAttributes, - tooltipRef?: RefObject, - ) => ReactNode, - defaultTooltipPlacement: OverlayProps['placement'], - ) => { - // Handle tooltip rendering based on tooltip prop type - if (tooltip) { - // String tooltip - simple case - if (typeof tooltip === 'string') { + const renderWithTooltip = ( + renderElement: ( + tooltipTriggerProps?: HTMLAttributes, + tooltipRef?: RefObject, + ) => ReactNode, + defaultTooltipPlacement: OverlayProps['placement'], + ) => { + // Handle tooltip rendering based on tooltip prop type + if (tooltip) { + // String tooltip - simple case + if (typeof tooltip === 'string') { + return ( + + {(triggerProps, ref) => renderElement(triggerProps, ref)} + + ); + } + + // Boolean tooltip - auto tooltip on overflow + if (tooltip === true) { + if ((children || labelProps) && (isLabelOverflowed || isDynamicLabel)) { return ( {(triggerProps, ref) => renderElement(triggerProps, ref)} ); } + } - // Boolean tooltip - auto tooltip on overflow - if (tooltip === true) { - if ( - (children || labelProps) && - (isLabelOverflowed || isDynamicLabel) - ) { - return ( - - {(triggerProps, ref) => renderElement(triggerProps, ref)} - - ); - } - } + // Object tooltip - advanced configuration + if (typeof tooltip === 'object') { + const { auto, ...tooltipProps } = tooltip; - // Object tooltip - advanced configuration - if (typeof tooltip === 'object') { - const { auto, ...tooltipProps } = tooltip; + // If title is provided and auto is not explicitly true, always show the tooltip + if (tooltipProps.title && auto !== true) { + return ( + + {(triggerProps, ref) => renderElement(triggerProps, ref)} + + ); + } - // If title is provided and auto is not explicitly true, always show the tooltip - if (tooltipProps.title && auto !== true) { - return ( - - {(triggerProps, ref) => renderElement(triggerProps, ref)} - - ); - } - - // If title is provided with auto=true, OR no title but auto behavior enabled - if ( - (children || labelProps) && - (isLabelOverflowed || isDynamicLabel) - ) { - return ( - - {(triggerProps, ref) => renderElement(triggerProps, ref)} - - ); - } + // If title is provided with auto=true, OR no title but auto behavior enabled + if ((children || labelProps) && (isLabelOverflowed || isDynamicLabel)) { + return ( + + {(triggerProps, ref) => renderElement(triggerProps, ref)} + + ); } } + } - return renderElement(); - }, - [tooltip, children, labelProps, isLabelOverflowed], - ); + return renderElement(); + }; return { labelRef: handleLabelElementRef, @@ -834,111 +822,80 @@ const Item = ( isDynamicLabel: !!actions, }); - // Create a stable render function that doesn't call hooks - const renderItemElement = useCallback( - ( - tooltipTriggerProps?: HTMLAttributes, - tooltipRef?: RefObject, - ) => { - // Use callback ref to merge multiple refs without calling hooks - const handleRef = (element: HTMLElement | null) => { - // Set the component's forwarded ref - if (typeof ref === 'function') { - ref(element as T | null); - } else if (ref) { - (ref as any).current = element; - } - // Set the tooltip ref if provided - if (tooltipRef) { - (tooltipRef as any).current = element; + // Render function that creates the item element + const renderItemElement = ( + tooltipTriggerProps?: HTMLAttributes, + tooltipRef?: RefObject, + ) => { + // Use callback ref to merge multiple refs without calling hooks + const handleRef = (element: HTMLElement | null) => { + // Set the component's forwarded ref + if (typeof ref === 'function') { + ref(element as T | null); + } else if (ref) { + (ref as any).current = element; + } + // Set the tooltip ref if provided + if (tooltipRef) { + (tooltipRef as any).current = element; + } + }; + + // Merge custom size style with provided style + const finalStyle = + typeof size === 'number' + ? ({ ...style, '--size': `${size}px` } as any) + : style; + + return ( + - {finalIcon && ( -
- {hasCheckbox ? : finalIcon} -
- )} - {finalPrefix &&
{finalPrefix}
} - {children || labelProps ? ( -
- {children} -
- ) : null} - {showDescription ? ( -
- {description} -
- ) : null} - {finalSuffix &&
{finalSuffix}
} - {finalRightIcon && ( -
{finalRightIcon}
- )} - {actions && ( -
- {actions !== true ? ( - - {actions} - - ) : null} -
- )} -
- ); - }, - [ - ref, - theme, - type, - finalIsDisabled, - size, - isSelected, - mods, - styles, - htmlType, - rest, - finalIcon, - hasCheckbox, - finalPrefix, - children, - labelProps, - finalLabelProps, - description, - descriptionProps, - finalSuffix, - finalRightIcon, - actions, - showActionsOnHover, - size, - style, - shape, - ], - ); + disabled={finalIsDisabled} + aria-disabled={finalIsDisabled} + aria-selected={isSelected} + mods={mods} + styles={styles} + type={htmlType as any} + {...mergeProps(rest, tooltipTriggerProps || {})} + style={finalStyle} + > + {finalIcon && ( +
+ {hasCheckbox ? : finalIcon} +
+ )} + {finalPrefix &&
{finalPrefix}
} + {children || labelProps ? ( +
+ {children} +
+ ) : null} + {showDescription ? ( +
+ {description} +
+ ) : null} + {finalSuffix &&
{finalSuffix}
} + {finalRightIcon &&
{finalRightIcon}
} + {actions && ( +
+ {actions !== true ? ( + + {actions} + + ) : null} +
+ )} + + ); + }; return renderWithTooltip(renderItemElement, defaultTooltipPlacement); }; diff --git a/src/components/content/Text.tsx b/src/components/content/Text.tsx index e26c959ec..18938d0ad 100644 --- a/src/components/content/Text.tsx +++ b/src/components/content/Text.tsx @@ -142,7 +142,7 @@ const SelectionText = tasty(Text, { const PlaceholderText = tasty(Text, { styles: { - opacity: '$disabled-opacity', + color: '#current.5', }, }); diff --git a/src/components/fields/Checkbox/Checkbox.tsx b/src/components/fields/Checkbox/Checkbox.tsx index b5710cfe4..e531d5bac 100644 --- a/src/components/fields/Checkbox/Checkbox.tsx +++ b/src/components/fields/Checkbox/Checkbox.tsx @@ -230,11 +230,12 @@ function Checkbox( const checkbox = ( <> - + {markIcon} diff --git a/src/components/fields/ComboBox/ComboBox.stories.tsx b/src/components/fields/ComboBox/ComboBox.stories.tsx index 72d9beb20..82213fc95 100644 --- a/src/components/fields/ComboBox/ComboBox.stories.tsx +++ b/src/components/fields/ComboBox/ComboBox.stories.tsx @@ -1,5 +1,5 @@ -import { userEvent, within } from '@storybook/test'; import { useMemo, useState } from 'react'; +import { userEvent, within } from 'storybook/test'; import { baseProps } from '../../../stories/lists/baseProps'; diff --git a/src/components/fields/ComboBox/ComboBox.tsx b/src/components/fields/ComboBox/ComboBox.tsx index f704f5bfc..2018c6740 100644 --- a/src/components/fields/ComboBox/ComboBox.tsx +++ b/src/components/fields/ComboBox/ComboBox.tsx @@ -85,7 +85,7 @@ const ComboBoxOverlayElement = tasty({ display: 'grid', gridRows: '1sf', gridColumns: '1sf', - width: '$min-width max-content 50vw', + width: '$overlay-min-width max-content 50vw', height: 'initial max-content (50vh - 5x)', overflow: 'auto', background: '#white', @@ -120,7 +120,7 @@ const ComboBoxOverlayElement = tasty({ '!open': 0.001, }, - '$min-width': 'min 30x', + '$overlay-min-width': 'min 30x', }, }); @@ -234,6 +234,8 @@ export interface CubeComboBoxProps direction?: 'bottom' | 'top'; /** Offset for the popover */ overlayOffset?: number; + /** Minimum padding in pixels between the popover and viewport edges */ + containerPadding?: number; /** Whether the combobox is read-only */ isReadOnly?: boolean; /** Suffix position goes before or after the validation and loading statuses */ @@ -760,6 +762,7 @@ const ComboBoxInput = forwardRef( styles={inputStyles} mods={mods} data-size={size} + data-input-type="combobox" role="combobox" aria-expanded={isPopoverOpen && hasResults} aria-haspopup="listbox" @@ -791,6 +794,7 @@ interface ComboBoxOverlayProps { direction: 'bottom' | 'top'; shouldFlip: boolean; overlayOffset: number; + containerPadding: number; comboBoxWidth?: number; comboBoxId: string; overlayStyles?: Styles; @@ -824,6 +828,7 @@ function ComboBoxOverlay({ direction, shouldFlip, overlayOffset, + containerPadding, comboBoxWidth, comboBoxId, overlayStyles, @@ -857,6 +862,7 @@ function ComboBoxOverlay({ shouldFlip, isOpen, offset: overlayOffset, + containerPadding: containerPadding, }); // Overlay behavior (dismiss on outside click, escape) @@ -912,7 +918,9 @@ function ComboBoxOverlay({ }} styles={overlayStyles} style={{ - '--min-width': comboBoxWidth ? `${comboBoxWidth}px` : undefined, + '--overlay-min-width': comboBoxWidth + ? `${comboBoxWidth}px` + : undefined, }} > ( headingStyles, isReadOnly, overlayOffset = 8, + containerPadding = 8, onSelectionChange: externalOnSelectionChange, sortSelectedToTop: sortSelectedToTopProp, onFocus, @@ -1816,6 +1825,7 @@ export const ComboBox = forwardRef(function ComboBox( direction={direction} shouldFlip={shouldFlip} overlayOffset={overlayOffset} + containerPadding={containerPadding} comboBoxWidth={comboBoxWidth} comboBoxId={comboBoxId} overlayStyles={overlayStyles} diff --git a/src/components/fields/DatePicker/DateInput.tsx b/src/components/fields/DatePicker/DateInput.tsx index 561bc456d..5e88a3557 100644 --- a/src/components/fields/DatePicker/DateInput.tsx +++ b/src/components/fields/DatePicker/DateInput.tsx @@ -56,6 +56,7 @@ function DateInput( props = Object.assign({}, DEFAULT_DATE_PROPS, props); let { + qa, autoFocus, isDisabled, inputStyles, @@ -86,6 +87,8 @@ function DateInput( const component = ( ( let styles = extractStyles(props, CONTAINER_STYLES); let { + qa, size, placeholderValue, isDisabled, @@ -119,6 +120,8 @@ function DatePicker( const component = ( ( let styles = extractStyles(props, CONTAINER_STYLES); let { + qa, size, shouldFlip, placeholderValue, @@ -131,6 +132,8 @@ function DateRangePicker( const component = ( ( let styles = extractStyles(props, CONTAINER_STYLES); let { + qa, size, placeholderValue, isDisabled, @@ -179,7 +180,12 @@ function DateRangeSeparatedPicker( } const component = ( - + ( let styles = extractStyles(props, CONTAINER_STYLES); let { + qa, inputStyles, wrapperStyles, autoFocus, @@ -93,6 +94,8 @@ function TimeInput( const timeInput = ( { const listState = listStateRef.current; @@ -586,9 +587,54 @@ export const FilterListBox = forwardRef(function FilterListBox< return; } - // Set focus to the first visible item - selectionManager.setFocusedKey(visibleKeys[0]); - }, [searchValue, enhancedChildren]); + // Helper to find the first selected item that's visible + const findFirstVisibleSelectedKey = (): Key | null => { + if (selectionMode === 'single') { + // Single selection: check if selectedKey is visible + if (selectedKey != null) { + const selectedKeyStr = String(selectedKey); + if (visibleKeys.some((k) => String(k) === selectedKeyStr)) { + return selectedKey; + } + } + } else if (selectionMode === 'multiple') { + // Multiple selection: find first selected key that's visible + if (selectedKeys && selectedKeys !== 'all') { + for (const key of selectedKeys) { + const keyStr = String(key); + if (visibleKeys.some((k) => String(k) === keyStr)) { + return key; + } + } + } + } + return null; + }; + + // Determine which key to focus + let keyToFocus: Key | null = null; + + // If there's no focus yet (initial state), prioritize selected items + if (currentFocused == null) { + keyToFocus = findFirstVisibleSelectedKey(); + } else { + // If current focused item was filtered out, try to focus another selected item + keyToFocus = findFirstVisibleSelectedKey(); + } + + // Fallback to first visible item if no selected item found + if (keyToFocus == null) { + keyToFocus = visibleKeys[0]; + } + + // Mark this focus change as keyboard navigation so ListBox will scroll to it + if (listState.lastFocusSourceRef) { + listState.lastFocusSourceRef.current = 'keyboard'; + } + + // Set focus to the determined key + selectionManager.setFocusedKey(keyToFocus); + }, [searchValue, enhancedChildren, selectionMode, selectedKey, selectedKeys]); // Keyboard navigation handler for search input const { keyboardProps } = useKeyboard({ @@ -824,6 +870,7 @@ export const FilterListBox = forwardRef(function FilterListBox< data-autofocus={autoFocus ? '' : undefined} styles={searchInputStyles} data-size={size} + data-input-type="filterlistbox" role="combobox" aria-expanded="true" aria-haspopup="listbox" diff --git a/src/components/fields/FilterPicker/FilterPicker.stories.tsx b/src/components/fields/FilterPicker/FilterPicker.stories.tsx index 022ab7f28..35e4bd631 100644 --- a/src/components/fields/FilterPicker/FilterPicker.stories.tsx +++ b/src/components/fields/FilterPicker/FilterPicker.stories.tsx @@ -1,5 +1,5 @@ -import { userEvent, within } from '@storybook/test'; import { useEffect, useMemo, useState } from 'react'; +import { userEvent, within } from 'storybook/test'; import { CheckIcon, diff --git a/src/components/fields/FilterPicker/FilterPicker.tsx b/src/components/fields/FilterPicker/FilterPicker.tsx index 665cba331..f85e173ba 100644 --- a/src/components/fields/FilterPicker/FilterPicker.tsx +++ b/src/components/fields/FilterPicker/FilterPicker.tsx @@ -82,6 +82,8 @@ export interface CubeFilterPickerProps isCheckable?: boolean; /** Whether to flip the popover placement */ shouldFlip?: boolean; + /** Minimum padding in pixels between the popover and viewport edges */ + containerPadding?: number; /** Tooltip for the trigger button (separate from field tooltip) */ triggerTooltip?: CubeItemProps['tooltip']; /** Description for the trigger button (separate from field description) */ @@ -207,6 +209,7 @@ export const FilterPicker = forwardRef(function FilterPicker( shouldFocusWrap, children, shouldFlip = true, + containerPadding = 8, selectedKey, defaultSelectedKey, selectedKeys, @@ -249,6 +252,7 @@ export const FilterPicker = forwardRef(function FilterPicker( searchValue, onSearchChange, sortSelectedToTop: sortSelectedToTopProp, + isButton = false, form, ...otherProps } = props; @@ -609,7 +613,7 @@ export const FilterPicker = forwardRef(function FilterPicker( let content: ReactNode = ''; if (!hasSelection) { - content = placeholder; + return {placeholder}; } else if (selectionMode === 'single') { content = selectedLabels[0]; } else if (effectiveSelectedKeys === 'all') { @@ -622,18 +626,14 @@ export const FilterPicker = forwardRef(function FilterPicker( return null; } - return ( - - {content} - - ); + return content; }; const [shouldUpdatePosition, setShouldUpdatePosition] = useState(true); + // Capture trigger width for overlay min-width + const triggerWidth = triggerRef?.current?.offsetWidth; + // The trigger is rendered as a function so we can access the dialog state const renderTrigger = (state) => { // Listen for other menus opening and close this one if needed @@ -723,13 +723,14 @@ export const FilterPicker = forwardRef(function FilterPicker( ( type="popover" placement="bottom start" styles={triggerStyles} + containerPadding={containerPadding} shouldUpdatePosition={shouldUpdatePosition} shouldFlip={shouldFlip && shouldUpdatePosition} isDismissable={true} @@ -794,12 +796,19 @@ export const FilterPicker = forwardRef(function FilterPicker( {renderTrigger} {(close) => ( ) { - return ; - }), - { - Text: TextInput, - Password: PasswordInput, - Number: NumberInput, - TextArea: TextArea, - File: FileInput, - }, -); +export const Input: CubeInput = Object.assign(TextInput, { + Text: TextInput, + Password: PasswordInput, + Number: NumberInput, + TextArea: TextArea, + File: FileInput, +}); diff --git a/src/components/fields/ListBox/ListBox.tsx b/src/components/fields/ListBox/ListBox.tsx index 7e5106173..5dba3bf5f 100644 --- a/src/components/fields/ListBox/ListBox.tsx +++ b/src/components/fields/ListBox/ListBox.tsx @@ -919,6 +919,7 @@ export const ListBox = forwardRef(function ListBox( aria-disabled={isDisabled || undefined} mods={{ sections: hasSections }} data-shape={shape} + data-input-type="listbox" style={ shouldVirtualize ? { diff --git a/src/components/fields/NumberInput/NumberInput.tsx b/src/components/fields/NumberInput/NumberInput.tsx index 0fd93e564..ef3e6fbce 100644 --- a/src/components/fields/NumberInput/NumberInput.tsx +++ b/src/components/fields/NumberInput/NumberInput.tsx @@ -91,7 +91,7 @@ function NumberInput( {...otherProps} ref={ref} labelProps={labelProps} - inputProps={inputProps} + inputProps={{ ...inputProps, 'data-input-type': 'numberinput' }} inputRef={inputRef} wrapperProps={groupProps} suffixPosition="after" diff --git a/src/components/fields/PasswordInput/PasswordInput.tsx b/src/components/fields/PasswordInput/PasswordInput.tsx index 394f55cc3..19591d54c 100644 --- a/src/components/fields/PasswordInput/PasswordInput.tsx +++ b/src/components/fields/PasswordInput/PasswordInput.tsx @@ -61,7 +61,7 @@ function PasswordInput( ( + {fruit.label} + )), + }, +}; diff --git a/src/components/fields/Picker/Picker.tsx b/src/components/fields/Picker/Picker.tsx index efe49bffc..31831f4d3 100644 --- a/src/components/fields/Picker/Picker.tsx +++ b/src/components/fields/Picker/Picker.tsx @@ -69,6 +69,8 @@ export interface CubePickerProps isCheckable?: boolean; /** Whether to flip the popover placement */ shouldFlip?: boolean; + /** Minimum padding in pixels between the popover and viewport edges */ + containerPadding?: number; /** Tooltip for the trigger button (separate from field tooltip) */ triggerTooltip?: CubeItemProps['tooltip']; /** Description for the trigger button (separate from field description) */ @@ -194,6 +196,7 @@ export const Picker = forwardRef(function Picker( shouldFocusWrap, children, shouldFlip = true, + containerPadding = 8, selectedKey, defaultSelectedKey, selectedKeys, @@ -226,6 +229,7 @@ export const Picker = forwardRef(function Picker( isClearable, onClear, sortSelectedToTop, + isButton = false, listStateRef: externalListStateRef, ...otherProps } = props; @@ -446,7 +450,7 @@ export const Picker = forwardRef(function Picker( const renderTriggerContent = () => { // When there is a selection and a custom summary renderer is provided – use it. - if (hasSelection && typeof renderSummary === 'function') { + if (typeof renderSummary === 'function') { if (selectionMode === 'single') { return renderSummary({ selectedLabel: selectedLabels[0], @@ -462,14 +466,14 @@ export const Picker = forwardRef(function Picker( selectedKeys: effectiveSelectedKeys, selectionMode: 'multiple', }); - } else if (hasSelection && renderSummary === false) { + } else if (renderSummary === false) { return null; } let content: ReactNode = ''; if (!hasSelection) { - content = placeholder; + return {placeholder}; } else if (selectionMode === 'single') { content = selectedLabels[0]; } else if (effectiveSelectedKeys === 'all') { @@ -482,18 +486,14 @@ export const Picker = forwardRef(function Picker( return null; } - return ( - - {content} - - ); + return content; }; const [shouldUpdatePosition, setShouldUpdatePosition] = useState(true); + // Capture trigger width for overlay min-width + const triggerWidth = triggerRef?.current?.offsetWidth; + // The trigger is rendered as a function so we can access the dialog state const renderTrigger = (state) => { // Listen for other menus opening and close this one if needed @@ -577,13 +577,14 @@ export const Picker = forwardRef(function Picker( ( type="popover" placement="bottom start" styles={triggerStyles} + containerPadding={containerPadding} shouldUpdatePosition={shouldUpdatePosition} shouldFlip={shouldFlip && shouldUpdatePosition} isDismissable={true} @@ -647,12 +649,19 @@ export const Picker = forwardRef(function Picker( {renderTrigger} {(close) => ( , ref) { props = useFieldProps(props, { defaultValidationTrigger: 'onChange' }); let { + qa, isDisabled, isRequired, labelPosition = 'top', @@ -122,7 +123,9 @@ function RadioGroup(props: WithNullableValue, ref) { let radioGroup = ( } diff --git a/src/components/fields/Select/Select.stories.tsx b/src/components/fields/Select/Select.stories.tsx index 7d768c7e0..3610b3831 100644 --- a/src/components/fields/Select/Select.stories.tsx +++ b/src/components/fields/Select/Select.stories.tsx @@ -1,5 +1,5 @@ -import { userEvent, within } from '@storybook/test'; import { IconCoin, IconUser } from '@tabler/icons-react'; +import { userEvent, within } from 'storybook/test'; import { baseProps } from '../../../stories/lists/baseProps'; import { Text } from '../../content/Text'; @@ -678,3 +678,19 @@ WithTooltips.parameters = { }, }, }; + +export const LoadingState = Template.bind({}); +LoadingState.args = { + isLoading: true, + placeholder: 'Loading...', + label: 'Color', +}; + +LoadingState.parameters = { + docs: { + description: { + story: + 'Select displays a loading indicator when `isLoading` is true, preventing user interaction until data is loaded.', + }, + }, +}; diff --git a/src/components/fields/Select/Select.tsx b/src/components/fields/Select/Select.tsx index 909670d01..ea616926a 100644 --- a/src/components/fields/Select/Select.tsx +++ b/src/components/fields/Select/Select.tsx @@ -60,6 +60,7 @@ import { } from '../../actions/Menu/styled'; import { CollectionItem } from '../../CollectionItem'; import { CubeItemProps, Item } from '../../content/Item'; +import { Text } from '../../content/Text'; import { useFieldProps, useFormProps, wrapWithField } from '../../form'; import { DisplayTransition } from '../../helpers'; import { Portal } from '../../portal'; @@ -67,6 +68,7 @@ import { InvalidIcon } from '../../shared/InvalidIcon'; import { ValidIcon } from '../../shared/ValidIcon'; const SelectWrapperElement = tasty({ + qa: 'SelectWrapper', styles: { display: 'grid', position: 'relative', @@ -87,20 +89,11 @@ const SelectWrapperElement = tasty({ const SelectTrigger = tasty(Item, { as: 'button', - qa: 'Trigger', - styles: { - reset: 'button', - - Label: { - opacity: { - '': 1, - placeholder: '$disabled-opacity', - }, - }, - }, + qa: 'SelectTrigger', }); export const ListBoxElement = tasty({ + qa: 'ListBox', as: 'ul', styles: { display: 'flex', @@ -132,6 +125,7 @@ const SelectOverlayWrapper = tasty({ }); const OverlayElement = tasty({ + qa: 'SelectOverlay', styles: { width: 'min $overlay-min-width', display: 'grid', @@ -215,6 +209,8 @@ export interface CubeSelectBaseProps wrapperStyles?: Styles; direction?: 'top' | 'bottom'; shouldFlip?: boolean; + /** Minimum padding in pixels between the popover and viewport edges */ + containerPadding?: number; inputProps?: Props; type?: 'outline' | 'clear' | 'primary' | (string & {}); suffixPosition?: 'before' | 'after'; @@ -223,6 +219,10 @@ export interface CubeSelectBaseProps isClearable?: boolean; /** Callback called when the clear button is pressed */ onClear?: () => void; + /** Whether the trigger should use button styling + * @default false + */ + isButton?: boolean; } export interface CubeSelectProps extends CubeSelectBaseProps { @@ -260,7 +260,7 @@ function Select( necessityIndicator, validationState, prefix, - isDisabled, + isDisabled = props.isLoading || false, autoFocus, inputProps, triggerRef, @@ -282,6 +282,7 @@ function Select( hotkeys, direction = 'bottom', shouldFlip = true, + containerPadding = 8, placeholder, tooltip, size = 'medium', @@ -291,6 +292,7 @@ function Select( labelSuffix, suffixPosition = 'before', isClearable, + isButton = false, form, ...otherProps } = props; @@ -343,6 +345,7 @@ function Select( isOpen: state.isOpen, onClose: state.close, offset: overlayOffset, + containerPadding: containerPadding, }); let { isFocused, focusProps } = useFocus({ isDisabled }, true); @@ -417,14 +420,15 @@ function Select( let selectField = ( ( descriptionPlacement={descriptionPlacement} hotkeys={hotkeys} tooltip={tooltip} + isButton={isButton} labelProps={valueProps} > - {state.selectedItem - ? state.selectedItem.rendered - : placeholder || <> } + {state.selectedItem ? ( + state.selectedItem.rendered + ) : placeholder ? ( + {placeholder} + ) : null} ) { styles = extractStyles(otherProps, OUTER_STYLES, styles); const sliderField = ( - + {children({ trackRef, diff --git a/src/components/fields/Switch/Switch.tsx b/src/components/fields/Switch/Switch.tsx index 5ff80febf..cab989a61 100644 --- a/src/components/fields/Switch/Switch.tsx +++ b/src/components/fields/Switch/Switch.tsx @@ -189,24 +189,20 @@ function Switch(props: WithNullableSelected, ref) { const switchField = ( - +