Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/has-selector-element-transformation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@cube-dev/ui-kit': minor
---

Add support for `:has(Item)` syntax in style mappings. Capitalized element names inside `:has()` pseudo-class selectors are now automatically transformed to `data-element` attribute selectors (`:has(Item)``:has([data-element="Item"])`).
7 changes: 7 additions & 0 deletions .changeset/value-mods.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@cube-dev/ui-kit': major
---

**BREAKING:** Boolean mods now generate `data-*` instead of `data-is-*` attributes (`mods={{ hovered: true }}``data-hovered=""` instead of `data-is-hovered=""`).

**NEW:** Value mods support - `mods` now accepts string values (`mods={{ theme: 'danger' }}``data-theme="danger"`). Includes shorthand syntax in styles (`theme=danger`, `theme="danger"`). See Tasty documentation for details.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ coverage
size-limit-report/stats.json
docs-static
*.plan.md
*.spec.md
4 changes: 2 additions & 2 deletions .size-limit.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ module.exports = [
path: './dist/es/index.js',
webpack: true,
import: '{ Button }',
limit: '33 kB',
limit: '35 kB',
},
{
name: 'Tree shaking (just an Icon)',
path: './dist/es/index.js',
webpack: true,
import: '{ AiIcon }',
limit: '20 kB',
limit: '22 kB',
},
];
2 changes: 1 addition & 1 deletion src/components/actions/Button/Button.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ The `mods` prop accepts the following modifiers you can override:
| disabled | `boolean` | Forces disabled appearance. |
| loading | `boolean` | Displays loading spinner. |
| selected | `boolean` | Displays selected state. |
| with-icons | `boolean` | Indicates that the button contains at least one icon. |
| has-icons | `boolean` | Indicates that the button contains at least one icon. |
| single-icon | `boolean` | Icon-only button without text. |

