Skip to content

feat(FilterListBox): add component #730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 70 commits into from
Jul 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
d371d62
feat(FilterListBox): add component
tenphi Jul 17, 2025
289c69a
feat(FilterListBox): add component * 2
tenphi Jul 17, 2025
dc9ff0f
feat(FilterListBox): add component * 3
tenphi Jul 17, 2025
1239c8d
feat(FilterListBox): add component * 4
tenphi Jul 17, 2025
a2bb5a1
feat(FilterListBox): add component * 5
tenphi Jul 17, 2025
dbd639f
feat(FilterListBox): support allowsCustomValue
tenphi Jul 17, 2025
28041a9
feat(FilterListBox): support allowsCustomValue * 2
tenphi Jul 17, 2025
9417a8a
feat(FilterListBox): support allowsCustomValue * 3
tenphi Jul 17, 2025
56b4948
feat(FilterListBox): support allowsCustomValue * 4
tenphi Jul 17, 2025
6302fc5
feat(FilterPicker): add component
tenphi Jul 18, 2025
1489319
feat(FilterPicker): add component * 2
tenphi Jul 18, 2025
f4adbbe
feat(FilterPicker): add component * 3
tenphi Jul 18, 2025
8c2f434
feat(FilterPicker): add renderSummary
tenphi Jul 18, 2025
d139fa7
feat(FilterPicker): add component * 4
tenphi Jul 18, 2025
ad503e7
feat(FilterPicker): add component * 5
tenphi Jul 18, 2025
97d074b
feat(FilterPicker): add component * 6
tenphi Jul 18, 2025
58df5ae
feat(FilterPicker): add component * 7
tenphi Jul 18, 2025
01a766d
feat(FilterPicker): add component * 8
tenphi Jul 18, 2025
8d1f9db
chore: remove tests
tenphi Jul 21, 2025
cec9113
feat(FilterPicker): accessibility warnings
tenphi Jul 21, 2025
d467ffc
feat(FilterPicker): renderSummary support null value
tenphi Jul 21, 2025
4453793
feat(FilterPicker): renderSummary support false value
tenphi Jul 21, 2025
13fc5a9
feat(FilterPicker): checkbox support
tenphi Jul 21, 2025
2114fc6
feat(FilterPicker): add more stories and minor fixes
tenphi Jul 21, 2025
5fc8121
chore: update docs
tenphi Jul 21, 2025
a0923f6
fix(ListBox): add size support
tenphi Jul 21, 2025
9bdc651
feat(ListBox): add virtualization
tenphi Jul 21, 2025
d32c1b1
fix(FilterPicker): example
tenphi Jul 21, 2025
703160d
fix(ListBox): virtualization scroll area and layout
tenphi Jul 22, 2025
ad663f5
fix(ListBox): virtualization scroll area and layout * 2
tenphi Jul 22, 2025
15a62f7
feat(ChartKPIIcon): add component
tenphi Jul 22, 2025
3023ba8
fix(ListBox): virtualization scroll area and layout * 6
tenphi Jul 22, 2025
bd7fca4
fix(FilterListBox): proper enhancement
tenphi Jul 22, 2025
2110731
fix(FilterListBox): proper enhancement children
tenphi Jul 22, 2025
4c72d2d
fix: default sizes for various components
tenphi Jul 22, 2025
a71320c
fix(ListBox): improve documentation
tenphi Jul 22, 2025
4706593
fix(FilterListBox): pass size to the search input
tenphi Jul 22, 2025
1402cea
fix(Menu): layout
tenphi Jul 22, 2025
914b7ae
chore: add changeset
tenphi Jul 22, 2025
770c3e2
chore: update tests
tenphi Jul 22, 2025
4f5db41
fix(Menu): styles
tenphi Jul 22, 2025
cd854a2
fix(ListBox): fix margin
tenphi Jul 22, 2025
e6e8241
fix(ListBox): popover/inline paddings
tenphi Jul 22, 2025
84592a3
fix(ListBox): virtual index
tenphi Jul 22, 2025
5511858
fix(ListBox): select/deselect glitches
tenphi Jul 22, 2025
b844367
fix(Select): style passing
tenphi Jul 22, 2025
ad46e7f
fix(Slider): style passing
tenphi Jul 22, 2025
3ddc1a9
fix(FilterListBox): remove sortSelectOnTop flag
tenphi Jul 22, 2025
c2ba853
fix(FilterListBox): prop reference
tenphi Jul 22, 2025
5f33d87
fix(FilterPicker): props
tenphi Jul 22, 2025
b16fcf2
fix(FilterPicker): support custom values
tenphi Jul 22, 2025
81e80f0
fix(FilterListBox): improve custom value storage
tenphi Jul 23, 2025
6425626
fix(FilterPicker): sort selected custom values on top
tenphi Jul 23, 2025
42ba781
fix(FilterListBox): better navigation
tenphi Jul 23, 2025
6ba6f0d
chore: add a rule
tenphi Jul 23, 2025
4afd1b0
fix(ListBox): improve virtualization measurement
tenphi Jul 23, 2025
9aff190
fix(ListBox): improvements
tenphi Jul 23, 2025
3a60522
fix(FilterListBox): no selection in no results state
tenphi Jul 23, 2025
3c12968
fix: improve listbox item styles in all components
tenphi Jul 23, 2025
7d5e5b0
fix: improve listbox item styles in all components * 2
tenphi Jul 23, 2025
e1d61cd
fix(FilterListBox): fix autoscroll
tenphi Jul 23, 2025
5a4903a
fix(FilterListBox): focus behavior
tenphi Jul 23, 2025
dd3b37b
fix(FilterListBox): autoscroll
tenphi Jul 23, 2025
699aa30
fix(FilterPicker): focus button
tenphi Jul 23, 2025
dcc7ec1
chore(FilterPicker): fix warning
tenphi Jul 23, 2025
1ac77a4
chore: update size limit
tenphi Jul 23, 2025
4b9a6bd
chore: improve tests
tenphi Jul 23, 2025
7beda84
chore: improve tests * 2
tenphi Jul 23, 2025
7a48311
chore: fix documentation import
tenphi Jul 23, 2025
b2071f3
fix(ListBox): focus issues
tenphi Jul 23, 2025
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/angry-boxes-speak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cube-dev/ui-kit": patch
---

