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

Open
wants to merge 41 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 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
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.
11 changes: 11 additions & 0 deletions .cursor/rules/coding.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
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.

# 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: '273kB',
},
{
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