diff --git a/.changeset/calm-monkeys-serve.md b/.changeset/calm-monkeys-serve.md new file mode 100644 index 000000000..dd80e342e --- /dev/null +++ b/.changeset/calm-monkeys-serve.md @@ -0,0 +1,5 @@ +--- +"@cube-dev/ui-kit": patch +--- + +Add @property definition support via `property` method. diff --git a/.changeset/clever-feet-report.md b/.changeset/clever-feet-report.md new file mode 100644 index 000000000..fb1e13669 --- /dev/null +++ b/.changeset/clever-feet-report.md @@ -0,0 +1,5 @@ +--- +"@cube-dev/ui-kit": patch +--- + +Fix MenuItem prop passing. diff --git a/.changeset/sharp-books-lie.md b/.changeset/sharp-books-lie.md new file mode 100644 index 000000000..674d69232 --- /dev/null +++ b/.changeset/sharp-books-lie.md @@ -0,0 +1,5 @@ +--- +"@cube-dev/ui-kit": minor +--- + +A brand new style injector. Drop `styled-components` dependency. diff --git a/.changeset/smart-pumpkins-exist.md b/.changeset/smart-pumpkins-exist.md new file mode 100644 index 000000000..ec6d0aff2 --- /dev/null +++ b/.changeset/smart-pumpkins-exist.md @@ -0,0 +1,5 @@ +--- +"@cube-dev/ui-kit": patch +--- + +Add `tastyDebug` tool for debugging. diff --git a/.cursor/rules/coding.mdc b/.cursor/rules/coding.mdc index 26c257a47..68b4bcebe 100644 --- a/.cursor/rules/coding.mdc +++ b/.cursor/rules/coding.mdc @@ -8,6 +8,7 @@ alwaysApply: true - Do not run tests if you only changed stories or documentation since the last test run. - If you need to move or rename a file: use command line tools for that. - If you need to move a part of code from one file to another: First, write the code at the new place, then delete the code in the original place. +- Don't implement backward compatibility unless asked. # Coding rules diff --git a/.cursor/rules/guidelines.mdc b/.cursor/rules/guidelines.mdc index 2b7a43f33..51fdabca1 100644 --- a/.cursor/rules/guidelines.mdc +++ b/.cursor/rules/guidelines.mdc @@ -27,6 +27,7 @@ Package name: `@cube-dev/ui-kit` All tests: `$ pnpm test` Specific test: `$ pnpm test -- {TestFileName}` +Update snaphosts: `$ pnpm test -u -- {TestFileName}` ## Build @@ -45,7 +46,6 @@ Specific test: `$ pnpm test -- {TestFileName}` - `src/stories/CreateComponent.docs.mdx` - create components using tasty helper. - Storybook v8.6 - React and React DOM v18 -- `styled-components` v6 - `react-aria` and `react-stately` with the latest versions. - `tabler/icons-react` - icons. @@ -113,7 +113,7 @@ Specific test: `$ pnpm test -- {TestFileName}` - Sub-elements: Target inner elements using capitalized keys in styles - Style props: Direct style application without `styles` prop - CSS custom properties: Use `@token-name` syntax for design tokens -- To declare a CSS animation use `styled-components` and then pass the animation name to the tasty styles. +- To declare a CSS animation use `keyframes` method and then pass the animation name to the tasty styles. ## Export Patterns @@ -187,7 +187,6 @@ Specific test: `$ pnpm test -- {TestFileName}` - `src/stories/CreateComponent.docs.mdx` - create components using tasty helper. - Storybook v8.6 - React and React DOM v18 -- `styled-components` v6 - `react-aria` and `react-stately` with the latest versions. - `tabler/icons-react` - icons. @@ -255,7 +254,7 @@ Specific test: `$ pnpm test -- {TestFileName}` - Sub-elements: Target inner elements using capitalized keys in styles - Style props: Direct style application without `styles` prop - CSS custom properties: Use `@token-name` syntax for design tokens -- To declare a CSS animation use `styled-components` and then pass the animation name to the tasty styles. +- To declare a CSS animation use `keyframes` method and then pass the animation name to the tasty styles. ## Export Patterns diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ba88c208e..221569748 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,10 +23,14 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 10.14.0 + - name: Update Corepack + run: npm i -g corepack@latest + + - name: Enable Corepack (pre) + run: corepack enable + + - name: Prepare pnpm (pre) + run: corepack prepare pnpm@10.14.0 --activate - name: Setup Node.js uses: actions/setup-node@v4 @@ -34,6 +38,12 @@ jobs: node-version-file: '.nvmrc' cache: 'pnpm' + - name: Enable Corepack + run: corepack enable + + - name: Prepare pnpm + run: corepack prepare pnpm@10.14.0 --activate + - name: Install Dependencies run: pnpm install @@ -63,10 +73,14 @@ jobs: with: fetch-depth: 0 - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 10.14.0 + - name: Update Corepack + run: npm i -g corepack@latest + + - name: Enable Corepack (pre) + run: corepack enable + + - name: Prepare pnpm (pre) + run: corepack prepare pnpm@10.14.0 --activate - uses: actions/cache@v4 name: Download storybook cache @@ -82,6 +96,12 @@ jobs: node-version-file: '.nvmrc' cache: 'pnpm' + - name: Enable Corepack + run: corepack enable + + - name: Prepare pnpm + run: corepack prepare pnpm@10.14.0 --activate + - name: Install dependencies run: pnpm install diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index a9c79add2..f489708c1 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -27,16 +27,26 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 10.14.0 + - name: Update Corepack + run: npm i -g corepack@latest + + - name: Enable Corepack (pre) + run: corepack enable + + - name: Prepare pnpm (pre) + run: corepack prepare pnpm@10.14.0 --activate - uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' cache: 'pnpm' + - name: Enable Corepack + run: corepack enable + + - name: Prepare pnpm + run: corepack prepare pnpm@10.14.0 --activate + - name: Install dependencies run: pnpm install @@ -81,10 +91,14 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 10.14.0 + - name: Update Corepack + run: npm i -g corepack@latest + + - name: Enable Corepack (pre) + run: corepack enable + + - name: Prepare pnpm (pre) + run: corepack prepare pnpm@10.14.0 --activate - uses: actions/cache@v4 name: Download eslint cache @@ -98,6 +112,12 @@ jobs: node-version-file: '.nvmrc' cache: 'pnpm' + - name: Enable Corepack + run: corepack enable + + - name: Prepare pnpm + run: corepack prepare pnpm@10.14.0 --activate + - name: Install dependencies run: pnpm install @@ -121,10 +141,14 @@ jobs: with: fetch-depth: 0 - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 10.14.0 + - name: Update Corepack + run: npm i -g corepack@latest + + - name: Enable Corepack (pre) + run: corepack enable + + - name: Prepare pnpm (pre) + run: corepack prepare pnpm@10.14.0 --activate - uses: actions/cache@v4 name: Download storybook cache @@ -140,6 +164,12 @@ jobs: node-version-file: '.nvmrc' cache: 'pnpm' + - name: Enable Corepack + run: corepack enable + + - name: Prepare pnpm + run: corepack prepare pnpm@10.14.0 --activate + - name: Install dependencies run: pnpm install diff --git a/.github/workflows/size-limit.yml b/.github/workflows/size-limit.yml index 9f8699513..35508cdcb 100644 --- a/.github/workflows/size-limit.yml +++ b/.github/workflows/size-limit.yml @@ -25,16 +25,26 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 10.14.0 + - name: Update Corepack + run: npm i -g corepack@latest - uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' cache: 'pnpm' + - name: Enable Corepack (pre) + run: corepack enable + + - name: Prepare pnpm (pre) + run: corepack prepare pnpm@10.14.0 --activate + + - name: Enable Corepack + run: corepack enable + + - name: Prepare pnpm + run: corepack prepare pnpm@10.14.0 --activate + - name: Install dependencies run: pnpm install diff --git a/.size-limit.cjs b/.size-limit.cjs index 19d54290e..81f558f79 100644 --- a/.size-limit.cjs +++ b/.size-limit.cjs @@ -20,20 +20,20 @@ module.exports = [ }), ); }, - limit: '295kB', + limit: '305kB', }, { name: 'Tree shaking (just a Button)', path: './dist/es/index.js', webpack: true, import: '{ Button }', - limit: '26 kB', + limit: '32 kB', }, { name: 'Tree shaking (just an Icon)', path: './dist/es/index.js', webpack: true, import: '{ AiIcon }', - limit: '13 kB', + limit: '19 kB', }, ]; diff --git a/.storybook/preview.jsx b/.storybook/preview.jsx index eaf7db55a..b434d5683 100644 --- a/.storybook/preview.jsx +++ b/.storybook/preview.jsx @@ -6,6 +6,17 @@ import { Root } from '../src'; configure({ testIdAttribute: 'data-qa', asyncUtilTimeout: 10000 }); +// Load tasty debug utilities in local Storybook only (exclude Chromatic) +if (!isChromatic() && import.meta.env.DEV) { + import('../src/tasty/debug').then(({ installGlobalDebug }) => { + try { + installGlobalDebug({ force: true }); + } catch (e) { + console.warn('tastyDebug installation failed:', e); + } + }); +} + if (isChromatic()) { // disabling transitions config.disabled = true; diff --git a/eslint.config.js b/eslint.config.js index 6d3e085e3..ad1b1ff24 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -151,7 +151,12 @@ export default [ // Test files override { - files: ['**/*.test.ts', '**/*.test.tsx'], + files: ['**/*.test.ts', '**/*.test.tsx', '**/test/**/*.ts'], + languageOptions: { + globals: { + ...globals.jest, + }, + }, rules: { 'no-unused-vars': 'off', 'react/prop-types': 'off', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7134c11e3..5a14b54f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -347,9 +347,6 @@ packages: '@actions/io@1.1.3': resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==} - '@adobe/css-tools@4.4.2': - resolution: {integrity: sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==} - '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} @@ -6842,9 +6839,6 @@ packages: tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@2.5.2: - resolution: {integrity: sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==} - tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} @@ -7318,8 +7312,6 @@ snapshots: '@actions/io@1.1.3': {} - '@adobe/css-tools@4.4.2': {} - '@adobe/css-tools@4.4.4': {} '@ampproject/remapping@2.2.1': @@ -10600,7 +10592,7 @@ snapshots: '@swc/helpers@0.5.1': dependencies: - tslib: 2.5.2 + tslib: 2.8.1 '@swc/helpers@0.5.17': dependencies: @@ -11345,7 +11337,7 @@ snapshots: ast-types@0.16.1: dependencies: - tslib: 2.5.2 + tslib: 2.8.1 asynckit@0.4.0: {} @@ -12667,7 +12659,7 @@ snapshots: focus-lock@1.3.6: dependencies: - tslib: 2.5.2 + tslib: 2.8.1 follow-redirects@1.15.9: {} @@ -13462,7 +13454,7 @@ snapshots: jest-styled-components@7.2.0(styled-components@6.1.19(react-dom@19.1.1(react@19.1.1))(react@19.1.1)): dependencies: - '@adobe/css-tools': 4.4.2 + '@adobe/css-tools': 4.4.4 styled-components: 6.1.19(react-dom@19.1.1(react@19.1.1))(react@19.1.1) jest-util@29.7.0: @@ -14759,7 +14751,7 @@ snapshots: esprima: 4.0.1 source-map: 0.6.1 tiny-invariant: 1.3.3 - tslib: 2.5.2 + tslib: 2.8.1 redent@3.0.0: dependencies: @@ -15469,8 +15461,6 @@ snapshots: tslib@1.14.1: {} - tslib@2.5.2: {} - tslib@2.6.2: {} tslib@2.8.1: {} @@ -15640,7 +15630,7 @@ snapshots: use-callback-ref@1.3.3(@types/react@19.1.10)(react@19.1.1): dependencies: react: 19.1.1 - tslib: 2.5.2 + tslib: 2.8.1 optionalDependencies: '@types/react': 19.1.10 @@ -15648,7 +15638,7 @@ snapshots: dependencies: detect-node-es: 1.1.0 react: 19.1.1 - tslib: 2.5.2 + tslib: 2.8.1 optionalDependencies: '@types/react': 19.1.10 diff --git a/src/components/GlobalStyles.tsx b/src/components/GlobalStyles.tsx index 7151d8bd4..21f5b7188 100644 --- a/src/components/GlobalStyles.tsx +++ b/src/components/GlobalStyles.tsx @@ -1,5 +1,4 @@ -import { createGlobalStyle } from 'styled-components'; - +import { createGlobalStyle } from '../tasty'; import { TOKENS } from '../tokens'; interface GlobalStylesProps { @@ -37,13 +36,6 @@ const BODY_STYLES = { 'font-weight': '400', }; -const fontsProvider = ({ publicUrl = '', fontDisplay = 'swap' }) => ` - @font-face { - font-family: text-security-disc; - src: url(data:font/woff2;base64,d09GMgABAAAAAAjoAAsAAAAAMGgAAAidAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGVgDWYgpQdQE2AiQDCAsGAAQgBYUOBy4bvi8lYxtWw7BxAPB87x5FmeAMlf3/96RzDN74RcXUcjTKmrJ3T2VDSShiPhfiIJxxS7DiLkHFfQV33CM4427mAred74pWur/J3dyVsKy7coREA8fzvPvpfUk+tB3R8YTCzE0SCLepejmJ2u1yqp+kC7W4Rc/tDTs3GpNJ8ttRPOSTPhsXlwbi4kVYWQmAcXmlrqYHMMsBwP/zHMz7fkF1gijOKuFQIxjwlGa2lkARhYaBxFHT54IOgBMQADi3LipIMAA3geO41EUkBTCO2gkxnOwnKYBx1E6p5WS+QUCMq50rNch6MwUCAAiAcdgttYVSIfPJ5kn6ApRFQ6I88BxLvvIC/maHUHS3TIoKiwLbbM8nEFWgE1oDz3woSxpagWbBXcQWhKtPeIlg6tK+7vX57QOszwU3sGUJrA7h2Mx1IWCNr9BKxsYo+pzS/OCO0OG9mwBkx337+lcuSxRdBcc+fJxlcAjK/zCfdgtBzuxQcTqfY4Yn6EB/Az3JS/RMu5f6B8wrn55S0IxdlLn+4Yb/ctIT+ocWYPcGAOvxSjEjpSiVMqSgFWVjzpCCXjAIRirTABpEQ2gYjaBRNIbG0QSaRFNoGs2gWTSH5tECWkRLaBmtoFW0htbRBtpEW2gb7aBdtIf20QE6REdFDlkZEh2jE3SKztA5ukCX6Apdoxt0i+7QPXpAj+gJPaMX9Ire0Dv6QJ/oC/qKvqHv6Af6iX6h3+gP+ov+of+I+ECMxETMiDmxIJbEilgTG2JL7Ig9cSCOxIk4ExfiStyIO/EgnsSLeBMf4kv8iD/taQANoiE0jEbQKBpD42gCTaIpNI1m0CyaQ/NoAS2iJbSMVtAqWkPraANtoi20jXbQLtpD++gAHaIjdIxO0Ck6Q+foAl2iK3SNbtAtukP36AE9oif0jF7QK3pD79B79AF9RJ/QZ/QFfUXf0Hf0A/1Ev9Bv9Af9Rf/Qf9DQABpEQ2gYjaBRNIbG0QSaRFNoGs2gWTSH5tECWkRLaBmtoFW0htbRBtpEW2gb7aBdtIf20QE6REfoGJ2gU3SGztEFukRX6BrdoFt0h+7RA3pET+gZvaBX9Aa9Re/Qe/QBfUSf0Gf0BX1F39B39AP9RL/Qb/QH/UX/0P8l9vq9gXwDIUCliyAhRAgTIoQoIUaIExKEJCFFSBMyhCwhR8gTCoQioUQoEyqEKqFGqBMahCahRWgTOoQuoUfoEwaEIWFEGBMmhClhRpgTFoQlYUVYEzaELWFH2BMOhGPCCeGUcEY4J1wQLglXhGvCDeGWcEe4JzwQHglPhGfCC+GV8EZ4J3wQPglfhG/CD+GX8Ef4p9sdgoQQIUyIEKKEGCFOSBCShBQhTcgQsoQcIU8oEIqEEqFMqBCqhBqhTmgkNBGaCS2EVkIboZ3QQegkdBG6CT2EXkIfoZ8wQBgkDBGGCSOEUcIYYZwwQZgkTBGmCTOEWcIcYZ6wQFgkLBGWCSuEVcIaYZ2wQdgkbBG2CTuEXcIeYZ9wQDgkHBGOCSeEU8IZ4ZxwQbgkXBGuCTeEW8Id4Z7wQHgkPBGeCS+EV8Ib4Z3wQfgkfBG+CT+EX8If4Z8AZpAQIoQJEUKUECPECQlCkpAipAkZQpaQI+QJBUKRUCKUCRVClVAj1AkNQpPQIrQJHUKX0CP0CQPCkDAijAkTwpQwI8wJC8KSsCKsCRvClrAj7AkHwpFwIpwJF8IV4ZpwQ7gl3BHuCQ+ER8IT4ZnwQnglvBHeCR+ET8IX4ZvwQ/gl/BH+lzv+AmMkTYAmSBOiCdNEaKI0MZo4TYImSZOiSdNkaLI0OZo8TYGmSFOiKdNUaKo0NZo6TYOmSdOiadN0aLo0PZo+zYBmSDOiGdNMaKY0M5o5zYJmSbOiWdNsaLY0O5o9zYHmmOaE5pTmjOac5oLmkuaK5prmhuaW5o7mnuaB5pHmieaZ5oXmleaN5p3mg+aT5ovmm+aH5pfmj2ZRAqCCoEKgwqAioKKgYqDioBKgkqBSoNKgMqCyoHKg8qAKoIqgSqDKoCqgqqBqoOqgGkE1gWoG1QKqFVQbqHZQHaA6QXWB6gbVA6oXVB+oflADoAZBDYH+uxaEWDBiIYiFIhaGWDhiEYhFIhaFWDRiMYjFIhaHWDxiCYglIpaEWDJiKYilIpaGWDpiGYhlIpaFWDZiOYjlIpaHWD5iBYgVIlaEWDFiJYiVIlaGWDliFYhVIlaFWDViNYjVIlaHWD1iDYg1ItaEWDNiLYi1ItaGWDtiHYh1ItaFWDdiPYj1ItaHWD9iA4gNIjaE2DBiI4iNIjaG2DhiE4hNIjaF2DRiM4jNIjaH2DxiC4gtIraE2DJiK4itIraG2DpiG4htIraF2DZiO4jtIraH2D5iB4gdInaE2DFiJ4idInaG2DliF4hdInaF2DViN4jdInaH2D1iD4g9IvaE2DNiL4i9IvaG2DvE3iP2AbGPiH1C7DNiXxD7itg3xL4j9gOxn4j9Quw3Yn8Q+4vYP8T+M6cIDBz9EXfeUHR1JyygPL/++I3R1cRvdDr+E12Jfh3Q0EN/fHn2mXptpJxUkIqu/Cs2egM33OjSLcT33I82+B9nP37X/c0W52623s45CYCo03QIBCVrAFAycnSYSqvO4YJt/NP73YqA/giNZhJ6sBbmql+0SQZaxNOZudJbc2nqxNvpM+veq7Sz2LUgFEu+VLs+Ay3yp7MVertp6i23v2Rmv5gmHDhSQ6t5GmTaqTsqhpWwmbOk3uKJrNOmwSSMC17jghqygilDOUU3KlLmHHNrajw3DVNVGWytGZDisM/cbkdRnvfIUJkaGJlgAYcoQ5bGptTmGc1R7pBC3XhFsLXnXR54qrMc+dGNBkqE4laBi4KmZYGom8vIy0lTyBkppBjLoTndMmrofIRORirsNlCbXzCgulmo36KztS2iV8rrNoRUL5VdkMSGoSXroC1KOQAA) format('woff2'); - } -`; - const GlobalStylesElement = createGlobalStyle` body { ${({ $applyLegacyTokens }) => { @@ -70,6 +62,11 @@ const GlobalStylesElement = createGlobalStyle` }} } + @font-face { + font-family: text-security-disc; + src: url(data:font/woff2;base64,d09GMgABAAAAAAjoAAsAAAAAMGgAAAidAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGVgDWYgpQdQE2AiQDCAsGAAQgBYUOBy4bvi8lYxtWw7BxAPB87x5FmeAMlf3/96RzDN74RcXUcjTKmrJ3T2VDSShiPhfiIJxxS7DiLkHFfQV33CM4427mAred74pWur/J3dyVsKy7coREA8fzvPvpfUk+tB3R8YTCzE0SCLepejmJ2u1yqp+kC7W4Rc/tDTs3GpNJ8ttRPOSTPhsXlwbi4kVYWQmAcXmlrqYHMMsBwP/zHMz7fkF1gijOKuFQIxjwlGa2lkARhYaBxFHT54IOgBMQADi3LipIMAA3geO41EUkBTCO2gkxnOwnKYBx1E6p5WS+QUCMq50rNch6MwUCAAiAcdgttYVSIfPJ5kn6ApRFQ6I88BxLvvIC/maHUHS3TIoKiwLbbM8nEFWgE1oDz3woSxpagWbBXcQWhKtPeIlg6tK+7vX57QOszwU3sGUJrA7h2Mx1IWCNr9BKxsYo+pzS/OCO0OG9mwBkx337+lcuSxRdBcc+fJxlcAjK/zCfdgtBzuxQcTqfY4Yn6EB/Az3JS/RMu5f6B8wrn55S0IxdlLn+4Yb/ctIT+ocWYPcGAOvxSjEjpSiVMqSgFWVjzpCCXjAIRirTABpEQ2gYjaBRNIbG0QSaRFNoGs2gWTSH5tECWkRLaBmtoFW0htbRBtpEW2gb7aBdtIf20QE6REdFDlkZEh2jE3SKztA5ukCX6Apdoxt0i+7QPXpAj+gJPaMX9Ire0Dv6QJ/oC/qKvqHv6Af6iX6h3+gP+ov+of+I+ECMxETMiDmxIJbEilgTG2JL7Ig9cSCOxIk4ExfiStyIO/EgnsSLeBMf4kv8iD/taQANoiE0jEbQKBpD42gCTaIpNI1m0CyaQ/NoAS2iJbSMVtAqWkPraANtoi20jXbQLtpD++gAHaIjdIxO0Ck6Q+foAl2iK3SNbtAtukP36AE9oif0jF7QK3pD79B79AF9RJ/QZ/QFfUXf0Hf0A/1Ev9Bv9Af9Rf/Qf9DQABpEQ2gYjaBRNIbG0QSaRFNoGs2gWTSH5tECWkRLaBmtoFW0htbRBtpEW2gb7aBdtIf20QE6REfoGJ2gU3SGztEFukRX6BrdoFt0h+7RA3pET+gZvaBX9Aa9Re/Qe/QBfUSf0Gf0BX1F39B39AP9RL/Qb/QH/UX/0P8l9vq9gXwDIUCliyAhRAgTIoQoIUaIExKEJCFFSBMyhCwhR8gTCoQioUQoEyqEKqFGqBMahCahRWgTOoQuoUfoEwaEIWFEGBMmhClhRpgTFoQlYUVYEzaELWFH2BMOhGPCCeGUcEY4J1wQLglXhGvCDeGWcEe4JzwQHglPhGfCC+GV8EZ4J3wQPglfhG/CD+GX8Ef4p9sdgoQQIUyIEKKEGCFOSBCShBQhTcgQsoQcIU8oEIqEEqFMqBCqhBqhTmgkNBGaCS2EVkIboZ3QQegkdBG6CT2EXkIfoZ8wQBgkDBGGCSOEUcIYYZwwQZgkTBGmCTOEWcIcYZ6wQFgkLBGWCSuEVcIaYZ2wQdgkbBG2CTuEXcIeYZ9wQDgkHBGOCSeEU8IZ4ZxwQbgkXBGuCTeEW8Id4Z7wQHgkPBGeCS+EV8Ib4Z3wQfgkfBG+CT+EX8If4Z8AZpAQIoQJEUKUECPECQlCkpAipAkZQpaQI+QJBUKRUCKUCRVClVAj1AkNQpPQIrQJHUKX0CP0CQPCkDAijAkTwpQwI8wJC8KSsCKsCRvClrAj7AkHwpFwIpwJF8IV4ZpwQ7gl3BHuCQ+ER8IT4ZnwQnglvBHeCR+ET8IX4ZvwQ/gl/BH+lzv+AmMkTYAmSBOiCdNEaKI0MZo4TYImSZOiSdNkaLI0OZo8TYGmSFOiKdNUaKo0NZo6TYOmSdOiadN0aLo0PZo+zYBmSDOiGdNMaKY0M5o5zYJmSbOiWdNsaLY0O5o9zYHmmOaE5pTmjOac5oLmkuaK5prmhuaW5o7mnuaB5pHmieaZ5oXmleaN5p3mg+aT5ovmm+aH5pfmj2ZRAqCCoEKgwqAioKKgYqDioBKgkqBSoNKgMqCyoHKg8qAKoIqgSqDKoCqgqqBqoOqgGkE1gWoG1QKqFVQbqHZQHaA6QXWB6gbVA6oXVB+oflADoAZBDYH+uxaEWDBiIYiFIhaGWDhiEYhFIhaFWDRiMYjFIhaHWDxiCYglIpaEWDJiKYilIpaGWDpiGYhlIpaFWDZiOYjlIpaHWD5iBYgVIlaEWDFiJYiVIlaGWDliFYhVIlaFWDViNYjVIlaHWD1iDYg1ItaEWDNiLYi1ItaGWDtiHYh1ItaFWDdiPYj1ItaHWD9iA4gNIjaE2DBiI4iNIjaG2DhiE4hNIjaF2DRiM4jNIjaH2DxiC4gtIraE2DJiK4itIraG2DpiG4htIraF2DZiO4jtIraH2D5iB4gdInaE2DFiJ4idInaG2DliF4hdInaF2DViN4jdInaH2D1iD4g9IvaE2DNiL4i9IvaG2DvE3iP2AbGPiH1C7DNiXxD7itg3xL4j9gOxn4j9Quw3Yn8Q+4vYP8T+M6cIDBz9EXfeUHR1JyygPL/++I3R1cRvdDr+E12Jfh3Q0EN/fHn2mXptpJxUkIqu/Cs2egM33OjSLcT33I82+B9nP37X/c0W52623s45CYCo03QIBCVrAFAycnSYSqvO4YJt/NP73YqA/giNZhJ6sBbmql+0SQZaxNOZudJbc2nqxNvpM+veq7Sz2LUgFEu+VLs+Ay3yp7MVertp6i23v2Rmv5gmHDhSQ6t5GmTaqTsqhpWwmbOk3uKJrNOmwSSMC17jghqygilDOUU3KlLmHHNrajw3DVNVGWytGZDisM/cbkdRnvfIUJkaGJlgAYcoQ5bGptTmGc1R7pBC3XhFsLXnXR54qrMc+dGNBkqE4laBi4KmZYGom8vIy0lTyBkppBjLoTndMmrofIRORirsNlCbXzCgulmo36KztS2iV8rrNoRUL5VdkMSGoSXroC1KOQAA) format('woff2'); + } + html { overscroll-behavior-y: none; --font: ${({ $font }) => @@ -180,14 +177,9 @@ const GlobalStylesElement = createGlobalStyle` font-family: var(--monospace-font); } - ${({ $fonts, $publicUrl, $fontDisplay }) => - $fonts === false - ? '' - : fontsProvider({ - publicUrl: $publicUrl, - ...($fontDisplay ? { fontDisplay: $fontDisplay } : {}), - })} - // Prism Code + + + // Prism Code code[class*="language-"], pre[class*="language-"] { color: var(--dark-color); diff --git a/src/components/HiddenInput.tsx b/src/components/HiddenInput.tsx index 49e8f4110..64337112a 100644 --- a/src/components/HiddenInput.tsx +++ b/src/components/HiddenInput.tsx @@ -1,24 +1,25 @@ -import styled from 'styled-components'; +import { tasty } from '../tasty'; -export const HiddenInput = styled.input<{ $isButton: boolean }>` - &&&&& { - display: block; - font-family: inherit; - font-size: 100%; - line-height: 1.15; - margin: 0; - overflow: visible; - box-sizing: border-box; - padding: 0; - position: absolute; - top: 0; - right: 0; - left: 0; - bottom: 0; - opacity: 0.0001; - z-index: 1; - width: 100%; - height: 100%; - cursor: ${({ $isButton }) => ($isButton ? 'pointer' : 'default')}; - } -`; +export const HiddenInput = tasty({ + as: 'input', + styles: { + display: 'block', + fontFamily: 'inherit', + fontSize: '100%', + lineHeight: '1.15', + margin: '0', + overflow: 'visible', + boxSizing: 'border-box', + padding: '0', + position: 'absolute', + inset: '0', + opacity: '0.0001', + zIndex: '1', + width: '100%', + height: '100%', + cursor: { + '': 'default', + button: 'pointer', + }, + }, +}); diff --git a/src/components/Root.tsx b/src/components/Root.tsx index a17c8ceb3..54b2ac869 100644 --- a/src/components/Root.tsx +++ b/src/components/Root.tsx @@ -23,7 +23,7 @@ import { PortalProvider } from './portal'; const RootElement = tasty({ id: 'cube-ui-kit-root', - className: 'root', + // className: 'root', }); const DEFAULT_STYLES = { diff --git a/src/components/actions/Action/Action.tsx b/src/components/actions/Action/Action.tsx index 5caf047dd..1cf86fdab 100644 --- a/src/components/actions/Action/Action.tsx +++ b/src/components/actions/Action/Action.tsx @@ -29,26 +29,21 @@ export interface CubeActionProps< download?: string; } -const DEFAULT_ACTION_STYLES: Styles = { - reset: 'button', - position: 'relative', - margin: 0, - preset: 'inherit', - border: 0, - padding: 0, - outline: { - '': '#purple-03.0', - focused: '#purple-03', - }, - transition: 'theme', - cursor: 'pointer', - textDecoration: 'none', - fill: '#clear', -} as const; - const ActionElement = tasty({ as: 'button', - styles: DEFAULT_ACTION_STYLES, + styles: { + reset: 'button', + position: 'relative', + margin: 0, + preset: 'inherit', + border: 0, + padding: 0, + outline: 0, + transition: 'theme', + cursor: 'pointer', + textDecoration: 'none', + fill: '#clear', + }, }); const STYLE_PROPS = [...CONTAINER_STYLES, ...TEXT_STYLES]; @@ -79,7 +74,6 @@ export const Action = forwardRef(function Action( data-theme={theme} download={download} {...actionProps} - isDisabled={undefined} styles={styles} /> ); diff --git a/src/components/actions/Button/Button.tsx b/src/components/actions/Button/Button.tsx index 8b64d581c..e979e4c16 100644 --- a/src/components/actions/Button/Button.tsx +++ b/src/components/actions/Button/Button.tsx @@ -115,6 +115,7 @@ export const DEFAULT_BUTTON_STYLES = { textDecoration: 'none', transition: 'theme', reset: 'button', + outline: 0, outlineOffset: 1, padding: { '': '.5x (1.5x - 1bw)', diff --git a/src/components/actions/Menu/MenuItem.tsx b/src/components/actions/Menu/MenuItem.tsx index 3db31ed52..db7a4d92e 100644 --- a/src/components/actions/Menu/MenuItem.tsx +++ b/src/components/actions/Menu/MenuItem.tsx @@ -75,6 +75,8 @@ export function MenuItem(props: MenuItemProps) { suffix, description, icon, + rightIcon, + prefix, tooltip, mods: itemMods, qa: itemQa, @@ -82,11 +84,6 @@ export function MenuItem(props: MenuItemProps) { ...restCleanProps } = cleanItemProps as any; - // Build final suffix: submenu icon, custom suffix or HotKeys hint - const finalSuffix = submenuContext - ? suffix ?? - : suffix ?? (hotkeys ? {hotkeys} : undefined); - // Selection indicator will be handled by ItemBase component const isVirtualFocused = state.selectionManager.focusedKey === key; @@ -131,7 +128,9 @@ export function MenuItem(props: MenuItemProps) { })} ref={elementRef} icon={icon} - suffix={finalSuffix} + rightIcon={submenuContext ? : rightIcon} + prefix={prefix} + suffix={suffix} description={description} hotkeys={hotkeys} tooltip={tooltip} diff --git a/src/components/content/ItemBase/ItemBase.tsx b/src/components/content/ItemBase/ItemBase.tsx index eeb2032c1..a677cdb5c 100644 --- a/src/components/content/ItemBase/ItemBase.tsx +++ b/src/components/content/ItemBase/ItemBase.tsx @@ -168,6 +168,7 @@ const ItemBaseElement = tasty({ display: 'inline-grid', flow: 'column dense', gap: 0, + outline: 0, placeItems: 'stretch', placeContent: 'stretch', gridColumns: { @@ -518,7 +519,7 @@ const ItemBase = ( }, [children, isAutoTooltipEnabled, checkLabelOverflow]); useEffect(() => { - if (!isAutoTooltipEnabled) return; + if (!isAutoTooltipEnabled || typeof children !== 'string') return; const label = mergedLabelRef.current; if (!label) return; @@ -527,7 +528,12 @@ const ItemBase = ( resizeObserver.observe(label); return () => resizeObserver.disconnect(); - }, [isAutoTooltipEnabled, checkLabelOverflow, children, mergedLabelRef]); + }, [ + isAutoTooltipEnabled, + checkLabelOverflow, + typeof children === 'string' ? children : null, + mergedLabelRef, + ]); const finalLabelProps = useMemo(() => { return { diff --git a/src/components/content/Placeholder/Placeholder.tsx b/src/components/content/Placeholder/Placeholder.tsx index 8480491f1..5fa8642d3 100644 --- a/src/components/content/Placeholder/Placeholder.tsx +++ b/src/components/content/Placeholder/Placeholder.tsx @@ -1,5 +1,4 @@ import { forwardRef } from 'react'; -import styled from 'styled-components'; import { BaseProps, @@ -7,11 +6,22 @@ import { ContainerStyleProps, extractStyles, filterBaseProps, + keyframes, Styles, tasty, } from '../../../tasty'; -const PlaceholderElement = tasty({ +// Create the placeholder animation using keyframes helper +const placeholderAnimation = keyframes({ + '0%': { + 'background-position': '0 0', + }, + '100%': { + 'background-position': '$placeholder-animation-size 0', + }, +}); + +const StyledPlaceholder = tasty({ role: 'alert', 'aria-live': 'polite', 'aria-label': 'Content is loading', @@ -20,43 +30,44 @@ const PlaceholderElement = tasty({ fill: '#dark.10', height: '2x', opacity: '.35', - }, -}); - -const StyledPlaceholder = styled(PlaceholderElement)` - --placeholder-animation-time: 1.4s; - --placeholder-animation-size: calc((180rem + 100vw) / 3); - background-repeat: repeat; - background-size: var(--placeholder-animation-size); + aspectRatio: { + '': 'initial', + circle: '1 / 1', + }, + radius: { + '': '1r', + circle: 'round', + }, - && { - background-color: rgb(var(--dark-color-rgb) / 0.15); - } + // CSS custom properties for animation + '$placeholder-animation-time': '1.4s', + '$placeholder-animation-size': 'calc((180rem + 100vw) / 3)', - &[data-is-animated] { - animation: placeholder-animation var(--placeholder-animation-time) linear - infinite; - background-image: linear-gradient( - 135deg, - rgb(var(--dark-color-rgb) / 0.15) 0%, - rgb(var(--dark-color-rgb) / 0.15) 5%, - rgb(var(--dark-color-rgb) / 0) 35%, - rgb(var(--dark-03-color-rgb) / 0.2) 50%, - rgb(var(--dark-03-color-rgb) / 0) 65%, - rgb(var(--dark-color-rgb) / 0.15) 95%, - rgb(var(--dark-color-rgb) / 0.15) 100% - ); - } + // Base background styling + backgroundRepeat: 'repeat', + backgroundSize: '$placeholder-animation-size', + backgroundColor: '#dark.15', - @keyframes placeholder-animation { - 0% { - background-position: 0 0; - } - 100% { - background-position: var(--placeholder-animation-size) 0; - } - } -`; + // Animated state styling + animation: { + '': 'none', + animated: `${placeholderAnimation} $placeholder-animation-time linear infinite`, + }, + backgroundImage: { + '': 'none', + animated: `linear-gradient( + 135deg, + #dark.15 0%, + #dark.15 5%, + #dark.0 35%, + #dark-03.2 50%, + #dark-03.0 65%, + #dark.15 95%, + #dark.15 100% + )`, + }, + }, +}); export interface CubePlaceholderProps extends BaseProps, ContainerStyleProps { size?: Styles['fontSize']; @@ -77,11 +88,9 @@ export const Placeholder = forwardRef(function Placeholder( role="region" {...filterBaseProps(props, { eventProps: true })} ref={ref} - mods={{ animated: !isStatic }} + mods={{ animated: !isStatic, circle }} styles={{ height: size, - width: circle ? size : false, - radius: circle ? '9999rem' : '1r', ...styles, }} /> diff --git a/src/components/content/Text.tsx b/src/components/content/Text.tsx index ca202bfde..f7bc69370 100644 --- a/src/components/content/Text.tsx +++ b/src/components/content/Text.tsx @@ -80,14 +80,13 @@ const TextElement = tasty({ const Text = forwardRef(function CubeText(allProps: CubeTextProps, ref) { allProps = useSlotProps(allProps, 'text'); - const { as, qa, block, styleName, ellipsis, nowrap, ...props } = allProps; + const { as, qa, block, ellipsis, nowrap, ...props } = allProps; const styles = extractStyles(props, STYLE_LIST, {}, TEXT_PROP_MAP); return ( .cube-modal': { + '$base-translate': 'calc((50vh - 50%) / -3)', + transform: 'translate(0, calc(var(--base-translate)))', + }, - &.cube-modal-transition-enter { - opacity: 0; - display: flex; + '&.cube-modal-transition-enter': { + opacity: 0, + display: 'flex', + }, - & .cube-modal { - transform: translate(0, calc(-32px + var(--base-translate))) scale(0.5); - } - } + '&.cube-modal-transition-enter > .cube-modal': { + transform: 'translate(0, calc(-32px + var(--base-translate))) scale(0.5)', + }, - &.cube-modal-transition-enter-active { - opacity: 1; - transition: all var(--enter-transition-time) cubic-bezier(0, 0.5, 0, 1); + '&.cube-modal-transition-enter-active': { + opacity: 1, + transition: 'all var(--enter-transition-time) cubic-bezier(0, 0.5, 0, 1)', + }, - & .cube-modal { - transform: translate(0, calc(var(--base-translate))) scale(1); - transition: all var(--enter-transition-time) cubic-bezier(0.5, 0.5, 0, 1); - } - } + '&.cube-modal-transition-enter-active > .cube-modal': { + transform: 'translate(0, calc(var(--base-translate))) scale(1)', + transition: + 'all var(--enter-transition-time) cubic-bezier(0.5, 0.5, 0, 1)', + }, - &.cube-modal-transition-enter-done { - display: flex; - } + '&.cube-modal-transition-enter-done': { + display: 'flex', + }, - &.cube-modal-transition-exit { - opacity: 1; - display: flex; + '&.cube-modal-transition-exit': { + opacity: 1, + display: 'flex', + }, - & .cube-modal { - transform: translate(0, calc(var(--base-translate))) scale(1); - } - } + '&.cube-modal-transition-exit > .cube-modal': { + transform: 'translate(0, calc(var(--base-translate))) scale(1)', + }, - &.cube-modal-transition-exit-active { - opacity: 0; - transition: all var(--leave-transition-time) ease-in; + '&.cube-modal-transition-exit-active': { + opacity: 0, + transition: 'all var(--leave-transition-time) ease-in', + }, - & .cube-modal { - transform: translate(0, calc(-32px + var(--base-translate))) scale(0.5); - transition: all var(--leave-transition-time) ease-in; - } - } + '&.cube-modal-transition-exit-active > .cube-modal': { + transform: 'translate(0, calc(-32px + var(--base-translate))) scale(0.5)', + transition: 'all var(--leave-transition-time) ease-in', + }, - &.cube-modal-transition-exit-done { - display: none; - } -`; + '&.cube-modal-transition-exit-done': { + display: 'none', + }, + }, +}); export interface CubeModalProps extends CubeCardProps { title?: string; diff --git a/src/stories/Tasty.docs.mdx b/src/stories/Tasty.docs.mdx index 5a020ec5f..292ed5821 100644 --- a/src/stories/Tasty.docs.mdx +++ b/src/stories/Tasty.docs.mdx @@ -185,7 +185,14 @@ color: '#purple', // Full opacity color: '#purple.5', // 50% opacity color: '#purple.05', // 5% opacity -// RGB values (no commas!) +// Color token definition syntax +'#primary': 'rgb(255 120 45)', // Define custom color variables +'#brand': '#purple', // Reference existing color tokens +'#accent': '#purple.5', // With opacity +'#custom': '#aaffbb', // Hex colors +'#theme': 'var(--purple-color)', // CSS custom properties + +// Via custom property '$custom-color': 'rgb(255 128 0)', ``` @@ -611,7 +618,37 @@ const Component = tasty({ }); ``` ---- +### Custom Color Definitions + +Define custom color variables with enhanced syntax: + +```jsx +const ThemedComponent = tasty({ + styles: { + // Define custom color variables (maps to --name-color CSS properties) + '#primary': 'rgb(255 120 45)', // Creates --primary-color + '#secondary': '#purple', // Creates --secondary-color, references purple token + '#accent': '#purple.5', // Creates --accent-color with 50% opacity + '#success': '#aaffbb', // Creates --success-color from hex + '#brand': 'var(--purple-color)', // Creates --brand-color from CSS variable + + // Use the defined colors + fill: '#primary', // Uses var(--primary-color) + color: '#secondary', // Uses var(--secondary-color) + border: '1bw solid #accent', // Uses var(--accent-color) + + // Color definitions work with state styling + '#interactive': { + '': '#primary', + 'hovered': '#primary.8', + 'pressed': '#primary.6', + }, + }, +}); + +// Color variables are automatically scoped and provide RGB variants +// Generates: --primary-color, --primary-color-rgb, etc. +``` ## ✅ Best Practices & Anti-patterns @@ -631,6 +668,14 @@ styles: { radius: '1r', } +// ✅ Define custom color tokens with #name syntax +styles: { + '#primary': 'rgb(255 120 45)', + '#accent': '#purple.5', + fill: '#primary', + border: '1bw solid #accent', +} + // ✅ Use semantic transition names transition: 'theme 0.3s' diff --git a/src/stories/lists/baseProps.ts b/src/stories/lists/baseProps.ts index 9e92b4448..92f1120f1 100644 --- a/src/stories/lists/baseProps.ts +++ b/src/stories/lists/baseProps.ts @@ -33,7 +33,6 @@ export const baseProps = [ 'style', 'styles', 'css', - 'styleName', 'hidden', 'disabled', 'mods', diff --git a/src/tasty/DEBUG.md b/src/tasty/DEBUG.md new file mode 100644 index 000000000..55a4ec659 --- /dev/null +++ b/src/tasty/DEBUG.md @@ -0,0 +1,148 @@ +# Tasty CSS Runtime Debug Utilities + +The tasty system provides powerful debug utilities to inspect generated CSS at runtime. These are especially useful for debugging complex responsive layouts and state-based styling. + +## Basic Usage + +```typescript +import { tastyDebug } from '@cube-dev/ui-kit'; + +// 🎯 Inspect an element by selector +const css = tastyDebug.inspectElement('[data-qa="my-header"]'); + +// 🎯 Get CSS for a specific tasty class +const classCSS = tastyDebug.getCSSForClass('t24'); + +// 🎯 Inspect a DOM element directly +const element = document.querySelector('.my-component'); +tastyDebug.inspectDOMElement(element); + +// 🎯 Get all generated CSS +const allCSS = tastyDebug.getAllCSS(); + +// 🎯 Get a summary of all tasty usage +tastyDebug.getSummary(); +``` + +## Browser Console Usage + +In development mode, `tastyDebug` is automatically available on `window`: + +```javascript +// Check what's available +tastyDebug.getSummary() + +// Inspect your components +tastyDebug.inspectElement('[data-qa="header"]') +tastyDebug.inspectElement('.some-component') + +// Check specific classes +tastyDebug.getCSSForClass('t24') + +// Find all tasty classes in use +tastyDebug.findAllTastyClasses() +``` + +## Advanced Inspection + +```typescript +// Detailed inspection with breakdown +const inspection = tastyDebug.inspect('[data-qa="complex-grid"]'); +console.log('Element:', inspection.element); +console.log('Tasty classes:', inspection.tastyClasses); +console.log('Full CSS:', inspection.css); +console.log('Per-class breakdown:', inspection.breakdown); + +// Pretty-print CSS +tastyDebug.logCSS(someCSS, 'My Component CSS'); +``` + +## Example Output + +When you run `tastyDebug.inspectElement('[data-qa="header"]')`, you'll see: + +```css +.t24:not([data-is-sticky]) { + position: static; + background-color: transparent; + z-index: auto; + box-shadow: none var(--shadow-color); +} + +.t24[data-is-sticky] { + position: sticky; + top: 0; + background-color: var(--white-color); + z-index: 10; + box-shadow: 0 calc(0.5 * var(--gap)) calc(0.5 * var(--gap)) var(--white-color); +} + +.t24 { + display: grid; + padding: var(--gap) calc(2 * var(--gap)); + height: auto; + min-height: calc(6 * var(--gap)); + place-items: center stretch; + place-content: stretch; +} + +@media (min-width: 1200px) { + .t24:not([data-is-back-button-top]) { + grid-template-areas: + "breadcrumbs breadcrumbs breadcrumbs breadcrumbs breadcrumbs breadcrumbs" + "back title . subtitle spacer extra" + "back title . subtitle spacer extra" + "content content content content content content" + "footer footer footer footer footer footer"; + } +} + +/* ...more responsive and state-based CSS... */ +``` + +## Use Cases + +- **🐛 Debugging**: Why isn't my grid layout working? +- **🔍 Understanding**: What CSS is actually being generated? +- **⚡ Performance**: How much CSS is being generated? +- **📱 Responsive**: Are my breakpoints working correctly? +- **🎛️ State Logic**: Are my modifiers applying the right styles? + +## Environment Behavior + +### Development Mode +The global `window.tastyDebug` is automatically available when `NODE_ENV` is 'development' or not 'production': + +```javascript +// Available automatically in browser console +tastyDebug.getSummary() +``` + +### Production Mode +In production, the global `window.tastyDebug` is not installed automatically. You can either: + +1. **Import directly** (recommended): +```typescript +import { tastyDebug } from '@cube-dev/ui-kit'; +tastyDebug.inspectElement('[data-qa="my-component"]'); +``` + +2. **Manually install globally**: +```typescript +import { installGlobalDebug } from '@cube-dev/ui-kit'; +installGlobalDebug(); // Makes window.tastyDebug available +``` + +### Manual Installation + +You can manually install the global debug utilities at any time: + +```typescript +import { installGlobalDebug, tastyDebug } from '@cube-dev/ui-kit'; + +// Install globally for easy console access +installGlobalDebug(); + +// Or use directly +tastyDebug.inspectElement('[data-qa="header"]'); +``` diff --git a/src/tasty/__snapshots__/tasty.test.tsx.snap b/src/tasty/__snapshots__/tasty.test.tsx.snap index 5df81e98b..8f84d671f 100644 --- a/src/tasty/__snapshots__/tasty.test.tsx.snap +++ b/src/tasty/__snapshots__/tasty.test.tsx.snap @@ -1,469 +1,526 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`tasty() API should allow multiple wrapping 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -.c0.c0 { - position: static; -} - -.c0.c0 { - padding-top: calc(2 * var(--gap)); -} - -.c0.c0 { - border: var(--border-width) solid var(--black-color); -} - -.c0.c0 { - color: var(--white-color); - --current-color: var(--white-color, white); - --current-color-rgb: var(--white-color-rgb); -} - -.c0.c0 { - display: flex; -} - -
-
-
-`; +exports[`tasty() API should allow multiple wrapping 1`] = `".t15.t15 {position: static; padding-top: calc(2 * var(--gap)); border: var(--border-width) solid var(--black-color); color: var(--white-color); --current-color: var(--white-color, white); --current-color-rgb: var(--white-color-rgb); display: flex;}"`; exports[`tasty() API should allow nested modifiers 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -.c0.c0 { - display: block; -} - -.c0.c0:first-child { - color: var(--clear-color); - --current-color: var(--clear-color, clear); - --current-color-rgb: var(--clear-color-rgb); -} - -.c0.c0:not(:first-child) { - color: var(--black-color); - --current-color: var(--black-color, black); - --current-color-rgb: var(--black-color-rgb); -} - -
-
-
+".t16.t16 {display: block;} +.t16.t16:first-child {color: var(--clear-color); --current-color: var(--clear-color, clear); --current-color-rgb: var(--clear-color-rgb);} +.t16.t16:not(:first-child) {color: var(--black-color); --current-color: var(--black-color, black); --current-color-rgb: var(--black-color-rgb);}" `; -exports[`tasty() API should be able to override styles 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -.c0.c0 { - display: block; -} - -.c0.c0 { - color: rgb(var(--black-color-rgb) / .1); - --current-color: var(--black-color, black); - --current-color-rgb: var(--black-color-rgb); -} - -
-
-
-`; +exports[`tasty() API should be able to override styles 1`] = `".t7.t7 {display: block; color: rgb(var(--black-color-rgb) / .1); --current-color: var(--black-color, black); --current-color-rgb: var(--black-color-rgb);}"`; exports[`tasty() API should create element styles 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -.c0 [data-element="Element"] { - outline: none; -} - -.c0 [data-element="Element"][hidden] { - display: none !important; -} - -.c0.c0:not([data-is-modified]) [data-element="Element"] { - color: var(--dark-color); - --current-color: var(--dark-color, dark); - --current-color-rgb: var(--dark-color-rgb); -} - -.c0.c0[data-is-modified] [data-element="Element"] { - color: var(--purple-color); - --current-color: var(--purple-color, purple); - --current-color-rgb: var(--purple-color-rgb); -} - -
-
-
+".t12.t12:not([data-is-modified]) [data-element="Element"] {color: var(--dark-color); --current-color: var(--dark-color, dark); --current-color-rgb: var(--dark-color-rgb);} +.t12.t12[data-is-modified] [data-element="Element"] {color: var(--purple-color); --current-color: var(--purple-color, purple); --current-color-rgb: var(--purple-color-rgb);}" `; exports[`tasty() API should create responsive styles 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -@media (min-width: 980px) { - .c0.c0 { - display: grid; - } -} - -@media (max-width: 979px) { - .c0.c0 { - display: flex; - } -} - -
-
-
+"@media (min-width: 980px) {.t11.t11 {display: grid;}} +@media (max-width: 979px) {.t11.t11 {display: flex;}}" `; -exports[`tasty() API should define style props 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -.c0.c0 { - border: var(--border-width) solid var(--border-color); -} - -
-
-
+exports[`tasty() API should define style props 1`] = `".t14.t14 {border: var(--border-width) solid var(--border-color);}"`; + +exports[`tasty() API should fallback to default variant 1`] = `".t9.t9 {color: var(--white-color); --current-color: var(--white-color, white); --current-color-rgb: var(--white-color-rgb);}"`; + +exports[`tasty() API should handle arrays containing state maps 1`] = ` +".t20.t20 {display: block;} +@media (min-width: 1200px) {.t20.t20 {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap)); margin-top: var(--gap); margin-right: var(--gap); margin-bottom: var(--gap); margin-left: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t20.t20:not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap); background-color: rgb(var(--gray-color-rgb) / .05);}} +@media (min-width: 768px) and (max-width: 1199px) {.t20.t20[data-is-hovered] {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap)); background-color: rgb(var(--blue-color-rgb) / .10);}} +@media (max-width: 767px) {.t20.t20:not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap); background-color: rgb(var(--gray-color-rgb) / .05);}} +@media (max-width: 767px) {.t20.t20[data-is-hovered] {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap)); background-color: rgb(var(--blue-color-rgb) / .10);}} +@media (min-width: 768px) and (max-width: 1199px) {.t20.t20:not([data-is-disabled]):not([data-is-pressed]) {margin-top: calc(2 * var(--gap)); margin-right: calc(2 * var(--gap)); margin-bottom: calc(2 * var(--gap)); margin-left: calc(2 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t20.t20[data-is-disabled]:not([data-is-pressed]) {margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0;}} +@media (min-width: 768px) and (max-width: 1199px) {.t20.t20[data-is-pressed]:not([data-is-disabled]) {margin-top: var(--gap); margin-right: var(--gap); margin-bottom: var(--gap); margin-left: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t20.t20[data-is-disabled][data-is-pressed] {margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0;}} +@media (max-width: 767px) {.t20.t20:not([data-is-focused]) {margin-top: calc(0.5 * var(--gap)); margin-right: calc(0.5 * var(--gap)); margin-bottom: calc(0.5 * var(--gap)); margin-left: calc(0.5 * var(--gap));}} +@media (max-width: 767px) {.t20.t20[data-is-focused] {margin-top: var(--gap); margin-right: var(--gap); margin-bottom: var(--gap); margin-left: var(--gap);}} +@media (min-width: 1200px) {.t20.t20:not([data-is-hovered]) {background-color: var(--white-color);}} +@media (min-width: 1200px) {.t20.t20:not([data-is-hovered])>* {--context-fill-color: var(--white-color); --context-fill-color-rgb: var(--white-color-rgb);}} +@media (min-width: 1200px) {.t20.t20[data-is-hovered] {background-color: rgb(var(--blue-color-rgb) / .05);}} +@media (min-width: 1200px) {.t20.t20[data-is-hovered]>* {--context-fill-color: rgb(var(--blue-color-rgb) / .05); --context-fill-color-rgb: var(--blue-color-rgb);}} +@media (min-width: 768px) and (max-width: 1199px) {.t20.t20:not([data-is-hovered])>* {--context-fill-color: rgb(var(--gray-color-rgb) / .05); --context-fill-color-rgb: var(--gray-color-rgb);}} +@media (min-width: 768px) and (max-width: 1199px) {.t20.t20[data-is-hovered]>* {--context-fill-color: rgb(var(--blue-color-rgb) / .10); --context-fill-color-rgb: var(--blue-color-rgb);}} +@media (max-width: 767px) {.t20.t20:not([data-is-hovered])>* {--context-fill-color: rgb(var(--gray-color-rgb) / .05); --context-fill-color-rgb: var(--gray-color-rgb);}} +@media (max-width: 767px) {.t20.t20[data-is-hovered]>* {--context-fill-color: rgb(var(--blue-color-rgb) / .10); --context-fill-color-rgb: var(--blue-color-rgb);}}" `; -exports[`tasty() API should fallback to default variant 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} +exports[`tasty() API should handle complex gridAreas with responsive arrays and state modifiers 1`] = ` +".t24.t24:not([data-is-sticky]) {position: static; background-color: transparent; z-index: auto; box-shadow: none var(--shadow-color);} +.t24.t24[data-is-sticky] {position: sticky; top: 0; background-color: var(--white-color); z-index: 10; box-shadow: 0 calc(0.5 * var(--gap)) calc(0.5 * var(--gap)) var(--white-color);} +.t24.t24[data-is-sticky]>* {--context-fill-color: var(--white-color); --context-fill-color-rgb: var(--white-color-rgb);} +.t24.t24 {display: grid; padding-top: var(--gap); padding-right: calc(2 * var(--gap)); padding-bottom: var(--gap); padding-left: calc(2 * var(--gap)); height: auto; min-height: calc(6 * var(--gap)); max-height: initial; place-items: center stretch; place-content: stretch;} +@media (min-width: 1200px) {.t24.t24:not([data-is-back-button-top]) {grid-template-areas: "breadcrumbs breadcrumbs breadcrumbs breadcrumbs breadcrumbs breadcrumbs" "back title . subtitle spacer extra" "back title . subtitle spacer extra" "content content content content content content" "footer footer footer footer footer footer";}} +@media (min-width: 1200px) {.t24.t24[data-is-back-button-top] {grid-template-areas: "back back back back back back" "breadcrumbs breadcrumbs breadcrumbs breadcrumbs breadcrumbs breadcrumbs" ". title . subtitle spacer extra" ". title . subtitle spacer extra" "content content content content content content" "footer footer footer footer footer footer";}} +@media (max-width: 1199px) {.t24.t24:not([data-is-back-button-top]) {grid-template-areas: "breadcrumbs breadcrumbs breadcrumbs breadcrumbs" "back title spacer extra" "back subtitle subtitle extra" "back . . extra" "content content content content" "footer footer footer footer";}} +@media (max-width: 1199px) {.t24.t24[data-is-back-button-top] {grid-template-areas: "back back back back" "breadcrumbs breadcrumbs breadcrumbs breadcrumbs" ". title spacer extra" ". subtitle subtitle extra" ". . . extra" "content content content content" "footer footer footer footer";}} +@media (min-width: 1200px) {.t24.t24 {grid-template-columns: max-content minmax(calc(2 * var(--gap)), auto) calc(2 * var(--gap)) minmax(0, auto) minmax(calc(2 * var(--gap)), 1fr) minmax(min-content, max-content);}} +@media (max-width: 1199px) {.t24.t24 {grid-template-columns: max-content minmax(calc(2 * var(--gap)), auto) minmax(calc(2 * var(--gap)), 1fr) minmax(min-content, max-content);}}" +`; -.c0.c0 { - color: var(--white-color); - --current-color: var(--white-color, white); - --current-color-rgb: var(--white-color-rgb); -} +exports[`tasty() API should handle complex responsive styles with state binding 1`] = ` +"@media (min-width: 1200px) {.t23.t23 [data-element="Header"] {--font-size: var(--h2-font-size, var(--default-font-size, inherit)); font-size: var(--h2-font-size, var(--default-font-size, inherit)); --line-height: var(--h2-line-height, var(--default-line-height, inherit)); line-height: var(--h2-line-height, var(--default-line-height, inherit)); --letter-spacing: var(--h2-letter-spacing, var(--default-letter-spacing, inherit)); letter-spacing: var(--h2-letter-spacing, var(--default-letter-spacing, inherit)); --font-weight: var(--h2-font-weight, var(--default-font-weight, inherit)); font-weight: var(--h2-font-weight, var(--default-font-weight, inherit)); --font-style: var(--h2-font-style, var(--default-font-style, inherit)); font-style: var(--h2-font-style, var(--default-font-style, inherit)); --text-transform: var(--h2-text-transform, var(--default-text-transform, inherit)); text-transform: var(--h2-text-transform, var(--default-text-transform, inherit)); --font-family: var(--h2-font-family, var(--default-font-family, var(--font, NonexistentFontName))), var(--font, sans-serif); font-family: var(--h2-font-family, var(--default-font-family, var(--font, NonexistentFontName))), var(--font, sans-serif); --bold-font-weight: var(--h2-bold-font-weight, var(--default-bold-font-weight, inherit)); --icon-size: var(--h2-icon-size, var(--default-icon-size, inherit)); margin-top: 0; margin-right: 0; margin-bottom: calc(2 * var(--gap)); margin-left: 0;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23 [data-element="Header"] {--font-size: var(--h3-font-size, var(--default-font-size, inherit)); font-size: var(--h3-font-size, var(--default-font-size, inherit)); --line-height: var(--h3-line-height, var(--default-line-height, inherit)); line-height: var(--h3-line-height, var(--default-line-height, inherit)); --letter-spacing: var(--h3-letter-spacing, var(--default-letter-spacing, inherit)); letter-spacing: var(--h3-letter-spacing, var(--default-letter-spacing, inherit)); --font-weight: var(--h3-font-weight, var(--default-font-weight, inherit)); font-weight: var(--h3-font-weight, var(--default-font-weight, inherit)); --font-style: var(--h3-font-style, var(--default-font-style, inherit)); font-style: var(--h3-font-style, var(--default-font-style, inherit)); --text-transform: var(--h3-text-transform, var(--default-text-transform, inherit)); text-transform: var(--h3-text-transform, var(--default-text-transform, inherit)); --font-family: var(--h3-font-family, var(--default-font-family, var(--font, NonexistentFontName))), var(--font, sans-serif); font-family: var(--h3-font-family, var(--default-font-family, var(--font, NonexistentFontName))), var(--font, sans-serif); --bold-font-weight: var(--h3-bold-font-weight, var(--default-bold-font-weight, inherit)); --icon-size: var(--h3-icon-size, var(--default-icon-size, inherit)); margin-top: 0; margin-right: 0; margin-bottom: var(--gap); margin-left: 0;}} +@media (max-width: 767px) {.t23.t23 [data-element="Header"] {--font-size: var(--h4-font-size, var(--default-font-size, inherit)); font-size: var(--h4-font-size, var(--default-font-size, inherit)); --line-height: var(--h4-line-height, var(--default-line-height, inherit)); line-height: var(--h4-line-height, var(--default-line-height, inherit)); --letter-spacing: var(--h4-letter-spacing, var(--default-letter-spacing, inherit)); letter-spacing: var(--h4-letter-spacing, var(--default-letter-spacing, inherit)); --font-weight: var(--h4-font-weight, var(--default-font-weight, inherit)); font-weight: var(--h4-font-weight, var(--default-font-weight, inherit)); --font-style: var(--h4-font-style, var(--default-font-style, inherit)); font-style: var(--h4-font-style, var(--default-font-style, inherit)); --text-transform: var(--h4-text-transform, var(--default-text-transform, inherit)); text-transform: var(--h4-text-transform, var(--default-text-transform, inherit)); --font-family: var(--h4-font-family, var(--default-font-family, var(--font, NonexistentFontName))), var(--font, sans-serif); font-family: var(--h4-font-family, var(--default-font-family, var(--font, NonexistentFontName))), var(--font, sans-serif); --bold-font-weight: var(--h4-bold-font-weight, var(--default-bold-font-weight, inherit)); --icon-size: var(--h4-icon-size, var(--default-icon-size, inherit)); margin-top: 0; margin-right: 0; margin-bottom: calc(0.5 * var(--gap)); margin-left: 0;}} +.t23.t23:not([data-is-hovered]):not([data-variant="danger"]) [data-element="Header"] {color: var(--text-primary-color); --current-color: var(--text-primary-color, text-primary); --current-color-rgb: var(--text-primary-color-rgb);} +.t23.t23[data-is-hovered]:not([data-variant="danger"]) [data-element="Header"] {color: var(--text-primary-hover-color); --current-color: var(--text-primary-hover-color, text-primary-hover); --current-color-rgb: var(--text-primary-hover-color-rgb);} +.t23.t23[data-variant="danger"]:not([data-is-hovered]) [data-element="Header"] {color: var(--danger-color); --current-color: var(--danger-color, danger); --current-color-rgb: var(--danger-color-rgb);} +.t23.t23[data-is-hovered][data-variant="danger"] [data-element="Header"] {color: var(--text-primary-hover-color); --current-color: var(--text-primary-hover-color, text-primary-hover); --current-color-rgb: var(--text-primary-hover-color-rgb);} +@media (min-width: 1200px) {.t23.t23 [data-element="Content"] {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23 [data-element="Content"] {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (max-width: 767px) {.t23.t23 [data-element="Content"] {padding-top: calc(0.5 * var(--gap)); padding-right: calc(0.5 * var(--gap)); padding-bottom: calc(0.5 * var(--gap)); padding-left: calc(0.5 * var(--gap));}} +.t23.t23:not([data-is-highlighted]):not([data-is-disabled]):not([disabled]) [data-element="Content"] {color: var(--text-color); --current-color: var(--text-color, text); --current-color-rgb: var(--text-color-rgb);} +.t23.t23[data-is-highlighted]:not([data-is-disabled]):not([disabled]) [data-element="Content"] {color: var(--text-highlighted-color); --current-color: var(--text-highlighted-color, text-highlighted); --current-color-rgb: var(--text-highlighted-color-rgb);} +.t23.t23[data-is-disabled]:not([data-is-highlighted]):not([disabled]) [data-element="Content"] {color: var(--text-color); --current-color: var(--text-color, text); --current-color-rgb: var(--text-color-rgb);} +.t23.t23[data-is-highlighted][data-is-disabled]:not([disabled]) [data-element="Content"] {color: var(--text-color); --current-color: var(--text-color, text); --current-color-rgb: var(--text-color-rgb);} +.t23.t23[disabled]:not([data-is-highlighted]):not([data-is-disabled]) [data-element="Content"] {color: var(--text-disabled-color); --current-color: var(--text-disabled-color, text-disabled); --current-color-rgb: var(--text-disabled-color-rgb);} +.t23.t23[data-is-highlighted][disabled]:not([data-is-disabled]) [data-element="Content"] {color: var(--text-highlighted-color); --current-color: var(--text-highlighted-color, text-highlighted); --current-color-rgb: var(--text-highlighted-color-rgb);} +.t23.t23[data-is-disabled][disabled]:not([data-is-highlighted]) [data-element="Content"] {color: var(--text-disabled-color); --current-color: var(--text-disabled-color, text-disabled); --current-color-rgb: var(--text-disabled-color-rgb);} +.t23.t23[data-is-highlighted][data-is-disabled][disabled] [data-element="Content"] {color: var(--text-disabled-color); --current-color: var(--text-disabled-color, text-disabled); --current-color-rgb: var(--text-disabled-color-rgb);} +@media (min-width: 1200px) {.t23.t23:not([data-is-expanded]) [data-element="Footer"] {display: flex; gap: calc(2 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-is-expanded] [data-element="Footer"] {display: flex; gap: calc(2 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23:not([data-is-expanded]) [data-element="Footer"] {display: flex; gap: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-expanded] [data-element="Footer"] {display: flex; gap: var(--gap);}} +@media (max-width: 767px) {.t23.t23:not([data-is-expanded]) [data-element="Footer"] {display: none;}} +@media (max-width: 767px) {.t23.t23[data-is-expanded] [data-element="Footer"] {display: flex; gap: calc(0.5 * var(--gap));}} +@media (max-width: 767px) {.t23.t23:not([data-is-expanded]) [data-element="Footer"] > *:not(:last-child) {margin-bottom: calc(0.5 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23:not([data-is-compact]) [data-element="Footer"] {padding-top: calc(2 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-is-compact] [data-element="Footer"] {padding-top: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23:not([data-is-compact]) [data-element="Footer"] {padding-top: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-compact] [data-element="Footer"] {padding-top: calc(0.5 * var(--gap));}} +@media (max-width: 767px) {.t23.t23:not([data-is-compact]) [data-element="Footer"] {padding-top: calc(0.5 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-is-compact] [data-element="Footer"] {padding-top: 0; padding-right: 0; padding-bottom: 0; padding-left: 0;}} +@media (min-width: 1200px) {.t23.t23 {display: grid; gap: calc(3 * var(--gap)); --local-radius: calc(2 * var(--radius)); border-radius: var(--local-radius);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23 {display: flex; gap: calc(2 * var(--gap)); --local-radius: var(--radius); border-radius: var(--local-radius);}} +@media (max-width: 767px) {.t23.t23 {display: block; --local-radius: calc(0.5 * var(--radius)); border-radius: var(--local-radius);}} +@media (max-width: 767px) {.t23.t23 > *:not(:last-child) {margin-bottom: var(--gap);}} +@media (min-width: 1200px) {.t23.t23:not([data-variant="compact"]):not([data-is-pressed]):not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(4 * var(--gap)); padding-right: calc(4 * var(--gap)); padding-bottom: calc(4 * var(--gap)); padding-left: calc(4 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-variant="compact"]:not([data-is-pressed]):not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-is-pressed]:not([data-variant="compact"]):not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-variant="compact"][data-is-pressed]:not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-is-disabled]:not([data-variant="compact"]):not([data-is-pressed]):not([data-is-hovered]) {padding-top: calc(4 * var(--gap)); padding-right: calc(4 * var(--gap)); padding-bottom: calc(4 * var(--gap)); padding-left: calc(4 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-variant="compact"][data-is-disabled]:not([data-is-pressed]):not([data-is-hovered]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-is-pressed][data-is-disabled]:not([data-variant="compact"]):not([data-is-hovered]) {padding-top: calc(4 * var(--gap)); padding-right: calc(4 * var(--gap)); padding-bottom: calc(4 * var(--gap)); padding-left: calc(4 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-variant="compact"][data-is-pressed][data-is-disabled]:not([data-is-hovered]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered]:not([data-variant="compact"]):not([data-is-pressed]):not([data-is-disabled]) {padding-top: calc(5 * var(--gap)); padding-right: calc(5 * var(--gap)); padding-bottom: calc(5 * var(--gap)); padding-left: calc(5 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-variant="compact"][data-is-hovered]:not([data-is-pressed]):not([data-is-disabled]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-is-pressed][data-is-hovered]:not([data-variant="compact"]):not([data-is-disabled]) {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-variant="compact"][data-is-pressed][data-is-hovered]:not([data-is-disabled]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-is-disabled][data-is-hovered]:not([data-variant="compact"]):not([data-is-pressed]) {padding-top: calc(5 * var(--gap)); padding-right: calc(5 * var(--gap)); padding-bottom: calc(5 * var(--gap)); padding-left: calc(5 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-variant="compact"][data-is-disabled][data-is-hovered]:not([data-is-pressed]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-is-pressed][data-is-disabled][data-is-hovered]:not([data-variant="compact"]) {padding-top: calc(5 * var(--gap)); padding-right: calc(5 * var(--gap)); padding-bottom: calc(5 * var(--gap)); padding-left: calc(5 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23[data-variant="compact"][data-is-pressed][data-is-disabled][data-is-hovered] {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23:not([data-variant="compact"]):not([data-is-pressed]):not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="compact"]:not([data-is-pressed]):not([data-is-disabled]):not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-pressed]:not([data-variant="compact"]):not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="compact"][data-is-pressed]:not([data-is-disabled]):not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-disabled]:not([data-variant="compact"]):not([data-is-pressed]):not([data-is-hovered]) {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="compact"][data-is-disabled]:not([data-is-pressed]):not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-pressed][data-is-disabled]:not([data-variant="compact"]):not([data-is-hovered]) {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="compact"][data-is-pressed][data-is-disabled]:not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered]:not([data-variant="compact"]):not([data-is-pressed]):not([data-is-disabled]) {padding-top: calc(4 * var(--gap)); padding-right: calc(4 * var(--gap)); padding-bottom: calc(4 * var(--gap)); padding-left: calc(4 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="compact"][data-is-hovered]:not([data-is-pressed]):not([data-is-disabled]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-pressed][data-is-hovered]:not([data-variant="compact"]):not([data-is-disabled]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="compact"][data-is-pressed][data-is-hovered]:not([data-is-disabled]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-disabled][data-is-hovered]:not([data-variant="compact"]):not([data-is-pressed]) {padding-top: calc(4 * var(--gap)); padding-right: calc(4 * var(--gap)); padding-bottom: calc(4 * var(--gap)); padding-left: calc(4 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="compact"][data-is-disabled][data-is-hovered]:not([data-is-pressed]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-pressed][data-is-disabled][data-is-hovered]:not([data-variant="compact"]) {padding-top: calc(4 * var(--gap)); padding-right: calc(4 * var(--gap)); padding-bottom: calc(4 * var(--gap)); padding-left: calc(4 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="compact"][data-is-pressed][data-is-disabled][data-is-hovered] {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (max-width: 767px) {.t23.t23:not([data-variant="compact"]):not([data-is-pressed]):not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-variant="compact"]:not([data-is-pressed]):not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(0.5 * var(--gap)); padding-right: calc(0.5 * var(--gap)); padding-bottom: calc(0.5 * var(--gap)); padding-left: calc(0.5 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-is-pressed]:not([data-variant="compact"]):not([data-is-disabled]):not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (max-width: 767px) {.t23.t23[data-variant="compact"][data-is-pressed]:not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(0.5 * var(--gap)); padding-right: calc(0.5 * var(--gap)); padding-bottom: calc(0.5 * var(--gap)); padding-left: calc(0.5 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-is-disabled]:not([data-variant="compact"]):not([data-is-pressed]):not([data-is-hovered]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-variant="compact"][data-is-disabled]:not([data-is-pressed]):not([data-is-hovered]) {padding-top: calc(0.5 * var(--gap)); padding-right: calc(0.5 * var(--gap)); padding-bottom: calc(0.5 * var(--gap)); padding-left: calc(0.5 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-is-pressed][data-is-disabled]:not([data-variant="compact"]):not([data-is-hovered]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-variant="compact"][data-is-pressed][data-is-disabled]:not([data-is-hovered]) {padding-top: calc(0.5 * var(--gap)); padding-right: calc(0.5 * var(--gap)); padding-bottom: calc(0.5 * var(--gap)); padding-left: calc(0.5 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-is-hovered]:not([data-variant="compact"]):not([data-is-pressed]):not([data-is-disabled]) {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-variant="compact"][data-is-hovered]:not([data-is-pressed]):not([data-is-disabled]) {padding-top: calc(0.5 * var(--gap)); padding-right: calc(0.5 * var(--gap)); padding-bottom: calc(0.5 * var(--gap)); padding-left: calc(0.5 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-is-pressed][data-is-hovered]:not([data-variant="compact"]):not([data-is-disabled]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (max-width: 767px) {.t23.t23[data-variant="compact"][data-is-pressed][data-is-hovered]:not([data-is-disabled]) {padding-top: calc(0.5 * var(--gap)); padding-right: calc(0.5 * var(--gap)); padding-bottom: calc(0.5 * var(--gap)); padding-left: calc(0.5 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-is-disabled][data-is-hovered]:not([data-variant="compact"]):not([data-is-pressed]) {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-variant="compact"][data-is-disabled][data-is-hovered]:not([data-is-pressed]) {padding-top: calc(0.5 * var(--gap)); padding-right: calc(0.5 * var(--gap)); padding-bottom: calc(0.5 * var(--gap)); padding-left: calc(0.5 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-is-pressed][data-is-disabled][data-is-hovered]:not([data-variant="compact"]) {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap));}} +@media (max-width: 767px) {.t23.t23[data-variant="compact"][data-is-pressed][data-is-disabled][data-is-hovered] {padding-top: calc(0.5 * var(--gap)); padding-right: calc(0.5 * var(--gap)); padding-bottom: calc(0.5 * var(--gap)); padding-left: calc(0.5 * var(--gap));}} +@media (min-width: 1200px) {.t23.t23:not([data-is-hovered]):not([data-is-focused]):not([data-is-disabled]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1200px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered]:not([data-is-focused]):not([data-is-disabled]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1300px;}} +@media (min-width: 1200px) {.t23.t23[data-is-focused]:not([data-is-hovered]):not([data-is-disabled]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1300px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-focused]:not([data-is-disabled]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1300px;}} +@media (min-width: 1200px) {.t23.t23[data-is-disabled]:not([data-is-hovered]):not([data-is-focused]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1200px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-disabled]:not([data-is-focused]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1200px;}} +@media (min-width: 1200px) {.t23.t23[data-is-focused][data-is-disabled]:not([data-is-hovered]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1200px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-focused][data-is-disabled]:not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1200px;}} +@media (min-width: 1200px) {.t23.t23[data-is-expanded]:not([data-is-hovered]):not([data-is-focused]):not([data-is-disabled]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-expanded]:not([data-is-focused]):not([data-is-disabled]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1300px;}} +@media (min-width: 1200px) {.t23.t23[data-is-focused][data-is-expanded]:not([data-is-hovered]):not([data-is-disabled]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1300px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-focused][data-is-expanded]:not([data-is-disabled]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1300px;}} +@media (min-width: 1200px) {.t23.t23[data-is-disabled][data-is-expanded]:not([data-is-hovered]):not([data-is-focused]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-disabled][data-is-expanded]:not([data-is-focused]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-focused][data-is-disabled][data-is-expanded]:not([data-is-hovered]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-focused][data-is-disabled][data-is-expanded]:not([data-size="large"]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-size="large"]:not([data-is-hovered]):not([data-is-focused]):not([data-is-disabled]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-size="large"]:not([data-is-focused]):not([data-is-disabled]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1300px;}} +@media (min-width: 1200px) {.t23.t23[data-is-focused][data-size="large"]:not([data-is-hovered]):not([data-is-disabled]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1300px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-focused][data-size="large"]:not([data-is-disabled]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1300px;}} +@media (min-width: 1200px) {.t23.t23[data-is-disabled][data-size="large"]:not([data-is-hovered]):not([data-is-focused]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-disabled][data-size="large"]:not([data-is-focused]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-focused][data-is-disabled][data-size="large"]:not([data-is-hovered]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-focused][data-is-disabled][data-size="large"]:not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-expanded][data-size="large"]:not([data-is-hovered]):not([data-is-focused]):not([data-is-disabled]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-expanded][data-size="large"]:not([data-is-focused]):not([data-is-disabled]) {width: auto; min-width: initial; max-width: 1300px;}} +@media (min-width: 1200px) {.t23.t23[data-is-focused][data-is-expanded][data-size="large"]:not([data-is-hovered]):not([data-is-disabled]) {width: auto; min-width: initial; max-width: 1300px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-focused][data-is-expanded][data-size="large"]:not([data-is-disabled]) {width: auto; min-width: initial; max-width: 1300px;}} +@media (min-width: 1200px) {.t23.t23[data-is-disabled][data-is-expanded][data-size="large"]:not([data-is-hovered]):not([data-is-focused]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-disabled][data-is-expanded][data-size="large"]:not([data-is-focused]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-focused][data-is-disabled][data-is-expanded][data-size="large"]:not([data-is-hovered]) {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-focused][data-is-disabled][data-is-expanded][data-size="large"] {width: auto; min-width: initial; max-width: 1400px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23:not([data-is-hovered]):not([data-is-focused]):not([data-is-disabled]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 800px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered]:not([data-is-focused]):not([data-is-disabled]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 900px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-focused]:not([data-is-hovered]):not([data-is-disabled]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 900px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-focused]:not([data-is-disabled]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 900px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-disabled]:not([data-is-hovered]):not([data-is-focused]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 800px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-disabled]:not([data-is-focused]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 800px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-focused][data-is-disabled]:not([data-is-hovered]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 800px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-focused][data-is-disabled]:not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 800px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-expanded]:not([data-is-hovered]):not([data-is-focused]):not([data-is-disabled]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-expanded]:not([data-is-focused]):not([data-is-disabled]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 900px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-focused][data-is-expanded]:not([data-is-hovered]):not([data-is-disabled]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 900px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-focused][data-is-expanded]:not([data-is-disabled]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 900px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-disabled][data-is-expanded]:not([data-is-hovered]):not([data-is-focused]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-disabled][data-is-expanded]:not([data-is-focused]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-focused][data-is-disabled][data-is-expanded]:not([data-is-hovered]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-focused][data-is-disabled][data-is-expanded]:not([data-size="large"]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-size="large"]:not([data-is-hovered]):not([data-is-focused]):not([data-is-disabled]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-size="large"]:not([data-is-focused]):not([data-is-disabled]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 900px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-focused][data-size="large"]:not([data-is-hovered]):not([data-is-disabled]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 900px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-focused][data-size="large"]:not([data-is-disabled]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 900px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-disabled][data-size="large"]:not([data-is-hovered]):not([data-is-focused]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-disabled][data-size="large"]:not([data-is-focused]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-focused][data-is-disabled][data-size="large"]:not([data-is-hovered]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-focused][data-is-disabled][data-size="large"]:not([data-is-expanded]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-expanded][data-size="large"]:not([data-is-hovered]):not([data-is-focused]):not([data-is-disabled]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-expanded][data-size="large"]:not([data-is-focused]):not([data-is-disabled]) {width: auto; min-width: initial; max-width: 900px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-focused][data-is-expanded][data-size="large"]:not([data-is-hovered]):not([data-is-disabled]) {width: auto; min-width: initial; max-width: 900px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-focused][data-is-expanded][data-size="large"]:not([data-is-disabled]) {width: auto; min-width: initial; max-width: 900px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-disabled][data-is-expanded][data-size="large"]:not([data-is-hovered]):not([data-is-focused]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-disabled][data-is-expanded][data-size="large"]:not([data-is-focused]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-focused][data-is-disabled][data-is-expanded][data-size="large"]:not([data-is-hovered]) {width: auto; min-width: initial; max-width: 1000px;}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-focused][data-is-disabled][data-is-expanded][data-size="large"] {width: auto; min-width: initial; max-width: 1000px;}} +@media (max-width: 767px) {.t23.t23:not([data-is-hovered]):not([data-is-focused]):not([data-is-disabled]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered]:not([data-is-focused]):not([data-is-disabled]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-focused]:not([data-is-hovered]):not([data-is-disabled]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-focused]:not([data-is-disabled]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-disabled]:not([data-is-hovered]):not([data-is-focused]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-disabled]:not([data-is-focused]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-focused][data-is-disabled]:not([data-is-hovered]):not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-focused][data-is-disabled]:not([data-is-expanded]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-expanded]:not([data-is-hovered]):not([data-is-focused]):not([data-is-disabled]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-expanded]:not([data-is-focused]):not([data-is-disabled]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-focused][data-is-expanded]:not([data-is-hovered]):not([data-is-disabled]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-focused][data-is-expanded]:not([data-is-disabled]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-disabled][data-is-expanded]:not([data-is-hovered]):not([data-is-focused]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-disabled][data-is-expanded]:not([data-is-focused]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-focused][data-is-disabled][data-is-expanded]:not([data-is-hovered]):not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-focused][data-is-disabled][data-is-expanded]:not([data-size="large"]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-size="large"]:not([data-is-hovered]):not([data-is-focused]):not([data-is-disabled]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-size="large"]:not([data-is-focused]):not([data-is-disabled]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-focused][data-size="large"]:not([data-is-hovered]):not([data-is-disabled]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-focused][data-size="large"]:not([data-is-disabled]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-disabled][data-size="large"]:not([data-is-hovered]):not([data-is-focused]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-disabled][data-size="large"]:not([data-is-focused]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-focused][data-is-disabled][data-size="large"]:not([data-is-hovered]):not([data-is-expanded]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-focused][data-is-disabled][data-size="large"]:not([data-is-expanded]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-expanded][data-size="large"]:not([data-is-hovered]):not([data-is-focused]):not([data-is-disabled]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-expanded][data-size="large"]:not([data-is-focused]):not([data-is-disabled]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-focused][data-is-expanded][data-size="large"]:not([data-is-hovered]):not([data-is-disabled]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-focused][data-is-expanded][data-size="large"]:not([data-is-disabled]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-disabled][data-is-expanded][data-size="large"]:not([data-is-hovered]):not([data-is-focused]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-disabled][data-is-expanded][data-size="large"]:not([data-is-focused]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-focused][data-is-disabled][data-is-expanded][data-size="large"]:not([data-is-hovered]) {width: auto; min-width: initial; max-width: 100%;}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-focused][data-is-disabled][data-is-expanded][data-size="large"] {width: auto; min-width: initial; max-width: 100%;}} +.t23.t23:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([data-is-hovered]):not([disabled]):not([data-is-pressed]) {background-color: var(--surface-color);} +.t23.t23:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([data-is-hovered]):not([disabled]):not([data-is-pressed])>* {--context-fill-color: var(--surface-color); --context-fill-color-rgb: var(--surface-color-rgb);} +.t23.t23[data-variant="success"]:not([data-is-disabled]):not([data-is-hovered]):not([disabled]):not([data-is-pressed]) {background-color: var(--success-color);} +.t23.t23[data-variant="success"]:not([data-is-disabled]):not([data-is-hovered]):not([disabled]):not([data-is-pressed])>* {--context-fill-color: var(--success-color); --context-fill-color-rgb: var(--success-color-rgb);} +.t23.t23[data-is-disabled]:not([data-variant="success"]):not([data-variant="danger"]):not([data-is-hovered]):not([disabled]):not([data-is-pressed]) {background-color: var(--surface-color);} +.t23.t23[data-is-disabled]:not([data-variant="success"]):not([data-variant="danger"]):not([data-is-hovered]):not([disabled]):not([data-is-pressed])>* {--context-fill-color: var(--surface-color); --context-fill-color-rgb: var(--surface-color-rgb);} +.t23.t23[data-variant="success"][data-is-disabled]:not([data-is-hovered]):not([disabled]):not([data-is-pressed]) {background-color: var(--surface-color);} +.t23.t23[data-variant="success"][data-is-disabled]:not([data-is-hovered]):not([disabled]):not([data-is-pressed])>* {--context-fill-color: var(--surface-color); --context-fill-color-rgb: var(--surface-color-rgb);} +.t23.t23[data-variant="danger"]:not([data-is-disabled]):not([data-is-hovered]):not([disabled]):not([data-is-pressed]) {background-color: var(--surface-color);} +.t23.t23[data-variant="danger"]:not([data-is-disabled]):not([data-is-hovered]):not([disabled]):not([data-is-pressed])>* {--context-fill-color: var(--surface-color); --context-fill-color-rgb: var(--surface-color-rgb);} +.t23.t23[data-is-disabled][data-variant="danger"]:not([data-is-hovered]):not([disabled]):not([data-is-pressed]) {background-color: var(--surface-color);} +.t23.t23[data-is-disabled][data-variant="danger"]:not([data-is-hovered]):not([disabled]):not([data-is-pressed])>* {--context-fill-color: var(--surface-color); --context-fill-color-rgb: var(--surface-color-rgb);} +.t23.t23[data-is-hovered]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([disabled]):not([data-is-pressed]) {background-color: var(--surface-hover-color);} +.t23.t23[data-is-hovered]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([disabled]):not([data-is-pressed])>* {--context-fill-color: var(--surface-hover-color); --context-fill-color-rgb: var(--surface-hover-color-rgb);} +.t23.t23[data-variant="success"][data-is-hovered]:not([data-is-disabled]):not([disabled]):not([data-is-pressed]) {background-color: var(--success-color);} +.t23.t23[data-variant="success"][data-is-hovered]:not([data-is-disabled]):not([disabled]):not([data-is-pressed])>* {--context-fill-color: var(--success-color); --context-fill-color-rgb: var(--success-color-rgb);} +.t23.t23[data-is-disabled][data-is-hovered]:not([data-variant="success"]):not([data-variant="danger"]):not([disabled]):not([data-is-pressed]) {background-color: var(--surface-hover-color);} +.t23.t23[data-is-disabled][data-is-hovered]:not([data-variant="success"]):not([data-variant="danger"]):not([disabled]):not([data-is-pressed])>* {--context-fill-color: var(--surface-hover-color); --context-fill-color-rgb: var(--surface-hover-color-rgb);} +.t23.t23[data-variant="success"][data-is-disabled][data-is-hovered]:not([disabled]):not([data-is-pressed]) {background-color: var(--surface-hover-color);} +.t23.t23[data-variant="success"][data-is-disabled][data-is-hovered]:not([disabled]):not([data-is-pressed])>* {--context-fill-color: var(--surface-hover-color); --context-fill-color-rgb: var(--surface-hover-color-rgb);} +.t23.t23[data-variant="danger"][data-is-hovered]:not([data-is-disabled]):not([disabled]):not([data-is-pressed]) {background-color: var(--danger-hover-color);} +.t23.t23[data-variant="danger"][data-is-hovered]:not([data-is-disabled]):not([disabled]):not([data-is-pressed])>* {--context-fill-color: var(--danger-hover-color); --context-fill-color-rgb: var(--danger-hover-color-rgb);} +.t23.t23[data-is-disabled][data-variant="danger"][data-is-hovered]:not([disabled]):not([data-is-pressed]) {background-color: var(--danger-hover-color);} +.t23.t23[data-is-disabled][data-variant="danger"][data-is-hovered]:not([disabled]):not([data-is-pressed])>* {--context-fill-color: var(--danger-hover-color); --context-fill-color-rgb: var(--danger-hover-color-rgb);} +.t23.t23[disabled]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([data-is-hovered]):not([data-is-pressed]) {background-color: var(--surface-disabled-color);} +.t23.t23[disabled]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([data-is-hovered]):not([data-is-pressed])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-variant="success"][disabled]:not([data-is-disabled]):not([data-is-hovered]):not([data-is-pressed]) {background-color: var(--success-color);} +.t23.t23[data-variant="success"][disabled]:not([data-is-disabled]):not([data-is-hovered]):not([data-is-pressed])>* {--context-fill-color: var(--success-color); --context-fill-color-rgb: var(--success-color-rgb);} +.t23.t23[data-is-disabled][disabled]:not([data-variant="success"]):not([data-variant="danger"]):not([data-is-hovered]):not([data-is-pressed]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-is-disabled][disabled]:not([data-variant="success"]):not([data-variant="danger"]):not([data-is-hovered]):not([data-is-pressed])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-variant="success"][data-is-disabled][disabled]:not([data-is-hovered]):not([data-is-pressed]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-variant="success"][data-is-disabled][disabled]:not([data-is-hovered]):not([data-is-pressed])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-variant="danger"][disabled]:not([data-is-disabled]):not([data-is-hovered]):not([data-is-pressed]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-variant="danger"][disabled]:not([data-is-disabled]):not([data-is-hovered]):not([data-is-pressed])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-is-disabled][data-variant="danger"][disabled]:not([data-is-hovered]):not([data-is-pressed]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-is-disabled][data-variant="danger"][disabled]:not([data-is-hovered]):not([data-is-pressed])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-is-hovered][disabled]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([data-is-pressed]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-is-hovered][disabled]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([data-is-pressed])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-variant="success"][data-is-hovered][disabled]:not([data-is-disabled]):not([data-is-pressed]) {background-color: var(--success-color);} +.t23.t23[data-variant="success"][data-is-hovered][disabled]:not([data-is-disabled]):not([data-is-pressed])>* {--context-fill-color: var(--success-color); --context-fill-color-rgb: var(--success-color-rgb);} +.t23.t23[data-is-disabled][data-is-hovered][disabled]:not([data-variant="success"]):not([data-variant="danger"]):not([data-is-pressed]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-is-disabled][data-is-hovered][disabled]:not([data-variant="success"]):not([data-variant="danger"]):not([data-is-pressed])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-variant="success"][data-is-disabled][data-is-hovered][disabled]:not([data-is-pressed]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-variant="success"][data-is-disabled][data-is-hovered][disabled]:not([data-is-pressed])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-variant="danger"][data-is-hovered][disabled]:not([data-is-disabled]):not([data-is-pressed]) {background-color: var(--danger-hover-color);} +.t23.t23[data-variant="danger"][data-is-hovered][disabled]:not([data-is-disabled]):not([data-is-pressed])>* {--context-fill-color: var(--danger-hover-color); --context-fill-color-rgb: var(--danger-hover-color-rgb);} +.t23.t23[data-is-disabled][data-variant="danger"][data-is-hovered][disabled]:not([data-is-pressed]) {background-color: var(--danger-hover-color);} +.t23.t23[data-is-disabled][data-variant="danger"][data-is-hovered][disabled]:not([data-is-pressed])>* {--context-fill-color: var(--danger-hover-color); --context-fill-color-rgb: var(--danger-hover-color-rgb);} +.t23.t23[data-is-pressed]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([data-is-hovered]):not([disabled]) {background-color: var(--surface-pressed-color);} +.t23.t23[data-is-pressed]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([data-is-hovered]):not([disabled])>* {--context-fill-color: var(--surface-pressed-color); --context-fill-color-rgb: var(--surface-pressed-color-rgb);} +.t23.t23[data-variant="success"][data-is-pressed]:not([data-is-disabled]):not([data-is-hovered]):not([disabled]) {background-color: var(--success-color);} +.t23.t23[data-variant="success"][data-is-pressed]:not([data-is-disabled]):not([data-is-hovered]):not([disabled])>* {--context-fill-color: var(--success-color); --context-fill-color-rgb: var(--success-color-rgb);} +.t23.t23[data-is-disabled][data-is-pressed]:not([data-variant="success"]):not([data-variant="danger"]):not([data-is-hovered]):not([disabled]) {background-color: var(--surface-pressed-color);} +.t23.t23[data-is-disabled][data-is-pressed]:not([data-variant="success"]):not([data-variant="danger"]):not([data-is-hovered]):not([disabled])>* {--context-fill-color: var(--surface-pressed-color); --context-fill-color-rgb: var(--surface-pressed-color-rgb);} +.t23.t23[data-variant="success"][data-is-disabled][data-is-pressed]:not([data-is-hovered]):not([disabled]) {background-color: var(--surface-pressed-color);} +.t23.t23[data-variant="success"][data-is-disabled][data-is-pressed]:not([data-is-hovered]):not([disabled])>* {--context-fill-color: var(--surface-pressed-color); --context-fill-color-rgb: var(--surface-pressed-color-rgb);} +.t23.t23[data-variant="danger"][data-is-pressed]:not([data-is-disabled]):not([data-is-hovered]):not([disabled]) {background-color: var(--surface-pressed-color);} +.t23.t23[data-variant="danger"][data-is-pressed]:not([data-is-disabled]):not([data-is-hovered]):not([disabled])>* {--context-fill-color: var(--surface-pressed-color); --context-fill-color-rgb: var(--surface-pressed-color-rgb);} +.t23.t23[data-is-disabled][data-variant="danger"][data-is-pressed]:not([data-is-hovered]):not([disabled]) {background-color: var(--surface-pressed-color);} +.t23.t23[data-is-disabled][data-variant="danger"][data-is-pressed]:not([data-is-hovered]):not([disabled])>* {--context-fill-color: var(--surface-pressed-color); --context-fill-color-rgb: var(--surface-pressed-color-rgb);} +.t23.t23[data-is-hovered][data-is-pressed]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([disabled]) {background-color: var(--surface-pressed-color);} +.t23.t23[data-is-hovered][data-is-pressed]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([disabled])>* {--context-fill-color: var(--surface-pressed-color); --context-fill-color-rgb: var(--surface-pressed-color-rgb);} +.t23.t23[data-variant="success"][data-is-hovered][data-is-pressed]:not([data-is-disabled]):not([disabled]) {background-color: var(--success-color);} +.t23.t23[data-variant="success"][data-is-hovered][data-is-pressed]:not([data-is-disabled]):not([disabled])>* {--context-fill-color: var(--success-color); --context-fill-color-rgb: var(--success-color-rgb);} +.t23.t23[data-is-disabled][data-is-hovered][data-is-pressed]:not([data-variant="success"]):not([data-variant="danger"]):not([disabled]) {background-color: var(--surface-pressed-color);} +.t23.t23[data-is-disabled][data-is-hovered][data-is-pressed]:not([data-variant="success"]):not([data-variant="danger"]):not([disabled])>* {--context-fill-color: var(--surface-pressed-color); --context-fill-color-rgb: var(--surface-pressed-color-rgb);} +.t23.t23[data-variant="success"][data-is-disabled][data-is-hovered][data-is-pressed]:not([disabled]) {background-color: var(--surface-pressed-color);} +.t23.t23[data-variant="success"][data-is-disabled][data-is-hovered][data-is-pressed]:not([disabled])>* {--context-fill-color: var(--surface-pressed-color); --context-fill-color-rgb: var(--surface-pressed-color-rgb);} +.t23.t23[data-variant="danger"][data-is-hovered][data-is-pressed]:not([data-is-disabled]):not([disabled]) {background-color: var(--danger-hover-color);} +.t23.t23[data-variant="danger"][data-is-hovered][data-is-pressed]:not([data-is-disabled]):not([disabled])>* {--context-fill-color: var(--danger-hover-color); --context-fill-color-rgb: var(--danger-hover-color-rgb);} +.t23.t23[data-is-disabled][data-variant="danger"][data-is-hovered][data-is-pressed]:not([disabled]) {background-color: var(--danger-hover-color);} +.t23.t23[data-is-disabled][data-variant="danger"][data-is-hovered][data-is-pressed]:not([disabled])>* {--context-fill-color: var(--danger-hover-color); --context-fill-color-rgb: var(--danger-hover-color-rgb);} +.t23.t23[disabled][data-is-pressed]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([data-is-hovered]) {background-color: var(--surface-disabled-color);} +.t23.t23[disabled][data-is-pressed]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]):not([data-is-hovered])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-variant="success"][disabled][data-is-pressed]:not([data-is-disabled]):not([data-is-hovered]) {background-color: var(--success-color);} +.t23.t23[data-variant="success"][disabled][data-is-pressed]:not([data-is-disabled]):not([data-is-hovered])>* {--context-fill-color: var(--success-color); --context-fill-color-rgb: var(--success-color-rgb);} +.t23.t23[data-is-disabled][disabled][data-is-pressed]:not([data-variant="success"]):not([data-variant="danger"]):not([data-is-hovered]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-is-disabled][disabled][data-is-pressed]:not([data-variant="success"]):not([data-variant="danger"]):not([data-is-hovered])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-variant="success"][data-is-disabled][disabled][data-is-pressed]:not([data-is-hovered]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-variant="success"][data-is-disabled][disabled][data-is-pressed]:not([data-is-hovered])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-variant="danger"][disabled][data-is-pressed]:not([data-is-disabled]):not([data-is-hovered]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-variant="danger"][disabled][data-is-pressed]:not([data-is-disabled]):not([data-is-hovered])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-is-disabled][data-variant="danger"][disabled][data-is-pressed]:not([data-is-hovered]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-is-disabled][data-variant="danger"][disabled][data-is-pressed]:not([data-is-hovered])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-is-hovered][disabled][data-is-pressed]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-is-hovered][disabled][data-is-pressed]:not([data-variant="success"]):not([data-is-disabled]):not([data-variant="danger"])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-variant="success"][data-is-hovered][disabled][data-is-pressed]:not([data-is-disabled]) {background-color: var(--success-color);} +.t23.t23[data-variant="success"][data-is-hovered][disabled][data-is-pressed]:not([data-is-disabled])>* {--context-fill-color: var(--success-color); --context-fill-color-rgb: var(--success-color-rgb);} +.t23.t23[data-is-disabled][data-is-hovered][disabled][data-is-pressed]:not([data-variant="success"]):not([data-variant="danger"]) {background-color: var(--surface-disabled-color);} +.t23.t23[data-is-disabled][data-is-hovered][disabled][data-is-pressed]:not([data-variant="success"]):not([data-variant="danger"])>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-variant="success"][data-is-disabled][data-is-hovered][disabled][data-is-pressed] {background-color: var(--surface-disabled-color);} +.t23.t23[data-variant="success"][data-is-disabled][data-is-hovered][disabled][data-is-pressed]>* {--context-fill-color: var(--surface-disabled-color); --context-fill-color-rgb: var(--surface-disabled-color-rgb);} +.t23.t23[data-variant="danger"][data-is-hovered][disabled][data-is-pressed]:not([data-is-disabled]) {background-color: var(--danger-hover-color);} +.t23.t23[data-variant="danger"][data-is-hovered][disabled][data-is-pressed]:not([data-is-disabled])>* {--context-fill-color: var(--danger-hover-color); --context-fill-color-rgb: var(--danger-hover-color-rgb);} +.t23.t23[data-is-disabled][data-variant="danger"][data-is-hovered][disabled][data-is-pressed] {background-color: var(--danger-hover-color);} +.t23.t23[data-is-disabled][data-variant="danger"][data-is-hovered][disabled][data-is-pressed]>* {--context-fill-color: var(--danger-hover-color); --context-fill-color-rgb: var(--danger-hover-color-rgb);} +@media (min-width: 1200px) {.t23.t23:not([data-variant="borderless"]):not([data-is-hovered]):not([data-is-error]):not([data-is-focused]) {border: calc(2 * var(--border-width)) solid var(--border-color);}} +@media (min-width: 1200px) {.t23.t23[data-variant="borderless"]:not([data-is-hovered]):not([data-is-error]):not([data-is-focused]) {border: calc(2 * var(--border-width)) solid var(--border-color);}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered]:not([data-variant="borderless"]):not([data-is-error]):not([data-is-focused]) {border: calc(2 * var(--border-width)) solid var(--border-hover-color);}} +@media (min-width: 1200px) {.t23.t23[data-variant="borderless"][data-is-hovered]:not([data-is-error]):not([data-is-focused]) {border: calc(2 * var(--border-width)) solid var(--border-color);}} +@media (min-width: 1200px) {.t23.t23[data-is-error]:not([data-variant="borderless"]):not([data-is-hovered]):not([data-is-focused]) {border: calc(2 * var(--border-width)) solid var(--border-color);}} +@media (min-width: 1200px) {.t23.t23[data-variant="borderless"][data-is-error]:not([data-is-hovered]):not([data-is-focused]) {border: calc(2 * var(--border-width)) solid var(--border-color);}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-error]:not([data-variant="borderless"]):not([data-is-focused]) {border: calc(2 * var(--border-width)) solid var(--border-hover-color);}} +@media (min-width: 1200px) {.t23.t23[data-variant="borderless"][data-is-hovered][data-is-error]:not([data-is-focused]) {border: calc(2 * var(--border-width)) solid var(--border-color);}} +@media (min-width: 1200px) {.t23.t23[data-is-focused]:not([data-variant="borderless"]):not([data-is-hovered]):not([data-is-error]) {border: calc(3 * var(--border-width)) solid var(--primary-color);}} +@media (min-width: 1200px) {.t23.t23[data-variant="borderless"][data-is-focused]:not([data-is-hovered]):not([data-is-error]) {border: calc(3 * var(--border-width)) solid var(--primary-color);}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-focused]:not([data-variant="borderless"]):not([data-is-error]) {border: calc(2 * var(--border-width)) solid var(--border-hover-color);}} +@media (min-width: 1200px) {.t23.t23[data-variant="borderless"][data-is-hovered][data-is-focused]:not([data-is-error]) {border: calc(3 * var(--border-width)) solid var(--primary-color);}} +@media (min-width: 1200px) {.t23.t23[data-is-error][data-is-focused]:not([data-variant="borderless"]):not([data-is-hovered]) {border: calc(3 * var(--border-width)) solid var(--danger-color);}} +@media (min-width: 1200px) {.t23.t23[data-variant="borderless"][data-is-error][data-is-focused]:not([data-is-hovered]) {border: calc(3 * var(--border-width)) solid var(--danger-color);}} +@media (min-width: 1200px) {.t23.t23[data-is-hovered][data-is-error][data-is-focused]:not([data-variant="borderless"]) {border: calc(2 * var(--border-width)) solid var(--border-hover-color);}} +@media (min-width: 1200px) {.t23.t23[data-variant="borderless"][data-is-hovered][data-is-error][data-is-focused] {border: calc(3 * var(--border-width)) solid var(--danger-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23:not([data-variant="borderless"]):not([data-is-hovered]):not([data-is-error]):not([data-is-focused]) {border: var(--border-width) solid var(--border-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="borderless"]:not([data-is-hovered]):not([data-is-error]):not([data-is-focused]) {border: var(--border-width) solid var(--border-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered]:not([data-variant="borderless"]):not([data-is-error]):not([data-is-focused]) {border: var(--border-width) solid var(--border-hover-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="borderless"][data-is-hovered]:not([data-is-error]):not([data-is-focused]) {border: var(--border-width) solid var(--border-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-error]:not([data-variant="borderless"]):not([data-is-hovered]):not([data-is-focused]) {border: var(--border-width) solid var(--border-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="borderless"][data-is-error]:not([data-is-hovered]):not([data-is-focused]) {border: var(--border-width) solid var(--border-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-error]:not([data-variant="borderless"]):not([data-is-focused]) {border: var(--border-width) solid var(--border-hover-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="borderless"][data-is-hovered][data-is-error]:not([data-is-focused]) {border: var(--border-width) solid var(--border-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-focused]:not([data-variant="borderless"]):not([data-is-hovered]):not([data-is-error]) {border: calc(2 * var(--border-width)) solid var(--primary-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="borderless"][data-is-focused]:not([data-is-hovered]):not([data-is-error]) {border: calc(2 * var(--border-width)) solid var(--primary-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-focused]:not([data-variant="borderless"]):not([data-is-error]) {border: var(--border-width) solid var(--border-hover-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="borderless"][data-is-hovered][data-is-focused]:not([data-is-error]) {border: calc(2 * var(--border-width)) solid var(--primary-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-error][data-is-focused]:not([data-variant="borderless"]):not([data-is-hovered]) {border: calc(2 * var(--border-width)) solid var(--danger-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="borderless"][data-is-error][data-is-focused]:not([data-is-hovered]) {border: calc(2 * var(--border-width)) solid var(--danger-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-is-hovered][data-is-error][data-is-focused]:not([data-variant="borderless"]) {border: var(--border-width) solid var(--border-hover-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23[data-variant="borderless"][data-is-hovered][data-is-error][data-is-focused] {border: calc(2 * var(--border-width)) solid var(--danger-color);}} +@media (max-width: 767px) {.t23.t23:not([data-variant="borderless"]):not([data-is-hovered]):not([data-is-error]):not([data-is-focused]) {border: var(--border-width) none var(--border-color);}} +@media (max-width: 767px) {.t23.t23[data-variant="borderless"]:not([data-is-hovered]):not([data-is-error]):not([data-is-focused]) {border: var(--border-width) none var(--border-color);}} +@media (max-width: 767px) {.t23.t23[data-is-hovered]:not([data-variant="borderless"]):not([data-is-error]):not([data-is-focused]) {border: var(--border-width) solid var(--border-hover-color);}} +@media (max-width: 767px) {.t23.t23[data-variant="borderless"][data-is-hovered]:not([data-is-error]):not([data-is-focused]) {border: var(--border-width) none var(--border-color);}} +@media (max-width: 767px) {.t23.t23[data-is-error]:not([data-variant="borderless"]):not([data-is-hovered]):not([data-is-focused]) {border: var(--border-width) none var(--border-color);}} +@media (max-width: 767px) {.t23.t23[data-variant="borderless"][data-is-error]:not([data-is-hovered]):not([data-is-focused]) {border: var(--border-width) none var(--border-color);}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-error]:not([data-variant="borderless"]):not([data-is-focused]) {border: var(--border-width) solid var(--border-hover-color);}} +@media (max-width: 767px) {.t23.t23[data-variant="borderless"][data-is-hovered][data-is-error]:not([data-is-focused]) {border: var(--border-width) none var(--border-color);}} +@media (max-width: 767px) {.t23.t23[data-is-focused]:not([data-variant="borderless"]):not([data-is-hovered]):not([data-is-error]) {border: var(--border-width) solid var(--primary-color);}} +@media (max-width: 767px) {.t23.t23[data-variant="borderless"][data-is-focused]:not([data-is-hovered]):not([data-is-error]) {border: var(--border-width) solid var(--primary-color);}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-focused]:not([data-variant="borderless"]):not([data-is-error]) {border: var(--border-width) solid var(--border-hover-color);}} +@media (max-width: 767px) {.t23.t23[data-variant="borderless"][data-is-hovered][data-is-focused]:not([data-is-error]) {border: var(--border-width) solid var(--primary-color);}} +@media (max-width: 767px) {.t23.t23[data-is-error][data-is-focused]:not([data-variant="borderless"]):not([data-is-hovered]) {border: var(--border-width) solid var(--danger-color);}} +@media (max-width: 767px) {.t23.t23[data-variant="borderless"][data-is-error][data-is-focused]:not([data-is-hovered]) {border: var(--border-width) solid var(--danger-color);}} +@media (max-width: 767px) {.t23.t23[data-is-hovered][data-is-error][data-is-focused]:not([data-variant="borderless"]) {border: var(--border-width) solid var(--border-hover-color);}} +@media (max-width: 767px) {.t23.t23[data-variant="borderless"][data-is-hovered][data-is-error][data-is-focused] {border: var(--border-width) solid var(--danger-color);}} +@media (min-width: 1200px) {.t23.t23>* {--context-radius: calc(2 * var(--radius));}} +@media (min-width: 768px) and (max-width: 1199px) {.t23.t23>* {--context-radius: var(--radius);}} +@media (max-width: 767px) {.t23.t23>* {--context-radius: calc(0.5 * var(--radius));}}" +`; -
-
-
+exports[`tasty() API should handle state-map-of-arrays pattern 1`] = ` +".t21.t21 {display: block;} +@media (min-width: 1200px) {.t21.t21:not([data-variant="compact"]):not([data-is-hovered]) {padding-top: calc(4 * var(--gap)); padding-right: calc(4 * var(--gap)); padding-bottom: calc(4 * var(--gap)); padding-left: calc(4 * var(--gap));}} +@media (min-width: 1200px) {.t21.t21[data-variant="compact"]:not([data-is-hovered]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 1200px) {.t21.t21[data-is-hovered]:not([data-variant="compact"]) {padding-top: calc(6 * var(--gap)); padding-right: calc(6 * var(--gap)); padding-bottom: calc(6 * var(--gap)); padding-left: calc(6 * var(--gap));}} +@media (min-width: 1200px) {.t21.t21[data-variant="compact"][data-is-hovered] {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t21.t21:not([data-variant="compact"]):not([data-is-hovered]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t21.t21[data-variant="compact"]:not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (min-width: 768px) and (max-width: 1199px) {.t21.t21[data-is-hovered]:not([data-variant="compact"]) {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap));}} +@media (min-width: 768px) and (max-width: 1199px) {.t21.t21[data-variant="compact"][data-is-hovered] {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (max-width: 767px) {.t21.t21:not([data-variant="compact"]):not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (max-width: 767px) {.t21.t21[data-variant="compact"]:not([data-is-hovered]) {padding-top: calc(0.5 * var(--gap)); padding-right: calc(0.5 * var(--gap)); padding-bottom: calc(0.5 * var(--gap)); padding-left: calc(0.5 * var(--gap));}} +@media (max-width: 767px) {.t21.t21[data-is-hovered]:not([data-variant="compact"]) {padding-top: calc(1.5 * var(--gap)); padding-right: calc(1.5 * var(--gap)); padding-bottom: calc(1.5 * var(--gap)); padding-left: calc(1.5 * var(--gap));}} +@media (max-width: 767px) {.t21.t21[data-variant="compact"][data-is-hovered] {padding-top: calc(0.5 * var(--gap)); padding-right: calc(0.5 * var(--gap)); padding-bottom: calc(0.5 * var(--gap)); padding-left: calc(0.5 * var(--gap));}} +@media (min-width: 1200px) {.t21.t21:not([data-is-error]):not([data-is-focused]) {border: calc(2 * var(--border-width)) solid var(--border-color);}} +@media (min-width: 1200px) {.t21.t21[data-is-error]:not([data-is-focused]) {border: calc(2 * var(--border-width)) solid var(--border-color);}} +@media (min-width: 1200px) {.t21.t21[data-is-focused]:not([data-is-error]) {border: calc(3 * var(--border-width)) solid var(--primary-color);}} +@media (min-width: 1200px) {.t21.t21[data-is-error][data-is-focused] {border: calc(3 * var(--border-width)) solid var(--danger-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t21.t21:not([data-is-error]):not([data-is-focused]) {border: var(--border-width) solid var(--border-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t21.t21[data-is-error]:not([data-is-focused]) {border: var(--border-width) solid var(--border-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t21.t21[data-is-focused]:not([data-is-error]) {border: calc(2 * var(--border-width)) solid var(--primary-color);}} +@media (min-width: 768px) and (max-width: 1199px) {.t21.t21[data-is-error][data-is-focused] {border: calc(2 * var(--border-width)) solid var(--danger-color);}} +@media (max-width: 767px) {.t21.t21:not([data-is-error]):not([data-is-focused]) {border: var(--border-width) none var(--border-color);}} +@media (max-width: 767px) {.t21.t21[data-is-error]:not([data-is-focused]) {border: var(--border-width) none var(--border-color);}} +@media (max-width: 767px) {.t21.t21[data-is-focused]:not([data-is-error]) {border: var(--border-width) solid var(--primary-color);}} +@media (max-width: 767px) {.t21.t21[data-is-error][data-is-focused] {border: var(--border-width) solid var(--danger-color);}}" `; exports[`tasty() API should merge element styles 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -.c0 [data-element="Element"] { - outline: none; -} - -.c0 [data-element="Element"][hidden] { - display: none !important; -} - -.c0.c0:not([data-is-modified]) [data-element="Element"] { - color: var(--dark-color); - --current-color: var(--dark-color, dark); - --current-color-rgb: var(--dark-color-rgb); -} - -.c0.c0[data-is-modified] [data-element="Element"] { - color: var(--purple-color); - --current-color: var(--purple-color, purple); - --current-color-rgb: var(--purple-color-rgb); -} - -.c0.c0 [data-element="Element"] { - background-color: var(--black-color); -} - -.c0.c0 [data-element="Element"]>* { - --context-fill-color: var(--black-color); - --context-fill-color-rgb: var(--black-color-rgb); -} - -
-
-
+".t13.t13:not([data-is-modified]) [data-element="Element"] {color: var(--dark-color); --current-color: var(--dark-color, dark); --current-color-rgb: var(--dark-color-rgb);} +.t13.t13[data-is-modified] [data-element="Element"] {color: var(--purple-color); --current-color: var(--purple-color, purple); --current-color-rgb: var(--purple-color-rgb);} +.t13.t13 [data-element="Element"] {background-color: var(--black-color);} +.t13.t13 [data-element="Element"]>* {--context-fill-color: var(--black-color); --context-fill-color-rgb: var(--black-color-rgb);}" `; exports[`tasty() API should merge styles 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -.c0.c0:not([data-is-modified]) { - color: var(--dark-color); - --current-color: var(--dark-color, dark); - --current-color-rgb: var(--dark-color-rgb); -} - -.c0.c0[data-is-modified] { - color: var(--purple-color); - --current-color: var(--purple-color, purple); - --current-color-rgb: var(--purple-color-rgb); -} - -.c0.c0 { - background-color: var(--black-color); -} - -.c0.c0>* { - --context-fill-color: var(--black-color); - --context-fill-color-rgb: var(--black-color-rgb); -} - -
-
-
+".t6.t6:not([data-is-modified]) {color: var(--dark-color); --current-color: var(--dark-color, dark); --current-color-rgb: var(--dark-color-rgb);} +.t6.t6[data-is-modified] {color: var(--purple-color); --current-color: var(--purple-color, purple); --current-color-rgb: var(--purple-color-rgb);} +.t6.t6 {background-color: var(--black-color);} +.t6.t6>* {--context-fill-color: var(--black-color); --context-fill-color-rgb: var(--black-color-rgb);}" `; exports[`tasty() API should merge styles in custom prop 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -.c0.c0:not([data-is-modified]) { - color: var(--dark-color); - --current-color: var(--dark-color, dark); - --current-color-rgb: var(--dark-color-rgb); -} - -.c0.c0[data-is-modified] { - color: var(--purple-color); - --current-color: var(--purple-color, purple); - --current-color-rgb: var(--purple-color-rgb); -} - -.c0.c0 { - background-color: var(--black-color); -} - -.c0.c0>* { - --context-fill-color: var(--black-color); - --context-fill-color-rgb: var(--black-color-rgb); -} - -
-
-
+".t6.t6:not([data-is-modified]) {color: var(--dark-color); --current-color: var(--dark-color, dark); --current-color-rgb: var(--dark-color-rgb);} +.t6.t6[data-is-modified] {color: var(--purple-color); --current-color: var(--purple-color, purple); --current-color-rgb: var(--purple-color-rgb);} +.t6.t6 {background-color: var(--black-color);} +.t6.t6>* {--context-fill-color: var(--black-color); --context-fill-color-rgb: var(--black-color-rgb);}" `; -exports[`tasty() API should pass styles from tasty 1`] = ` -.c0 { - outline: none; -} +exports[`tasty() API should optimize attribute selectors 1`] = ` +".t17.t17 {display: block;} +.t17.t17:not([data-size="large"]):not([data-size="medium"]) {padding-top: var(--gap);} +.t17.t17[data-size="large"] {padding-top: calc(3 * var(--gap));} +.t17.t17[data-size="medium"] {padding-top: calc(2 * var(--gap));}" +`; -.c0[hidden] { - display: none !important; -} +exports[`tasty() API should optimize attribute selectors 2`] = ` +".t18.t18 {display: block;} +.t18.t18:not([data-size="large"]):not([data-size="medium"]):not([data-is-selected]) {padding-top: var(--gap);} +.t18.t18[data-size="large"]:not([data-is-selected]) {padding-top: calc(3 * var(--gap));} +.t18.t18[data-size="medium"]:not([data-is-selected]) {padding-top: var(--gap);} +.t18.t18[data-is-selected]:not([data-size="large"]):not([data-size="medium"]) {padding-top: var(--gap);} +.t18.t18[data-size="large"][data-is-selected] {padding-top: calc(3 * var(--gap));} +.t18.t18[data-size="medium"][data-is-selected] {padding-top: calc(2 * var(--gap));}" +`; -.c0.c0 { - display: block; -} +exports[`tasty() API should optimize attribute selectors 3`] = ` +".t19.t19 {display: block;} +.t19.t19:not([data-size="large"]):not([data-is-selected]):not([data-size="medium"]) {padding-top: var(--gap);} +.t19.t19[data-size="large"]:not([data-is-selected]) {padding-top: var(--gap);} +.t19.t19[data-is-selected]:not([data-size="large"]):not([data-size="medium"]) {padding-top: calc(2 * var(--gap));} +.t19.t19[data-size="large"][data-is-selected] {padding-top: calc(3 * var(--gap));} +.t19.t19[data-size="medium"]:not([data-is-selected]) {padding-top: calc(2 * var(--gap));} +.t19.t19[data-is-selected][data-size="medium"] {padding-top: calc(2 * var(--gap));}" +`; -.c0.c0 { - color: rgb(var(--clear-color-rgb) / .1); - --current-color: var(--clear-color, clear); - --current-color-rgb: var(--clear-color-rgb); -} +exports[`tasty() API should pass styles from tasty 1`] = `".t2.t2 {display: block; color: rgb(var(--clear-color-rgb) / .1); --current-color: var(--clear-color, clear); --current-color-rgb: var(--clear-color-rgb);}"`; + +exports[`tasty() API should preserve null values in state-map-of-arrays conversion 1`] = ` +".t22.t22 {display: block;} +@media (min-width: 768px) {.t22.t22:not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(4 * var(--gap)); padding-right: calc(4 * var(--gap)); padding-bottom: calc(4 * var(--gap)); padding-left: calc(4 * var(--gap));}} +@media (min-width: 768px) {.t22.t22[data-is-disabled]:not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (min-width: 768px) {.t22.t22[data-is-disabled][data-is-hovered] {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (max-width: 767px) {.t22.t22:not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (max-width: 767px) {.t22.t22[data-is-disabled]:not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (max-width: 767px) {.t22.t22[data-is-hovered]:not([data-is-disabled]) {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap));}} +@media (max-width: 767px) {.t22.t22[data-is-disabled][data-is-hovered] {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +.t22.t22:not([data-is-disabled]):not([data-is-hovered]) {background-color: var(--white-color);} +.t22.t22:not([data-is-disabled]):not([data-is-hovered])>* {--context-fill-color: var(--white-color); --context-fill-color-rgb: var(--white-color-rgb);} +.t22.t22[data-is-disabled]:not([data-is-hovered]) {background-color: var(--gray-color);} +.t22.t22[data-is-disabled]:not([data-is-hovered])>* {--context-fill-color: var(--gray-color); --context-fill-color-rgb: var(--gray-color-rgb);} +.t22.t22[data-is-hovered]:not([data-is-disabled]) {background-color: var(--blue-color);} +.t22.t22[data-is-hovered]:not([data-is-disabled])>* {--context-fill-color: var(--blue-color); --context-fill-color-rgb: var(--blue-color-rgb);} +.t22.t22[data-is-disabled][data-is-hovered] {background-color: var(--gray-color);} +.t22.t22[data-is-disabled][data-is-hovered]>* {--context-fill-color: var(--gray-color); --context-fill-color-rgb: var(--gray-color-rgb);}" +`; -
-
-
+exports[`tasty() API should preserve null values in state-map-of-arrays conversion 2`] = ` +".t22.t22 {display: block;} +@media (min-width: 768px) {.t22.t22:not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(4 * var(--gap)); padding-right: calc(4 * var(--gap)); padding-bottom: calc(4 * var(--gap)); padding-left: calc(4 * var(--gap));}} +@media (min-width: 768px) {.t22.t22[data-is-disabled]:not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (min-width: 768px) {.t22.t22[data-is-disabled][data-is-hovered] {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (max-width: 767px) {.t22.t22:not([data-is-disabled]):not([data-is-hovered]) {padding-top: calc(2 * var(--gap)); padding-right: calc(2 * var(--gap)); padding-bottom: calc(2 * var(--gap)); padding-left: calc(2 * var(--gap));}} +@media (max-width: 767px) {.t22.t22[data-is-disabled]:not([data-is-hovered]) {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +@media (max-width: 767px) {.t22.t22[data-is-hovered]:not([data-is-disabled]) {padding-top: calc(3 * var(--gap)); padding-right: calc(3 * var(--gap)); padding-bottom: calc(3 * var(--gap)); padding-left: calc(3 * var(--gap));}} +@media (max-width: 767px) {.t22.t22[data-is-disabled][data-is-hovered] {padding-top: var(--gap); padding-right: var(--gap); padding-bottom: var(--gap); padding-left: var(--gap);}} +.t22.t22:not([data-is-disabled]):not([data-is-hovered]) {background-color: var(--white-color);} +.t22.t22:not([data-is-disabled]):not([data-is-hovered])>* {--context-fill-color: var(--white-color); --context-fill-color-rgb: var(--white-color-rgb);} +.t22.t22[data-is-disabled]:not([data-is-hovered]) {background-color: var(--gray-color);} +.t22.t22[data-is-disabled]:not([data-is-hovered])>* {--context-fill-color: var(--gray-color); --context-fill-color-rgb: var(--gray-color-rgb);} +.t22.t22[data-is-hovered]:not([data-is-disabled]) {background-color: var(--blue-color);} +.t22.t22[data-is-hovered]:not([data-is-disabled])>* {--context-fill-color: var(--blue-color); --context-fill-color-rgb: var(--blue-color-rgb);} +.t22.t22[data-is-disabled][data-is-hovered] {background-color: var(--gray-color);} +.t22.t22[data-is-disabled][data-is-hovered]>* {--context-fill-color: var(--gray-color); --context-fill-color-rgb: var(--gray-color-rgb);}" `; exports[`tasty() API should support camelCase modifiers 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -.c0.c0 { - display: block; -} - -.c0.c0:not([data-is-somehow-modified]) { - color: var(--dark-color); - --current-color: var(--dark-color, dark); - --current-color-rgb: var(--dark-color-rgb); -} - -.c0.c0[data-is-somehow-modified] { - color: var(--purple-color); - --current-color: var(--purple-color, purple); - --current-color-rgb: var(--purple-color-rgb); -} - -
-
-
+".t5.t5 {display: block;} +.t5.t5:not([data-is-somehow-modified]) {color: var(--dark-color); --current-color: var(--dark-color, dark); --current-color-rgb: var(--dark-color-rgb);} +.t5.t5[data-is-somehow-modified] {color: var(--purple-color); --current-color: var(--purple-color, purple); --current-color-rgb: var(--purple-color-rgb);}" `; exports[`tasty() API should support kebab-case modifiers 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -.c0.c0 { - display: block; -} - -.c0.c0:not([data-is-somehow-modified]) { - color: var(--dark-color); - --current-color: var(--dark-color, dark); - --current-color-rgb: var(--dark-color-rgb); -} - -.c0.c0[data-is-somehow-modified] { - color: var(--purple-color); - --current-color: var(--purple-color, purple); - --current-color-rgb: var(--purple-color-rgb); -} - -
-
-
+".t4.t4 {display: block;} +.t4.t4:not([data-is-somehow-modified]) {color: var(--dark-color); --current-color: var(--dark-color, dark); --current-color-rgb: var(--dark-color-rgb);} +.t4.t4[data-is-somehow-modified] {color: var(--purple-color); --current-color: var(--purple-color, purple); --current-color-rgb: var(--purple-color-rgb);}" `; exports[`tasty() API should support modifiers 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -.c0.c0 { - display: block; -} - -.c0.c0:not([data-is-modified]) { - color: var(--dark-color); - --current-color: var(--dark-color, dark); - --current-color-rgb: var(--dark-color-rgb); -} - -.c0.c0[data-is-modified] { - color: var(--purple-color); - --current-color: var(--purple-color, purple); - --current-color-rgb: var(--purple-color-rgb); -} - -
-
-
+".t3.t3 {display: block;} +.t3.t3:not([data-is-modified]) {color: var(--dark-color); --current-color: var(--dark-color, dark); --current-color-rgb: var(--dark-color-rgb);} +.t3.t3[data-is-modified] {color: var(--purple-color); --current-color: var(--purple-color, purple); --current-color-rgb: var(--purple-color-rgb);}" `; -exports[`tasty() API should support variants 1`] = ` -.c0 { - outline: none; -} - -.c0[hidden] { - display: none !important; -} - -.c0.c0 { - color: var(--black-color); - --current-color: var(--black-color, black); - --current-color-rgb: var(--black-color-rgb); -} - -
-
-
-`; +exports[`tasty() API should support variants 1`] = `".t8.t8 {color: var(--black-color); --current-color: var(--black-color, black); --current-color-rgb: var(--black-color-rgb);}"`; diff --git a/src/tasty/debug.ts b/src/tasty/debug.ts new file mode 100644 index 000000000..9fd3210b8 --- /dev/null +++ b/src/tasty/debug.ts @@ -0,0 +1,1248 @@ +/** + * Debug utilities for inspecting tasty-generated CSS at runtime + */ + +import { getCssText, getCssTextForNode, injector } from './injector'; + +/** + * Pretty-print CSS with proper indentation and formatting + */ +function prettifyCSS(css: string): string { + if (!css || css.trim() === '') { + return ''; + } + + // First, normalize whitespace but preserve structure + let formatted = css.replace(/\s+/g, ' ').trim(); + + // Add newlines after opening braces + formatted = formatted.replace(/\s*\{\s*/g, ' {\n'); + + // Add newlines after semicolons (but not inside strings or functions) + formatted = formatted.replace(/;(?![^"']*["'][^"']*$)(?![^()]*\))/g, ';\n'); + + // Add newlines before closing braces + formatted = formatted.replace(/\s*\}\s*/g, '\n}\n'); + + // Handle comma-separated selectors (only outside of property values) + // This regex looks for commas that are: + // 1. Not inside quotes + // 2. Not inside parentheses (CSS functions) + // 3. Not followed by a colon (not in a property value) + formatted = formatted.replace( + /,(?![^"']*["'][^"']*$)(?![^()]*\))(?=.*:.*\{|.*\{)/g, + ',\n', + ); + + // Process line by line for proper indentation + const lines = formatted.split('\n'); + let indentLevel = 0; + const indentSize = 2; + + const formattedLines = lines.map((line) => { + const trimmed = line.trim(); + if (!trimmed) return ''; + + // Handle closing braces - decrease indent first + if (trimmed === '}') { + indentLevel = Math.max(0, indentLevel - 1); + return ' '.repeat(indentLevel * indentSize) + trimmed; + } + + // Current line with proper indentation + const indent = ' '.repeat(indentLevel * indentSize); + let result = indent + trimmed; + + // Handle opening braces - increase indent for next line + if (trimmed.endsWith('{')) { + indentLevel++; + } + + return result; + }); + + // Clean up the result and ensure proper spacing + let result = formattedLines + .filter((line) => line.trim()) // Remove empty lines + .join('\n') + .replace(/\n{3,}/g, '\n\n') // Max 2 consecutive newlines + .trim(); + + // Final cleanup: ensure single spaces in function calls + result = result.replace(/,\s+/g, ', '); + + return result; +} + +/** + * Debug utilities for inspecting tasty styles in runtime applications + */ +export const tastyDebug = { + /** + * Get CSS for a specific tasty class (e.g., 't24') + */ + getCSSForClass(className: string): string { + if (!className.match(/^t\d+$/)) { + console.warn( + `"${className}" doesn't look like a tasty class. Expected format: t{number}`, + ); + } + const css = injector.instance.getCssTextForClasses([className]); + return prettifyCSS(css); + }, + + /** + * Get CSS for multiple tasty classes + */ + getCSSForClasses(classNames: string[]): string { + const css = injector.instance.getCssTextForClasses(classNames); + return prettifyCSS(css); + }, + + /** + * Log CSS for a specific tasty class (e.g., 't24') to console + */ + logCSSForClass(className: string): void { + if (!className.match(/^t\d+$/)) { + console.warn( + `"${className}" doesn't look like a tasty class. Expected format: t{number}`, + ); + } + const css = this.getCSSForClass(className); + this.logCSS(css, `CSS for class "${className}"`); + }, + + /** + * Log CSS for multiple tasty classes to console + */ + logCSSForClasses(classNames: string[]): void { + const css = this.getCSSForClasses(classNames); + const title = `CSS for classes [${classNames.join(', ')}]`; + this.logCSS(css, title); + }, + + /** + * Inspect an element by CSS selector and get its tasty CSS + */ + inspectElement(selector: string): string { + const element = document.querySelector(selector); + if (!element) { + return `Element not found: ${selector}`; + } + + console.group(`🎨 Tasty CSS for "${selector}"`); + console.log('Element:', element); + + const css = getCssTextForNode(element); + if (css) { + const prettified = prettifyCSS(css); + console.log('Generated CSS:\n' + prettified); + console.groupEnd(); + return prettified; + } else { + console.log('No tasty CSS found for this element'); + console.groupEnd(); + return 'No tasty CSS found'; + } + }, + + /** + * Inspect a DOM element directly and get its tasty CSS + */ + inspectDOMElement(element: Element): string { + if (!element) { + return 'Element is null or undefined'; + } + + console.group('🎨 Tasty CSS for element'); + console.log('Element:', element); + + const css = getCssTextForNode(element); + if (css) { + const prettified = prettifyCSS(css); + console.log('Generated CSS:\n' + prettified); + console.groupEnd(); + return prettified; + } else { + console.log('No tasty CSS found for this element'); + console.groupEnd(); + return 'No tasty CSS found'; + } + }, + + /** + * Get all tasty CSS currently injected into the page + */ + getAllCSS(): string { + return getCssText(); + }, + + /** + * Find all tasty classes used in the page (in DOM) + */ + findAllTastyClasses(): string[] { + const classes = new Set(); + + // Find all elements with class attributes + const elements = document.querySelectorAll('[class]'); + elements.forEach((element) => { + const classList = element.getAttribute('class'); + if (classList) { + // Extract tasty classes (t + digits) + const tastyClasses = classList + .split(/\s+/) + .filter((cls) => /^t\d+$/.test(cls)); + tastyClasses.forEach((cls) => classes.add(cls)); + } + }); + + return Array.from(classes).sort((a, b) => { + // Sort numerically by the number part + const aNum = parseInt(a.slice(1)); + const bNum = parseInt(b.slice(1)); + return aNum - bNum; + }); + }, + + /** + * Find all tasty classes that have styles in the stylesheet (used + unused) + */ + findAllStyledClasses(): string[] { + const registry = (injector.instance as any)['sheetManager'].getRegistry( + document, + ); + const classes = new Set(); + + // Add all classes from rules map (active + unused) + if (registry?.rules) { + for (const className of registry.rules.keys()) { + if (/^t\d+$/.test(className)) { + classes.add(className); + } + } + } + + return Array.from(classes).sort((a, b) => { + // Sort numerically by the number part + const aNum = parseInt(a.slice(1)); + const bNum = parseInt(b.slice(1)); + return aNum - bNum; + }); + }, + + /** + * Get active vs cached class breakdown + */ + getClassUsage(): { + activeClasses: string[]; + cachedClasses: string[]; + totalStyledClasses: string[]; + } { + const domClasses = this.findAllTastyClasses(); + const styledClasses = this.findAllStyledClasses(); + const registry = (injector.instance as any)['sheetManager'].getRegistry( + document, + ); + + const activeClasses = domClasses; + const cachedClasses = styledClasses.filter( + (cls) => !domClasses.includes(cls), + ); + + // Also check unusedRules registry for classes that are marked as cached (unused but kept for performance) + if (registry?.unusedRules) { + for (const className of registry.unusedRules.keys()) { + if (/^t\d+$/.test(className) && !cachedClasses.includes(className)) { + cachedClasses.push(className); + } + } + } + + return { + activeClasses: activeClasses.sort((a, b) => { + const aNum = parseInt(a.slice(1)); + const bNum = parseInt(b.slice(1)); + return aNum - bNum; + }), + cachedClasses: cachedClasses.sort((a, b) => { + const aNum = parseInt(a.slice(1)); + const bNum = parseInt(b.slice(1)); + return aNum - bNum; + }), + totalStyledClasses: styledClasses, + }; + }, + + /** + * Get a comprehensive summary of all tasty styles + */ + getSummary(): { + activeClasses: string[]; + cachedClasses: string[]; + totalStyledClasses: string[]; + activeCSSSize: number; + cachedCSSSize: number; + totalCSSSize: number; + activeCSS: string; + cachedCSS: string; + allCSS: string; + globalCSS: string; + globalCSSSize: number; + globalRuleCount: number; + metrics: any; + definedProperties: string[]; + definedKeyframes: { name: string; refCount: number; cssText?: string }[]; + propertyCount: number; + keyframeCount: number; + cleanupSummary: { + enabled: boolean; + totalCleanups: number; + totalClassesDeleted: number; + totalCssDeleted: number; + totalRulesDeleted: number; + averageClassesPerCleanup: number; + averageCssPerCleanup: number; + averageRulesPerCleanup: number; + lastCleanup?: { + timestamp: number; + date: string; + classesDeleted: number; + cssSize: number; + rulesDeleted: number; + }; + }; + } { + const usage = this.getClassUsage(); + const allCSS = this.getAllCSS(); + const activeCSS = this.getCSSForClasses(usage.activeClasses); + const cachedCSS = this.getCSSForClasses(usage.cachedClasses); + const globalCSS = this.getGlobalCSS(); + const globalBreakdown = this.getGlobalCSSBreakdown(); + const metrics = injector.instance.getMetrics(); + const definedProperties = this.getDefinedProperties(); + const definedKeyframes = this.getDefinedKeyframes(); + const cleanupSummary = this.getCleanupSummary(); + + const summary = { + activeClasses: usage.activeClasses, + cachedClasses: usage.cachedClasses, + totalStyledClasses: usage.totalStyledClasses, + activeCSSSize: activeCSS.length, + cachedCSSSize: cachedCSS.length, + totalCSSSize: allCSS.length, + activeCSS, + cachedCSS, + allCSS, + globalCSS, + globalCSSSize: globalCSS.length, + globalRuleCount: globalBreakdown.totalRules, + metrics, + definedProperties, + definedKeyframes, + propertyCount: definedProperties.length, + keyframeCount: definedKeyframes.length, + cleanupSummary, + }; + + console.group('🎨 Comprehensive Tasty Debug Summary'); + console.log(`📊 Style Cache Status:`); + console.log(` • Active classes (in DOM): ${summary.activeClasses.length}`); + console.log( + ` • Cached classes (performance cache): ${summary.cachedClasses.length}`, + ); + console.log( + ` • Total styled classes: ${summary.totalStyledClasses.length}`, + ); + console.log(`💾 CSS Size:`); + console.log(` • Active CSS: ${summary.activeCSSSize} characters`); + console.log(` • Cached CSS: ${summary.cachedCSSSize} characters`); + console.log( + ` • Global CSS: ${summary.globalCSSSize} characters (${summary.globalRuleCount} rules)`, + ); + console.log(` • Total CSS: ${summary.totalCSSSize} characters`); + console.log('🏷️ Properties & Keyframes:'); + console.log(` • Defined @property: ${definedProperties.length}`); + console.log(` • Defined keyframes: ${definedKeyframes.length}`); + if (definedProperties.length > 0) { + console.log(' • Properties:', definedProperties); + } + if (definedKeyframes.length > 0) { + console.log( + ' • Keyframes:', + definedKeyframes.map((k) => `${k.name} (refs: ${k.refCount})`), + ); + } + console.log('🧹 Cleanup Statistics:'); + if (cleanupSummary.enabled) { + console.log( + ` • Total cleanups performed: ${cleanupSummary.totalCleanups}`, + ); + console.log( + ` • Total classes deleted: ${cleanupSummary.totalClassesDeleted}`, + ); + console.log( + ` • Total CSS deleted: ${cleanupSummary.totalCssDeleted} chars`, + ); + console.log( + ` • Total rules deleted: ${cleanupSummary.totalRulesDeleted}`, + ); + if (cleanupSummary.totalCleanups > 0) { + console.log( + ` • Avg classes per cleanup: ${cleanupSummary.averageClassesPerCleanup.toFixed(1)}`, + ); + console.log( + ` • Avg CSS per cleanup: ${cleanupSummary.averageCssPerCleanup.toFixed(0)} chars`, + ); + console.log( + ` • Avg rules per cleanup: ${cleanupSummary.averageRulesPerCleanup.toFixed(1)}`, + ); + } + if (cleanupSummary.lastCleanup) { + console.log(` • Last cleanup: ${cleanupSummary.lastCleanup.date}`); + } + } else { + console.log( + ' • Metrics collection disabled (enable with collectMetrics: true)', + ); + } + console.log(`⚡ Performance Metrics:`); + if (metrics) { + console.log(` • Cache hits: ${metrics.hits}`); + console.log(` • Cache misses: ${metrics.misses}`); + console.log(` • Cached style reuses: ${metrics.unusedHits}`); + console.log(` • Total insertions: ${metrics.totalInsertions}`); + console.log(` • Styles cleaned up: ${metrics.stylesCleanedUp}`); + + const hitRate = + metrics.hits + metrics.misses > 0 + ? ( + ((metrics.hits + metrics.unusedHits) / + (metrics.hits + metrics.misses)) * + 100 + ).toFixed(1) + : 0; + console.log(` • Overall cache hit rate: ${hitRate}%`); + } else { + console.log( + ` • Metrics not available (enable with collectMetrics: true)`, + ); + } + console.log('🔍 Details:'); + console.log(' • Active classes:', summary.activeClasses); + console.log(' • Cached classes:', summary.cachedClasses); + console.log( + 'ℹ️ Note: Cached styles are kept for performance - avoiding expensive DOM operations', + ); + console.groupEnd(); + + return summary; + }, + + /** + * Helper to log CSS in a readable format + */ + logCSS(css: string, title = 'CSS'): void { + if (!css || css.trim() === '') { + console.log(`${title}: (empty)`); + return; + } + + console.group(`🎨 ${title}`); + const prettified = prettifyCSS(css); + console.log(prettified); + console.groupEnd(); + }, + + /** + * Advanced inspection with detailed breakdown and statistics + */ + inspect(target: string | Element): { + element: Element | null; + tastyClasses: string[]; + css: string; + cssSize: number; + ruleCount: number; + breakdown: { + [className: string]: { + css: string; + cssSize: number; + ruleCount: number; + }; + }; + stats: { + totalClasses: number; + totalRules: number; + totalCSSSize: number; + averageRulesPerClass: number; + averageCSSPerClass: number; + }; + } { + const element = + typeof target === 'string' ? document.querySelector(target) : target; + + if (!element) { + console.error(`Element not found: ${target}`); + return { + element: null, + tastyClasses: [], + css: '', + cssSize: 0, + ruleCount: 0, + breakdown: {}, + stats: { + totalClasses: 0, + totalRules: 0, + totalCSSSize: 0, + averageRulesPerClass: 0, + averageCSSPerClass: 0, + }, + }; + } + + // Find tasty classes on this element + const classList = element.getAttribute('class') || ''; + const tastyClasses = classList + .split(/\s+/) + .filter((cls) => /^t\d+$/.test(cls)); + + // Get CSS for the entire subtree + const fullCSS = getCssTextForNode(element); + const prettifiedCSS = prettifyCSS(fullCSS); + + // Count CSS rules in the full CSS + const ruleCount = (fullCSS.match(/\{[^}]*\}/g) || []).length; + + // Get CSS breakdown per class with detailed stats + const breakdown: { + [className: string]: { + css: string; + cssSize: number; + ruleCount: number; + }; + } = {}; + + let totalClassRules = 0; + let totalClassCSSSize = 0; + + tastyClasses.forEach((className) => { + const classCSS = this.getCSSForClass(className); + const classRuleCount = (classCSS.match(/\{[^}]*\}/g) || []).length; + breakdown[className] = { + css: classCSS, + cssSize: classCSS.length, + ruleCount: classRuleCount, + }; + totalClassRules += classRuleCount; + totalClassCSSSize += classCSS.length; + }); + + // Calculate statistics + const stats = { + totalClasses: tastyClasses.length, + totalRules: totalClassRules, + totalCSSSize: totalClassCSSSize, + averageRulesPerClass: + tastyClasses.length > 0 ? totalClassRules / tastyClasses.length : 0, + averageCSSPerClass: + tastyClasses.length > 0 ? totalClassCSSSize / tastyClasses.length : 0, + }; + + const result = { + element, + tastyClasses, + css: prettifiedCSS, + cssSize: fullCSS.length, + ruleCount, + breakdown, + stats, + }; + + console.group(`🔍 Detailed Tasty Inspection`); + console.log('Element:', element); + console.log('📊 Overview:'); + console.log(` • Tasty classes: ${stats.totalClasses}`); + console.log(` • Total rules applied: ${ruleCount}`); + console.log(` • Total CSS size: ${fullCSS.length} characters`); + console.log('🏷️ Classes:', tastyClasses); + console.log('📈 Statistics:'); + console.log( + ` • Rules per class (avg): ${stats.averageRulesPerClass.toFixed(1)}`, + ); + console.log( + ` • CSS per class (avg): ${stats.averageCSSPerClass.toFixed(0)} chars`, + ); + console.log('🎨 Element CSS:\n' + prettifiedCSS); + console.log('🔨 CSS breakdown by class:'); + Object.entries(breakdown).forEach(([className, data]) => { + console.log( + ` ${className}: ${data.ruleCount} rules, ${data.cssSize} chars`, + ); + }); + console.groupEnd(); + + return result; + }, + + /** + * Get CSS for active classes only + */ + getActiveCSS(): string { + const usage = this.getClassUsage(); + return this.getCSSForClasses(usage.activeClasses); + }, + + /** + * Get CSS for cached classes only + */ + getCachedCSS(): string { + const usage = this.getClassUsage(); + return this.getCSSForClasses(usage.cachedClasses); + }, + + /** + * Get all defined @property custom properties + */ + getDefinedProperties(): string[] { + const registry = (injector.instance as any)['sheetManager'].getRegistry( + document, + ); + if (!registry?.injectedProperties) { + return []; + } + return Array.from(registry.injectedProperties as Set).sort(); + }, + + /** + * Get all defined keyframes + */ + getDefinedKeyframes(): { + name: string; + refCount: number; + cssText?: string; + }[] { + const registry = (injector.instance as any)['sheetManager'].getRegistry( + document, + ); + if (!registry?.keyframesCache) { + return []; + } + + const keyframes: { + name: string; + refCount: number; + cssText?: string; + }[] = []; + + for (const [cacheKey, entry] of registry.keyframesCache.entries()) { + keyframes.push({ + name: entry.name, + refCount: entry.refCount, + cssText: entry.info?.cssText, + }); + } + + return keyframes.sort((a, b) => a.name.localeCompare(b.name)); + }, + + /** + * Check if a specific @property is defined + */ + isPropertyDefined(propertyName: string): boolean { + return injector.instance.isPropertyDefined(propertyName); + }, + + /** + * Check if a specific keyframe is defined + */ + isKeyframeDefined(keyframeName: string): boolean { + const registry = (injector.instance as any)['sheetManager'].getRegistry( + document, + ); + if (!registry?.keyframesCache) { + return false; + } + + for (const entry of registry.keyframesCache.values()) { + if (entry.name === keyframeName) { + return true; + } + } + return false; + }, + + /** + * Get detailed cleanup statistics history + */ + getCleanupHistory(): { + totalCleanups: number; + totalClassesDeleted: number; + totalCssDeleted: number; + totalRulesDeleted: number; + cleanupHistory: Array<{ + timestamp: number; + date: string; + classesDeleted: number; + cssSize: number; + rulesDeleted: number; + }>; + } { + const registry = (injector.instance as any)['sheetManager'].getRegistry( + document, + ); + + if (!registry?.metrics?.cleanupHistory) { + return { + totalCleanups: 0, + totalClassesDeleted: 0, + totalCssDeleted: 0, + totalRulesDeleted: 0, + cleanupHistory: [], + }; + } + + const history = registry.metrics.cleanupHistory; + const totalClassesDeleted = history.reduce( + (sum, cleanup) => sum + cleanup.classesDeleted, + 0, + ); + const totalCssDeleted = history.reduce( + (sum, cleanup) => sum + cleanup.cssSize, + 0, + ); + const totalRulesDeleted = history.reduce( + (sum, cleanup) => sum + cleanup.rulesDeleted, + 0, + ); + + return { + totalCleanups: history.length, + totalClassesDeleted, + totalCssDeleted, + totalRulesDeleted, + cleanupHistory: history.map((cleanup) => ({ + ...cleanup, + date: new Date(cleanup.timestamp).toISOString(), + })), + }; + }, + + /** + * Get cleanup statistics summary + */ + getCleanupSummary(): { + enabled: boolean; + totalCleanups: number; + totalClassesDeleted: number; + totalCssDeleted: number; + totalRulesDeleted: number; + averageClassesPerCleanup: number; + averageCssPerCleanup: number; + averageRulesPerCleanup: number; + lastCleanup?: { + timestamp: number; + date: string; + classesDeleted: number; + cssSize: number; + rulesDeleted: number; + }; + } { + const registry = (injector.instance as any)['sheetManager'].getRegistry( + document, + ); + + if (!registry?.metrics) { + return { + enabled: false, + totalCleanups: 0, + totalClassesDeleted: 0, + totalCssDeleted: 0, + totalRulesDeleted: 0, + averageClassesPerCleanup: 0, + averageCssPerCleanup: 0, + averageRulesPerCleanup: 0, + }; + } + + const history = registry.metrics.cleanupHistory || []; + const totalClassesDeleted = history.reduce( + (sum, cleanup) => sum + cleanup.classesDeleted, + 0, + ); + const totalCssDeleted = history.reduce( + (sum, cleanup) => sum + cleanup.cssSize, + 0, + ); + const totalRulesDeleted = history.reduce( + (sum, cleanup) => sum + cleanup.rulesDeleted, + 0, + ); + const totalCleanups = history.length; + + const lastCleanup = + history.length > 0 ? history[history.length - 1] : undefined; + + return { + enabled: true, + totalCleanups, + totalClassesDeleted, + totalCssDeleted, + totalRulesDeleted, + averageClassesPerCleanup: + totalCleanups > 0 ? totalClassesDeleted / totalCleanups : 0, + averageCssPerCleanup: + totalCleanups > 0 ? totalCssDeleted / totalCleanups : 0, + averageRulesPerCleanup: + totalCleanups > 0 ? totalRulesDeleted / totalCleanups : 0, + lastCleanup: lastCleanup + ? { + ...lastCleanup, + date: new Date(lastCleanup.timestamp).toISOString(), + } + : undefined, + }; + }, + + /** + * Log cleanup history to console in a readable format + */ + logCleanupHistory(): void { + const cleanupData = this.getCleanupHistory(); + + if (cleanupData.totalCleanups === 0) { + console.log('🧹 No cleanup history available'); + return; + } + + console.group(`🧹 Cleanup History (${cleanupData.totalCleanups} cleanups)`); + console.log('📊 Total Statistics:'); + console.log( + ` • Total classes deleted: ${cleanupData.totalClassesDeleted}`, + ); + console.log( + ` • Total CSS deleted: ${cleanupData.totalCssDeleted} characters`, + ); + console.log(` • Total rules deleted: ${cleanupData.totalRulesDeleted}`); + + console.log('\n📅 Cleanup Sessions:'); + cleanupData.cleanupHistory.forEach((cleanup, index) => { + console.log(` ${index + 1}. ${cleanup.date}`); + console.log(` • Classes: ${cleanup.classesDeleted}`); + console.log(` • CSS: ${cleanup.cssSize} chars`); + console.log(` • Rules: ${cleanup.rulesDeleted}`); + }); + + console.groupEnd(); + }, + + /** + * Get all global CSS rules (non-tasty class selectors) + */ + getGlobalCSS(): string { + const allCSS = this.getAllCSS(); + + // Split CSS into rules and filter out tasty class rules + const rules = this.extractCSSRules(allCSS); + const globalRules = rules.filter((rule) => { + // Filter out rules that only contain tasty classes (t + digits) + const selectors = rule.selector.split(',').map((s) => s.trim()); + return !selectors.every((selector) => { + // Check if selector is purely a tasty class or contains only tasty classes + const cleanSelector = selector.replace(/[.#:\s>+~[\]()]/g, ' '); + const parts = cleanSelector.split(/\s+/).filter(Boolean); + return parts.length > 0 && parts.every((part) => /^t\d+$/.test(part)); + }); + }); + + const globalCSS = globalRules + .map((rule) => `${rule.selector} { ${rule.declarations} }`) + .join('\n'); + return prettifyCSS(globalCSS); + }, + + /** + * Log global CSS to console + */ + logGlobalCSS(): void { + const globalCSS = this.getGlobalCSS(); + if (!globalCSS.trim()) { + console.log('🌍 No global CSS found'); + return; + } + this.logCSS(globalCSS, 'Global CSS (createGlobalStyle)'); + }, + + /** + * Get global CSS rules breakdown with detailed analysis + */ + getGlobalCSSBreakdown(): { + globalRules: Array<{ + selector: string; + declarations: string; + ruleCount: number; + }>; + totalRules: number; + totalCSSSize: number; + css: string; + selectors: { + elements: string[]; + classes: string[]; + ids: string[]; + pseudoClasses: string[]; + mediaQueries: string[]; + keyframes: string[]; + other: string[]; + }; + } { + const allCSS = this.getAllCSS(); + const rules = this.extractCSSRules(allCSS); + + const globalRules = rules.filter((rule) => { + const selectors = rule.selector.split(',').map((s) => s.trim()); + return !selectors.every((selector) => { + const cleanSelector = selector.replace(/[.#:\s>+~[\]()]/g, ' '); + const parts = cleanSelector.split(/\s+/).filter(Boolean); + return parts.length > 0 && parts.every((part) => /^t\d+$/.test(part)); + }); + }); + + const breakdown = globalRules.map((rule) => ({ + selector: rule.selector, + declarations: rule.declarations, + ruleCount: 1, + })); + + const css = globalRules + .map((rule) => `${rule.selector} { ${rule.declarations} }`) + .join('\n'); + const prettifiedCSS = prettifyCSS(css); + + // Analyze selectors + const selectors = { + elements: [] as string[], + classes: [] as string[], + ids: [] as string[], + pseudoClasses: [] as string[], + mediaQueries: [] as string[], + keyframes: [] as string[], + other: [] as string[], + }; + + globalRules.forEach((rule) => { + const selector = rule.selector; + + // Categorize selectors + if (selector.startsWith('@media')) { + selectors.mediaQueries.push(selector); + } else if (selector.startsWith('@keyframes')) { + selectors.keyframes.push(selector); + } else if ( + selector.includes('.') && + !selector.includes('#') && + !selector.includes(':') + ) { + selectors.classes.push(selector); + } else if ( + selector.includes('#') && + !selector.includes('.') && + !selector.includes(':') + ) { + selectors.ids.push(selector); + } else if (selector.includes(':')) { + selectors.pseudoClasses.push(selector); + } else if (/^[a-zA-Z][a-zA-Z0-9]*$/.test(selector.trim())) { + selectors.elements.push(selector); + } else { + selectors.other.push(selector); + } + }); + + return { + globalRules: breakdown, + totalRules: breakdown.length, + totalCSSSize: css.length, + css: prettifiedCSS, + selectors, + }; + }, + + /** + * Log detailed global CSS breakdown + */ + logGlobalCSSBreakdown(): void { + const breakdown = this.getGlobalCSSBreakdown(); + + if (breakdown.totalRules === 0) { + console.log('🌍 No global CSS rules found'); + return; + } + + console.group(`🌍 Global CSS Breakdown (${breakdown.totalRules} rules)`); + console.log(`📊 Statistics:`); + console.log(` • Total global rules: ${breakdown.totalRules}`); + console.log(` • Total CSS size: ${breakdown.totalCSSSize} characters`); + + console.log(`🎯 Selector Analysis:`); + if (breakdown.selectors.elements.length > 0) { + console.log( + ` • Element selectors: ${breakdown.selectors.elements.length}`, + breakdown.selectors.elements.slice(0, 5), + ); + } + if (breakdown.selectors.classes.length > 0) { + console.log( + ` • Class selectors: ${breakdown.selectors.classes.length}`, + breakdown.selectors.classes.slice(0, 5), + ); + } + if (breakdown.selectors.ids.length > 0) { + console.log( + ` • ID selectors: ${breakdown.selectors.ids.length}`, + breakdown.selectors.ids.slice(0, 5), + ); + } + if (breakdown.selectors.pseudoClasses.length > 0) { + console.log( + ` • Pseudo-class selectors: ${breakdown.selectors.pseudoClasses.length}`, + breakdown.selectors.pseudoClasses.slice(0, 5), + ); + } + if (breakdown.selectors.mediaQueries.length > 0) { + console.log( + ` • Media queries: ${breakdown.selectors.mediaQueries.length}`, + breakdown.selectors.mediaQueries.slice(0, 3), + ); + } + if (breakdown.selectors.keyframes.length > 0) { + console.log( + ` • Keyframe rules: ${breakdown.selectors.keyframes.length}`, + breakdown.selectors.keyframes.slice(0, 3), + ); + } + if (breakdown.selectors.other.length > 0) { + console.log( + ` • Other selectors: ${breakdown.selectors.other.length}`, + breakdown.selectors.other.slice(0, 5), + ); + } + + console.log(`🎨 CSS Output:`); + console.log(breakdown.css); + console.groupEnd(); + }, + + /** + * Helper to extract CSS rules from raw CSS text + */ + extractCSSRules( + css: string, + ): Array<{ selector: string; declarations: string }> { + const rules: Array<{ selector: string; declarations: string }> = []; + + // Remove comments + let cleanCSS = css.replace(/\/\*[\s\S]*?\*\//g, ''); + + // Enhanced parser that handles nested CSS properly + this.parseCSSSafe(cleanCSS, rules); + + return rules; + }, + + /** + * Safe CSS parser that handles nested rules properly + */ + parseCSSSafe( + css: string, + rules: Array<{ selector: string; declarations: string }>, + ): void { + let i = 0; + + while (i < css.length) { + // Skip whitespace + while (i < css.length && /\s/.test(css[i])) { + i++; + } + + if (i >= css.length) break; + + // Find selector start + const selectorStart = i; + let braceDepth = 0; + let inString = false; + let stringChar = ''; + + // Find opening brace for this rule + while (i < css.length) { + const char = css[i]; + + if (inString) { + if (char === stringChar && css[i - 1] !== '\\') { + inString = false; + } + } else { + if (char === '"' || char === "'") { + inString = true; + stringChar = char; + } else if (char === '{') { + braceDepth++; + if (braceDepth === 1) { + break; // Found opening brace + } + } + } + i++; + } + + if (i >= css.length) break; + + const selector = css.substring(selectorStart, i).trim(); + i++; // Skip opening brace + + // Find matching closing brace and extract content + const contentStart = i; + braceDepth = 1; + inString = false; + + while (i < css.length && braceDepth > 0) { + const char = css[i]; + + if (inString) { + if (char === stringChar && css[i - 1] !== '\\') { + inString = false; + } + } else { + if (char === '"' || char === "'") { + inString = true; + stringChar = char; + } else if (char === '{') { + braceDepth++; + } else if (char === '}') { + braceDepth--; + } + } + i++; + } + + const content = css.substring(contentStart, i - 1).trim(); + + // Check if content has nested rules + if (content.includes('{') && content.includes('}')) { + // Extract declarations (before any nested rules) + const declarationMatch = content.match(/^([^{]*)/); + const declarations = declarationMatch ? declarationMatch[1].trim() : ''; + + if (declarations) { + rules.push({ selector, declarations }); + } + + // Extract and parse nested rules recursively + const nestedStart = content.indexOf('{'); + if (nestedStart !== -1) { + const nestedCSS = content.substring(nestedStart); + this.parseCSSSafe(nestedCSS, rules); + } + } else if (content.trim()) { + // Simple rule with just declarations + rules.push({ selector, declarations: content }); + } + } + }, + + /** + * Debug method to see raw CSS content and rule parsing + */ + debugRawCSS(): void { + const allCSS = this.getAllCSS(); + console.group('🔍 Raw CSS Debug'); + console.log('📝 Raw CSS length:', allCSS.length); + console.log('📝 Raw CSS preview (first 2000 chars):'); + console.log(allCSS.substring(0, 2000)); + + const rules = this.extractCSSRules(allCSS); + console.log('📊 Total extracted rules:', rules.length); + console.log('📋 First 10 rules:'); + rules.slice(0, 10).forEach((rule, i) => { + console.log(` ${i + 1}. ${rule.selector}`); + }); + + // Show some examples of what gets filtered as tasty vs global + const tastyRules = rules.filter((rule) => { + const selectors = rule.selector.split(',').map((s) => s.trim()); + return selectors.every((selector) => { + const cleanSelector = selector.replace(/[.#:\s>+~[\]()]/g, ' '); + const parts = cleanSelector.split(/\s+/).filter(Boolean); + return parts.length > 0 && parts.every((part) => /^t\d+$/.test(part)); + }); + }); + + const globalRules = rules.filter((rule) => { + const selectors = rule.selector.split(',').map((s) => s.trim()); + return !selectors.every((selector) => { + const cleanSelector = selector.replace(/[.#:\s>+~[\]()]/g, ' '); + const parts = cleanSelector.split(/\s+/).filter(Boolean); + return parts.length > 0 && parts.every((part) => /^t\d+$/.test(part)); + }); + }); + + console.log('🏷️ Tasty class rules found:', tastyRules.length); + console.log('🌍 Global rules found:', globalRules.length); + + if (globalRules.length > 0) { + console.log('📋 First 5 global rules:'); + globalRules.slice(0, 5).forEach((rule, i) => { + console.log(` ${i + 1}. ${rule.selector}`); + }); + } + + console.groupEnd(); + }, +}; + +/** + * Check if we're in a development environment at runtime + * Uses bracket notation to avoid bundler compilation + */ +function isDevelopmentEnvironment(): boolean { + if (typeof process === 'undefined') return false; + + // Use bracket notation to avoid bundler replacement + const nodeEnv = process.env?.['NODE_ENV']; + return nodeEnv === 'development' || nodeEnv !== 'production'; +} + +/** + * Install tastyDebug on window object for easy access in browser console + * Only in non-production environments + */ +export function installGlobalDebug(options?: { force?: boolean }): void { + const shouldInstall = options?.force || isDevelopmentEnvironment(); + + if ( + typeof window !== 'undefined' && + shouldInstall && + (window as any).tastyDebug !== tastyDebug + ) { + (window as any).tastyDebug = tastyDebug; + console.log( + '🎨 tastyDebug installed on window.\n' + + '💡 Quick start:\n' + + ' • tastyDebug.getSummary() - comprehensive overview with properties, keyframes & global CSS\n' + + ' • tastyDebug.inspect(".my-element") - detailed element inspection\n' + + ' • tastyDebug.getGlobalCSS() - get all global CSS from createGlobalStyle()\n' + + ' • tastyDebug.logGlobalCSS() - log global CSS to console\n' + + ' • tastyDebug.logGlobalCSSBreakdown() - detailed global CSS analysis\n' + + ' • tastyDebug.debugRawCSS() - debug raw CSS parsing and filtering\n' + + ' • tastyDebug.getDefinedProperties() - list all @property definitions\n' + + ' • tastyDebug.getDefinedKeyframes() - list all keyframe definitions\n' + + ' • tastyDebug.getActiveCSS() / getCachedCSS() - get specific CSS\n' + + ' • tastyDebug.getCleanupSummary() - cleanup statistics overview\n' + + ' • tastyDebug.logCleanupHistory() - detailed cleanup history', + ); + } +} + +/** + * Auto-install in development + */ +if (typeof window !== 'undefined' && isDevelopmentEnvironment()) { + installGlobalDebug(); +} diff --git a/src/tasty/index.ts b/src/tasty/index.ts index 259b17802..96ff2c68e 100644 --- a/src/tasty/index.ts +++ b/src/tasty/index.ts @@ -11,6 +11,8 @@ export * from './providers/BreakpointsProvider'; export * from './utils/mergeStyles'; export * from './utils/warnings'; export * from './utils/getDisplayName'; +export * from './injector'; +export * from './debug'; export type { TastyProps, GlobalTastyProps, diff --git a/src/tasty/injector/README.md b/src/tasty/injector/README.md new file mode 100644 index 000000000..74b7d43a1 --- /dev/null +++ b/src/tasty/injector/README.md @@ -0,0 +1,228 @@ +# Tasty Style Injector + +A high-performance CSS-in-JS solution designed to replace styled-components in the Tasty design system. + +## Overview + +The Style Injector provides: +- **Hash-based deduplication** - identical CSS gets the same className +- **Reference counting** - automatic cleanup when components unmount +- **CSS nesting flattening** - handles `&`, `.Class`, `SubElement` patterns +- **Keyframes injection** - first-class `@keyframes` support with deduplication +- **Efficient bulk cleanup** - unused styles are marked and cleaned up in batches +- **SSR support** - deterministic class names and CSS extraction +- **Multiple roots** - works with Document and ShadowRoot +- **Style elements** - reliable DOM insertion with fallbacks + +## Quick Start + +```typescript +import { inject, keyframes, configure } from './tasty/injector'; + +// Configure once (optional) +configure({ + cacheSize: 1000, + collectMetrics: true, +}); + +// Inject component styles +const { className, dispose } = inject([{ + selector: '.t-123', + declarations: 'color: red; padding: 10px;' +}]); + +// Inject keyframes +const fadeIn = keyframes({ + from: { opacity: 0 }, + to: { opacity: 1 }, +}); + +// Use keyframes in styles +const animatedComponent = inject([{ + selector: '.t-456', + declarations: `animation: ${fadeIn} 300ms ease-in;` +}]); + +// Inject global styles +const globalDispose = inject([ + { selector: 'body', declarations: 'margin: 0; font-family: Arial;' }, + { selector: '.header', declarations: 'background: blue; height: 60px;' } +]); + +// Cleanup when component unmounts +useEffect(() => { + return () => { + dispose(); + fadeIn.dispose(); + animatedComponent.dispose(); + globalDispose(); + }; +}, []); +``` + +## API Reference + +### `inject(rules: StyleResult[], options?): InjectResult` + +Injects CSS rules and returns a className with dispose function. Supports both component injection (with generated class names) and global injection (with custom selectors). + +```typescript +// Component injection - for tasty components +const componentResult = inject([{ + selector: '.t-abc123', + declarations: 'color: red; padding: 10px;', +}]); +// Returns: { className: 't-abc123', dispose: () => void } + +// Global injection - for global styles +const globalResult = inject([ + { + selector: 'body', + declarations: 'margin: 0; font-family: Arial;', + }, + { + selector: '.header', + declarations: 'background: blue; color: white;', + atRules: ['@media (min-width: 768px)'], + } +]); +// Returns: { className: 't-def456', dispose: () => void } +``` + +### `configure(config: Partial): void` + +Configures the global injector instance. + +```typescript +configure({ + maxRulesPerSheet: 8000, // Cap rules per sheet (infinite by default) + unusedStylesThreshold: 500, // Threshold for bulk cleanup of unused styles + bulkCleanupDelay: 5000, // Delay before bulk cleanup (ms, ignored if idleCleanup is true) + idleCleanup: true, // Use requestIdleCallback for cleanup when available + collectMetrics: false, // Collect performance metrics + forceTextInjection: false, // Force textContent insertion (auto-detected for tests) + nonce: 'csp-nonce', // CSP nonce for style elements +}); +``` + +### `keyframes(steps, nameOrOptions?): KeyframesResult` + +Injects CSS keyframes and returns an object with `toString()` and `dispose()` methods. + +```typescript +// Generated name (k0, k1, ...) +const fadeIn = keyframes({ + from: { opacity: 0 }, + to: { opacity: 1 }, +}); + +// Custom name via string parameter +const slideIn = keyframes({ + '0%': 'transform: translateX(-100%)', + '100%': 'transform: translateX(0)', +}, 'slideInAnimation'); + +// Custom name via options +const pulse = keyframes({ + '0%': { opacity: 0.5 }, + '50%': { opacity: 1 }, + '100%': { opacity: 0.5 }, +}, { name: 'pulseAnimation' }); + +// With custom root (ShadowDOM) +const spinInShadow = keyframes({ + from: 'transform: rotate(0deg)', + to: 'transform: rotate(360deg)', +}, { name: 'spin', root: shadowRoot }); + +// Use in CSS +const css = `animation: ${fadeIn} 300ms ease-in;`; +console.log(fadeIn.toString()); // "k0" or custom name + +// Cleanup +fadeIn.dispose(); +``` + +### `getCssText(options?): string` + +Extracts CSS text for SSR. + +```typescript +const cssForSSR = getCssText(); +``` + +## Architecture + +``` +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ tastyElement │────│ StyleInjector │────│ SheetManager │ +│ tastyGlobal │ │ │ │ │ +└─────────────────┘ └──────────────────┘ └─────────────────┘ + │ │ │ + │ │ │ + ▼ ▼ ▼ +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ renderStyles │ │ KeyframesManager │ │ RootRegistry │ +│ │ │ │ │ │ +└─────────────────┘ └──────────────────┘ └─────────────────┘ + │ │ + │ │ + ▼ ▼ +┌─────────────────┐ ┌─────────────────┐ +│ StyleResult │ │ CSSStyleSheet │ +│ Array │ │