diff --git a/.changeset/breezy-planes-talk.md b/.changeset/breezy-planes-talk.md new file mode 100644 index 000000000..e513d71e9 --- /dev/null +++ b/.changeset/breezy-planes-talk.md @@ -0,0 +1,5 @@ +--- +"@cube-dev/ui-kit": patch +--- + +Fix cleanup of style in the new style injector. diff --git a/.changeset/chatty-radios-agree.md b/.changeset/chatty-radios-agree.md new file mode 100644 index 000000000..fd96d6257 --- /dev/null +++ b/.changeset/chatty-radios-agree.md @@ -0,0 +1,5 @@ +--- +"@cube-dev/ui-kit": minor +--- + +Improved debug tools with better DX and simpler API. diff --git a/.changeset/curly-vans-crash.md b/.changeset/curly-vans-crash.md new file mode 100644 index 000000000..1a77cd65a --- /dev/null +++ b/.changeset/curly-vans-crash.md @@ -0,0 +1,5 @@ +--- +"@cube-dev/ui-kit": patch +--- + +Optimize rule generation by sorting in cache keys. diff --git a/.changeset/perfect-jars-jump.md b/.changeset/perfect-jars-jump.md new file mode 100644 index 000000000..e9147a6f7 --- /dev/null +++ b/.changeset/perfect-jars-jump.md @@ -0,0 +1,5 @@ +--- +"@cube-dev/ui-kit": patch +--- + +Improve cache cleanup logic and cache checks. diff --git a/.size-limit.cjs b/.size-limit.cjs index 81f558f79..9c85f889d 100644 --- a/.size-limit.cjs +++ b/.size-limit.cjs @@ -20,20 +20,20 @@ module.exports = [ }), ); }, - limit: '305kB', + limit: '310kB', }, { name: 'Tree shaking (just a Button)', path: './dist/es/index.js', webpack: true, import: '{ Button }', - limit: '32 kB', + limit: '33 kB', }, { name: 'Tree shaking (just an Icon)', path: './dist/es/index.js', webpack: true, import: '{ AiIcon }', - limit: '19 kB', + limit: '20 kB', }, ]; diff --git a/.storybook/preview.jsx b/.storybook/preview.jsx index b434d5683..83047906f 100644 --- a/.storybook/preview.jsx +++ b/.storybook/preview.jsx @@ -8,9 +8,9 @@ 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 }) => { + import('../src/tasty/debug').then(({ tastyDebug }) => { try { - installGlobalDebug({ force: true }); + tastyDebug.install(); } catch (e) { console.warn('tastyDebug installation failed:', e); } diff --git a/src/components/fields/ComboBox/ComboBox.tsx b/src/components/fields/ComboBox/ComboBox.tsx index 433933770..d5fc970f1 100644 --- a/src/components/fields/ComboBox/ComboBox.tsx +++ b/src/components/fields/ComboBox/ComboBox.tsx @@ -3,7 +3,6 @@ import { ForwardedRef, forwardRef, ReactElement, - ReactNode, RefObject, useEffect, useMemo, @@ -71,18 +70,14 @@ const TriggerElement = tasty({ placeContent: 'center', placeSelf: 'stretch', radius: '(1r - 1bw) right', - width: { - '': '4x', - '[data-size="small"]': '3x', - '[data-size="medium"]': '4x', - }, + width: '3x', color: { '': '#dark-02', hovered: '#dark-02', pressed: '#purple', '[disabled]': '#dark.30', }, - border: 0, + border: 'left', reset: 'button', margin: 0, fill: { diff --git a/src/components/fields/FilterPicker/FilterPicker.tsx b/src/components/fields/FilterPicker/FilterPicker.tsx index 94b0b745a..cf2475886 100644 --- a/src/components/fields/FilterPicker/FilterPicker.tsx +++ b/src/components/fields/FilterPicker/FilterPicker.tsx @@ -220,6 +220,21 @@ export const FilterPicker = forwardRef(function FilterPicker( allValueProps, customValueProps, newCustomValueProps, + searchPlaceholder, + autoFocus, + filter, + emptyLabel, + searchInputStyles, + searchInputRef, + listStyles, + optionStyles, + sectionStyles, + headingStyles, + listRef, + disallowEmptySelection, + shouldUseVirtualFocus, + onEscape, + onOptionClick, ...otherProps } = props; @@ -1005,6 +1020,17 @@ export const FilterPicker = forwardRef(function FilterPicker( selectedKeys={ selectionMode === 'multiple' ? mappedSelectedKeys : undefined } + searchPlaceholder={searchPlaceholder} + filter={filter} + listStyles={listStyles} + optionStyles={optionStyles} + sectionStyles={sectionStyles} + headingStyles={headingStyles} + listRef={listRef} + disallowEmptySelection={disallowEmptySelection} + emptyLabel={emptyLabel} + searchInputStyles={searchInputStyles} + searchInputRef={searchInputRef} disabledKeys={disabledKeys} focusOnHover={focusOnHover} shouldFocusWrap={shouldFocusWrap} diff --git a/src/stories/StyleInjector.docs.mdx b/src/stories/StyleInjector.docs.mdx new file mode 100644 index 000000000..dbb4c9595 --- /dev/null +++ b/src/stories/StyleInjector.docs.mdx @@ -0,0 +1,474 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + + + +# Tasty Style Injector + +A high-performance CSS-in-JS solution that powers the Tasty design system with efficient style injection, automatic cleanup, and first-class SSR support. + +--- + +## πŸš€ Overview + +The Style Injector is the core engine behind Tasty's styling system, providing: + +- **πŸ”„ Hash-based deduplication** - Identical CSS gets the same className +- **πŸ“Š Reference counting** - Automatic cleanup when components unmount (refCount = 0) +- **🎯 CSS nesting flattening** - Handles `&`, `.Class`, `SubElement` patterns +- **🎬 Keyframes injection** - First-class `@keyframes` support with immediate disposal +- **🧹 Smart cleanup** - CSS rules batched cleanup, keyframes disposed immediately +- **πŸ–₯️ SSR support** - Deterministic class names and CSS extraction +- **πŸŒ™ Multiple roots** - Works with Document and ShadowRoot +- **⚑ Non-stacking cleanups** - Prevents timeout accumulation for better performance + +> **πŸ’‘ Note:** This is internal infrastructure that powers Tasty components. Most developers will interact with the higher-level `tasty()` API instead. + +--- + +## πŸ—οΈ Architecture + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ tasty() │────│ Style Injector │────│ Sheet Manager β”‚ +β”‚ components β”‚ β”‚ β”‚ β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ β”‚ + β”‚ β”‚ β”‚ + β–Ό β–Ό β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Style Results β”‚ β”‚ Keyframes Managerβ”‚ β”‚ Root Registry β”‚ +β”‚ (CSS rules) β”‚ β”‚ β”‚ β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ + β”‚ β”‚ + β–Ό β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Hash Cache β”‚ β”‚