## Variants
Expand Down
44 changes: 22 additions & 22 deletions src/components/actions/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,12 @@ export const DEFAULT_BUTTON_STYLES = {
},
gap: {
'': '.75x',
'[data-size="small"]': '.5x',
'size=small': '.5x',
},
preset: {
'': 't3m',
'[data-size="xsmall"]': 't4',
'[data-size="xlarge"]': 't2m',
'size=xsmall': 't4',
'size=xlarge': 't2m',
},
textDecoration: 'none',
transition: 'theme',
Expand All @@ -119,34 +119,34 @@ export const DEFAULT_BUTTON_STYLES = {
outlineOffset: 1,
padding: {
'': '.5x (1.5x - 1bw)',
'[data-size="small"] | [data-size="xsmall"]': '.5x (1.25x - 1bw)',
'[data-size="medium"]': '.5x (1.5x - 1bw)',
'[data-size="large"]': '.5x (1.75x - 1bw)',
'[data-size="xlarge"]': '.5x (2x - 1bw)',
'single-icon | [data-type="link"]': 0,
'size=small | size=xsmall': '.5x (1.25x - 1bw)',
'size=medium': '.5x (1.5x - 1bw)',
'size=large': '.5x (1.75x - 1bw)',
'size=xlarge': '.5x (2x - 1bw)',
'single-icon | type=link': 0,
},
width: {
'': 'initial',
'[data-size="xsmall"] & single-icon': '$size-xs $size-xs',
'[data-size="small"] & single-icon': '$size-sm $size-sm',
'[data-size="medium"] & single-icon': '$size-md $size-md',
'[data-size="large"] & single-icon': '$size-lg $size-lg',
'[data-size="xlarge"] & single-icon': '$size-xl $size-xl',
'[data-type="link"]': 'initial',
'size=xsmall & single-icon': '$size-xs $size-xs',
'size=small & single-icon': '$size-sm $size-sm',
'size=medium & single-icon': '$size-md $size-md',
'size=large & single-icon': '$size-lg $size-lg',
'size=xlarge & single-icon': '$size-xl $size-xl',
'type=link': 'initial',
},
height: {
'': 'initial',
'[data-size="xsmall"]': '$size-xs $size-xs',
'[data-size="small"]': '$size-sm $size-sm',
'[data-size="medium"]': '$size-md $size-md',
'[data-size="large"]': '$size-lg $size-lg',
'[data-size="xlarge"]': '$size-xl $size-xl',
'[data-type="link"]': 'initial',
'size=xsmall': '$size-xs $size-xs',
'size=small': '$size-sm $size-sm',
'size=medium': '$size-md $size-md',
'size=large': '$size-lg $size-lg',
'size=xlarge': '$size-xl $size-xl',
'type=link': 'initial',
},
whiteSpace: 'nowrap',
radius: {
'': true,
'[data-type="link"] & !focused': 0,
'type=link & !focused': 0,
},

ButtonIcon: {
Expand Down Expand Up @@ -272,7 +272,7 @@ export const Button = forwardRef(function Button(
() => ({
loading: isLoading,
selected: isSelected,
'with-icons': hasIcons,
'has-icons': hasIcons,
'left-icon': !!icon,
'right-icon': !!rightIcon,
'single-icon': singleIcon,
Expand Down
8 changes: 4 additions & 4 deletions src/components/actions/Button/button.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ describe('<Button />', () => {
expect(screen.getByTestId('test')).toBeInTheDocument();
});

it('should have data-is-loading', () => {
it('should have data-loading', () => {
render(
<Button isLoading data-qa="ApplyDbConnection">
Apply
</Button>,
);

expect(screen.getByTestId('ApplyDbConnection')).toHaveAttribute(
'data-is-loading',
'data-loading',
'',
);
});

it('should have data-is-loading after rerender', () => {
it('should have data-loading after rerender', () => {
const { rerender } = render(
<Button isLoading={false} data-qa="ApplyDbConnection">
Apply
Expand All @@ -38,7 +38,7 @@ describe('<Button />', () => {
);

expect(screen.getByTestId('ApplyDbConnection')).toHaveAttribute(
'data-is-loading',
'data-loading',
'',
);
});
Expand Down
8 changes: 4 additions & 4 deletions src/components/actions/CommandMenu/CommandMenu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ describe('CommandMenu', () => {
);

const commandMenu = screen.getByTestId('test-command-menu');
expect(commandMenu).toHaveAttribute('data-is-popover');
expect(commandMenu).toHaveAttribute('data-popover');
});

it('should apply tray mod when used with MenuTrigger', () => {
Expand All @@ -875,7 +875,7 @@ describe('CommandMenu', () => {
);

const commandMenu = screen.getByTestId('test-command-menu');
expect(commandMenu).toHaveAttribute('data-is-tray');
expect(commandMenu).toHaveAttribute('data-tray');
});

it('should not apply any special mods when used standalone', () => {
Expand All @@ -887,8 +887,8 @@ describe('CommandMenu', () => {
);

const commandMenu = screen.getByTestId('test-command-menu');
expect(commandMenu).not.toHaveAttribute('data-is-popover');
expect(commandMenu).not.toHaveAttribute('data-is-tray');
expect(commandMenu).not.toHaveAttribute('data-popover');
expect(commandMenu).not.toHaveAttribute('data-tray');
});
});
});
6 changes: 3 additions & 3 deletions src/components/actions/CommandMenu/styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ export const StyledSearchInput = tasty({

$size: {
'': '$size-md',
'[data-size="small"]': '$size-sm',
'[data-size="medium"]': '$size-md',
'[data-size="large"]': '$size-lg',
'size=small': '$size-sm',
'size=medium': '$size-md',
'size=large': '$size-lg',
},
},
});
Expand Down
10 changes: 5 additions & 5 deletions src/components/actions/ItemAction/ItemAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@ const ItemActionElement = tasty({
cursor: { '': 'pointer', disabled: 'default' },
padding: {
'': '0 $inline-padding',
'with-icon': 0,
'with-icon & with-label': '0 $inline-padding 0 0',
'has-icon': 0,
'has-icon & has-label': '0 $inline-padding 0 0',
},

'$inline-padding': {
'': 'max($min-inline-padding, (($action-size - 1lh - 2bw) / 2 + $inline-compensation))',
'[data-size="inline"]': '.25x',
'size=inline': '.25x',
},
'$inline-compensation': '.5x',
'$min-inline-padding': '(.5x - 1bw)',
Expand Down Expand Up @@ -162,9 +162,9 @@ export const ItemAction = forwardRef(function ItemAction(
checkbox: hasCheckbox,
selected: isSelected,
loading: isLoading,
'with-label': !!children,
'has-label': !!children,
context: !!contextType,
'with-icon': !!icon,
'has-icon': !!icon,
...mods,
}),
[hasCheckbox, isSelected, isLoading, children, contextType, mods],
Expand Down
14 changes: 7 additions & 7 deletions src/components/actions/ItemButton/ItemButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,17 @@ const ActionsWrapper = tasty({
placeItems: 'stretch',
preset: {
'': 't3m',
'[data-size="xsmall"]': 't4',
'[data-size="xlarge"]': 't2m',
'size=xsmall': 't4',
'size=xlarge': 't2m',
},

$size: {
'': '$size-md',
'[data-size="xsmall"]': '$size-xs',
'[data-size="small"]': '$size-sm',
'[data-size="medium"]': '$size-md',
'[data-size="large"]': '$size-lg',
'[data-size="xlarge"]': '$size-xl',
'size=xsmall': '$size-xs',
'size=small': '$size-sm',
'size=medium': '$size-md',
'size=large': '$size-lg',
'size=xlarge': '$size-xl',
},

Actions: {
Expand Down
16 changes: 8 additions & 8 deletions src/components/actions/Menu/Menu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ describe('<Menu />', () => {
);

// With first strategy, first menu item gets focus
const focusedItem = container.querySelector('[data-is-focused]');
const focusedItem = container.querySelector('[data-focused]');
expect(focusedItem).toBeInTheDocument();
});

Expand All @@ -568,7 +568,7 @@ describe('<Menu />', () => {
);

// With last strategy, last menu item gets focus
const focusedItem = container.querySelector('[data-is-focused]');
const focusedItem = container.querySelector('[data-focused]');
expect(focusedItem).toBeInTheDocument();
});

Expand Down Expand Up @@ -646,12 +646,12 @@ describe('<Menu />', () => {

// Check wrapper mods (header, footer are on wrapper)
const menuWrapper = container.querySelector('[data-qa="Menu"]');
expect(menuWrapper).toHaveAttribute('data-is-header', '');
expect(menuWrapper).toHaveAttribute('data-is-footer', '');
expect(menuWrapper).toHaveAttribute('data-header', '');
expect(menuWrapper).toHaveAttribute('data-footer', '');

// Check menu list mods (sections mod is on the menu list)
const menu = getByRole('menu');
expect(menu).toHaveAttribute('data-is-sections', '');
expect(menu).toHaveAttribute('data-sections', '');
});

// Ref tests
Expand Down Expand Up @@ -1048,7 +1048,7 @@ describe('Menu popover mod', () => {
);

const menuWrapper = container.querySelector('[data-qa="Menu"]');
expect(menuWrapper).toHaveAttribute('data-is-popover');
expect(menuWrapper).toHaveAttribute('data-popover');
});

it('should not apply popover mod when used standalone', () => {
Expand All @@ -1060,7 +1060,7 @@ describe('Menu popover mod', () => {
);

const menuWrapper = container.querySelector('[data-qa="Menu"]');
expect(menuWrapper).not.toHaveAttribute('data-is-popover');
expect(menuWrapper).not.toHaveAttribute('data-popover');
});

it('should not apply popover mod when context provides false', () => {
Expand All @@ -1076,7 +1076,7 @@ describe('Menu popover mod', () => {
);

const menuWrapper = container.querySelector('[data-qa="Menu"]');
expect(menuWrapper).not.toHaveAttribute('data-is-popover');
expect(menuWrapper).not.toHaveAttribute('data-popover');
});
});

Expand Down
16 changes: 8 additions & 8 deletions src/components/actions/Menu/SubMenuTrigger.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ describe('<SubMenuTrigger />', () => {
// Verify Share item is focused before trying to open submenu
await waitFor(() => {
const shareItem = getByText('Share').closest('li');
expect(shareItem).toHaveAttribute('data-is-focused');
expect(shareItem).toHaveAttribute('data-focused');
});

await act(async () => {
Expand Down Expand Up @@ -221,7 +221,7 @@ describe('<SubMenuTrigger />', () => {
// Verify Share item is focused before trying to open submenu
await waitFor(() => {
const shareItem = getByText('Share').closest('li');
expect(shareItem).toHaveAttribute('data-is-focused');
expect(shareItem).toHaveAttribute('data-focused');
});

await act(async () => {
Expand Down Expand Up @@ -279,7 +279,7 @@ describe('<SubMenuTrigger />', () => {
// Verify Share item is focused before trying to open submenu
await waitFor(() => {
const shareItem = getByText('Share').closest('li');
expect(shareItem).toHaveAttribute('data-is-focused');
expect(shareItem).toHaveAttribute('data-focused');
});

await act(async () => {
Expand Down Expand Up @@ -337,7 +337,7 @@ describe('<SubMenuTrigger />', () => {
// Verify Share item is focused before trying to open submenu
await waitFor(() => {
const shareItem = getByText('Share').closest('li');
expect(shareItem).toHaveAttribute('data-is-focused');
expect(shareItem).toHaveAttribute('data-focused');
});

await act(async () => {
Expand Down Expand Up @@ -401,7 +401,7 @@ describe('<SubMenuTrigger />', () => {
// Verify Share item is focused before trying to open submenu
await waitFor(() => {
const shareItem = getByText('Share').closest('li');
expect(shareItem).toHaveAttribute('data-is-focused');
expect(shareItem).toHaveAttribute('data-focused');
});

await act(async () => {
Expand Down Expand Up @@ -713,7 +713,7 @@ describe('<SubMenuTrigger />', () => {
// Verify Share item is focused before trying to open submenu
await waitFor(() => {
const shareItem = getByText('Share').closest('li');
expect(shareItem).toHaveAttribute('data-is-focused');
expect(shareItem).toHaveAttribute('data-focused');
});

await act(async () => {
Expand All @@ -731,9 +731,9 @@ describe('<SubMenuTrigger />', () => {
// The actual DOM focus might be on the menu itself with aria-activedescendant
const firstSubmenuItem = getByText('Copy link').closest('li');

// Check for focus indication - tasty sets data-is-focused based on mods.focused
// Check for focus indication - tasty sets data-focused based on mods.focused
await waitFor(() => {
expect(firstSubmenuItem).toHaveAttribute('data-is-focused');
expect(firstSubmenuItem).toHaveAttribute('data-focused');
});
});
});
Expand Down
Loading
Loading