From 542961d2a0b809a0cf0232ccf801b45925c54fa4 Mon Sep 17 00:00:00 2001 From: Powerplex Date: Tue, 5 Dec 2023 20:16:45 +0100 Subject: [PATCH] docs(dropdown): stories description for dropdown --- package-lock.json | 1 + .../components/dropdown/src/Dropdown.doc.mdx | 48 +++++++++++++++---- .../dropdown/src/Dropdown.stories.tsx | 41 +++++++++++----- .../dropdown/src/DropdownContext.tsx | 20 ++++++-- .../dropdown/src/DropdownItemContext.tsx | 4 +- 5 files changed, 88 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 86c61d4a14..7afabfb633 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2402,6 +2402,7 @@ }, "node_modules/@clack/prompts/node_modules/is-unicode-supported": { "version": "1.3.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { diff --git a/packages/components/dropdown/src/Dropdown.doc.mdx b/packages/components/dropdown/src/Dropdown.doc.mdx index 1b4e4e06b8..b7726da1f7 100644 --- a/packages/components/dropdown/src/Dropdown.doc.mdx +++ b/packages/components/dropdown/src/Dropdown.doc.mdx @@ -84,50 +84,82 @@ import { Dropdown } from '@spark-ui/dropdown' -### Controlled value +### Controlled + +Use `value` and `onValueChange` props to control the value of the dropdown. ### Controlled open state +Use `open` and `onOpenChange` props to control when the dropdown is opened or closed. + ### Disabled +Use `disabled` on the root component to disable the dropdown entirely. + TODO ### Disabled Item +Use `disabled` on individual `Dropdown.Item` to disable them. + -### Grouped items +### Groups + +Similar to `optgroup` HTML tag, you can gather your items in groups. + +It is important to use `Dropdown.Label` inside each `Dropdown.Group` to give it an accessible name. ### Item indicator +Renders when the parent `DropdownMenu.Item` is selected. + +You can style this element directly, or you can use it as a wrapper to put an icon into, or both. + ### Trigger leading icon +Use `Dropdown.LeadingIcon` inside `Dropdown.Trigger` to prefix your trigger with an icon. + + + +### Read only + TODO -### Multiple selection +## Multiple selection - +When using `multiple` mode, the component manages an array of values and no longer a single value. -### Multiple selection (controlled) +It means you must adapt `value`, `onValueChange` and `defaultValue` accordingly. - +In `multiple` mode, the dropdown won't close when the user selects an item, and it is possible to unselect every item. -### Read only +### Default -TODO + + +### Controlled - multiple selection + +Use `value` and `onValueChange` props to control the value of the dropdown. + + ## Advanced usage ### Custom item +If your `Dropdown.Item` contains anything else than raw text, you may use any JSX markup to customize it. + +**If you do so, you MUST use `Dropdown.ItemText` inside of your item to give it a proper accessible name.** + ### With form field label diff --git a/packages/components/dropdown/src/Dropdown.stories.tsx b/packages/components/dropdown/src/Dropdown.stories.tsx index bd918ae15d..2098308e1b 100644 --- a/packages/components/dropdown/src/Dropdown.stories.tsx +++ b/packages/components/dropdown/src/Dropdown.stories.tsx @@ -19,9 +19,6 @@ export const Default: StoryFn = _args => {
- - - @@ -198,10 +195,36 @@ export const Grouped: StoryFn = _args => { ) } +export const LeadingIcon: StoryFn = _args => { + return ( +
+ + + + + + + + + + + To Kill a Mockingbird + War and Peace + The Idiot + A Picture of Dorian Gray + 1984 + Pride and Prejudice + + + +
+ ) +} + export const ItemIndicator: StoryFn = _args => { return (
- + @@ -211,30 +234,26 @@ export const ItemIndicator: StoryFn = _args => { To Kill a Mockingbird - New War and Peace - New The Idiot - New - A Picture of Dorian Gray - New + A Picture of Dorian Gray + 1984 - New + Pride and Prejudice - New diff --git a/packages/components/dropdown/src/DropdownContext.tsx b/packages/components/dropdown/src/DropdownContext.tsx index a0b69de0c7..fa617bf8e5 100644 --- a/packages/components/dropdown/src/DropdownContext.tsx +++ b/packages/components/dropdown/src/DropdownContext.tsx @@ -97,7 +97,8 @@ export const DropdownProvider = ({ const [hasPopover, setHasPopover] = useState(false) const field = useFormFieldControl() - const items = Array.from(itemsMap.values()) + const items = [...itemsMap.values()] + const id = useId(field.id) const labelId = useId(field.labelId) @@ -180,9 +181,9 @@ export const DropdownProvider = ({ /** * Indices in a Map are set when an element is added to the Map. * If for some reason, in the Dropdown: - * - children order changes - * - children are added - * - children are removed + * - items order changes + * - items are added + * - items are removed * * The Map must be rebuilt from the new children in order to preserve logical indices. * @@ -191,7 +192,16 @@ export const DropdownProvider = ({ useEffect(() => { const newMap = getItemsFromChildren(children) - setItemsMap(newMap) + const previousItems = [...itemsMap.values()] + const newItems = [...newMap.values()] + + const hasItemsChanges = + previousItems.length !== newItems.length || + previousItems.some((item, index) => item.value !== newItems[index]?.value) + + if (hasItemsChanges) { + setItemsMap(newMap) + } }, [children]) /** diff --git a/packages/components/dropdown/src/DropdownItemContext.tsx b/packages/components/dropdown/src/DropdownItemContext.tsx index 53189163f9..6772c7e1b2 100644 --- a/packages/components/dropdown/src/DropdownItemContext.tsx +++ b/packages/components/dropdown/src/DropdownItemContext.tsx @@ -22,11 +22,11 @@ export const DropdownItemProvider = ({ disabled = false, children, }: PropsWithChildren<{ value: string; disabled?: boolean }>) => { - const { multiple, computedItems, selectedItem, selectedItems } = useDropdownContext() + const { multiple, itemsMap, selectedItem, selectedItems } = useDropdownContext() const [textId, setTextId] = useState(undefined) - const index = getIndexByKey(computedItems, value) + const index = getIndexByKey(itemsMap, value) const itemData: DropdownItem = { disabled, value, text: getItemText(children) } const isSelected = multiple