Improve the layout of Menu component.
5 changes: 5 additions & 0 deletions .changeset/clever-rings-float.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cube-dev/ui-kit": patch
---

`wrapWithField` no longer wrap the input component with a field if no label is provided and `forceField` prop is not set.
5 changes: 5 additions & 0 deletions .changeset/cool-pianos-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cube-dev/ui-kit": patch
---

Add a new icon ChartKPI.
5 changes: 5 additions & 0 deletions .changeset/purple-carrots-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cube-dev/ui-kit": minor
---

Add FilterPicker component for single and multiple picker experience with a filter.
5 changes: 5 additions & 0 deletions .changeset/short-humans-crash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cube-dev/ui-kit": minor
---

Split ListBox into two components: simple ListBox and FilterListBox with search input.
12 changes: 12 additions & 0 deletions .cursor/rules/coding.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
alwaysApply: true
---

# Flow rules
- Don't respond with "You're right!", "Great idea!" and so on. Get straight to the point.
- **Stop and describe the reason**, if you can't closely implement the task or need a different approach from what was asked.
- Do not run tests if you only changed stories or documentation since the last test run.

# Coding rules

- Use named imports from react (like `useCallback`) instead of using the `React` instance. Avoid: `React.useCallback`.
2 changes: 1 addition & 1 deletion .size-limit.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module.exports = [
}),
);
},
limit: '270kB',
limit: '279kB',
},
{
name: 'Tree shaking (just a Button)',
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"@react-types/shared": "^3.27.0",
"@sparticuz/chromium": "^137.0.1",
"@tabler/icons-react": "^3.31.0",
"@tanstack/react-virtual": "^3.13.12",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"@vitejs/plugin-react": "^4.3.2",
"clipboard-copy": "^4.0.1",
Expand Down
20 changes: 20 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/components/actions/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default {
},
},
size: {
options: ['small', 'medium', 'large'],
options: ['tiny', 'small', 'medium', 'large'],
control: { type: 'radio' },
description: 'Button size',
table: {
Expand Down
45 changes: 24 additions & 21 deletions src/components/actions/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface CubeButtonProps extends CubeActionProps {
| 'outline'
| 'neutral'
| (string & {});
size?: 'small' | 'medium' | 'large' | (string & {});
size?: 'tiny' | 'small' | 'medium' | 'large' | (string & {});
}

export type ButtonVariant =
Expand Down Expand Up @@ -83,20 +83,23 @@ export const DEFAULT_BUTTON_STYLES = {
reset: 'button',
outlineOffset: 1,
padding: {
'': '0 (2x - 1bw)',
'[data-size="small"]': '0 (1x - 1bw)',
'[data-size="medium"]': '0 (1.5x - 1bw)',
'[data-size="large"]': '0 (2.25x - 1bw)',
'': '.5x (2x - 1bw)',
'[data-size="tiny"]': '.5x (1x - 1bw)',
'[data-size="small"]': '.5x (1x - 1bw)',
'[data-size="medium"]': '.5x (1.5x - 1bw)',
'[data-size="large"]': '.5x (2.25x - 1bw)',
'single-icon-only | [data-type="link"]': 0,
},
width: {
'': 'initial',
'[data-size="tiny"] & single-icon-only': '3.5x 3.5x',
'[data-size="small"] & single-icon-only': '4x 4x',
'[data-size="medium"] & single-icon-only': '5x 5x',
'[data-size="large"] & single-icon-only': '6x 6x',
},
height: {
'': 'initial',
'[data-size="tiny"]': '3.5x 3.5x',
'[data-size="small"]': '4x 4x',
'[data-size="medium"]': '5x 5x',
'[data-size="large"]': '6x 6x',
Expand Down Expand Up @@ -161,13 +164,13 @@ export const DEFAULT_OUTLINE_STYLES: Styles = {
fill: {
'': '#dark.0',
hovered: '#dark.03',
'pressed | selected': '#dark.06',
'pressed | (selected & !hovered)': '#dark.06',
'[disabled] | disabled': '#dark.04',
},
color: {
'': '#dark-02',
hovered: '#dark-02',
'pressed | selected': '#dark',
'pressed | (selected & !hovered)': '#dark',
'[disabled] | disabled': '#dark-04',
},
} as const;
Expand All @@ -180,7 +183,7 @@ export const DEFAULT_NEUTRAL_STYLES: Styles = {
fill: {
'': '#dark.0',
hovered: '#dark.03',
'pressed | selected': '#dark.06',
'pressed | (selected & !hovered)': '#dark.06',
},
color: {
'': '#dark-02',
Expand All @@ -199,7 +202,7 @@ export const DEFAULT_CLEAR_STYLES: Styles = {
fill: {
'': '#purple.0',
hovered: '#purple.16',
'pressed | selected': '#purple.10',
'pressed | (selected & !hovered)': '#purple.10',
},
color: {
'': '#purple-text',
Expand Down Expand Up @@ -273,7 +276,7 @@ export const DANGER_OUTLINE_STYLES: Styles = {
fill: {
'': '#danger.0',
hovered: '#danger.1',
'pressed | selected': '#danger.05',
'pressed | (selected & !hovered)': '#danger.05',
'[disabled] | disabled': '#dark.04',
},
color: {
Expand All @@ -290,11 +293,11 @@ export const DANGER_NEUTRAL_STYLES: Styles = {
fill: {
'': '#dark.0',
hovered: '#dark.04',
'pressed | selected': '#dark.05',
'pressed | (selected & !hovered)': '#dark.05',
},
color: {
'': '#dark-02',
'pressed | selected': '#danger-text',
'pressed | (selected & !hovered)': '#danger-text',
'[disabled] | disabled': '#dark-04',
},
} as const;
Expand All @@ -308,7 +311,7 @@ export const DANGER_CLEAR_STYLES: Styles = {
fill: {
'': '#danger.0',
hovered: '#danger.1',
'pressed | selected': '#danger.05',
'pressed | (selected & !hovered)': '#danger.05',
},
color: {
'': '#danger-text',
Expand Down Expand Up @@ -382,7 +385,7 @@ export const SUCCESS_OUTLINE_STYLES: Styles = {
fill: {
'': '#success.0',
hovered: '#success.1',
'pressed | selected': '#success.05',
'pressed | (selected & !hovered)': '#success.05',
'[disabled] | disabled': '#dark.04',
},
color: {
Expand All @@ -399,11 +402,11 @@ export const SUCCESS_NEUTRAL_STYLES: Styles = {
fill: {
'': '#dark.0',
hovered: '#dark.04',
'pressed | selected': '#dark.05',
'pressed | (selected & !hovered)': '#dark.05',
},
color: {
'': '#dark-02',
'pressed | selected': '#success-text',
'pressed | (selected & !hovered)': '#success-text',
'[disabled] | disabled': '#dark-04',
},
} as const;
Expand All @@ -417,7 +420,7 @@ export const SUCCESS_CLEAR_STYLES: Styles = {
fill: {
'': '#success.0',
hovered: '#success.1',
'pressed | selected': '#success.05',
'pressed | (selected & !hovered)': '#success.05',
},
color: {
'': '#success-text',
Expand Down Expand Up @@ -489,7 +492,7 @@ export const SPECIAL_OUTLINE_STYLES: Styles = {
fill: {
'': '#white.0',
hovered: '#white.18',
'pressed | selected': '#white.12',
'pressed | (selected & !hovered)': '#white.12',
'[disabled] | disabled': '#white.12',
},
color: {
Expand All @@ -506,7 +509,7 @@ export const SPECIAL_NEUTRAL_STYLES: Styles = {
fill: {
'': '#white.0',
hovered: '#white.12',
'pressed | selected': '#white.18',
'pressed | (selected & !hovered)': '#white.18',
},
color: {
'': '#white',
Expand Down Expand Up @@ -619,14 +622,14 @@ export const Button = forwardRef(function Button(
if (icon) {
if (!specifiedLabel) {
accessibilityWarning(
'If you provide `icon` property for a Button and do not provide any children then you should specify the `label` property to make sure the Button element stays accessible.',
'If you provide `icon` property for a Button and do not provide any children then you should specify the `aria-label` property to make sure the Button element stays accessible.',
);
label = 'Unnamed'; // fix to avoid warning in production
}
} else {
if (!specifiedLabel) {
accessibilityWarning(
'If you provide no children for a Button then you should specify the `label` property to make sure the Button element stays accessible.',
'If you provide no children for a Button then you should specify the `aria-label` property to make sure the Button element stays accessible.',
);
label = 'Unnamed'; // fix to avoid warning in production
}
Expand Down
5 changes: 4 additions & 1 deletion src/components/actions/CommandMenu/CommandMenu.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,7 @@ HotkeyTesting.args = {
};

export const MediumSize: StoryFn<CubeCommandMenuProps<any>> = (args) => (
<CommandMenu width="20x 50x" {...args} size="medium">
<CommandMenu width="20x 50x" {...args}>
{basicCommands.map((command) => (
<CommandMenu.Item
key={command.key}
Expand All @@ -774,6 +774,7 @@ export const MediumSize: StoryFn<CubeCommandMenuProps<any>> = (args) => (
MediumSize.args = {
searchPlaceholder: 'Medium size command palette...',
autoFocus: true,
size: 'medium',
};

export const WithDialog: StoryFn<CubeCommandMenuProps<any>> = (args) => (
Expand Down Expand Up @@ -834,6 +835,7 @@ export const WithHeaderAndFooter: StoryFn<CubeCommandMenuProps<any>> = (
</FooterText>
</>
}
size="medium"
>
{basicCommands.map((command) => (
<CommandMenu.Item
Expand Down Expand Up @@ -929,6 +931,7 @@ export const WithDialogContainer: StoryFn<CubeCommandMenuProps<any>> = (
WithDialogContainer.args = {
searchPlaceholder: 'Search commands...',
autoFocus: true,
size: 'medium',
};

WithDialogContainer.play = async ({ canvasElement }) => {
Expand Down
17 changes: 0 additions & 17 deletions src/components/actions/CommandMenu/CommandMenu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -878,22 +878,6 @@ describe('CommandMenu', () => {
expect(commandMenu).toHaveAttribute('data-is-tray');
});

it('should apply modal mod when used inside a modal dialog', () => {
const { DialogContext } = require('../../overlays/Dialog/context');

render(
<DialogContext.Provider value={{ type: 'modal' }}>
<CommandMenu qa="test-command-menu">
<CommandMenu.Item key="item1">Item 1</CommandMenu.Item>
<CommandMenu.Item key="item2">Item 2</CommandMenu.Item>
</CommandMenu>
</DialogContext.Provider>,
);

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

it('should not apply any special mods when used standalone', () => {
render(
<CommandMenu qa="test-command-menu">
Expand All @@ -905,7 +889,6 @@ 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-is-modal');
});
});
});
Loading
Loading