From 41b3c86e708fc8d5898a428b88bce179f3f0d1b1 Mon Sep 17 00:00:00 2001 From: Peterl561 Date: Tue, 3 Dec 2024 19:46:20 -0800 Subject: [PATCH 1/9] fix(select): hideEmptyContent API --- packages/components/select/src/use-select.ts | 7 ++++++ .../src/use-multiselect-state.ts | 25 +++++++++++++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/components/select/src/use-select.ts b/packages/components/select/src/use-select.ts index 9fd67a73c5..f33f802d4d 100644 --- a/packages/components/select/src/use-select.ts +++ b/packages/components/select/src/use-select.ts @@ -166,6 +166,11 @@ export type UseSelectProps = Omit< * @default undefined */ isVirtualized?: boolean; + /** + * Whether the listbox should be openable when there are no items. + * @default true + */ + hideEmptyContent?: boolean; }; export function useSelect(originalProps: UseSelectProps) { @@ -209,6 +214,7 @@ export function useSelect(originalProps: UseSelectProps) { onClose, className, classNames, + hideEmptyContent = true, ...otherProps } = props; @@ -263,6 +269,7 @@ export function useSelect(originalProps: UseSelectProps) { isDisabled: originalProps.isDisabled, isInvalid: originalProps.isInvalid, defaultOpen, + hideEmptyContent, onOpenChange: (open) => { onOpenChange?.(open); if (!open) { diff --git a/packages/hooks/use-aria-multiselect/src/use-multiselect-state.ts b/packages/hooks/use-aria-multiselect/src/use-multiselect-state.ts index 8e2d5535c6..f1b531ac8d 100644 --- a/packages/hooks/use-aria-multiselect/src/use-multiselect-state.ts +++ b/packages/hooks/use-aria-multiselect/src/use-multiselect-state.ts @@ -36,6 +36,10 @@ export interface MultiSelectProps * @default true */ shouldFlip?: boolean; + /** + * Whether the menu should be hidden when there are no items. + */ + hideEmptyContent?: boolean; } export interface MultiSelectState @@ -91,18 +95,23 @@ export function useMultiSelectState(props: MultiSelectProps): M triggerState.close(); }, open(focusStrategy: FocusStrategy | null = null) { - // Don't open if the collection is empty. - if (listState.collection.size !== 0) { - setFocusStrategy(focusStrategy); - triggerState.open(); + // Don't open if the collection is empty and hideEmptyContent is true. + if (listState.collection.size === 0 && props.hideEmptyContent) { + return; } + + setFocusStrategy(focusStrategy); + triggerState.open(); }, toggle(focusStrategy: FocusStrategy | null = null) { - if (listState.collection.size !== 0) { - setFocusStrategy(focusStrategy); - triggerState.toggle(); - validationState.commitValidation(); + // Don't toggle if the collection is empty and hideEmptyContent is true. + if (listState.collection.size === 0 && props.hideEmptyContent) { + return; } + + setFocusStrategy(focusStrategy); + triggerState.toggle(); + validationState.commitValidation(); }, isFocused, setFocused, From 937ef9917b1e01b76c8844f08ed6b4a3eea0be1c Mon Sep 17 00:00:00 2001 From: Peterl561 Date: Tue, 3 Dec 2024 19:33:05 -0800 Subject: [PATCH 2/9] test(select): hideEmptyContent tests --- .../select/__tests__/select.test.tsx | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/packages/components/select/__tests__/select.test.tsx b/packages/components/select/__tests__/select.test.tsx index 8f90aa7678..52505c6c85 100644 --- a/packages/components/select/__tests__/select.test.tsx +++ b/packages/components/select/__tests__/select.test.tsx @@ -828,6 +828,48 @@ describe("Select", () => { "Invalid value", ); }); + + it("should not open dropdown when hideEmptyContent is true", async () => { + const wrapper = render( + , + ); + + const select = wrapper.getByTestId("hide-empty-content-true-test"); + + // open the select dropdown + await user.click(select); + + // assert that the select is not open + expect(select).not.toHaveAttribute("aria-expanded", "true"); + }); + + it("should open dropdown when hideEmptyContent is false", async () => { + const wrapper = render( + , + ); + + const select = wrapper.getByTestId("hide-empty-content-false-test"); + + // open the select dropdown + await user.click(select); + + // assert that the select is open + expect(select).toHaveAttribute("aria-expanded", "true"); + }); }); describe("Select virtualization tests", () => { From e39bbeb747804b4f39c9292da6f6df6050f01ec9 Mon Sep 17 00:00:00 2001 From: Peterl561 Date: Tue, 3 Dec 2024 19:33:58 -0800 Subject: [PATCH 3/9] docs(select): hideEmptyContent API --- apps/docs/content/docs/components/select.mdx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/docs/content/docs/components/select.mdx b/apps/docs/content/docs/components/select.mdx index 570cfa86ca..afceb342f9 100644 --- a/apps/docs/content/docs/components/select.mdx +++ b/apps/docs/content/docs/components/select.mdx @@ -485,7 +485,7 @@ the popover and listbox components. }, { attribute: "endContent", - type: "ReactNode", + type: "ReactNode", description: "Element to be rendered in the right side of the select.", default: "-" }, @@ -515,7 +515,7 @@ the popover and listbox components. }, { attribute: "itemHeight", - type: "number", + type: "number", description: "The fixed height of each item in pixels. Required when using virtualization.", default: "32" }, @@ -603,6 +603,12 @@ the popover and listbox components. description: "Whether the select should disable the rotation of the selector icon.", default: "false" }, + { + attribute: "hideEmptyContent", + type: "boolean", + description: "Whether to hide the listbox when there are no items.", + default: "true" + }, { attribute: "popoverProps", type: "PopoverProps", From 44ba9b73242ec0e5cfc24ab4cb582736e3bd1ea5 Mon Sep 17 00:00:00 2001 From: Peterl561 Date: Tue, 3 Dec 2024 19:22:10 -0800 Subject: [PATCH 4/9] chore(select): hideEmptyContent storybook --- .../select/stories/select.stories.tsx | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/packages/components/select/stories/select.stories.tsx b/packages/components/select/stories/select.stories.tsx index f768f58e49..70920b4247 100644 --- a/packages/components/select/stories/select.stories.tsx +++ b/packages/components/select/stories/select.stories.tsx @@ -411,6 +411,31 @@ const StartContentTemplate = ({color, variant, ...args}: SelectProps) => ( ); +const EmptyTemplate = ({color, variant, ...args}: SelectProps) => ( +
+ + +
+); + const CustomItemsTemplate = ({color, variant, ...args}: SelectProps) => (