@graphprotocol/gds-react 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/GDSContext.d.ts +13 -0
- package/dist/GDSContext.d.ts.map +1 -0
- package/dist/GDSContext.js +4 -0
- package/dist/GDSContext.js.map +1 -0
- package/dist/GDSProvider.d.ts +13 -19
- package/dist/GDSProvider.d.ts.map +1 -1
- package/dist/GDSProvider.js +14 -11
- package/dist/GDSProvider.js.map +1 -1
- package/dist/components/Address.js +2 -2
- package/dist/components/Address.meta.d.ts +1 -13
- package/dist/components/Address.meta.d.ts.map +1 -1
- package/dist/components/Avatar.d.ts.map +1 -1
- package/dist/components/Avatar.js +3 -11
- package/dist/components/Avatar.js.map +1 -1
- package/dist/components/Avatar.meta.d.ts +0 -2
- package/dist/components/Avatar.meta.d.ts.map +1 -1
- package/dist/components/AvatarGroup.meta.d.ts +8 -2
- package/dist/components/AvatarGroup.meta.d.ts.map +1 -1
- package/dist/components/Breadcrumbs.meta.d.ts +2 -3
- package/dist/components/Breadcrumbs.meta.d.ts.map +1 -1
- package/dist/components/Breadcrumbs.meta.js +3 -1
- package/dist/components/Breadcrumbs.meta.js.map +1 -1
- package/dist/components/Breadcrumbs.parts.d.ts.map +1 -1
- package/dist/components/Breadcrumbs.parts.js +13 -21
- package/dist/components/Breadcrumbs.parts.js.map +1 -1
- package/dist/components/Button.d.ts.map +1 -1
- package/dist/components/Button.js +70 -69
- package/dist/components/Button.js.map +1 -1
- package/dist/components/Button.meta.d.ts +1 -4
- package/dist/components/Button.meta.d.ts.map +1 -1
- package/dist/components/ButtonGroup.d.ts.map +1 -1
- package/dist/components/ButtonGroup.js +1 -5
- package/dist/components/ButtonGroup.js.map +1 -1
- package/dist/components/ButtonGroup.meta.d.ts +1 -5
- package/dist/components/ButtonGroup.meta.d.ts.map +1 -1
- package/dist/components/ButtonGroup.meta.js +8 -0
- package/dist/components/ButtonGroup.meta.js.map +1 -1
- package/dist/components/Card.js +2 -2
- package/dist/components/Card.js.map +1 -1
- package/dist/components/Card.meta.d.ts +1 -2
- package/dist/components/Card.meta.d.ts.map +1 -1
- package/dist/components/Card.meta.js +1 -0
- package/dist/components/Card.meta.js.map +1 -1
- package/dist/components/Checkbox.meta.d.ts +1 -6
- package/dist/components/Checkbox.meta.d.ts.map +1 -1
- package/dist/components/Checkbox.meta.js +1 -5
- package/dist/components/Checkbox.meta.js.map +1 -1
- package/dist/components/Chip.meta.d.ts +2 -4
- package/dist/components/Chip.meta.d.ts.map +1 -1
- package/dist/components/Chip.parts.d.ts.map +1 -1
- package/dist/components/Chip.parts.js +1 -9
- package/dist/components/Chip.parts.js.map +1 -1
- package/dist/components/Cluster.meta.d.ts +8 -2
- package/dist/components/Cluster.meta.d.ts.map +1 -1
- package/dist/components/CodeBlock.d.ts +1 -1
- package/dist/components/CodeBlock.meta.d.ts +2 -4
- package/dist/components/CodeBlock.meta.d.ts.map +1 -1
- package/dist/components/CodeBlock.parts.d.ts +6 -7
- package/dist/components/CodeBlock.parts.d.ts.map +1 -1
- package/dist/components/CodeBlock.parts.js +28 -10
- package/dist/components/CodeBlock.parts.js.map +1 -1
- package/dist/components/CodeInline.js +3 -3
- package/dist/components/CodeInline.meta.d.ts +1 -1
- package/dist/components/CodeInline.meta.d.ts.map +1 -1
- package/dist/components/CopyButton.d.ts +1 -1
- package/dist/components/CopyButton.d.ts.map +1 -1
- package/dist/components/CopyButton.js +46 -21
- package/dist/components/CopyButton.js.map +1 -1
- package/dist/components/CopyButton.meta.d.ts +1 -12
- package/dist/components/CopyButton.meta.d.ts.map +1 -1
- package/dist/components/CopyButton.meta.js +1 -6
- package/dist/components/CopyButton.meta.js.map +1 -1
- package/dist/components/CurrencyInput.meta.d.ts +1 -6
- package/dist/components/CurrencyInput.meta.d.ts.map +1 -1
- package/dist/components/CurrencyInput.meta.js +1 -5
- package/dist/components/CurrencyInput.meta.js.map +1 -1
- package/dist/components/DescriptionList.meta.d.ts +2 -5
- package/dist/components/DescriptionList.meta.d.ts.map +1 -1
- package/dist/components/DescriptionList.parts.d.ts +3 -0
- package/dist/components/DescriptionList.parts.d.ts.map +1 -1
- package/dist/components/DescriptionList.parts.js +1 -0
- package/dist/components/DescriptionList.parts.js.map +1 -1
- package/dist/components/Divider.meta.d.ts +1 -3
- package/dist/components/Divider.meta.d.ts.map +1 -1
- package/dist/components/Icon.js +4 -4
- package/dist/components/Icon.js.map +1 -1
- package/dist/components/Icon.meta.d.ts +0 -2
- package/dist/components/Icon.meta.d.ts.map +1 -1
- package/dist/components/Icon.meta.js +1 -0
- package/dist/components/Icon.meta.js.map +1 -1
- package/dist/components/Input.d.ts +5 -4
- package/dist/components/Input.d.ts.map +1 -1
- package/dist/components/Input.js +3 -2
- package/dist/components/Input.js.map +1 -1
- package/dist/components/Input.meta.d.ts +1 -6
- package/dist/components/Input.meta.d.ts.map +1 -1
- package/dist/components/Input.meta.js +1 -5
- package/dist/components/Input.meta.js.map +1 -1
- package/dist/components/Keyboard.js +1 -1
- package/dist/components/Keyboard.meta.d.ts +0 -1
- package/dist/components/Keyboard.meta.d.ts.map +1 -1
- package/dist/components/Label.meta.d.ts +1 -3
- package/dist/components/Label.meta.d.ts.map +1 -1
- package/dist/components/Link.d.ts +1 -1
- package/dist/components/Link.d.ts.map +1 -1
- package/dist/components/Link.js +3 -4
- package/dist/components/Link.js.map +1 -1
- package/dist/components/Link.meta.d.ts +1 -2
- package/dist/components/Link.meta.d.ts.map +1 -1
- package/dist/components/Link.meta.js +1 -0
- package/dist/components/Link.meta.js.map +1 -1
- package/dist/components/Menu.meta.d.ts +31 -2
- package/dist/components/Menu.meta.d.ts.map +1 -1
- package/dist/components/Menu.meta.js +39 -1
- package/dist/components/Menu.meta.js.map +1 -1
- package/dist/components/Menu.parts.d.ts +22 -32
- package/dist/components/Menu.parts.d.ts.map +1 -1
- package/dist/components/Menu.parts.js +286 -300
- package/dist/components/Menu.parts.js.map +1 -1
- package/dist/components/Modal.d.ts +1 -1
- package/dist/components/Modal.meta.d.ts +1 -3
- package/dist/components/Modal.meta.d.ts.map +1 -1
- package/dist/components/Modal.meta.js +1 -1
- package/dist/components/Modal.meta.js.map +1 -1
- package/dist/components/Modal.parts.d.ts +14 -15
- package/dist/components/Modal.parts.d.ts.map +1 -1
- package/dist/components/Modal.parts.js +20 -20
- package/dist/components/Modal.parts.js.map +1 -1
- package/dist/components/OTCInput.js +1 -1
- package/dist/components/OTCInput.meta.d.ts +1 -6
- package/dist/components/OTCInput.meta.d.ts.map +1 -1
- package/dist/components/OTCInput.meta.js +1 -5
- package/dist/components/OTCInput.meta.js.map +1 -1
- package/dist/components/Pane.d.ts +9 -0
- package/dist/components/Pane.d.ts.map +1 -0
- package/dist/components/Pane.js +8 -0
- package/dist/components/Pane.js.map +1 -0
- package/dist/components/Pane.meta.d.ts +20 -0
- package/dist/components/Pane.meta.d.ts.map +1 -0
- package/dist/components/Pane.meta.js +30 -0
- package/dist/components/Pane.meta.js.map +1 -0
- package/dist/components/Pane.parts.d.ts +77 -0
- package/dist/components/Pane.parts.d.ts.map +1 -0
- package/dist/components/Pane.parts.js +412 -0
- package/dist/components/Pane.parts.js.map +1 -0
- package/dist/components/Radio.meta.d.ts +1 -6
- package/dist/components/Radio.meta.d.ts.map +1 -1
- package/dist/components/Radio.meta.js +1 -5
- package/dist/components/Radio.meta.js.map +1 -1
- package/dist/components/Search.js +1 -1
- package/dist/components/Search.meta.d.ts +1 -3
- package/dist/components/Search.meta.d.ts.map +1 -1
- package/dist/components/SegmentedControl.meta.d.ts +2 -3
- package/dist/components/SegmentedControl.meta.d.ts.map +1 -1
- package/dist/components/SegmentedControl.meta.js +3 -1
- package/dist/components/SegmentedControl.meta.js.map +1 -1
- package/dist/components/SegmentedControl.parts.d.ts.map +1 -1
- package/dist/components/SegmentedControl.parts.js +4 -9
- package/dist/components/SegmentedControl.parts.js.map +1 -1
- package/dist/components/Status.meta.d.ts +0 -2
- package/dist/components/Status.meta.d.ts.map +1 -1
- package/dist/components/Stepper.meta.d.ts +1 -2
- package/dist/components/Stepper.meta.d.ts.map +1 -1
- package/dist/components/Stepper.meta.js +1 -0
- package/dist/components/Stepper.meta.js.map +1 -1
- package/dist/components/Stepper.parts.d.ts.map +1 -1
- package/dist/components/Stepper.parts.js +1 -1
- package/dist/components/Stepper.parts.js.map +1 -1
- package/dist/components/Switch.meta.d.ts +1 -6
- package/dist/components/Switch.meta.d.ts.map +1 -1
- package/dist/components/Switch.meta.js +1 -5
- package/dist/components/Switch.meta.js.map +1 -1
- package/dist/components/TabSet.meta.d.ts +2 -5
- package/dist/components/TabSet.meta.d.ts.map +1 -1
- package/dist/components/TabSet.meta.js +3 -1
- package/dist/components/TabSet.meta.js.map +1 -1
- package/dist/components/Tag.meta.d.ts +0 -2
- package/dist/components/Tag.meta.d.ts.map +1 -1
- package/dist/components/TextArea.meta.d.ts +1 -6
- package/dist/components/TextArea.meta.d.ts.map +1 -1
- package/dist/components/TextArea.meta.js +1 -5
- package/dist/components/TextArea.meta.js.map +1 -1
- package/dist/components/ToggleButton.js +2 -2
- package/dist/components/ToggleButton.js.map +1 -1
- package/dist/components/ToggleButton.meta.d.ts +1 -12
- package/dist/components/ToggleButton.meta.d.ts.map +1 -1
- package/dist/components/ToggleButton.meta.js +1 -6
- package/dist/components/ToggleButton.meta.js.map +1 -1
- package/dist/components/Tooltip.d.ts +2 -2
- package/dist/components/Tooltip.d.ts.map +1 -1
- package/dist/components/Tooltip.js +2 -2
- package/dist/components/Tooltip.js.map +1 -1
- package/dist/components/Tooltip.meta.d.ts +12 -7
- package/dist/components/Tooltip.meta.d.ts.map +1 -1
- package/dist/components/Tooltip.meta.js +13 -2
- package/dist/components/Tooltip.meta.js.map +1 -1
- package/dist/components/Tooltip.parts.d.ts +31 -22
- package/dist/components/Tooltip.parts.d.ts.map +1 -1
- package/dist/components/Tooltip.parts.js +127 -98
- package/dist/components/Tooltip.parts.js.map +1 -1
- package/dist/components/base/Addon.meta.d.ts +1 -1
- package/dist/components/base/Addon.meta.d.ts.map +1 -1
- package/dist/components/base/Addon.meta.js +3 -1
- package/dist/components/base/Addon.meta.js.map +1 -1
- package/dist/components/base/ButtonOrLink.d.ts +2 -2
- package/dist/components/base/ButtonOrLink.d.ts.map +1 -1
- package/dist/components/base/ButtonOrLink.parts.d.ts +14 -6
- package/dist/components/base/ButtonOrLink.parts.d.ts.map +1 -1
- package/dist/components/base/ButtonOrLink.parts.js +54 -65
- package/dist/components/base/ButtonOrLink.parts.js.map +1 -1
- package/dist/components/base/Checkable.meta.d.ts +1 -2
- package/dist/components/base/Checkable.meta.d.ts.map +1 -1
- package/dist/components/base/Checkable.parts.d.ts +6 -6
- package/dist/components/base/Checkable.parts.d.ts.map +1 -1
- package/dist/components/base/Checkable.parts.js +2 -2
- package/dist/components/base/Checkable.parts.js.map +1 -1
- package/dist/components/base/Field.meta.d.ts +1 -2
- package/dist/components/base/Field.meta.d.ts.map +1 -1
- package/dist/components/base/Field.parts.d.ts +5 -4
- package/dist/components/base/Field.parts.d.ts.map +1 -1
- package/dist/components/base/Field.parts.js +1 -1
- package/dist/components/base/Field.parts.js.map +1 -1
- package/dist/components/base/MaybeButtonOrLink.d.ts +20 -3
- package/dist/components/base/MaybeButtonOrLink.d.ts.map +1 -1
- package/dist/components/base/MaybeButtonOrLink.js +5 -3
- package/dist/components/base/MaybeButtonOrLink.js.map +1 -1
- package/dist/components/base/Portal.d.ts +1 -1
- package/dist/components/base/Portal.d.ts.map +1 -1
- package/dist/components/base/Portal.js +3 -6
- package/dist/components/base/Portal.js.map +1 -1
- package/dist/components/base/Presence.d.ts +157 -0
- package/dist/components/base/Presence.d.ts.map +1 -0
- package/dist/components/base/Presence.js +808 -0
- package/dist/components/base/Presence.js.map +1 -0
- package/dist/components/base/Render.d.ts +21 -6
- package/dist/components/base/Render.d.ts.map +1 -1
- package/dist/components/base/Render.js +3 -2
- package/dist/components/base/Render.js.map +1 -1
- package/dist/components/base/Transition.js +2 -2
- package/dist/components/base/Transition.meta.d.ts +1 -1
- package/dist/components/base/Transition.meta.d.ts.map +1 -1
- package/dist/components/base/Transition.meta.js +1 -0
- package/dist/components/base/Transition.meta.js.map +1 -1
- package/dist/components/base/index.d.ts +2 -2
- package/dist/components/base/index.d.ts.map +1 -1
- package/dist/components/base/index.js +2 -2
- package/dist/components/base/index.js.map +1 -1
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +3 -1
- package/dist/components/index.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useCSSProp.d.ts.map +1 -1
- package/dist/hooks/useCSSProp.js +7 -7
- package/dist/hooks/useCSSProp.js.map +1 -1
- package/dist/hooks/useCSSProps.d.ts +11 -13
- package/dist/hooks/useCSSProps.d.ts.map +1 -1
- package/dist/hooks/useCSSProps.js +11 -19
- package/dist/hooks/useCSSProps.js.map +1 -1
- package/dist/hooks/useCSSPropsPolyfill.d.ts +1 -1
- package/dist/hooks/useCSSPropsPolyfill.d.ts.map +1 -1
- package/dist/hooks/useCSSPropsPolyfill.js +12 -20
- package/dist/hooks/useCSSPropsPolyfill.js.map +1 -1
- package/dist/hooks/useCSSState.d.ts.map +1 -1
- package/dist/hooks/useCSSState.js +7 -3
- package/dist/hooks/useCSSState.js.map +1 -1
- package/dist/hooks/useControlled.d.ts.map +1 -1
- package/dist/hooks/useControlled.js +6 -4
- package/dist/hooks/useControlled.js.map +1 -1
- package/dist/hooks/useEffectWithRefDeps.d.ts +2 -2
- package/dist/hooks/useEffectWithRefDeps.d.ts.map +1 -1
- package/dist/hooks/useEffectWithRefDeps.js +1 -1
- package/dist/hooks/useEffectWithRefDeps.js.map +1 -1
- package/dist/hooks/useFirstRender.d.ts +14 -0
- package/dist/hooks/useFirstRender.d.ts.map +1 -0
- package/dist/hooks/useFirstRender.js +20 -0
- package/dist/hooks/useFirstRender.js.map +1 -0
- package/dist/hooks/useGDS.d.ts +1 -1
- package/dist/hooks/useGDS.js +1 -1
- package/dist/hooks/useGDS.js.map +1 -1
- package/dist/hooks/usePrevious.d.ts +6 -4
- package/dist/hooks/usePrevious.d.ts.map +1 -1
- package/dist/hooks/usePrevious.js +6 -4
- package/dist/hooks/usePrevious.js.map +1 -1
- package/dist/hooks/useRefWithInit.d.ts +2 -2
- package/dist/hooks/useRefWithInit.d.ts.map +1 -1
- package/dist/hooks/useRefWithInit.js.map +1 -1
- package/dist/hooks/useStyleObserver.d.ts +2 -2
- package/dist/hooks/useStyleObserver.d.ts.map +1 -1
- package/dist/hooks/useStyleObserver.js +1 -1
- package/dist/hooks/useStyleObserver.js.map +1 -1
- package/dist/icons/CalendarDynamicIcon.d.ts +8 -5
- package/dist/icons/CalendarDynamicIcon.d.ts.map +1 -1
- package/dist/icons/CalendarDynamicIcon.js +5 -2
- package/dist/icons/CalendarDynamicIcon.js.map +1 -1
- package/dist/icons/CopyInteractiveIcon.d.ts +5 -4
- package/dist/icons/CopyInteractiveIcon.d.ts.map +1 -1
- package/dist/icons/CopyInteractiveIcon.js +2 -2
- package/dist/icons/CopyInteractiveIcon.js.map +1 -1
- package/dist/icons/SidebarLeftInteractiveIcon.d.ts +4 -3
- package/dist/icons/SidebarLeftInteractiveIcon.d.ts.map +1 -1
- package/dist/icons/SidebarLeftInteractiveIcon.js +2 -2
- package/dist/icons/SidebarLeftInteractiveIcon.js.map +1 -1
- package/dist/icons/SidebarRightInteractiveIcon.d.ts +4 -3
- package/dist/icons/SidebarRightInteractiveIcon.d.ts.map +1 -1
- package/dist/icons/SidebarRightInteractiveIcon.js +2 -2
- package/dist/icons/SidebarRightInteractiveIcon.js.map +1 -1
- package/dist/tailwind-plugin.d.ts.map +1 -1
- package/dist/tailwind-plugin.js +8 -5
- package/dist/tailwind-plugin.js.map +1 -1
- package/dist/utils/InlineCounter.d.ts +3 -0
- package/dist/utils/InlineCounter.d.ts.map +1 -0
- package/dist/utils/InlineCounter.js +7 -0
- package/dist/utils/InlineCounter.js.map +1 -0
- package/dist/utils/RenderCount.d.ts +3 -0
- package/dist/utils/RenderCount.d.ts.map +1 -0
- package/dist/utils/RenderCount.js +7 -0
- package/dist/utils/RenderCount.js.map +1 -0
- package/dist/utils/cn.d.ts +3 -1
- package/dist/utils/cn.d.ts.map +1 -1
- package/dist/utils/cn.js +3 -1
- package/dist/utils/cn.js.map +1 -1
- package/dist/utils/getCSSPropsAttributes.d.ts +10 -3
- package/dist/utils/getCSSPropsAttributes.d.ts.map +1 -1
- package/dist/utils/getCSSPropsAttributes.js +4 -5
- package/dist/utils/getCSSPropsAttributes.js.map +1 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/splitProps.d.ts +1 -4
- package/dist/utils/splitProps.d.ts.map +1 -1
- package/dist/utils/splitProps.js +2 -7
- package/dist/utils/splitProps.js.map +1 -1
- package/dist/utils/trimReactNode.d.ts +10 -8
- package/dist/utils/trimReactNode.d.ts.map +1 -1
- package/dist/utils/trimReactNode.js +10 -8
- package/dist/utils/trimReactNode.js.map +1 -1
- package/package.json +21 -21
- package/src/GDSContext.ts +16 -0
- package/src/GDSProvider.tsx +31 -40
- package/src/components/Address.tsx +2 -2
- package/src/components/Avatar.tsx +8 -12
- package/src/components/Breadcrumbs.meta.ts +3 -1
- package/src/components/Breadcrumbs.parts.tsx +16 -28
- package/src/components/Button.tsx +114 -104
- package/src/components/ButtonGroup.meta.ts +8 -0
- package/src/components/ButtonGroup.tsx +1 -5
- package/src/components/Card.meta.ts +1 -0
- package/src/components/Card.tsx +2 -2
- package/src/components/Checkbox.meta.ts +1 -5
- package/src/components/Chip.parts.tsx +1 -11
- package/src/components/CodeBlock.parts.tsx +75 -50
- package/src/components/CodeInline.tsx +3 -3
- package/src/components/CopyButton.meta.ts +1 -6
- package/src/components/CopyButton.tsx +50 -27
- package/src/components/CurrencyInput.meta.ts +1 -5
- package/src/components/DescriptionList.parts.tsx +1 -0
- package/src/components/Icon.meta.ts +1 -0
- package/src/components/Icon.tsx +4 -4
- package/src/components/Input.meta.ts +1 -5
- package/src/components/Input.tsx +6 -7
- package/src/components/Keyboard.tsx +1 -1
- package/src/components/Link.meta.ts +1 -0
- package/src/components/Link.tsx +4 -5
- package/src/components/Menu.meta.ts +39 -1
- package/src/components/Menu.parts.tsx +554 -547
- package/src/components/Modal.meta.ts +1 -1
- package/src/components/Modal.parts.tsx +40 -46
- package/src/components/OTCInput.meta.ts +1 -5
- package/src/components/OTCInput.tsx +1 -1
- package/src/components/Pane.meta.ts +31 -0
- package/src/components/Pane.parts.tsx +713 -0
- package/src/components/Pane.tsx +17 -0
- package/src/components/Radio.meta.ts +1 -5
- package/src/components/Search.tsx +1 -1
- package/src/components/SegmentedControl.meta.ts +3 -1
- package/src/components/SegmentedControl.parts.tsx +7 -10
- package/src/components/Stepper.meta.ts +1 -0
- package/src/components/Stepper.parts.tsx +3 -1
- package/src/components/Switch.meta.ts +1 -5
- package/src/components/TabSet.meta.ts +3 -1
- package/src/components/TextArea.meta.ts +1 -5
- package/src/components/ToggleButton.meta.ts +1 -6
- package/src/components/ToggleButton.tsx +1 -1
- package/src/components/Tooltip.meta.ts +13 -2
- package/src/components/Tooltip.parts.tsx +241 -169
- package/src/components/Tooltip.tsx +2 -2
- package/src/components/base/Addon.meta.ts +3 -1
- package/src/components/base/ButtonOrLink.parts.tsx +118 -97
- package/src/components/base/ButtonOrLink.tsx +1 -0
- package/src/components/base/Checkable.parts.tsx +6 -13
- package/src/components/base/Field.parts.tsx +5 -5
- package/src/components/base/MaybeButtonOrLink.tsx +26 -5
- package/src/components/base/Portal.tsx +5 -7
- package/src/components/base/Presence.tsx +1375 -0
- package/src/components/base/Render.tsx +37 -15
- package/src/components/base/Transition.meta.ts +1 -0
- package/src/components/base/Transition.tsx +2 -2
- package/src/components/base/index.ts +9 -2
- package/src/components/index.ts +11 -2
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useCSSProp.ts +7 -9
- package/src/hooks/useCSSProps.ts +13 -22
- package/src/hooks/useCSSPropsPolyfill.ts +15 -23
- package/src/hooks/useCSSState.ts +11 -6
- package/src/hooks/useControlled.ts +16 -8
- package/src/hooks/useEffectWithRefDeps.ts +2 -2
- package/src/hooks/useFirstRender.ts +36 -0
- package/src/hooks/useGDS.ts +1 -1
- package/src/hooks/usePrevious.ts +6 -4
- package/src/hooks/useRefWithInit.ts +2 -2
- package/src/hooks/useStyleObserver.ts +6 -2
- package/src/icons/CalendarDynamicIcon.tsx +16 -6
- package/src/icons/CopyInteractiveIcon.tsx +10 -5
- package/src/icons/SidebarLeftInteractiveIcon.tsx +9 -5
- package/src/icons/SidebarRightInteractiveIcon.tsx +9 -5
- package/src/tailwind-plugin.ts +8 -5
- package/src/utils/InlineCounter.tsx +17 -0
- package/src/utils/RenderCount.tsx +7 -0
- package/src/utils/cn.ts +3 -1
- package/src/utils/getCSSPropsAttributes.ts +13 -8
- package/src/utils/index.ts +2 -0
- package/src/utils/splitProps.ts +9 -9
- package/src/utils/trimReactNode.tsx +10 -8
- package/dist/components/base/ButtonOrLink.meta.d.ts +0 -2
- package/dist/components/base/ButtonOrLink.meta.d.ts.map +0 -1
- package/dist/components/base/ButtonOrLink.meta.js +0 -6
- package/dist/components/base/ButtonOrLink.meta.js.map +0 -1
- package/src/components/base/ButtonOrLink.meta.ts +0 -6
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
createContext,
|
|
5
|
-
isValidElement,
|
|
6
|
-
useContext,
|
|
7
|
-
useRef,
|
|
8
|
-
type ComponentProps,
|
|
9
|
-
type HTMLProps,
|
|
10
|
-
type ReactElement,
|
|
11
|
-
type ReactNode,
|
|
12
|
-
} from 'react'
|
|
3
|
+
import { createContext, useContext, useRef, type ComponentProps, type ReactNode } from 'react'
|
|
13
4
|
import { Menu } from '@base-ui/react/menu'
|
|
14
5
|
import { useMergedRefs } from '@base-ui/utils/useMergedRefs'
|
|
15
6
|
import type { Merge } from 'type-fest'
|
|
@@ -25,27 +16,23 @@ import {
|
|
|
25
16
|
XIcon,
|
|
26
17
|
} from '@graphprotocol/gds-react/icons'
|
|
27
18
|
|
|
28
|
-
import {
|
|
29
|
-
|
|
19
|
+
import {
|
|
20
|
+
useAutoValue,
|
|
21
|
+
useControlled,
|
|
22
|
+
useCSSPropsPolyfill,
|
|
23
|
+
useCSSState,
|
|
24
|
+
useGDS,
|
|
25
|
+
} from '../hooks/index.ts'
|
|
26
|
+
import { cn, getCSSPropsAttributes, splitProps, type OptionValue } from '../utils/index.ts'
|
|
30
27
|
import { renderAddon, type AddonValue } from './base/Addon.tsx'
|
|
31
28
|
import { ButtonOrLink, type ButtonOrLinkProps } from './base/ButtonOrLink.tsx'
|
|
32
|
-
import { Render } from './base/Render.tsx'
|
|
29
|
+
import { Render, type RenderFnProps, type RenderProp } from './base/Render.tsx'
|
|
33
30
|
import { Button } from './Button.tsx'
|
|
34
31
|
import { Checkbox } from './Checkbox.tsx'
|
|
35
|
-
import
|
|
32
|
+
import { MenuMeta, type MenuItemMeta } from './Menu.meta.js'
|
|
36
33
|
|
|
37
34
|
const MenuTriggerContext = createContext<boolean>(false)
|
|
38
35
|
|
|
39
|
-
type MenuPosition = {
|
|
40
|
-
align: 'start' | 'center' | 'end'
|
|
41
|
-
alignOffset: number
|
|
42
|
-
side: 'top' | 'bottom' | 'inline-start' | 'inline-end'
|
|
43
|
-
gap: number
|
|
44
|
-
matchWidth: boolean | 'at-least' | 'at-most'
|
|
45
|
-
matchHeight: boolean | 'at-least' | 'at-most'
|
|
46
|
-
openOnHover: boolean | number
|
|
47
|
-
}
|
|
48
|
-
|
|
49
36
|
type MenuItemType = 'plain' | 'checkbox' | 'radio'
|
|
50
37
|
|
|
51
38
|
declare namespace GroupProps {
|
|
@@ -71,37 +58,28 @@ declare namespace MenuProps {
|
|
|
71
58
|
extends
|
|
72
59
|
Omit<ComponentProps<'div'>, 'defaultValue' | 'onChange'>,
|
|
73
60
|
GDSComponentProps<typeof MenuMeta> {
|
|
74
|
-
open?: boolean | undefined
|
|
75
|
-
defaultOpen?: boolean | undefined
|
|
76
|
-
onOpenChange?: ((open: boolean) => void) | undefined
|
|
77
|
-
/** Element that opens the menu when clicked, or function that returns such an element. */
|
|
78
|
-
trigger:
|
|
79
|
-
| ReactElement
|
|
80
|
-
| ((
|
|
81
|
-
renderProps: Record<string, unknown>,
|
|
82
|
-
state: {
|
|
83
|
-
open: boolean
|
|
84
|
-
setOpen: (open: boolean) => void
|
|
85
|
-
openMenu: () => void
|
|
86
|
-
},
|
|
87
|
-
) => ReactElement)
|
|
88
61
|
/**
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
62
|
+
* Element that opens the menu when clicked or hovered (depending on `triggerMode`), or a
|
|
63
|
+
* function that returns such an element. If not provided, the menu is rendered inline rather
|
|
64
|
+
* than as a floating overlay, and all positioning props are ignored (`side`, `gap`, `align`,
|
|
65
|
+
* `alignOffset`, `matchTriggerWidth`, and `matchTriggerHeight`).
|
|
66
|
+
*/
|
|
67
|
+
trigger?:
|
|
68
|
+
| RenderProp<{ open: boolean; setOpen: (open: boolean) => void; openMenu: () => void }>
|
|
69
|
+
| undefined
|
|
70
|
+
/**
|
|
71
|
+
* Controls how the menu is opened when `trigger` is an element. Ignored if `trigger` is a
|
|
72
|
+
* function, since you can fully customize the interaction that opens the menu (e.g.
|
|
73
|
+
* `trigger={(props, { openMenu }) => <button {...props} onMouseEnter={openMenu} />}`). Also
|
|
74
|
+
* ignored for submenus, which always open on hover.
|
|
93
75
|
*
|
|
94
|
-
* @default
|
|
95
|
-
* align: 'start'
|
|
96
|
-
* alignOffset: 0
|
|
97
|
-
* side: 'bottom'
|
|
98
|
-
* gap: 1
|
|
99
|
-
* matchWidth: false
|
|
100
|
-
* matchHeight: false
|
|
101
|
-
* openOnHover: false
|
|
102
|
-
* }
|
|
76
|
+
* @default 'click'
|
|
103
77
|
*/
|
|
104
|
-
|
|
78
|
+
triggerMode?: 'click' | 'hover' | undefined
|
|
79
|
+
/** Defaults to `true` if `trigger` is not provided, or `undefined` otherwise. */
|
|
80
|
+
open?: boolean | undefined
|
|
81
|
+
defaultOpen?: boolean | undefined
|
|
82
|
+
onOpenChange?: ((open: boolean) => void) | undefined
|
|
105
83
|
header?: ReactNode | undefined
|
|
106
84
|
footer?: ReactNode | undefined
|
|
107
85
|
}
|
|
@@ -115,11 +93,17 @@ export type MenuProps<T extends OptionValue = OptionValue> =
|
|
|
115
93
|
|
|
116
94
|
export function MenuRoot<T extends OptionValue>({
|
|
117
95
|
ref: passedRef,
|
|
96
|
+
trigger,
|
|
97
|
+
triggerMode,
|
|
98
|
+
side,
|
|
99
|
+
gap,
|
|
100
|
+
align,
|
|
101
|
+
alignOffset,
|
|
102
|
+
matchTriggerWidth,
|
|
103
|
+
matchTriggerHeight,
|
|
118
104
|
open: controlledOpen,
|
|
119
105
|
defaultOpen,
|
|
120
106
|
onOpenChange,
|
|
121
|
-
trigger,
|
|
122
|
-
position: passedPosition = {},
|
|
123
107
|
header,
|
|
124
108
|
footer,
|
|
125
109
|
label,
|
|
@@ -128,351 +112,377 @@ export function MenuRoot<T extends OptionValue>({
|
|
|
128
112
|
defaultValue,
|
|
129
113
|
onChange,
|
|
130
114
|
className,
|
|
115
|
+
style,
|
|
131
116
|
children,
|
|
132
117
|
...props
|
|
133
118
|
}: MenuProps<T>) {
|
|
134
|
-
useGDS()
|
|
135
|
-
|
|
136
|
-
const popupRef = useRef<HTMLDivElement>(null)
|
|
137
|
-
const popupPassedRef = useMergedRefs(popupRef, passedRef)
|
|
138
|
-
|
|
139
|
-
const isNested = useContext(MenuItemsContext) !== null
|
|
140
|
-
const Root = isNested ? Menu.SubmenuRoot : Menu.Root
|
|
141
|
-
const Trigger = isNested ? Menu.SubmenuTrigger : Menu.Trigger
|
|
142
|
-
const triggerIsElement = isValidElement<{ disabled?: boolean }>(trigger)
|
|
143
|
-
|
|
144
|
-
const [open, setOpen] = useControlled(controlledOpen, defaultOpen ?? false, onOpenChange)
|
|
145
|
-
|
|
146
|
-
const defaultPosition: MenuPosition = {
|
|
147
|
-
align: 'start',
|
|
148
|
-
alignOffset: 0,
|
|
149
|
-
side: 'bottom',
|
|
150
|
-
gap: 1,
|
|
151
|
-
matchWidth: false,
|
|
152
|
-
matchHeight: false,
|
|
153
|
-
openOnHover: false,
|
|
154
|
-
}
|
|
155
|
-
const defaultNestedPosition: MenuPosition = {
|
|
156
|
-
...defaultPosition,
|
|
157
|
-
alignOffset:
|
|
158
|
-
passedPosition &&
|
|
159
|
-
(passedPosition.side === 'top' ||
|
|
160
|
-
passedPosition.side === 'bottom' ||
|
|
161
|
-
passedPosition.align === 'center')
|
|
162
|
-
? 0
|
|
163
|
-
: -2,
|
|
164
|
-
side: 'inline-end',
|
|
165
|
-
gap:
|
|
166
|
-
passedPosition && (passedPosition.side === 'top' || passedPosition.side === 'bottom') ? 0 : 3,
|
|
167
|
-
openOnHover: true,
|
|
168
|
-
}
|
|
169
|
-
const position = isNested
|
|
170
|
-
? passedPosition === false
|
|
171
|
-
? defaultPosition
|
|
172
|
-
: { ...defaultNestedPosition, ...passedPosition }
|
|
173
|
-
: passedPosition === false
|
|
174
|
-
? false
|
|
175
|
-
: {
|
|
176
|
-
...defaultPosition,
|
|
177
|
-
...passedPosition,
|
|
178
|
-
}
|
|
119
|
+
const { dirProps } = useGDS()
|
|
179
120
|
|
|
180
|
-
const
|
|
181
|
-
window.setTimeout(() => {
|
|
182
|
-
const newEvent = new KeyboardEvent('keydown', {
|
|
183
|
-
key,
|
|
184
|
-
code: key,
|
|
185
|
-
keyCode,
|
|
186
|
-
which: keyCode,
|
|
187
|
-
bubbles: true,
|
|
188
|
-
cancelable: true,
|
|
189
|
-
})
|
|
190
|
-
element.dispatchEvent(newEvent)
|
|
191
|
-
}, 0)
|
|
192
|
-
}
|
|
121
|
+
const { rootProps, nestedProps } = splitProps(props)
|
|
193
122
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
123
|
+
const portalRef = useRef<HTMLDivElement>(null)
|
|
124
|
+
|
|
125
|
+
const [cssPropsPolyfillRef, cssPropsPolyfillAttributes, cssProps] = useCSSPropsPolyfill(
|
|
126
|
+
MenuMeta,
|
|
127
|
+
{
|
|
128
|
+
side,
|
|
129
|
+
align,
|
|
130
|
+
matchTriggerWidth,
|
|
131
|
+
matchTriggerHeight,
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
returnPropValues: { side, gap, align, alignOffset, matchTriggerWidth, matchTriggerHeight },
|
|
135
|
+
},
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
const isSubmenu = useContext(MenuGroupContext) !== null
|
|
139
|
+
const MenuRoot = isSubmenu ? Menu.SubmenuRoot : Menu.Root
|
|
140
|
+
|
|
141
|
+
const hasTrigger = trigger !== undefined
|
|
142
|
+
const triggerElement = (() => {
|
|
143
|
+
if (!hasTrigger) return null
|
|
144
|
+
const renderTrigger =
|
|
145
|
+
typeof trigger !== 'function'
|
|
146
|
+
? trigger
|
|
147
|
+
: (renderProps: RenderFnProps) => {
|
|
148
|
+
// Don't pass event handlers and other potentially too specific props (e.g. `type`)
|
|
149
|
+
const filteredRenderProps = Object.fromEntries(
|
|
150
|
+
Object.entries(renderProps).filter(
|
|
151
|
+
([prop]) =>
|
|
152
|
+
prop === 'ref' ||
|
|
153
|
+
prop === 'id' ||
|
|
154
|
+
prop === 'className' ||
|
|
155
|
+
prop.startsWith('aria-') ||
|
|
156
|
+
prop.startsWith('data-'),
|
|
157
|
+
),
|
|
158
|
+
)
|
|
159
|
+
return trigger(filteredRenderProps, {
|
|
160
|
+
open,
|
|
161
|
+
setOpen,
|
|
162
|
+
openMenu: () => setOpen(true),
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
if (isSubmenu) {
|
|
166
|
+
return <Render render={renderTrigger} />
|
|
167
|
+
} else {
|
|
168
|
+
return (
|
|
169
|
+
<Menu.Trigger
|
|
170
|
+
nativeButton
|
|
171
|
+
openOnHover={triggerMode === 'hover'}
|
|
172
|
+
data-open-on-hover={triggerMode === 'hover' || undefined}
|
|
224
173
|
className={`
|
|
225
174
|
u:i:open:data-open-on-hover:state-hover
|
|
226
175
|
u:iii:open:not-data-open-on-hover:state-active
|
|
227
176
|
`}
|
|
228
|
-
render={
|
|
229
|
-
typeof trigger === 'function'
|
|
230
|
-
? (renderProps: HTMLProps<unknown>) => {
|
|
231
|
-
// Don't pass event handlers and other potentially too specific props (e.g. `type`)
|
|
232
|
-
const filteredRenderProps = Object.fromEntries(
|
|
233
|
-
Object.entries(renderProps).filter(
|
|
234
|
-
([prop]) =>
|
|
235
|
-
prop === 'ref' ||
|
|
236
|
-
prop === 'id' ||
|
|
237
|
-
prop.startsWith('aria-') ||
|
|
238
|
-
prop.startsWith('data-'),
|
|
239
|
-
),
|
|
240
|
-
)
|
|
241
|
-
return trigger(filteredRenderProps, {
|
|
242
|
-
open,
|
|
243
|
-
setOpen,
|
|
244
|
-
openMenu: () => setOpen(true),
|
|
245
|
-
})
|
|
246
|
-
}
|
|
247
|
-
: // oxlint-disable-next-line no-explicit-any
|
|
248
|
-
(trigger satisfies ReactElement<any> as ReactElement<any>)
|
|
249
|
-
}
|
|
177
|
+
render={renderTrigger}
|
|
250
178
|
/>
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
})()
|
|
182
|
+
|
|
183
|
+
const [open, setOpen] = useControlled(
|
|
184
|
+
controlledOpen ?? (!hasTrigger ? true : undefined),
|
|
185
|
+
defaultOpen ?? false,
|
|
186
|
+
onOpenChange,
|
|
187
|
+
)
|
|
188
|
+
const initialOpen = useRef(open)
|
|
189
|
+
if (!open) {
|
|
190
|
+
initialOpen.current = false
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<div
|
|
195
|
+
ref={cssPropsPolyfillRef}
|
|
196
|
+
data-is-submenu={isSubmenu || undefined}
|
|
197
|
+
data-has-trigger={hasTrigger || undefined}
|
|
198
|
+
className={cn(
|
|
199
|
+
`gds-menu root-contents [anchor-scope:all]
|
|
200
|
+
not-data-has-trigger:**:data-base-ui-focus-guard:hidden
|
|
201
|
+
u:rounded-12
|
|
202
|
+
u:data-is-submenu:default-align-offset-[-2]
|
|
203
|
+
u:data-is-submenu:default-gap-3
|
|
204
|
+
u:data-is-submenu:default-side-end`,
|
|
205
|
+
// Very imperfect workaround for https://bugs.webkit.org/show_bug.cgi?id=301871
|
|
206
|
+
`safari:root-block
|
|
207
|
+
i:safari:not-data-is-submenu:size-max`,
|
|
208
|
+
className,
|
|
209
|
+
)}
|
|
210
|
+
{...getCSSPropsAttributes(
|
|
211
|
+
MenuMeta,
|
|
212
|
+
{ side, gap, align, alignOffset, matchTriggerWidth, matchTriggerHeight },
|
|
213
|
+
style,
|
|
214
|
+
)}
|
|
215
|
+
{...cssPropsPolyfillAttributes}
|
|
216
|
+
{...rootProps}
|
|
217
|
+
>
|
|
218
|
+
<MenuRoot
|
|
219
|
+
key={`${hasTrigger}-${triggerMode}`}
|
|
220
|
+
open={open}
|
|
221
|
+
onOpenChange={(newOpen) => {
|
|
222
|
+
// A menu with no trigger can still be opened/closed by the consumer, but it should not send events
|
|
223
|
+
if (hasTrigger) setOpen(newOpen)
|
|
224
|
+
}}
|
|
225
|
+
modal={!isSubmenu ? hasTrigger : (undefined as never)}
|
|
226
|
+
closeParentOnEsc
|
|
275
227
|
>
|
|
276
|
-
<
|
|
277
|
-
|
|
278
|
-
className={`
|
|
279
|
-
flex grow origin-(--transform-origin) flex-col overflow-clip rounded-inherit bg-muted outline-0 transition
|
|
280
|
-
data-ending-style:scale-95
|
|
281
|
-
data-ending-style:opacity-0
|
|
282
|
-
data-starting-style:scale-95
|
|
283
|
-
data-starting-style:opacity-0
|
|
284
|
-
`}
|
|
285
|
-
{...(props as ComponentProps<typeof Menu.Popup>)}
|
|
286
|
-
onKeyDown={(event) => {
|
|
287
|
-
props.onKeyDown?.(event)
|
|
228
|
+
<MenuTriggerContext.Provider value={true}>
|
|
229
|
+
{triggerElement ?? (
|
|
288
230
|
/**
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
231
|
+
* Base UI doesn't explicitly support menus with no `Menu.Trigger`, `Menu.Portal`, or
|
|
232
|
+
* `Menu.Positioner`, so we work around it. We render an invisible trigger to satisfy
|
|
233
|
+
* focus and keyboard expectations (note that it is visible when focused, as an
|
|
234
|
+
* outline). Then, to ensure the menu is rendered inline and not anchored to that
|
|
235
|
+
* trigger, we customize the portal container to be a sibling element (with `contents
|
|
236
|
+
* *:contents` so it's a transparent wrapper), and we apply positioning styles only when
|
|
237
|
+
* a trigger is provided (see `Menu.Positioner`'s `render` prop below). Finally, to
|
|
238
|
+
* prevent focus-trapping behavior that assumes a floating menu, we disable `modal` and
|
|
239
|
+
* hide Base UI’s focus guards with CSS (see root styles above).
|
|
292
240
|
*/
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
241
|
+
<>
|
|
242
|
+
<Menu.Trigger
|
|
243
|
+
aria-label={
|
|
244
|
+
props['aria-label'] ||
|
|
245
|
+
(label && typeof label === 'string' ? label : undefined) ||
|
|
246
|
+
'Menu'
|
|
247
|
+
}
|
|
248
|
+
className={`
|
|
249
|
+
pointer-events-none absolute inset-[anchor(inside)] rounded-inherit [position-anchor:--gds-menu]
|
|
250
|
+
not-open:hidden
|
|
251
|
+
`}
|
|
252
|
+
/>
|
|
253
|
+
<div ref={portalRef} className="contents *:contents" />
|
|
254
|
+
</>
|
|
255
|
+
)}
|
|
256
|
+
</MenuTriggerContext.Provider>
|
|
257
|
+
<Menu.Portal
|
|
258
|
+
container={
|
|
259
|
+
!hasTrigger
|
|
260
|
+
? portalRef
|
|
261
|
+
: /**
|
|
262
|
+
* Specifying `document.body` because while it is the default for top-level menus, a submenu
|
|
263
|
+
* defaults to using the same portal as its parent, which is not desirable when the parent is
|
|
264
|
+
* rendered inline (it can cause the submenu to appear behind other elements).
|
|
265
|
+
*/
|
|
266
|
+
document?.body
|
|
267
|
+
}
|
|
268
|
+
>
|
|
269
|
+
<Menu.Positioner
|
|
270
|
+
side={
|
|
271
|
+
cssProps.side === 'start'
|
|
272
|
+
? 'inline-start'
|
|
273
|
+
: cssProps.side === 'end'
|
|
274
|
+
? 'inline-end'
|
|
275
|
+
: cssProps.side
|
|
322
276
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
277
|
+
sideOffset={twToPx(cssProps.gap)}
|
|
278
|
+
align={cssProps.align}
|
|
279
|
+
alignOffset={twToPx(cssProps.alignOffset)}
|
|
280
|
+
collisionPadding={8}
|
|
281
|
+
collisionAvoidance={{
|
|
282
|
+
side: 'flip',
|
|
283
|
+
align: 'flip',
|
|
284
|
+
fallbackAxisSide:
|
|
285
|
+
cssProps.side === 'start' || cssProps.side === 'end' ? 'end' : 'none',
|
|
286
|
+
}}
|
|
287
|
+
data-has-trigger={hasTrigger || undefined}
|
|
288
|
+
data-match-trigger-width={cssProps.matchTriggerWidth || undefined}
|
|
289
|
+
data-match-trigger-height={cssProps.matchTriggerHeight || undefined}
|
|
290
|
+
className={cn(
|
|
291
|
+
`root-flex
|
|
292
|
+
[--available-height-but-not-too-small:max(var(--available-height),--spacing(16))]
|
|
293
|
+
[anchor-name:--gds-menu]
|
|
294
|
+
has-nested/menu-footer:[--available-height-but-not-too-small:max(var(--available-height),--spacing(32))]
|
|
295
|
+
has-nested/menu-header:[--available-height-but-not-too-small:max(var(--available-height),--spacing(32))]
|
|
296
|
+
u:w-max
|
|
297
|
+
u:max-w-full
|
|
298
|
+
u:rounded-12
|
|
299
|
+
u:data-has-trigger:max-h-(--available-height-but-not-too-small)
|
|
300
|
+
u:data-has-trigger:max-w-(--available-width)
|
|
301
|
+
u:i:data-[match-trigger-height=at-least]:min-h-[min(var(--anchor-height),var(--available-height-but-not-too-small))]
|
|
302
|
+
u:i:data-[match-trigger-height=at-most]:max-h-[min(var(--anchor-height),var(--available-height-but-not-too-small))]
|
|
303
|
+
u:i:data-[match-trigger-height=true]:h-(--anchor-height)
|
|
304
|
+
u:i:data-[match-trigger-width=at-least]:min-w-[min(var(--anchor-width),var(--available-width))]
|
|
305
|
+
u:i:data-[match-trigger-width=at-most]:max-w-[min(var(--anchor-width),var(--available-width))]
|
|
306
|
+
u:i:data-[match-trigger-width=true]:w-(--anchor-width)`,
|
|
307
|
+
className,
|
|
308
|
+
)}
|
|
309
|
+
{...dirProps}
|
|
310
|
+
render={(renderProps) => (
|
|
311
|
+
<div {...renderProps} style={hasTrigger ? renderProps.style : undefined} />
|
|
312
|
+
)}
|
|
313
|
+
>
|
|
314
|
+
<Menu.Popup
|
|
315
|
+
ref={passedRef}
|
|
316
|
+
data-initial-open={initialOpen.current || undefined}
|
|
317
|
+
className={`
|
|
318
|
+
flex grow origin-(--transform-origin) flex-col overflow-clip rounded-inherit bg-muted outline-0 transition
|
|
319
|
+
data-ending-style:scale-95
|
|
320
|
+
data-ending-style:opacity-0
|
|
321
|
+
data-starting-style:not-data-initial-open:scale-95
|
|
322
|
+
data-starting-style:not-data-initial-open:opacity-0
|
|
323
|
+
`}
|
|
324
|
+
{...(nestedProps as ComponentProps<typeof Menu.Popup>)}
|
|
325
|
+
onKeyDown={(event) => {
|
|
326
|
+
nestedProps.onKeyDown?.(event)
|
|
343
327
|
/**
|
|
344
|
-
*
|
|
345
|
-
* a
|
|
346
|
-
*
|
|
328
|
+
* Ensure Shift + Tab doesn't close the menu if there is a previous focusable
|
|
329
|
+
* element that is not a menu item (or if the previous focusable element is a menu
|
|
330
|
+
* item while the element that is currently focused is not).
|
|
347
331
|
*/
|
|
348
|
-
if (event.key === '
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
332
|
+
if (event.key === 'Tab' && event.shiftKey) {
|
|
333
|
+
const focusableElements = [
|
|
334
|
+
...event.currentTarget.querySelectorAll<HTMLElement>(`
|
|
335
|
+
a[href],
|
|
336
|
+
button:enabled,
|
|
337
|
+
input:enabled,
|
|
338
|
+
select:enabled,
|
|
339
|
+
textarea:enabled,
|
|
340
|
+
summary,
|
|
341
|
+
[tabindex]:not([tabindex="-1"]),
|
|
342
|
+
[contenteditable="true"]
|
|
343
|
+
`),
|
|
344
|
+
]
|
|
345
|
+
const previousElement = focusableElements.reverse().find((element) => {
|
|
346
|
+
return (
|
|
347
|
+
element.compareDocumentPosition(document.activeElement!) &
|
|
348
|
+
Node.DOCUMENT_POSITION_FOLLOWING
|
|
349
|
+
)
|
|
350
|
+
})
|
|
351
|
+
const activeElementIsMenuItem =
|
|
352
|
+
document.activeElement?.classList.contains('gds-menu-item')
|
|
353
|
+
const previousElementIsMenuItem =
|
|
354
|
+
previousElement?.classList.contains('gds-menu-item')
|
|
355
|
+
if (
|
|
356
|
+
(previousElement && !previousElementIsMenuItem) ||
|
|
357
|
+
(!activeElementIsMenuItem && previousElementIsMenuItem)
|
|
358
|
+
) {
|
|
359
|
+
event.preventBaseUIHandler()
|
|
360
|
+
return
|
|
361
|
+
}
|
|
360
362
|
}
|
|
361
|
-
// If
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
363
|
+
// If there is a search input in the menu...
|
|
364
|
+
const searchInput = event.currentTarget.querySelector('input[type="search"]')
|
|
365
|
+
if (searchInput instanceof HTMLInputElement) {
|
|
366
|
+
// If the user typed some text, ensure it goes in the input instead of Base UI focusing the item that matches
|
|
367
|
+
if (
|
|
368
|
+
(event.key.length === 1 && event.key !== ' ') ||
|
|
369
|
+
event.key === 'Backspace' ||
|
|
370
|
+
event.key === 'ArrowLeft' ||
|
|
371
|
+
event.key === 'ArrowRight'
|
|
372
|
+
) {
|
|
373
|
+
event.preventBaseUIHandler()
|
|
374
|
+
searchInput.focus()
|
|
375
|
+
} else {
|
|
376
|
+
const searchInputIsFocused = document.activeElement === searchInput
|
|
377
|
+
const menuItems = [
|
|
378
|
+
...event.currentTarget.querySelectorAll<HTMLElement>('.gds-menu-item'),
|
|
379
|
+
]
|
|
380
|
+
const highlightedMenuItem = menuItems.find((item) =>
|
|
381
|
+
item.matches('[data-highlighted]'),
|
|
382
|
+
)
|
|
383
|
+
/**
|
|
384
|
+
* If the user pressed the down arrow while the search input is focused and
|
|
385
|
+
* there is a single menu item in the results, move the focus to it because it
|
|
386
|
+
* may already be highlighted, which would prevent Base UI from focusing it.
|
|
387
|
+
*/
|
|
388
|
+
if (
|
|
389
|
+
event.key === 'ArrowDown' &&
|
|
390
|
+
searchInputIsFocused &&
|
|
391
|
+
menuItems.length === 1
|
|
392
|
+
) {
|
|
393
|
+
event.preventBaseUIHandler()
|
|
394
|
+
menuItems[0]!.focus()
|
|
395
|
+
}
|
|
396
|
+
// Inversely, if the user pressed the up arrow and the focus is on the only menu item, move it back to the search input
|
|
397
|
+
else if (
|
|
398
|
+
event.key === 'ArrowUp' &&
|
|
399
|
+
menuItems.length === 1 &&
|
|
400
|
+
document.activeElement === menuItems[0]
|
|
401
|
+
) {
|
|
402
|
+
event.preventDefault()
|
|
403
|
+
searchInput.focus()
|
|
404
|
+
}
|
|
405
|
+
// If the user pressed Enter while the search input is focused and a menu item is highlighted, select it
|
|
406
|
+
else if (event.key === 'Enter' && searchInputIsFocused && highlightedMenuItem) {
|
|
407
|
+
highlightedMenuItem.focus()
|
|
408
|
+
window.setTimeout(() => {
|
|
409
|
+
highlightedMenuItem.dispatchEvent(
|
|
410
|
+
new KeyboardEvent('keydown', {
|
|
411
|
+
key: 'Enter',
|
|
412
|
+
code: 'Enter',
|
|
413
|
+
keyCode: 13,
|
|
414
|
+
which: 13,
|
|
415
|
+
bubbles: true,
|
|
416
|
+
cancelable: true,
|
|
417
|
+
}),
|
|
418
|
+
)
|
|
419
|
+
}, 0)
|
|
420
|
+
}
|
|
421
|
+
}
|
|
365
422
|
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
{
|
|
397
|
-
|
|
423
|
+
}}
|
|
424
|
+
>
|
|
425
|
+
{/**
|
|
426
|
+
* This div gives the menu a "minimum width" that is not as strict as `min-width` (a fixed width
|
|
427
|
+
* overrides it, for example). A more elegant way to do this would be to change `u:w-max` to
|
|
428
|
+
* `u:w-[calc-size(max-content,max(size,theme(spacing.58)))]`, which would also allow to override
|
|
429
|
+
* that min width if needed, but `calc-size()` is not supported in Safari or Firefox yet.
|
|
430
|
+
*/}
|
|
431
|
+
<div className="w-58" />
|
|
432
|
+
{header ? (
|
|
433
|
+
<div className="nested/menu-header u:shrink-0 u:border-b u:border-muted u:p-4">
|
|
434
|
+
{header}
|
|
435
|
+
</div>
|
|
436
|
+
) : null}
|
|
437
|
+
<div className="scrollbar-thin grow scroll-p-8 overflow-x-clip overflow-y-auto gradient-mask-y">
|
|
438
|
+
<div className="overflow-clip p-2">
|
|
439
|
+
<MenuGroupContext.Provider value="root">
|
|
440
|
+
{/* When `label` or `type` is provided at the root level, automatically wrap `children` in a group */}
|
|
441
|
+
{label !== undefined || type !== undefined ? (
|
|
442
|
+
type === 'radio' ? (
|
|
443
|
+
<MenuGroup
|
|
444
|
+
label={label}
|
|
445
|
+
type={type}
|
|
446
|
+
value={value}
|
|
447
|
+
defaultValue={defaultValue}
|
|
448
|
+
onChange={onChange}
|
|
449
|
+
>
|
|
450
|
+
{children}
|
|
451
|
+
</MenuGroup>
|
|
452
|
+
) : (
|
|
453
|
+
<MenuGroup label={label} type={type}>
|
|
454
|
+
{children}
|
|
455
|
+
</MenuGroup>
|
|
456
|
+
)
|
|
398
457
|
) : (
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
<div className="pointer-events-none absolute inset-0 rounded-inherit border border-muted" />
|
|
417
|
-
</Menu.Popup>
|
|
418
|
-
</MaybePortal>
|
|
419
|
-
</Root>
|
|
458
|
+
children
|
|
459
|
+
)}
|
|
460
|
+
<div className="mt-[calc(-2*(--spacing(2))-1px)] not-preceded-by-peer/menu-group:hidden" />
|
|
461
|
+
</MenuGroupContext.Provider>
|
|
462
|
+
</div>
|
|
463
|
+
</div>
|
|
464
|
+
{footer ? (
|
|
465
|
+
<div className="nested/menu-footer u:shrink-0 u:border-t u:border-muted u:p-4">
|
|
466
|
+
{footer}
|
|
467
|
+
</div>
|
|
468
|
+
) : null}
|
|
469
|
+
<div className="pointer-events-none absolute inset-0 rounded-inherit border border-muted" />
|
|
470
|
+
</Menu.Popup>
|
|
471
|
+
</Menu.Positioner>
|
|
472
|
+
</Menu.Portal>
|
|
473
|
+
</MenuRoot>
|
|
474
|
+
</div>
|
|
420
475
|
)
|
|
421
476
|
}
|
|
422
477
|
MenuRoot.displayName = 'Menu'
|
|
423
478
|
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}: ComponentProps<'div'> & { position: MenuPosition | false }) => {
|
|
432
|
-
const containerRef = useRef<HTMLDivElement>(null)
|
|
433
|
-
const { dirProps } = useGDS()
|
|
434
|
-
|
|
435
|
-
return (
|
|
436
|
-
<>
|
|
437
|
-
{/**
|
|
438
|
-
* Ideally, we simply wouldn't render a `Menu.Portal` or `Menu.Positioner` when `position` is
|
|
439
|
-
* `false`, but they are required by Base UI, so we hack our way around them.
|
|
440
|
-
*/}
|
|
441
|
-
{!position ? <div ref={containerRef} className="contents *:contents" /> : null}
|
|
442
|
-
<Menu.Portal
|
|
443
|
-
container={
|
|
444
|
-
!position
|
|
445
|
-
? containerRef
|
|
446
|
-
: /**
|
|
447
|
-
* Specifying `document.body` because while it is the default for top-level menus, a nested menu
|
|
448
|
-
* defaults to using the same portal as its parent, which is not desirable when the parent is not
|
|
449
|
-
* positioned (it can cause the nested menu to appear behind other elements).
|
|
450
|
-
*/
|
|
451
|
-
document?.body
|
|
452
|
-
}
|
|
453
|
-
>
|
|
454
|
-
<Menu.Positioner
|
|
455
|
-
align={position ? position.align : 'start'}
|
|
456
|
-
alignOffset={position ? twToPx(position.alignOffset) : 0}
|
|
457
|
-
side={position ? position.side : 'bottom'}
|
|
458
|
-
sideOffset={position ? twToPx(position.gap) : 0}
|
|
459
|
-
collisionPadding={8}
|
|
460
|
-
{...dirProps}
|
|
461
|
-
render={({ style, ...otherPositionerProps }) => {
|
|
462
|
-
const allowedPositionerProps = position
|
|
463
|
-
? { style, ...otherPositionerProps }
|
|
464
|
-
: otherPositionerProps
|
|
465
|
-
return <div {...allowedPositionerProps} {...props} />
|
|
466
|
-
}}
|
|
467
|
-
/>
|
|
468
|
-
</Menu.Portal>
|
|
469
|
-
</>
|
|
470
|
-
)
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
const MenuGroupContext = createContext<{
|
|
474
|
-
type: MenuItemType
|
|
475
|
-
} | null>(null)
|
|
479
|
+
const MenuGroupContext = createContext<
|
|
480
|
+
| {
|
|
481
|
+
type: MenuItemType
|
|
482
|
+
}
|
|
483
|
+
| 'root'
|
|
484
|
+
| null
|
|
485
|
+
>(null)
|
|
476
486
|
|
|
477
487
|
declare namespace MenuGroupProps {
|
|
478
488
|
interface BaseProps extends Omit<ComponentProps<'div'>, 'defaultValue' | 'onChange'> {}
|
|
@@ -495,7 +505,8 @@ export function MenuGroup<T extends OptionValue>({
|
|
|
495
505
|
children,
|
|
496
506
|
...props
|
|
497
507
|
}: MenuGroupProps<T>) {
|
|
498
|
-
const
|
|
508
|
+
const groupContext = useContext(MenuGroupContext)
|
|
509
|
+
const isNested = groupContext !== null && groupContext !== 'root'
|
|
499
510
|
|
|
500
511
|
if (isNested) {
|
|
501
512
|
throw new Error(
|
|
@@ -617,178 +628,174 @@ export function MenuItem<T extends OptionValue>({
|
|
|
617
628
|
const hasAncestorMenuTrigger = useContext(MenuTriggerContext) !== false
|
|
618
629
|
const type = hasAncestorMenuTrigger
|
|
619
630
|
? 'submenu-trigger'
|
|
620
|
-
: (passedType ??
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
631
|
+
: (passedType ??
|
|
632
|
+
(groupContext !== null && groupContext !== 'root' ? groupContext.type : undefined) ??
|
|
633
|
+
'plain')
|
|
634
|
+
|
|
635
|
+
const renderItem = (renderProps: RenderFnProps) => {
|
|
636
|
+
let addonBefore: AddonValue = passedAddonBefore
|
|
637
|
+
let addonInside: AddonValue = undefined
|
|
638
|
+
let addonAfter: AddonValue = passedAddonAfter
|
|
639
|
+
if (type === 'checkbox') {
|
|
640
|
+
if (addonBefore) addonInside = addonBefore
|
|
641
|
+
addonBefore = (
|
|
642
|
+
<Checkbox
|
|
643
|
+
inert={true}
|
|
644
|
+
aria-label="" // Prevent console warning about missing label
|
|
645
|
+
className={`
|
|
646
|
+
@state-checked/menu-item:state-checked
|
|
647
|
+
@state-indeterminate/menu-item:state-indeterminate
|
|
648
|
+
@state-hover/menu-item:state-hover
|
|
649
|
+
@state-active/menu-item:state-active
|
|
650
|
+
@state-disabled/menu-item:state-idle
|
|
651
|
+
@state-disabled/menu-item:@state-checked/menu-item:state-disabled
|
|
652
|
+
`}
|
|
653
|
+
/>
|
|
654
|
+
)
|
|
632
655
|
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
case 'plain':
|
|
637
|
-
return { disabled } satisfies ComponentProps<typeof Menu.Item>
|
|
638
|
-
case 'checkbox':
|
|
639
|
-
return {
|
|
640
|
-
disabled,
|
|
641
|
-
checked,
|
|
642
|
-
defaultChecked,
|
|
643
|
-
onCheckedChange: onChange,
|
|
644
|
-
closeOnClick: false,
|
|
645
|
-
} satisfies ComponentProps<typeof CheckboxItem>
|
|
646
|
-
case 'radio':
|
|
647
|
-
return {
|
|
648
|
-
value: passedValue !== undefined ? passedValue : autoValue,
|
|
649
|
-
disabled,
|
|
650
|
-
closeOnClick: true,
|
|
651
|
-
} satisfies ComponentProps<typeof Menu.RadioItem>
|
|
652
|
-
case 'submenu-trigger':
|
|
653
|
-
return {}
|
|
656
|
+
if (type === 'radio') {
|
|
657
|
+
if (addonBefore) addonInside = addonBefore
|
|
658
|
+
addonBefore = <CheckIcon alt="" className="@state-unchecked/menu-item:invisible" />
|
|
654
659
|
}
|
|
655
|
-
|
|
660
|
+
if (loading) {
|
|
661
|
+
addonAfter = <LoadingIcon />
|
|
662
|
+
}
|
|
663
|
+
if (type === 'submenu-trigger' && addonAfter === undefined) {
|
|
664
|
+
addonAfter = <CaretRightIcon alt="" />
|
|
665
|
+
}
|
|
666
|
+
if (href !== undefined && addonAfter === undefined) {
|
|
667
|
+
addonAfter = (
|
|
668
|
+
<ButtonOrLink.Consumer
|
|
669
|
+
render={(buttonOrLinkState) =>
|
|
670
|
+
buttonOrLinkState?.target === '_blank' ? (
|
|
671
|
+
<ArrowUpRightInteractiveIcon hiddenByDefault />
|
|
672
|
+
) : (
|
|
673
|
+
<ArrowRightInteractiveIcon hiddenByDefault />
|
|
674
|
+
)
|
|
675
|
+
}
|
|
676
|
+
/>
|
|
677
|
+
)
|
|
678
|
+
}
|
|
679
|
+
return (
|
|
680
|
+
<Render
|
|
681
|
+
render={<ButtonOrLink href={href} target={target as undefined} />}
|
|
682
|
+
data-type={type}
|
|
683
|
+
data-variant={variant}
|
|
684
|
+
className={cn(
|
|
685
|
+
`gds-menu-item root-flex w-full items-center outline-0 select-none u:rounded-6 u:p-2 u:text-16
|
|
686
|
+
u:state-idle
|
|
687
|
+
u:checked:state-checked
|
|
688
|
+
u:indeterminate:state-indeterminate
|
|
689
|
+
u:disabled:pointer-events-none
|
|
690
|
+
u:disabled:state-disabled
|
|
691
|
+
u:data-highlighted:state-hover
|
|
692
|
+
u:data-[variant=danger]:text-status-error-default
|
|
693
|
+
u:ii:not-disabled:active:state-active
|
|
694
|
+
u:ii:data-[type=submenu-trigger]:not-[a]:cursor-default
|
|
695
|
+
u:ii:data-[type=submenu-trigger]:not-[a]:active:state-hover
|
|
696
|
+
${/* Disabled styles */ ''}
|
|
697
|
+
u:*:transition-opacity
|
|
698
|
+
u:disabled:*:opacity-disabled
|
|
699
|
+
u:disabled:*:grayscale`,
|
|
700
|
+
className,
|
|
701
|
+
)}
|
|
702
|
+
{...renderProps}
|
|
703
|
+
>
|
|
704
|
+
<span
|
|
705
|
+
className={`
|
|
706
|
+
absolute inset-0 rounded-inherit opacity-100 filter-none transition
|
|
707
|
+
@state-hover/menu-item:bg-elevated
|
|
708
|
+
@state-active/menu-item:bg-default
|
|
709
|
+
@state-active/menu-item:transition-none
|
|
710
|
+
`}
|
|
711
|
+
/>
|
|
712
|
+
{addonBefore ? (
|
|
713
|
+
<MenuItemAddon
|
|
714
|
+
className={`
|
|
715
|
+
me-2
|
|
716
|
+
has-checkbox:@state-checked/menu-item:opacity-100
|
|
717
|
+
has-checkbox:@state-checked/menu-item:filter-none
|
|
718
|
+
`}
|
|
719
|
+
>
|
|
720
|
+
{renderAddon(addonBefore)}
|
|
721
|
+
</MenuItemAddon>
|
|
722
|
+
) : null}
|
|
723
|
+
{addonInside ? (
|
|
724
|
+
<MenuItemAddon className="me-1">{renderAddon(addonInside)}</MenuItemAddon>
|
|
725
|
+
) : null}
|
|
726
|
+
<span className="grow truncate pe-1">{children || <> </>}</span>
|
|
727
|
+
{addonAfter ? (
|
|
728
|
+
<MenuItemAddon className="ms-2">{renderAddon(addonAfter)}</MenuItemAddon>
|
|
729
|
+
) : null}
|
|
730
|
+
</Render>
|
|
731
|
+
)
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// Filter out undefined values to satisfy Base UI's `exactOptionalPropertyTypes`
|
|
735
|
+
// TODO: Remove when https://github.com/mui/base-ui/pull/3302 is released
|
|
736
|
+
const definedProps = Object.fromEntries(
|
|
737
|
+
Object.entries(props).filter(([, value]) => value !== undefined),
|
|
738
|
+
)
|
|
739
|
+
const baseProps = {
|
|
740
|
+
ref: stateElementPassedRef,
|
|
741
|
+
...state.polyfillAttributes,
|
|
742
|
+
...definedProps,
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
if (type === 'submenu-trigger') {
|
|
746
|
+
return <Menu.SubmenuTrigger nativeButton disabled={disabled} render={renderItem(baseProps)} />
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
const nativeButton = href === undefined
|
|
750
|
+
const onKeyDown: ComponentProps<typeof Menu.Item>['onKeyDown'] = (event) => {
|
|
751
|
+
props.onKeyDown?.(event)
|
|
752
|
+
/**
|
|
753
|
+
* Allow Space to activate menu items that are links. This may not be needed in the future (see
|
|
754
|
+
* https://github.com/mui/base-ui/issues/1746).
|
|
755
|
+
*/
|
|
756
|
+
if (!event.baseUIHandlerPrevented && event.key === ' ' && href !== undefined) {
|
|
757
|
+
event.preventBaseUIHandler()
|
|
758
|
+
elementRef.current?.click()
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if (type === 'checkbox') {
|
|
763
|
+
return (
|
|
764
|
+
<CheckboxItem
|
|
765
|
+
{...baseProps}
|
|
766
|
+
nativeButton={nativeButton}
|
|
767
|
+
closeOnClick={false}
|
|
768
|
+
checked={checked}
|
|
769
|
+
defaultChecked={defaultChecked}
|
|
770
|
+
onCheckedChange={onChange}
|
|
771
|
+
onKeyDown={onKeyDown}
|
|
772
|
+
disabled={disabled}
|
|
773
|
+
render={renderItem}
|
|
774
|
+
/>
|
|
775
|
+
)
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
if (type === 'radio') {
|
|
779
|
+
return (
|
|
780
|
+
<Menu.RadioItem
|
|
781
|
+
{...baseProps}
|
|
782
|
+
nativeButton={nativeButton}
|
|
783
|
+
closeOnClick={true}
|
|
784
|
+
value={passedValue !== undefined ? passedValue : autoValue}
|
|
785
|
+
onKeyDown={onKeyDown}
|
|
786
|
+
disabled={disabled}
|
|
787
|
+
render={renderItem}
|
|
788
|
+
/>
|
|
789
|
+
)
|
|
790
|
+
}
|
|
656
791
|
|
|
657
792
|
return (
|
|
658
|
-
<
|
|
659
|
-
|
|
660
|
-
{
|
|
661
|
-
{
|
|
662
|
-
{
|
|
663
|
-
|
|
664
|
-
event: Parameters<
|
|
665
|
-
NonNullable<
|
|
666
|
-
ComponentProps<
|
|
667
|
-
typeof Menu.Item | typeof CheckboxItem | typeof Menu.RadioItem
|
|
668
|
-
>['onKeyDown']
|
|
669
|
-
>
|
|
670
|
-
>[0],
|
|
671
|
-
) => {
|
|
672
|
-
props.onKeyDown?.(event)
|
|
673
|
-
/**
|
|
674
|
-
* Allow Space to activate menu items that are links. TODO: This may not be needed in the
|
|
675
|
-
* future (see https://github.com/mui/base-ui/issues/1746).
|
|
676
|
-
*/
|
|
677
|
-
if (
|
|
678
|
-
'preventBaseUIHandler' in event &&
|
|
679
|
-
!event.baseUIHandlerPrevented &&
|
|
680
|
-
event.key === ' ' &&
|
|
681
|
-
href !== undefined
|
|
682
|
-
) {
|
|
683
|
-
event.preventBaseUIHandler()
|
|
684
|
-
elementRef.current?.click()
|
|
685
|
-
}
|
|
686
|
-
}}
|
|
687
|
-
render={(renderProps: Record<string, unknown>) => {
|
|
688
|
-
let addonBefore: AddonValue = passedAddonBefore
|
|
689
|
-
let addonInside: AddonValue = undefined
|
|
690
|
-
let addonAfter: AddonValue = passedAddonAfter
|
|
691
|
-
if (type === 'checkbox') {
|
|
692
|
-
if (addonBefore) addonInside = addonBefore
|
|
693
|
-
addonBefore = (
|
|
694
|
-
<Checkbox
|
|
695
|
-
inert={true}
|
|
696
|
-
aria-label="" // Prevent console warning about missing label
|
|
697
|
-
className={`
|
|
698
|
-
@state-checked/menu-item:state-checked
|
|
699
|
-
@state-indeterminate/menu-item:state-indeterminate
|
|
700
|
-
@state-hover/menu-item:state-hover
|
|
701
|
-
@state-active/menu-item:state-active
|
|
702
|
-
@state-disabled/menu-item:state-idle
|
|
703
|
-
@state-disabled/menu-item:@state-checked/menu-item:state-disabled
|
|
704
|
-
`}
|
|
705
|
-
/>
|
|
706
|
-
)
|
|
707
|
-
}
|
|
708
|
-
if (type === 'radio') {
|
|
709
|
-
if (addonBefore) addonInside = addonBefore
|
|
710
|
-
addonBefore = <CheckIcon alt="" className="@state-unchecked/menu-item:invisible" />
|
|
711
|
-
}
|
|
712
|
-
if (loading) {
|
|
713
|
-
addonAfter = <LoadingIcon />
|
|
714
|
-
}
|
|
715
|
-
if (type === 'submenu-trigger' && addonAfter === undefined) {
|
|
716
|
-
addonAfter = <CaretRightIcon alt="" />
|
|
717
|
-
}
|
|
718
|
-
if (href !== undefined && addonAfter === undefined) {
|
|
719
|
-
addonAfter = (
|
|
720
|
-
<ButtonOrLink.Consumer
|
|
721
|
-
render={(buttonOrLinkState) =>
|
|
722
|
-
buttonOrLinkState?.target === '_blank' ? (
|
|
723
|
-
<ArrowUpRightInteractiveIcon hiddenByDefault />
|
|
724
|
-
) : (
|
|
725
|
-
<ArrowRightInteractiveIcon hiddenByDefault />
|
|
726
|
-
)
|
|
727
|
-
}
|
|
728
|
-
/>
|
|
729
|
-
)
|
|
730
|
-
}
|
|
731
|
-
return (
|
|
732
|
-
<Render
|
|
733
|
-
data-type={type}
|
|
734
|
-
data-variant={variant}
|
|
735
|
-
className={cn(
|
|
736
|
-
// TODO: Replace `active:` with `data-pressed:` when https://github.com/mui/base-ui/issues/1726 is added, to style Space presses as well
|
|
737
|
-
`gds-menu-item root-flex w-full items-center outline-0 select-none u:rounded-6 u:p-2 u:text-16 u:text-default
|
|
738
|
-
u:state-idle
|
|
739
|
-
u:checked:state-checked
|
|
740
|
-
u:indeterminate:state-indeterminate
|
|
741
|
-
u:disabled:pointer-events-none
|
|
742
|
-
u:disabled:state-disabled
|
|
743
|
-
u:data-highlighted:state-hover
|
|
744
|
-
u:data-[variant=danger]:text-status-error-default
|
|
745
|
-
u:ii:active:state-active
|
|
746
|
-
u:ii:data-[type=submenu-trigger]:not-[a]:cursor-default
|
|
747
|
-
u:ii:data-[type=submenu-trigger]:not-[a]:active:state-hover
|
|
748
|
-
${/* Disabled styles */ ''}
|
|
749
|
-
u:*:transition-opacity
|
|
750
|
-
u:disabled:*:opacity-disabled
|
|
751
|
-
u:disabled:*:grayscale`,
|
|
752
|
-
className,
|
|
753
|
-
)}
|
|
754
|
-
{...renderProps}
|
|
755
|
-
render={
|
|
756
|
-
href !== undefined ? (
|
|
757
|
-
<ButtonOrLink href={href} target={target} disabled={disabled} />
|
|
758
|
-
) : (
|
|
759
|
-
<div />
|
|
760
|
-
)
|
|
761
|
-
}
|
|
762
|
-
>
|
|
763
|
-
<span
|
|
764
|
-
className={`
|
|
765
|
-
absolute inset-0 rounded-inherit opacity-100 filter-none transition
|
|
766
|
-
@state-hover/menu-item:bg-elevated
|
|
767
|
-
@state-active/menu-item:bg-default
|
|
768
|
-
@state-active/menu-item:transition-none
|
|
769
|
-
`}
|
|
770
|
-
/>
|
|
771
|
-
{addonBefore ? (
|
|
772
|
-
<MenuItemAddon
|
|
773
|
-
className={`
|
|
774
|
-
me-2
|
|
775
|
-
has-checkbox:@state-checked/menu-item:opacity-100
|
|
776
|
-
has-checkbox:@state-checked/menu-item:filter-none
|
|
777
|
-
`}
|
|
778
|
-
>
|
|
779
|
-
{renderAddon(addonBefore)}
|
|
780
|
-
</MenuItemAddon>
|
|
781
|
-
) : null}
|
|
782
|
-
{addonInside ? (
|
|
783
|
-
<MenuItemAddon className="me-1">{renderAddon(addonInside)}</MenuItemAddon>
|
|
784
|
-
) : null}
|
|
785
|
-
<span className="grow truncate pe-1">{children || <> </>}</span>
|
|
786
|
-
{addonAfter ? (
|
|
787
|
-
<MenuItemAddon className="ms-2">{renderAddon(addonAfter)}</MenuItemAddon>
|
|
788
|
-
) : null}
|
|
789
|
-
</Render>
|
|
790
|
-
)
|
|
791
|
-
}}
|
|
793
|
+
<Menu.Item
|
|
794
|
+
{...baseProps}
|
|
795
|
+
nativeButton={nativeButton}
|
|
796
|
+
onKeyDown={onKeyDown}
|
|
797
|
+
disabled={disabled}
|
|
798
|
+
render={renderItem}
|
|
792
799
|
/>
|
|
793
800
|
)
|
|
794
801
|
}
|
|
@@ -869,8 +876,8 @@ export function MenuSearch({
|
|
|
869
876
|
MenuSearch.displayName = 'Menu.Search'
|
|
870
877
|
|
|
871
878
|
/**
|
|
872
|
-
* Transparent wrapper for `Menu.CheckboxItem` to support `indeterminate`.
|
|
873
|
-
*
|
|
879
|
+
* Transparent wrapper for `Menu.CheckboxItem` to support `indeterminate`. This may not be needed in
|
|
880
|
+
* the future (see https://github.com/mui/base-ui/issues/1983).
|
|
874
881
|
*/
|
|
875
882
|
function CheckboxItem({
|
|
876
883
|
checked: controlledChecked,
|