@mortenbrudvik/waveui 0.4.0 → 0.7.0
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/README.md +1221 -173
- package/dist/_virtual/_rolldown/runtime.cjs +1 -0
- package/dist/components/button/Button.cjs +2 -0
- package/dist/components/button/Button.cjs.map +1 -0
- package/dist/components/button/Button.mjs +50 -0
- package/dist/components/button/Button.mjs.map +1 -0
- package/dist/components/button/Button.semantics.cjs +2 -0
- package/dist/components/button/Button.semantics.cjs.map +1 -0
- package/dist/components/button/Button.semantics.mjs +61 -0
- package/dist/components/button/Button.semantics.mjs.map +1 -0
- package/dist/components/button/Button.slots.cjs +2 -0
- package/dist/components/button/Button.slots.cjs.map +1 -0
- package/dist/components/button/Button.slots.mjs +47 -0
- package/dist/components/button/Button.slots.mjs.map +1 -0
- package/dist/components/button/CompoundButton.cjs +2 -0
- package/dist/components/button/CompoundButton.cjs.map +1 -0
- package/dist/components/button/CompoundButton.mjs +53 -0
- package/dist/components/button/CompoundButton.mjs.map +1 -0
- package/dist/components/button/Link.cjs +2 -0
- package/dist/components/button/Link.cjs.map +1 -0
- package/dist/components/button/Link.mjs +37 -0
- package/dist/components/button/Link.mjs.map +1 -0
- package/dist/components/button/MenuButton.cjs +2 -0
- package/dist/components/button/MenuButton.cjs.map +1 -0
- package/dist/components/button/MenuButton.mjs +45 -0
- package/dist/components/button/MenuButton.mjs.map +1 -0
- package/dist/components/button/SplitButton.cjs +2 -0
- package/dist/components/button/SplitButton.cjs.map +1 -0
- package/dist/components/button/SplitButton.mjs +66 -0
- package/dist/components/button/SplitButton.mjs.map +1 -0
- package/dist/components/button/ToggleButton.cjs +2 -0
- package/dist/components/button/ToggleButton.cjs.map +1 -0
- package/dist/components/button/ToggleButton.mjs +65 -0
- package/dist/components/button/ToggleButton.mjs.map +1 -0
- package/dist/components/button/Toolbar.cjs +2 -0
- package/dist/components/button/Toolbar.cjs.map +1 -0
- package/dist/components/button/Toolbar.context.cjs +2 -0
- package/dist/components/button/Toolbar.context.cjs.map +1 -0
- package/dist/components/button/Toolbar.context.mjs +31 -0
- package/dist/components/button/Toolbar.context.mjs.map +1 -0
- package/dist/components/button/Toolbar.mjs +63 -0
- package/dist/components/button/Toolbar.mjs.map +1 -0
- package/dist/components/button/Toolbar.parts.cjs +2 -0
- package/dist/components/button/Toolbar.parts.cjs.map +1 -0
- package/dist/components/button/Toolbar.parts.mjs +131 -0
- package/dist/components/button/Toolbar.parts.mjs.map +1 -0
- package/dist/components/button/buttonStyles.cjs +2 -0
- package/dist/components/button/buttonStyles.cjs.map +1 -0
- package/dist/components/button/buttonStyles.mjs +39 -0
- package/dist/components/button/buttonStyles.mjs.map +1 -0
- package/dist/components/data-display/Avatar.cjs +2 -0
- package/dist/components/data-display/Avatar.cjs.map +1 -0
- package/dist/components/data-display/Avatar.mjs +157 -0
- package/dist/components/data-display/Avatar.mjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.cjs +2 -0
- package/dist/components/data-display/AvatarGroup.cjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.mjs +134 -0
- package/dist/components/data-display/AvatarGroup.mjs.map +1 -0
- package/dist/components/data-display/Badge.cjs +2 -0
- package/dist/components/data-display/Badge.cjs.map +1 -0
- package/dist/components/data-display/Badge.colors.cjs +2 -0
- package/dist/components/data-display/Badge.colors.cjs.map +1 -0
- package/dist/components/data-display/Badge.colors.mjs +58 -0
- package/dist/components/data-display/Badge.colors.mjs.map +1 -0
- package/dist/components/data-display/Badge.mjs +32 -0
- package/dist/components/data-display/Badge.mjs.map +1 -0
- package/dist/components/data-display/CounterBadge.cjs +2 -0
- package/dist/components/data-display/CounterBadge.cjs.map +1 -0
- package/dist/components/data-display/CounterBadge.mjs +28 -0
- package/dist/components/data-display/CounterBadge.mjs.map +1 -0
- package/dist/components/data-display/Divider.cjs +2 -0
- package/dist/components/data-display/Divider.cjs.map +1 -0
- package/dist/components/data-display/Divider.mjs +52 -0
- package/dist/components/data-display/Divider.mjs.map +1 -0
- package/dist/components/data-display/Image.cjs +2 -0
- package/dist/components/data-display/Image.cjs.map +1 -0
- package/dist/components/data-display/Image.mjs +32 -0
- package/dist/components/data-display/Image.mjs.map +1 -0
- package/dist/components/data-display/InfoLabel.cjs +2 -0
- package/dist/components/data-display/InfoLabel.cjs.map +1 -0
- package/dist/components/data-display/InfoLabel.mjs +104 -0
- package/dist/components/data-display/InfoLabel.mjs.map +1 -0
- package/dist/components/data-display/List.cjs +2 -0
- package/dist/components/data-display/List.cjs.map +1 -0
- package/dist/components/data-display/List.mjs +381 -0
- package/dist/components/data-display/List.mjs.map +1 -0
- package/dist/components/data-display/List.registry.cjs +2 -0
- package/dist/components/data-display/List.registry.cjs.map +1 -0
- package/dist/components/data-display/List.registry.mjs +101 -0
- package/dist/components/data-display/List.registry.mjs.map +1 -0
- package/dist/components/data-display/Persona.cjs +2 -0
- package/dist/components/data-display/Persona.cjs.map +1 -0
- package/dist/components/data-display/Persona.mjs +48 -0
- package/dist/components/data-display/Persona.mjs.map +1 -0
- package/dist/components/data-display/PresenceBadge.cjs +2 -0
- package/dist/components/data-display/PresenceBadge.cjs.map +1 -0
- package/dist/components/data-display/PresenceBadge.mjs +71 -0
- package/dist/components/data-display/PresenceBadge.mjs.map +1 -0
- package/dist/components/data-display/Tag.cjs +2 -0
- package/dist/components/data-display/Tag.cjs.map +1 -0
- package/dist/components/data-display/Tag.mjs +147 -0
- package/dist/components/data-display/Tag.mjs.map +1 -0
- package/dist/components/feedback/MessageBar.cjs +2 -0
- package/dist/components/feedback/MessageBar.cjs.map +1 -0
- package/dist/components/feedback/MessageBar.mjs +144 -0
- package/dist/components/feedback/MessageBar.mjs.map +1 -0
- package/dist/components/feedback/MessageBar.status.cjs +2 -0
- package/dist/components/feedback/MessageBar.status.cjs.map +1 -0
- package/dist/components/feedback/MessageBar.status.mjs +45 -0
- package/dist/components/feedback/MessageBar.status.mjs.map +1 -0
- package/dist/components/feedback/ProgressBar.cjs +2 -0
- package/dist/components/feedback/ProgressBar.cjs.map +1 -0
- package/dist/components/feedback/ProgressBar.mjs +72 -0
- package/dist/components/feedback/ProgressBar.mjs.map +1 -0
- package/dist/components/feedback/Skeleton.cjs +2 -0
- package/dist/components/feedback/Skeleton.cjs.map +1 -0
- package/dist/components/feedback/Skeleton.mjs +47 -0
- package/dist/components/feedback/Skeleton.mjs.map +1 -0
- package/dist/components/feedback/Spinner.cjs +2 -0
- package/dist/components/feedback/Spinner.cjs.map +1 -0
- package/dist/components/feedback/Spinner.mjs +60 -0
- package/dist/components/feedback/Spinner.mjs.map +1 -0
- package/dist/components/feedback/Toast.cjs +2 -0
- package/dist/components/feedback/Toast.cjs.map +1 -0
- package/dist/components/feedback/Toast.mjs +347 -0
- package/dist/components/feedback/Toast.mjs.map +1 -0
- package/dist/components/input/Checkbox.cjs +2 -0
- package/dist/components/input/Checkbox.cjs.map +1 -0
- package/dist/components/input/Checkbox.mjs +96 -0
- package/dist/components/input/Checkbox.mjs.map +1 -0
- package/dist/components/input/ColorPicker.cjs +6 -0
- package/dist/components/input/ColorPicker.cjs.map +1 -0
- package/dist/components/input/ColorPicker.mjs +236 -0
- package/dist/components/input/ColorPicker.mjs.map +1 -0
- package/dist/components/input/Combobox.cjs +2 -0
- package/dist/components/input/Combobox.cjs.map +1 -0
- package/dist/components/input/Combobox.expand.cjs +2 -0
- package/dist/components/input/Combobox.expand.cjs.map +1 -0
- package/dist/components/input/Combobox.expand.mjs +38 -0
- package/dist/components/input/Combobox.expand.mjs.map +1 -0
- package/dist/components/input/Combobox.mjs +187 -0
- package/dist/components/input/Combobox.mjs.map +1 -0
- package/dist/components/input/DatePicker.cjs +2 -0
- package/dist/components/input/DatePicker.cjs.map +1 -0
- package/dist/components/input/DatePicker.mjs +340 -0
- package/dist/components/input/DatePicker.mjs.map +1 -0
- package/dist/components/input/Dropdown.cjs +2 -0
- package/dist/components/input/Dropdown.cjs.map +1 -0
- package/dist/components/input/Dropdown.mjs +128 -0
- package/dist/components/input/Dropdown.mjs.map +1 -0
- package/dist/components/input/Field.cjs +2 -0
- package/dist/components/input/Field.cjs.map +1 -0
- package/dist/components/input/Field.mjs +200 -0
- package/dist/components/input/Field.mjs.map +1 -0
- package/dist/components/input/Input.cjs +2 -0
- package/dist/components/input/Input.cjs.map +1 -0
- package/dist/components/input/Input.mjs +81 -0
- package/dist/components/input/Input.mjs.map +1 -0
- package/dist/components/input/Label.cjs +2 -0
- package/dist/components/input/Label.cjs.map +1 -0
- package/dist/components/input/Label.mjs +28 -0
- package/dist/components/input/Label.mjs.map +1 -0
- package/dist/components/input/Option.cjs +2 -0
- package/dist/components/input/Option.cjs.map +1 -0
- package/dist/components/input/Option.mjs +169 -0
- package/dist/components/input/Option.mjs.map +1 -0
- package/dist/components/input/RadioGroup.cjs +2 -0
- package/dist/components/input/RadioGroup.cjs.map +1 -0
- package/dist/components/input/RadioGroup.mjs +139 -0
- package/dist/components/input/RadioGroup.mjs.map +1 -0
- package/dist/components/input/Rating.cjs +2 -0
- package/dist/components/input/Rating.cjs.map +1 -0
- package/dist/components/input/Rating.mjs +196 -0
- package/dist/components/input/Rating.mjs.map +1 -0
- package/dist/components/input/SearchBox.cjs +2 -0
- package/dist/components/input/SearchBox.cjs.map +1 -0
- package/dist/components/input/SearchBox.mjs +205 -0
- package/dist/components/input/SearchBox.mjs.map +1 -0
- package/dist/components/input/Select.cjs +2 -0
- package/dist/components/input/Select.cjs.map +1 -0
- package/dist/components/input/Select.mjs +33 -0
- package/dist/components/input/Select.mjs.map +1 -0
- package/dist/components/input/Slider.cjs +2 -0
- package/dist/components/input/Slider.cjs.map +1 -0
- package/dist/components/input/Slider.mjs +79 -0
- package/dist/components/input/Slider.mjs.map +1 -0
- package/dist/components/input/SpinButton.cjs +2 -0
- package/dist/components/input/SpinButton.cjs.map +1 -0
- package/dist/components/input/SpinButton.mjs +157 -0
- package/dist/components/input/SpinButton.mjs.map +1 -0
- package/dist/components/input/SwatchPicker.cjs +2 -0
- package/dist/components/input/SwatchPicker.cjs.map +1 -0
- package/dist/components/input/SwatchPicker.mjs +113 -0
- package/dist/components/input/SwatchPicker.mjs.map +1 -0
- package/dist/components/input/Switch.cjs +2 -0
- package/dist/components/input/Switch.cjs.map +1 -0
- package/dist/components/input/Switch.mjs +92 -0
- package/dist/components/input/Switch.mjs.map +1 -0
- package/dist/components/input/TagPicker.cjs +2 -0
- package/dist/components/input/TagPicker.cjs.map +1 -0
- package/dist/components/input/TagPicker.mjs +249 -0
- package/dist/components/input/TagPicker.mjs.map +1 -0
- package/dist/components/input/Textarea.cjs +2 -0
- package/dist/components/input/Textarea.cjs.map +1 -0
- package/dist/components/input/Textarea.mjs +32 -0
- package/dist/components/input/Textarea.mjs.map +1 -0
- package/dist/components/input/TimePicker.cjs +2 -0
- package/dist/components/input/TimePicker.cjs.map +1 -0
- package/dist/components/input/TimePicker.mjs +292 -0
- package/dist/components/input/TimePicker.mjs.map +1 -0
- package/dist/components/input/colorUtils.cjs +2 -0
- package/dist/components/input/colorUtils.cjs.map +1 -0
- package/dist/components/input/colorUtils.mjs +96 -0
- package/dist/components/input/colorUtils.mjs.map +1 -0
- package/dist/components/input/dateUtils.cjs +2 -0
- package/dist/components/input/dateUtils.cjs.map +1 -0
- package/dist/components/input/dateUtils.mjs +250 -0
- package/dist/components/input/dateUtils.mjs.map +1 -0
- package/dist/components/input/pickerStyles.cjs +2 -0
- package/dist/components/input/pickerStyles.cjs.map +1 -0
- package/dist/components/input/pickerStyles.mjs +10 -0
- package/dist/components/input/pickerStyles.mjs.map +1 -0
- package/dist/components/internal/HiddenInput.cjs +2 -0
- package/dist/components/internal/HiddenInput.cjs.map +1 -0
- package/dist/components/internal/HiddenInput.mjs +88 -0
- package/dist/components/internal/HiddenInput.mjs.map +1 -0
- package/dist/components/layout/Accordion.cjs +2 -0
- package/dist/components/layout/Accordion.cjs.map +1 -0
- package/dist/components/layout/Accordion.mjs +236 -0
- package/dist/components/layout/Accordion.mjs.map +1 -0
- package/dist/components/layout/Card.cjs +2 -0
- package/dist/components/layout/Card.cjs.map +1 -0
- package/dist/components/layout/Card.mjs +121 -0
- package/dist/components/layout/Card.mjs.map +1 -0
- package/dist/components/layout/Carousel.cjs +2 -0
- package/dist/components/layout/Carousel.cjs.map +1 -0
- package/dist/components/layout/Carousel.mjs +205 -0
- package/dist/components/layout/Carousel.mjs.map +1 -0
- package/dist/components/layout/Flex.cjs +2 -0
- package/dist/components/layout/Flex.cjs.map +1 -0
- package/dist/components/layout/Flex.mjs +54 -0
- package/dist/components/layout/Flex.mjs.map +1 -0
- package/dist/components/layout/Grid.cjs +2 -0
- package/dist/components/layout/Grid.cjs.map +1 -0
- package/dist/components/layout/Grid.mjs +62 -0
- package/dist/components/layout/Grid.mjs.map +1 -0
- package/dist/components/layout/Overflow.cjs +2 -0
- package/dist/components/layout/Overflow.cjs.map +1 -0
- package/dist/components/layout/Overflow.mjs +269 -0
- package/dist/components/layout/Overflow.mjs.map +1 -0
- package/dist/components/layout/Stack.cjs +2 -0
- package/dist/components/layout/Stack.cjs.map +1 -0
- package/dist/components/layout/Stack.mjs +39 -0
- package/dist/components/layout/Stack.mjs.map +1 -0
- package/dist/components/layout/TabList.cjs +2 -0
- package/dist/components/layout/TabList.cjs.map +1 -0
- package/dist/components/layout/TabList.mjs +238 -0
- package/dist/components/layout/TabList.mjs.map +1 -0
- package/dist/components/layout/Tree.cjs +2 -0
- package/dist/components/layout/Tree.cjs.map +1 -0
- package/dist/components/layout/Tree.mjs +220 -0
- package/dist/components/layout/Tree.mjs.map +1 -0
- package/dist/components/layout/disclosureIds.cjs +2 -0
- package/dist/components/layout/disclosureIds.cjs.map +1 -0
- package/dist/components/layout/disclosureIds.mjs +12 -0
- package/dist/components/layout/disclosureIds.mjs.map +1 -0
- package/dist/components/motion/Presence.cjs +2 -0
- package/dist/components/motion/Presence.cjs.map +1 -0
- package/dist/components/motion/Presence.mjs +35 -0
- package/dist/components/motion/Presence.mjs.map +1 -0
- package/dist/components/navigation/Breadcrumb.cjs +2 -0
- package/dist/components/navigation/Breadcrumb.cjs.map +1 -0
- package/dist/components/navigation/Breadcrumb.mjs +144 -0
- package/dist/components/navigation/Breadcrumb.mjs.map +1 -0
- package/dist/components/navigation/Menu.cjs +2 -0
- package/dist/components/navigation/Menu.cjs.map +1 -0
- package/dist/components/navigation/Menu.context.cjs +2 -0
- package/dist/components/navigation/Menu.context.cjs.map +1 -0
- package/dist/components/navigation/Menu.context.mjs +82 -0
- package/dist/components/navigation/Menu.context.mjs.map +1 -0
- package/dist/components/navigation/Menu.group.cjs +2 -0
- package/dist/components/navigation/Menu.group.cjs.map +1 -0
- package/dist/components/navigation/Menu.group.mjs +58 -0
- package/dist/components/navigation/Menu.group.mjs.map +1 -0
- package/dist/components/navigation/Menu.items.cjs +2 -0
- package/dist/components/navigation/Menu.items.cjs.map +1 -0
- package/dist/components/navigation/Menu.items.mjs +127 -0
- package/dist/components/navigation/Menu.items.mjs.map +1 -0
- package/dist/components/navigation/Menu.link.cjs +2 -0
- package/dist/components/navigation/Menu.link.cjs.map +1 -0
- package/dist/components/navigation/Menu.link.mjs +41 -0
- package/dist/components/navigation/Menu.link.mjs.map +1 -0
- package/dist/components/navigation/Menu.mjs +27 -0
- package/dist/components/navigation/Menu.mjs.map +1 -0
- package/dist/components/navigation/Menu.popover.cjs +2 -0
- package/dist/components/navigation/Menu.popover.cjs.map +1 -0
- package/dist/components/navigation/Menu.popover.mjs +231 -0
- package/dist/components/navigation/Menu.popover.mjs.map +1 -0
- package/dist/components/navigation/Menu.root.cjs +2 -0
- package/dist/components/navigation/Menu.root.cjs.map +1 -0
- package/dist/components/navigation/Menu.root.mjs +308 -0
- package/dist/components/navigation/Menu.root.mjs.map +1 -0
- package/dist/components/navigation/Menu.selectable.cjs +2 -0
- package/dist/components/navigation/Menu.selectable.cjs.map +1 -0
- package/dist/components/navigation/Menu.selectable.mjs +89 -0
- package/dist/components/navigation/Menu.selectable.mjs.map +1 -0
- package/dist/components/navigation/Menu.shared.cjs +2 -0
- package/dist/components/navigation/Menu.shared.cjs.map +1 -0
- package/dist/components/navigation/Menu.shared.mjs +23 -0
- package/dist/components/navigation/Menu.shared.mjs.map +1 -0
- package/dist/components/navigation/Menu.splitGroup.cjs +2 -0
- package/dist/components/navigation/Menu.splitGroup.cjs.map +1 -0
- package/dist/components/navigation/Menu.splitGroup.mjs +51 -0
- package/dist/components/navigation/Menu.splitGroup.mjs.map +1 -0
- package/dist/components/navigation/Menu.trigger.cjs +2 -0
- package/dist/components/navigation/Menu.trigger.cjs.map +1 -0
- package/dist/components/navigation/Menu.trigger.mjs +79 -0
- package/dist/components/navigation/Menu.trigger.mjs.map +1 -0
- package/dist/components/navigation/Nav.cjs +2 -0
- package/dist/components/navigation/Nav.cjs.map +1 -0
- package/dist/components/navigation/Nav.mjs +276 -0
- package/dist/components/navigation/Nav.mjs.map +1 -0
- package/dist/components/navigation/Pagination.cjs +2 -0
- package/dist/components/navigation/Pagination.cjs.map +1 -0
- package/dist/components/navigation/Pagination.mjs +110 -0
- package/dist/components/navigation/Pagination.mjs.map +1 -0
- package/dist/components/navigation/Stepper.cjs +2 -0
- package/dist/components/navigation/Stepper.cjs.map +1 -0
- package/dist/components/navigation/Stepper.mjs +204 -0
- package/dist/components/navigation/Stepper.mjs.map +1 -0
- package/dist/components/overlays/Dialog.cjs +2 -0
- package/dist/components/overlays/Dialog.cjs.map +1 -0
- package/dist/components/overlays/Dialog.mjs +180 -0
- package/dist/components/overlays/Dialog.mjs.map +1 -0
- package/dist/components/overlays/Dialog.shared.cjs +2 -0
- package/dist/components/overlays/Dialog.shared.cjs.map +1 -0
- package/dist/components/overlays/Dialog.shared.mjs +227 -0
- package/dist/components/overlays/Dialog.shared.mjs.map +1 -0
- package/dist/components/overlays/Drawer.cjs +2 -0
- package/dist/components/overlays/Drawer.cjs.map +1 -0
- package/dist/components/overlays/Drawer.mjs +192 -0
- package/dist/components/overlays/Drawer.mjs.map +1 -0
- package/dist/components/overlays/Popover.cjs +2 -0
- package/dist/components/overlays/Popover.cjs.map +1 -0
- package/dist/components/overlays/Popover.mjs +365 -0
- package/dist/components/overlays/Popover.mjs.map +1 -0
- package/dist/components/overlays/Popover.shared.cjs +2 -0
- package/dist/components/overlays/Popover.shared.cjs.map +1 -0
- package/dist/components/overlays/Popover.shared.mjs +182 -0
- package/dist/components/overlays/Popover.shared.mjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.cjs +2 -0
- package/dist/components/overlays/TeachingPopover.cjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.mjs +181 -0
- package/dist/components/overlays/TeachingPopover.mjs.map +1 -0
- package/dist/components/overlays/Tooltip.cjs +2 -0
- package/dist/components/overlays/Tooltip.cjs.map +1 -0
- package/dist/components/overlays/Tooltip.mjs +160 -0
- package/dist/components/overlays/Tooltip.mjs.map +1 -0
- package/dist/components/portal/Portal.cjs +2 -0
- package/dist/components/portal/Portal.cjs.map +1 -0
- package/dist/components/portal/Portal.mjs +45 -0
- package/dist/components/portal/Portal.mjs.map +1 -0
- package/dist/components/provider/WaveProvider.cjs +2 -0
- package/dist/components/provider/WaveProvider.cjs.map +1 -0
- package/dist/components/provider/WaveProvider.mjs +51 -0
- package/dist/components/provider/WaveProvider.mjs.map +1 -0
- package/dist/components/table/DataGrid.cjs +2 -0
- package/dist/components/table/DataGrid.cjs.map +1 -0
- package/dist/components/table/DataGrid.mjs +489 -0
- package/dist/components/table/DataGrid.mjs.map +1 -0
- package/dist/components/table/Table.cjs +2 -0
- package/dist/components/table/Table.cjs.map +1 -0
- package/dist/components/table/Table.mjs +99 -0
- package/dist/components/table/Table.mjs.map +1 -0
- package/dist/components/table/useGridNavigation.cjs +2 -0
- package/dist/components/table/useGridNavigation.cjs.map +1 -0
- package/dist/components/table/useGridNavigation.mjs +336 -0
- package/dist/components/table/useGridNavigation.mjs.map +1 -0
- package/dist/components/typography/Text.cjs +2 -0
- package/dist/components/typography/Text.cjs.map +1 -0
- package/dist/components/typography/Text.mjs +38 -0
- package/dist/components/typography/Text.mjs.map +1 -0
- package/dist/hooks/useAnnounce.cjs +2 -0
- package/dist/hooks/useAnnounce.cjs.map +1 -0
- package/dist/hooks/useAnnounce.mjs +88 -0
- package/dist/hooks/useAnnounce.mjs.map +1 -0
- package/dist/hooks/useCheckedValues.cjs +2 -0
- package/dist/hooks/useCheckedValues.cjs.map +1 -0
- package/dist/hooks/useCheckedValues.mjs +102 -0
- package/dist/hooks/useCheckedValues.mjs.map +1 -0
- package/dist/hooks/useContextMenuAnchor.cjs +2 -0
- package/dist/hooks/useContextMenuAnchor.cjs.map +1 -0
- package/dist/hooks/useContextMenuAnchor.mjs +132 -0
- package/dist/hooks/useContextMenuAnchor.mjs.map +1 -0
- package/dist/hooks/useControllable.cjs +2 -0
- package/dist/hooks/useControllable.cjs.map +1 -0
- package/dist/hooks/useControllable.mjs +37 -0
- package/dist/hooks/useControllable.mjs.map +1 -0
- package/dist/hooks/useDirection.cjs +2 -0
- package/dist/hooks/useDirection.cjs.map +1 -0
- package/dist/hooks/useDirection.mjs +57 -0
- package/dist/hooks/useDirection.mjs.map +1 -0
- package/dist/hooks/useDismiss.cjs +2 -0
- package/dist/hooks/useDismiss.cjs.map +1 -0
- package/dist/hooks/useDismiss.mjs +57 -0
- package/dist/hooks/useDismiss.mjs.map +1 -0
- package/dist/hooks/useEventCallback.cjs +2 -0
- package/dist/hooks/useEventCallback.cjs.map +1 -0
- package/dist/hooks/useEventCallback.mjs +16 -0
- package/dist/hooks/useEventCallback.mjs.map +1 -0
- package/dist/hooks/useFieldControl.cjs +2 -0
- package/dist/hooks/useFieldControl.cjs.map +1 -0
- package/dist/hooks/useFieldControl.mjs +62 -0
- package/dist/hooks/useFieldControl.mjs.map +1 -0
- package/dist/hooks/useFocusTrap.cjs +2 -0
- package/dist/hooks/useFocusTrap.cjs.map +1 -0
- package/dist/hooks/useFocusTrap.mjs +266 -0
- package/dist/hooks/useFocusTrap.mjs.map +1 -0
- package/dist/hooks/useFormReset.cjs +2 -0
- package/dist/hooks/useFormReset.cjs.map +1 -0
- package/dist/hooks/useFormReset.mjs +33 -0
- package/dist/hooks/useFormReset.mjs.map +1 -0
- package/dist/hooks/useHoverIntent.cjs +2 -0
- package/dist/hooks/useHoverIntent.cjs.map +1 -0
- package/dist/hooks/useHoverIntent.mjs +201 -0
- package/dist/hooks/useHoverIntent.mjs.map +1 -0
- package/dist/hooks/useId.cjs +2 -0
- package/dist/hooks/useId.cjs.map +1 -0
- package/dist/hooks/useId.mjs +11 -0
- package/dist/hooks/useId.mjs.map +1 -0
- package/dist/hooks/useIsClient.cjs +2 -0
- package/dist/hooks/useIsClient.cjs.map +1 -0
- package/dist/hooks/useIsClient.mjs +19 -0
- package/dist/hooks/useIsClient.mjs.map +1 -0
- package/dist/hooks/useListbox.cjs +2 -0
- package/dist/hooks/useListbox.cjs.map +1 -0
- package/dist/hooks/useListbox.mjs +492 -0
- package/dist/hooks/useListbox.mjs.map +1 -0
- package/dist/hooks/useMergedRefs.cjs +2 -0
- package/dist/hooks/useMergedRefs.cjs.map +1 -0
- package/dist/hooks/useMergedRefs.mjs +57 -0
- package/dist/hooks/useMergedRefs.mjs.map +1 -0
- package/dist/hooks/useModalIsolation.cjs +2 -0
- package/dist/hooks/useModalIsolation.cjs.map +1 -0
- package/dist/hooks/useModalIsolation.mjs +87 -0
- package/dist/hooks/useModalIsolation.mjs.map +1 -0
- package/dist/hooks/useModalLayer.cjs +2 -0
- package/dist/hooks/useModalLayer.cjs.map +1 -0
- package/dist/hooks/useModalLayer.mjs +30 -0
- package/dist/hooks/useModalLayer.mjs.map +1 -0
- package/dist/hooks/usePopupPosition.cjs +2 -0
- package/dist/hooks/usePopupPosition.cjs.map +1 -0
- package/dist/hooks/usePopupPosition.mjs +117 -0
- package/dist/hooks/usePopupPosition.mjs.map +1 -0
- package/dist/hooks/usePrefersReducedMotion.cjs +2 -0
- package/dist/hooks/usePrefersReducedMotion.cjs.map +1 -0
- package/dist/hooks/usePrefersReducedMotion.mjs +24 -0
- package/dist/hooks/usePrefersReducedMotion.mjs.map +1 -0
- package/dist/hooks/usePresence.cjs +2 -0
- package/dist/hooks/usePresence.cjs.map +1 -0
- package/dist/hooks/usePresence.mjs +136 -0
- package/dist/hooks/usePresence.mjs.map +1 -0
- package/dist/hooks/usePreserveFocus.cjs +2 -0
- package/dist/hooks/usePreserveFocus.cjs.map +1 -0
- package/dist/hooks/usePreserveFocus.mjs +50 -0
- package/dist/hooks/usePreserveFocus.mjs.map +1 -0
- package/dist/hooks/useRestoreFocus.cjs +2 -0
- package/dist/hooks/useRestoreFocus.cjs.map +1 -0
- package/dist/hooks/useRestoreFocus.mjs +271 -0
- package/dist/hooks/useRestoreFocus.mjs.map +1 -0
- package/dist/hooks/useRovingTabIndex.cjs +2 -0
- package/dist/hooks/useRovingTabIndex.cjs.map +1 -0
- package/dist/hooks/useRovingTabIndex.mjs +389 -0
- package/dist/hooks/useRovingTabIndex.mjs.map +1 -0
- package/dist/hooks/useScrollLock.cjs +2 -0
- package/dist/hooks/useScrollLock.cjs.map +1 -0
- package/dist/hooks/useScrollLock.mjs +71 -0
- package/dist/hooks/useScrollLock.mjs.map +1 -0
- package/dist/hooks/useTriggerElement.cjs +2 -0
- package/dist/hooks/useTriggerElement.cjs.map +1 -0
- package/dist/hooks/useTriggerElement.mjs +126 -0
- package/dist/hooks/useTriggerElement.mjs.map +1 -0
- package/dist/hooks/useTypeahead.cjs +2 -0
- package/dist/hooks/useTypeahead.cjs.map +1 -0
- package/dist/hooks/useTypeahead.mjs +38 -0
- package/dist/hooks/useTypeahead.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +9099 -0
- package/dist/index.d.ts +7688 -1027
- package/dist/index.mjs +91 -5695
- package/dist/lib/aria.cjs +2 -0
- package/dist/lib/aria.cjs.map +1 -0
- package/dist/lib/aria.mjs +29 -0
- package/dist/lib/aria.mjs.map +1 -0
- package/dist/lib/children.cjs +2 -0
- package/dist/lib/children.cjs.map +1 -0
- package/dist/lib/children.mjs +37 -0
- package/dist/lib/children.mjs.map +1 -0
- package/dist/lib/cn.cjs +2 -0
- package/dist/lib/cn.cjs.map +1 -0
- package/dist/lib/cn.mjs +64 -0
- package/dist/lib/cn.mjs.map +1 -0
- package/dist/lib/composeEventHandlers.cjs +2 -0
- package/dist/lib/composeEventHandlers.cjs.map +1 -0
- package/dist/lib/composeEventHandlers.mjs +11 -0
- package/dist/lib/composeEventHandlers.mjs.map +1 -0
- package/dist/lib/dev.cjs +2 -0
- package/dist/lib/dev.cjs.map +1 -0
- package/dist/lib/dev.mjs +42 -0
- package/dist/lib/dev.mjs.map +1 -0
- package/dist/lib/direction.cjs +2 -0
- package/dist/lib/direction.cjs.map +1 -0
- package/dist/lib/direction.mjs +35 -0
- package/dist/lib/direction.mjs.map +1 -0
- package/dist/lib/events.cjs +2 -0
- package/dist/lib/events.cjs.map +1 -0
- package/dist/lib/events.mjs +31 -0
- package/dist/lib/events.mjs.map +1 -0
- package/dist/lib/focus.cjs +2 -0
- package/dist/lib/focus.cjs.map +1 -0
- package/dist/lib/focus.mjs +119 -0
- package/dist/lib/focus.mjs.map +1 -0
- package/dist/lib/globalRegistry.cjs +2 -0
- package/dist/lib/globalRegistry.cjs.map +1 -0
- package/dist/lib/globalRegistry.mjs +13 -0
- package/dist/lib/globalRegistry.mjs.map +1 -0
- package/dist/lib/icons.cjs +2 -0
- package/dist/lib/icons.cjs.map +1 -0
- package/dist/lib/icons.mjs +254 -0
- package/dist/lib/icons.mjs.map +1 -0
- package/dist/lib/labelInName.cjs +2 -0
- package/dist/lib/labelInName.cjs.map +1 -0
- package/dist/lib/labelInName.mjs +54 -0
- package/dist/lib/labelInName.mjs.map +1 -0
- package/dist/lib/layers.cjs +2 -0
- package/dist/lib/layers.cjs.map +1 -0
- package/dist/lib/layers.mjs +224 -0
- package/dist/lib/layers.mjs.map +1 -0
- package/dist/lib/mergeProps.cjs +2 -0
- package/dist/lib/mergeProps.cjs.map +1 -0
- package/dist/lib/mergeProps.mjs +21 -0
- package/dist/lib/mergeProps.mjs.map +1 -0
- package/dist/lib/mergeRefs.cjs +2 -0
- package/dist/lib/mergeRefs.cjs.map +1 -0
- package/dist/lib/mergeRefs.mjs +29 -0
- package/dist/lib/mergeRefs.mjs.map +1 -0
- package/dist/lib/renderTrigger.cjs +2 -0
- package/dist/lib/renderTrigger.cjs.map +1 -0
- package/dist/lib/renderTrigger.mjs +29 -0
- package/dist/lib/renderTrigger.mjs.map +1 -0
- package/dist/lib/slot.cjs +2 -0
- package/dist/lib/slot.cjs.map +1 -0
- package/dist/lib/slot.mjs +122 -0
- package/dist/lib/slot.mjs.map +1 -0
- package/dist/lib/styles.cjs +2 -0
- package/dist/lib/styles.cjs.map +1 -0
- package/dist/lib/styles.mjs +16 -0
- package/dist/lib/styles.mjs.map +1 -0
- package/dist/lib/theme.cjs +2 -0
- package/dist/lib/theme.cjs.map +1 -0
- package/dist/lib/theme.mjs +16 -0
- package/dist/lib/theme.mjs.map +1 -0
- package/dist/preflight.css +2 -0
- package/dist/styles.css +2 -0
- package/package.json +149 -100
- package/src/styles/animations.css +7 -39
- package/src/styles/base.css +103 -0
- package/src/styles/globals.css +10 -22
- package/src/styles/legacy-tokens.css +184 -0
- package/src/styles/preflight.css +7 -0
- package/src/styles/styles.css +32 -0
- package/src/styles/tailwind.css +17 -0
- package/src/styles/tokens.css +561 -221
- package/src/styles/variants.css +29 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../../lib/cn.mjs";
|
|
3
|
+
import { warnOnce as t } from "../../lib/dev.mjs";
|
|
4
|
+
import { materialiseSlotContent as n, renderSlot as r, slotRendersContent as i } from "../../lib/slot.mjs";
|
|
5
|
+
import { Button as a } from "./Button.mjs";
|
|
6
|
+
import { ChevronDownIcon as o } from "../../lib/icons.mjs";
|
|
7
|
+
import { unwrapButtonGlyph as s } from "./Button.slots.mjs";
|
|
8
|
+
import * as c from "react";
|
|
9
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
10
|
+
//#region src/components/button/MenuButton.tsx
|
|
11
|
+
var d = {
|
|
12
|
+
"extra-small": "min-w-0 px-1.5",
|
|
13
|
+
small: "min-w-0 px-1.5",
|
|
14
|
+
medium: "min-w-0 px-2",
|
|
15
|
+
large: "min-w-0 px-2",
|
|
16
|
+
"extra-large": "min-w-0 px-3"
|
|
17
|
+
}, f = ({ appearance: f = "outline", size: p = "medium", icon: m, menuIcon: h, expanded: g, className: _, children: v, "aria-haspopup": y, "aria-expanded": b, ...x }) => {
|
|
18
|
+
let { glyph: S, button: C } = s(h);
|
|
19
|
+
c.useEffect(() => {
|
|
20
|
+
C && t("MenuButton:menuIcon-button", `MenuButton: \`menuIcon\` received ${C}; its children render as the menu indicator and its props were dropped (buttons cannot be nested). Pass icon content instead, e.g. \`menuIcon={<MyIcon />}\`.`);
|
|
21
|
+
}, [C]);
|
|
22
|
+
let w = h == null || C !== null && !i(S) ? /* @__PURE__ */ l(o, { className: "shrink-0" }) : i(S) ? r(S, "span", "inline-flex shrink-0 items-center", { "aria-hidden": !0 }) : null, T = n(v), E = w !== null && !i(T), D = x["aria-label"], O = x["aria-labelledby"], k = x.title;
|
|
23
|
+
return c.useEffect(() => {
|
|
24
|
+
E && !D && !O && !k && t("MenuButton:icon-only-name", "MenuButton: an icon-only menu button has no accessible name. Pass `aria-label`, `aria-labelledby` or `title` (the icon and the menu indicator are decorative and hidden from assistive technology).");
|
|
25
|
+
}, [
|
|
26
|
+
E,
|
|
27
|
+
D,
|
|
28
|
+
O,
|
|
29
|
+
k
|
|
30
|
+
]), /* @__PURE__ */ u(a, {
|
|
31
|
+
...x,
|
|
32
|
+
"aria-haspopup": y ?? "menu",
|
|
33
|
+
"aria-expanded": b ?? g,
|
|
34
|
+
appearance: f,
|
|
35
|
+
size: p,
|
|
36
|
+
icon: m,
|
|
37
|
+
className: e("gap-1.5", E && d[p], _),
|
|
38
|
+
children: [T, w]
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
f.displayName = "MenuButton";
|
|
42
|
+
//#endregion
|
|
43
|
+
export { f as MenuButton };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=MenuButton.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MenuButton.mjs","names":["React","unlabelledSizeClasses","MenuButton","ariaHasPopup","ariaExpanded","props","menuIconButton","unwrapButtonGlyph","menuIcon","warnOnce","indicator","slotRendersContent","glyph","ChevronDownIcon","renderSlot","label","materialiseSlotContent","children","unlabelled","ariaLabel","ariaLabelledBy","title","Button","expanded","cn","size","className"],"sources":["../../../src/components/button/MenuButton.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { warnOnce } from '../../lib/dev';\nimport { ChevronDownIcon } from '../../lib/icons';\nimport { materialiseSlotContent, renderSlot, slotRendersContent } from '../../lib/slot';\nimport type { Size, Appearance, Slot } from '../../lib/types';\nimport { Button } from './Button';\nimport { unwrapButtonGlyph } from './Button.slots';\n\n/** Properties for the MenuButton component. */\nexport interface MenuButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style variant.\n * @default 'outline'\n */\n appearance?: Appearance;\n /** Size affecting height, padding and font size.\n * @default 'medium'\n */\n size?: Size;\n /**\n * Icon slot rendered before the label. Decorative: it renders with `aria-hidden=\"true\"` (a slot\n * object can override it). A menu button without a label (only the icon and/or the indicator)\n * needs `aria-label`, `aria-labelledby` or `title`.\n */\n icon?: Slot<'span'>;\n /**\n * Custom menu indicator rendered after the label, in place of the default chevron. Decorative\n * (`aria-hidden=\"true\"` unless a slot object overrides it). `false` hides the indicator, as does\n * any value that renders nothing (`true`, `''`, an empty array or Fragment, e.g. from\n * `menuIcon={cond && <X />}`); `null`/`undefined` keep the default chevron. A `<button>` or\n * `Button` element, or a slot object whose `as` is one, is not nested inside the menu button:\n * its children become the indicator (the chevron when they render nothing), its props (`icon`\n * included) are dropped, and a development warning says so.\n */\n menuIcon?: Slot<'span'>;\n /**\n * Whether the associated menu is open (`aria-expanded`). Leave it unset when the button is\n * wrapped in `Menu.Trigger`, which supplies `aria-expanded` itself.\n */\n expanded?: boolean;\n /**\n * Marks the menu button unavailable but keeps it focusable and in the tab order (see\n * `Button.disabledFocusable`): `aria-disabled=\"true\"`, `data-disabled` and\n * `data-disabled-focusable` instead of the native `disabled` attribute. Clicks, Enter and Space\n * are prevented and do not call `onClick`; other keys still reach `onKeyDown`, and\n * `Menu.Trigger` does not open its menu from an `aria-disabled` trigger. Wins over `disabled`\n * when both are set. In a `Toolbar` it stays in the arrow-key order.\n * @default false\n */\n disabledFocusable?: boolean;\n /** Ref to the rendered `<button>`. */\n ref?: React.Ref<HTMLButtonElement>;\n}\n\n/**\n * Minimum width and horizontal padding per size of a menu button without a label (an icon, the\n * menu indicator or both): no minimum width and the padding of SplitButton's menu half. Button\n * counts the indicator as content, so it would give such a button the labelled 96px minimum width.\n */\nconst unlabelledSizeClasses: Record<Size, string> = {\n 'extra-small': 'min-w-0 px-1.5',\n small: 'min-w-0 px-1.5',\n medium: 'min-w-0 px-2',\n large: 'min-w-0 px-2',\n 'extra-large': 'min-w-0 px-3',\n};\n\n/**\n * A button that opens a menu: {@link Button} with `aria-haspopup=\"menu\"`, `aria-expanded` and a\n * trailing chevron. Same appearances, sizes, `type=\"button\"` default and decorative icon slot as\n * Button. Without a label (only an icon and/or the chevron) it has no minimum width, and it warns\n * in development when it also has no `aria-label`, `aria-labelledby` or `title`.\n *\n * Use it as the child of `Menu.Trigger`, which supplies `id`, `aria-expanded`, `aria-controls`,\n * the open/keyboard handlers and the ref. A defined `aria-haspopup`/`aria-expanded` prop wins over\n * the built-in `\"menu\"` and `expanded` defaults, so the trigger's live state always wins; an\n * `undefined` or `null` one (a wrapper forwarding its own unset props) keeps the defaults.\n *\n * @example\n * <Menu>\n * <Menu.Trigger><MenuButton>Actions</MenuButton></Menu.Trigger>\n * <Menu.Popover>…</Menu.Popover>\n * </Menu>\n */\nexport const MenuButton = ({\n appearance = 'outline',\n size = 'medium',\n icon,\n menuIcon,\n expanded,\n className,\n children,\n 'aria-haspopup': ariaHasPopup,\n 'aria-expanded': ariaExpanded,\n ...props\n}: MenuButtonProps) => {\n // The indicator sits inside the button: a button passed as `menuIcon` is unwrapped (its children\n // are the indicator), never nested (C-SLOTS).\n const { glyph, button: menuIconButton } = unwrapButtonGlyph(menuIcon);\n React.useEffect(() => {\n if (menuIconButton) {\n warnOnce(\n 'MenuButton:menuIcon-button',\n `MenuButton: \\`menuIcon\\` received ${menuIconButton}; its children render as the menu indicator and its props were dropped (buttons cannot be nested). Pass icon content instead, e.g. \\`menuIcon={<MyIcon />}\\`.`,\n );\n }\n }, [menuIconButton]);\n\n // `menuIcon` follows the `icon` slot rule: unset keeps the chevron, a value that renders nothing\n // (`false`, `true`, `''`, an empty array, Set or Fragment) hides the indicator without leaving an\n // empty `aria-hidden` span behind. An unwrapped button whose children render nothing keeps the\n // chevron, as for a picker's `expandIcon`.\n const indicator =\n menuIcon == null || (menuIconButton !== null && !slotRendersContent(glyph)) ? (\n <ChevronDownIcon className=\"shrink-0\" />\n ) : slotRendersContent(glyph) ? (\n renderSlot(glyph, 'span', 'inline-flex shrink-0 items-center', { 'aria-hidden': true })\n ) : null;\n\n // While the indicator renders, Button counts it as content: it sizes the button as labelled and\n // skips its icon-only name check. A menu button whose only content is decorative (an icon, the\n // indicator or both) is therefore sized and checked here. Without an indicator\n // (`menuIcon={false}`, `''`, …) Button handles both by itself: checking here too would log the\n // same problem twice.\n // A generator label is read once by the check; its items are what renders.\n const label = materialiseSlotContent(children);\n const unlabelled = indicator !== null && !slotRendersContent(label);\n const ariaLabel = props['aria-label'];\n const ariaLabelledBy = props['aria-labelledby'];\n const title = props.title;\n React.useEffect(() => {\n if (unlabelled && !ariaLabel && !ariaLabelledBy && !title) {\n warnOnce(\n 'MenuButton:icon-only-name',\n 'MenuButton: an icon-only menu button has no accessible name. Pass `aria-label`, `aria-labelledby` or `title` (the icon and the menu indicator are decorative and hidden from assistive technology).',\n );\n }\n }, [unlabelled, ariaLabel, ariaLabelledBy, title]);\n\n // `aria-haspopup`/`aria-expanded` defaults apply wherever the consumer's value is `undefined` or\n // `null` (as Button does for `type`, `role` and `tabIndex`), so a forwarded unset prop keeps them.\n return (\n <Button\n {...props}\n aria-haspopup={ariaHasPopup ?? 'menu'}\n aria-expanded={ariaExpanded ?? expanded}\n appearance={appearance}\n size={size}\n icon={icon}\n className={cn('gap-1.5', unlabelled && unlabelledSizeClasses[size], className)}\n >\n {label}\n {indicator}\n </Button>\n );\n};\n\nMenuButton.displayName = 'MenuButton';\n"],"mappings":";;;;;;;;;;AA2DA,IAAMC,IAA8C;CAClD,eAAe;CACf,OAAO;CACP,QAAQ;CACR,OAAO;CACP,eAAe;AACjB,GAmBaC,KAAc,EACzB,gBAAa,WACb,UAAO,UACP,SACA,aACA,aACA,cACA,aACA,iBAAiBC,GACjB,iBAAiBC,GACjB,GAAGC,QACkB;CAGrB,IAAM,EAAE,UAAO,QAAQC,MAAmBC,EAAkBC,CAAQ;CACpE,EAAM,gBAAgB;EACpB,AAAIF,KACFG,EACE,8BACA,qCAAqCH,EAAe,8JACtD;CAEJ,GAAG,CAACA,CAAc,CAAC;CAMnB,IAAMI,IACJF,KAAY,QAASF,MAAmB,QAAQ,CAACK,EAAmBC,CAAK,IACvE,kBAACC,GAAD,EAAiB,WAAU,WAAY,CAAA,IACrCF,EAAmBC,CAAK,IAC1BE,EAAWF,GAAO,QAAQ,qCAAqC,EAAE,eAAe,GAAK,CAAC,IACpF,MAQAG,IAAQC,EAAuBC,CAAQ,GACvCC,IAAaR,MAAc,QAAQ,CAACC,EAAmBI,CAAK,GAC5DI,IAAYd,EAAM,eAClBe,IAAiBf,EAAM,oBACvBgB,IAAQhB,EAAM;CAYpB,OAXAL,EAAM,gBAAgB;EACpB,AAAIkB,KAAc,CAACC,KAAa,CAACC,KAAkB,CAACC,KAClDZ,EACE,6BACA,qMACF;CAEJ,GAAG;EAACS;EAAYC;EAAWC;EAAgBC;CAAK,CAAC,GAK/C,kBAACC,GAAD;EACE,GAAIjB;EACJ,iBAAeF,KAAgB;EAC/B,iBAAeC,KAAgBmB;EACnB;EACN;EACA;EACN,WAAWC,EAAG,WAAWN,KAAcjB,EAAsBwB,IAAOC,CAAS;EAP/E,UAAA,CASGX,GACAL,CACK;;AAEZ;AAEA,EAAW,cAAc"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/slot.cjs"),i=require("./Button.cjs"),a=require("../../lib/icons.cjs"),o=require("../../lib/mergeProps.cjs"),s=require("./Button.slots.cjs");let c=require("react");c=e.__toESM(c,1);let l=require("react/jsx-runtime");var u={"extra-small":`w-auto min-w-6 min-h-6 px-1.5`,small:`w-auto min-w-6 min-h-6 px-1.5`,medium:`w-auto min-w-6 min-h-6 px-2`,large:`w-auto min-w-6 min-h-6 px-2`,"extra-large":`w-auto min-w-6 min-h-6 px-3`},d={primary:`border-s-primary-foreground/30`,outline:`border-s-stroke`,subtle:`border-s-stroke`,transparent:`border-s-stroke`},f=`relative min-h-6 focus-visible:z-10`,p=({appearance:e=`outline`,size:p=`medium`,disabled:m=!1,disabledFocusable:h=!1,icon:g,iconPosition:_,menuIcon:v,className:y,children:b,onClick:x,onMenuClick:S,menuButtonLabel:C=`More options`,menuButtonProps:w,primaryActionButtonProps:T,"aria-describedby":E,role:D,ref:O,...k})=>{let A=o.mergeProps({"aria-describedby":E,onClick:x},T),j=o.mergeProps({"aria-label":C,"aria-haspopup":`menu`,onClick:S},w),M=h||!!A.disabledFocusable,N=h||!!j.disabledFocusable,{glyph:P,button:F}=s.unwrapButtonGlyph(v),I=r.slotRendersContent(P),L=F===null&&v!=null&&!I;return c.useEffect(()=>{L&&n.warnOnce(`SplitButton:menuIcon-empty`,"SplitButton: `menuIcon` renders nothing, so the menu button shows the default chevron. Unlike `MenuButton`, a SplitButton always shows a menu indicator: pass an icon, or leave `menuIcon` unset.")},[L]),c.useEffect(()=>{F&&n.warnOnce(`SplitButton:menuIcon-button`,`SplitButton: \`menuIcon\` received ${F}; its children render as the glyph of the menu button and its props were dropped (buttons cannot be nested). Pass icon content instead, e.g. \`menuIcon={<MyIcon />}\`.`)},[F]),(0,l.jsxs)(`div`,{ref:O,...k,role:D??`group`,className:t.cn(`inline-flex items-stretch`,y),children:[(0,l.jsx)(i.Button,{...A,appearance:e,size:p,disabled:!M&&(m||!!A.disabled),disabledFocusable:M,icon:g,iconPosition:_,className:t.cn(f,`rounded-e-none border-e-0`,A.className),children:b}),(0,l.jsx)(i.Button,{...j,appearance:e,size:p,disabled:!N&&(m||!!j.disabled),disabledFocusable:N,icon:I?P:(0,l.jsx)(a.ChevronDownIcon,{}),className:t.cn(f,u[p],`rounded-s-none`,d[e],j.className)})]})};p.displayName=`SplitButton`,exports.SplitButton=p;
|
|
2
|
+
//# sourceMappingURL=SplitButton.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SplitButton.cjs","names":["mergeProps","unwrapButtonGlyph","slotRendersContent","cn","Button","ChevronDownIcon","require_runtime","require_cn","require_dev","require_slot","require_Button","require_icons","require_mergeProps","require_Button_slots","react","react_jsx_runtime","menuButtonSizeClasses","separatorClasses","halfClasses","SplitButton","ariaDescribedBy","props","primary","primaryActionButtonProps","menu","menuButtonLabel","onMenuClick","menuButtonProps","primaryFocusable","disabledFocusable","menuFocusable","menuGlyph","menuIconButton","menuIcon","menuIconRenders","menuIconEmpty","role","className","disabled","size","appearance"],"sources":["../../../src/components/button/SplitButton.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { warnOnce } from '../../lib/dev';\nimport { ChevronDownIcon } from '../../lib/icons';\nimport { mergeProps } from '../../lib/mergeProps';\nimport { slotRendersContent } from '../../lib/slot';\nimport type { Size, Appearance, IconPosition, Slot } from '../../lib/types';\nimport { Button } from './Button';\nimport { unwrapButtonGlyph } from './Button.slots';\n\n/**\n * Props for one half of a SplitButton (`menuButtonProps`, `primaryActionButtonProps`): native\n * `<button>` attributes, `data-*` attributes and `ref`. They are merged onto the built-in props\n * of that half: handlers are composed (yours run first), `className` is merged, id lists are\n * joined and any other value you pass wins.\n */\nexport interface SplitButtonMenuButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /**\n * Makes only this half unavailable but focusable (see `SplitButton.disabledFocusable`, which\n * affects both halves). For each half, focusable-disabled wins over natively disabled.\n * @default false\n */\n disabledFocusable?: boolean;\n /** Ref to the `<button>` element of this half. */\n ref?: React.Ref<HTMLButtonElement>;\n /** Any `data-*` attribute. */\n [dataAttribute: `data-${string}`]: string | number | boolean | undefined;\n}\n\n/** Props for the primary action half of a SplitButton (same shape as the menu half). */\nexport type SplitButtonPrimaryActionButtonProps = SplitButtonMenuButtonProps;\n\n/** Properties for the SplitButton component. */\nexport interface SplitButtonProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onClick'> {\n /**\n * Disables both buttons. A half's own `disabled` (`primaryActionButtonProps`,\n * `menuButtonProps`) disables only that half.\n * @default false\n */\n disabled?: boolean;\n /**\n * Makes both halves unavailable but focusable (see `Button.disabledFocusable`): each half\n * renders `aria-disabled=\"true\"`, `data-disabled` and `data-disabled-focusable`, stays in the tab\n * order, and neither `onClick` nor the menu opens. A half's own `disabledFocusable` (in\n * `primaryActionButtonProps`/`menuButtonProps`) affects only that half. For each half,\n * focusable-disabled wins over natively disabled: the half is focusable-disabled when the root's\n * or its own `disabledFocusable` is set; otherwise it is natively disabled when the root's or its\n * own `disabled` is set.\n * @default false\n */\n disabledFocusable?: boolean;\n /**\n * Icon of the primary action, decorative (`aria-hidden`). For an icon-only primary action pass\n * `primaryActionButtonProps={{ 'aria-label': '…' }}`.\n */\n icon?: Slot<'span'>;\n /**\n * Where the primary action's icon renders: before its label (the inline start) or after it.\n * Has no effect on an icon-only primary action. The menu half is not affected.\n * @default 'before'\n */\n iconPosition?: IconPosition;\n /**\n * Replaces the chevron of the menu half (decorative, `aria-hidden`). The menu half always shows\n * an indicator: `null` and `undefined` keep the default chevron, and so does a value that renders\n * nothing (`false`, `''`, an empty array), which also logs a development warning. Unlike\n * `MenuButton.menuIcon`, a value that renders nothing does not hide the indicator. A `<button>`\n * or `Button` element, or a slot object whose `as` is one, is not nested inside the menu half:\n * its children become the glyph (the chevron when they render nothing), its props (`icon`\n * included) are dropped, and a development warning says so.\n */\n menuIcon?: Slot<'span'>;\n /** Visual style variant.\n * @default 'outline'\n */\n appearance?: Appearance;\n /** Size affecting height, padding and font size.\n * @default 'medium'\n */\n size?: Size;\n /** Click handler for the primary action button. */\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n /** Click handler for the menu (chevron) button. */\n onMenuClick?: React.MouseEventHandler<HTMLButtonElement>;\n /**\n * Accessible name of the menu button (it shows only a chevron). Localize it.\n * @default 'More options'\n */\n menuButtonLabel?: string;\n /**\n * Props for the menu button: `aria-expanded`, `aria-controls`, `id`, handlers (`onKeyDown` for\n * ArrowDown/ArrowUp), `ref` for focus restoration, … Pass the render-prop props of\n * `Menu.Trigger` here to open a Menu from the chevron.\n */\n menuButtonProps?: SplitButtonMenuButtonProps;\n /** Props for the primary action button (`ref`, `title`, handlers, …). */\n primaryActionButtonProps?: SplitButtonPrimaryActionButtonProps;\n /** Ref to the wrapping `role=\"group\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/**\n * Menu button size per SplitButton size: at least 24×24 CSS px at every size (WCAG 2.5.8 target\n * size; the chevron shares an edge with the primary button, so the spacing exception does not\n * apply). Overrides the square icon-only sizing of `Button` (`w-*`, `px-0`).\n */\nconst menuButtonSizeClasses: Record<Size, string> = {\n 'extra-small': 'w-auto min-w-6 min-h-6 px-1.5',\n small: 'w-auto min-w-6 min-h-6 px-1.5',\n medium: 'w-auto min-w-6 min-h-6 px-2',\n large: 'w-auto min-w-6 min-h-6 px-2',\n 'extra-large': 'w-auto min-w-6 min-h-6 px-3',\n};\n\n/** The separator is the menu button's start border (logical, so it mirrors in RTL). */\nconst separatorClasses: Record<Appearance, string> = {\n primary: 'border-s-primary-foreground/30',\n outline: 'border-s-stroke',\n subtle: 'border-s-stroke',\n transparent: 'border-s-stroke',\n};\n\n/**\n * Keeps each half's focus ring above its neighbour. `min-h-6` keeps both halves as tall as the\n * 24px menu button target at the extra-small size.\n */\nconst halfClasses = 'relative min-h-6 focus-visible:z-10';\n\n/**\n * A primary action button joined to a menu button (chevron), e.g. Save + \"Save as…\" options.\n * Both halves are {@link Button}s with the shared appearances and sizes, inside a\n * `role=\"group\"` wrapper.\n *\n * - `ref`, `className`, `style`, `aria-label` and other props go to the group; `aria-describedby`\n * is routed to the primary button (so a Tooltip around the SplitButton describes the action).\n * - `primaryActionButtonProps` / `menuButtonProps` reach the two buttons; the menu button is\n * named by `menuButtonLabel` (default `'More options'`).\n * - The menu button is at least 24×24 px at every size, so an extra-small SplitButton is 24px tall.\n * - `icon`/`iconPosition` belong to the primary action; `menuIcon` replaces the chevron, which the\n * menu half always shows (a `menuIcon` that renders nothing keeps it).\n * - `disabledFocusable` keeps both halves focusable while unavailable; `Menu.Trigger` does not open\n * its menu from an `aria-disabled` menu half.\n *\n * @example\n * <Menu>\n * <Menu.Trigger>\n * {(triggerProps) => (\n * <SplitButton menuButtonProps={triggerProps} onClick={save}>Save</SplitButton>\n * )}\n * </Menu.Trigger>\n * <Menu.Popover>…</Menu.Popover>\n * </Menu>\n */\nexport const SplitButton = ({\n appearance = 'outline',\n size = 'medium',\n disabled = false,\n disabledFocusable = false,\n icon,\n iconPosition,\n menuIcon,\n className,\n children,\n onClick,\n onMenuClick,\n menuButtonLabel = 'More options',\n menuButtonProps,\n primaryActionButtonProps,\n 'aria-describedby': ariaDescribedBy,\n role,\n ref,\n ...props\n}: SplitButtonProps) => {\n const primary = mergeProps(\n { 'aria-describedby': ariaDescribedBy, onClick } as SplitButtonMenuButtonProps,\n primaryActionButtonProps,\n );\n const menu = mergeProps(\n {\n 'aria-label': menuButtonLabel,\n 'aria-haspopup': 'menu',\n onClick: onMenuClick,\n } as SplitButtonMenuButtonProps,\n menuButtonProps,\n );\n\n // Per half: focusable-disabled (the root's or its own) wins over natively disabled.\n const primaryFocusable = disabledFocusable || Boolean(primary.disabledFocusable);\n const menuFocusable = disabledFocusable || Boolean(menu.disabledFocusable);\n\n // The glyph sits inside the menu half's button: a button passed as `menuIcon` is unwrapped (its\n // children are the glyph), never nested (C-SLOTS).\n const { glyph: menuGlyph, button: menuIconButton } = unwrapButtonGlyph(menuIcon);\n // The menu half always shows an indicator: a `menuIcon` that renders nothing keeps the chevron.\n const menuIconRenders = slotRendersContent(menuGlyph);\n // An unwrapped button reports its own warning only.\n const menuIconEmpty = menuIconButton === null && menuIcon != null && !menuIconRenders;\n React.useEffect(() => {\n if (menuIconEmpty) {\n warnOnce(\n 'SplitButton:menuIcon-empty',\n 'SplitButton: `menuIcon` renders nothing, so the menu button shows the default chevron. Unlike `MenuButton`, a SplitButton always shows a menu indicator: pass an icon, or leave `menuIcon` unset.',\n );\n }\n }, [menuIconEmpty]);\n React.useEffect(() => {\n if (menuIconButton) {\n warnOnce(\n 'SplitButton:menuIcon-button',\n `SplitButton: \\`menuIcon\\` received ${menuIconButton}; its children render as the glyph of the menu button and its props were dropped (buttons cannot be nested). Pass icon content instead, e.g. \\`menuIcon={<MyIcon />}\\`.`,\n );\n }\n }, [menuIconButton]);\n\n // `role=\"group\"` applies wherever the consumer's role is `undefined` or `null` (as in Button).\n return (\n <div\n ref={ref}\n {...props}\n role={role ?? 'group'}\n className={cn('inline-flex items-stretch', className)}\n >\n <Button\n {...primary}\n appearance={appearance}\n size={size}\n disabled={!primaryFocusable && (disabled || Boolean(primary.disabled))}\n disabledFocusable={primaryFocusable}\n icon={icon}\n iconPosition={iconPosition}\n className={cn(halfClasses, 'rounded-e-none border-e-0', primary.className)}\n >\n {children}\n </Button>\n <Button\n {...menu}\n appearance={appearance}\n size={size}\n disabled={!menuFocusable && (disabled || Boolean(menu.disabled))}\n disabledFocusable={menuFocusable}\n icon={menuIconRenders ? menuGlyph : <ChevronDownIcon />}\n className={cn(\n halfClasses,\n menuButtonSizeClasses[size],\n 'rounded-s-none',\n separatorClasses[appearance],\n menu.className,\n )}\n />\n </div>\n );\n};\n\nSplitButton.displayName = 'SplitButton';\n"],"mappings":"8WA0GA,IAAMgB,EAA8C,CAClD,cAAe,gCACf,MAAO,gCACP,OAAQ,8BACR,MAAO,8BACP,cAAe,6BACjB,EAGMC,EAA+C,CACnD,QAAS,iCACT,QAAS,kBACT,OAAQ,kBACR,YAAa,iBACf,EAMMC,EAAc,sCA2BPC,GAAe,CAC1B,aAAa,UACb,OAAO,SACP,WAAW,GACX,oBAAoB,GACpB,OACA,eACA,WACA,YACA,WACA,UACA,cACA,kBAAkB,eAClB,kBACA,2BACA,mBAAoBC,EACpB,OACA,MACA,GAAGC,KACmB,CACtB,IAAMC,EAAUtB,EAAAA,WACd,CAAE,mBAAoBoB,EAAiB,SAAQ,EAC/CG,CACF,EACMC,EAAOxB,EAAAA,WACX,CACE,aAAcyB,EACd,gBAAiB,OACjB,QAASC,CACX,EACAC,CACF,EAGMC,EAAmBC,GAAqB,EAAQP,EAAQ,kBACxDQ,EAAgBD,GAAqB,EAAQL,EAAK,kBAIlD,CAAE,MAAOO,EAAW,OAAQC,GAAmB/B,EAAAA,kBAAkBgC,CAAQ,EAEzEC,EAAkBhC,EAAAA,mBAAmB6B,CAAS,EAE9CI,EAAgBH,IAAmB,MAAQC,GAAY,MAAQ,CAACC,EAmBtE,OAlBApB,EAAM,cAAgB,CAChBqB,GACF3B,EAAA,SACE,6BACA,mMACF,CAEJ,EAAG,CAAC2B,CAAa,CAAC,EAClBrB,EAAM,cAAgB,CAChBkB,GACFxB,EAAA,SACE,8BACA,sCAAsCwB,EAAe,wKACvD,CAEJ,EAAG,CAACA,CAAc,CAAC,GAIjB,EAAAjB,EAAA,KAAA,CAAC,MAAD,CACO,MACL,GAAIM,EACJ,KAAMe,GAAQ,QACd,UAAWjC,EAAAA,GAAG,4BAA6BkC,CAAS,EAJtD,SAAA,EAME,EAAAtB,EAAA,IAAA,CAACX,EAAAA,OAAD,CACE,GAAIkB,EACQ,aACN,OACN,SAAU,CAACM,IAAqBU,GAAY,EAAQhB,EAAQ,UAC5D,kBAAmBM,EACb,OACQ,eACd,UAAWzB,EAAAA,GAAGe,EAAa,4BAA6BI,EAAQ,SAAS,EAExE,UACK,CAAA,GACR,EAAAP,EAAA,IAAA,CAACX,EAAAA,OAAD,CACE,GAAIoB,EACQ,aACN,OACN,SAAU,CAACM,IAAkBQ,GAAY,EAAQd,EAAK,UACtD,kBAAmBM,EACnB,KAAMI,EAAkBH,GAAY,EAAAhB,EAAA,IAAA,CAACV,EAAAA,gBAAD,CAAkB,CAAA,EACtD,UAAWF,EAAAA,GACTe,EACAF,EAAsBuB,GACtB,iBACAtB,EAAiBuB,GACjBhB,EAAK,SACP,CACD,CAAA,CACE,GAET,EAEA,EAAY,YAAc"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../../lib/cn.mjs";
|
|
3
|
+
import { warnOnce as t } from "../../lib/dev.mjs";
|
|
4
|
+
import { slotRendersContent as n } from "../../lib/slot.mjs";
|
|
5
|
+
import { Button as r } from "./Button.mjs";
|
|
6
|
+
import { ChevronDownIcon as i } from "../../lib/icons.mjs";
|
|
7
|
+
import { mergeProps as a } from "../../lib/mergeProps.mjs";
|
|
8
|
+
import { unwrapButtonGlyph as o } from "./Button.slots.mjs";
|
|
9
|
+
import * as s from "react";
|
|
10
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
11
|
+
//#region src/components/button/SplitButton.tsx
|
|
12
|
+
var u = {
|
|
13
|
+
"extra-small": "w-auto min-w-6 min-h-6 px-1.5",
|
|
14
|
+
small: "w-auto min-w-6 min-h-6 px-1.5",
|
|
15
|
+
medium: "w-auto min-w-6 min-h-6 px-2",
|
|
16
|
+
large: "w-auto min-w-6 min-h-6 px-2",
|
|
17
|
+
"extra-large": "w-auto min-w-6 min-h-6 px-3"
|
|
18
|
+
}, d = {
|
|
19
|
+
primary: "border-s-primary-foreground/30",
|
|
20
|
+
outline: "border-s-stroke",
|
|
21
|
+
subtle: "border-s-stroke",
|
|
22
|
+
transparent: "border-s-stroke"
|
|
23
|
+
}, f = "relative min-h-6 focus-visible:z-10", p = ({ appearance: p = "outline", size: m = "medium", disabled: h = !1, disabledFocusable: g = !1, icon: _, iconPosition: v, menuIcon: y, className: b, children: x, onClick: S, onMenuClick: C, menuButtonLabel: w = "More options", menuButtonProps: T, primaryActionButtonProps: E, "aria-describedby": D, role: O, ref: k, ...A }) => {
|
|
24
|
+
let j = a({
|
|
25
|
+
"aria-describedby": D,
|
|
26
|
+
onClick: S
|
|
27
|
+
}, E), M = a({
|
|
28
|
+
"aria-label": w,
|
|
29
|
+
"aria-haspopup": "menu",
|
|
30
|
+
onClick: C
|
|
31
|
+
}, T), N = g || !!j.disabledFocusable, P = g || !!M.disabledFocusable, { glyph: F, button: I } = o(y), L = n(F), R = I === null && y != null && !L;
|
|
32
|
+
return s.useEffect(() => {
|
|
33
|
+
R && t("SplitButton:menuIcon-empty", "SplitButton: `menuIcon` renders nothing, so the menu button shows the default chevron. Unlike `MenuButton`, a SplitButton always shows a menu indicator: pass an icon, or leave `menuIcon` unset.");
|
|
34
|
+
}, [R]), s.useEffect(() => {
|
|
35
|
+
I && t("SplitButton:menuIcon-button", `SplitButton: \`menuIcon\` received ${I}; its children render as the glyph of the menu button and its props were dropped (buttons cannot be nested). Pass icon content instead, e.g. \`menuIcon={<MyIcon />}\`.`);
|
|
36
|
+
}, [I]), /* @__PURE__ */ l("div", {
|
|
37
|
+
ref: k,
|
|
38
|
+
...A,
|
|
39
|
+
role: O ?? "group",
|
|
40
|
+
className: e("inline-flex items-stretch", b),
|
|
41
|
+
children: [/* @__PURE__ */ c(r, {
|
|
42
|
+
...j,
|
|
43
|
+
appearance: p,
|
|
44
|
+
size: m,
|
|
45
|
+
disabled: !N && (h || !!j.disabled),
|
|
46
|
+
disabledFocusable: N,
|
|
47
|
+
icon: _,
|
|
48
|
+
iconPosition: v,
|
|
49
|
+
className: e(f, "rounded-e-none border-e-0", j.className),
|
|
50
|
+
children: x
|
|
51
|
+
}), /* @__PURE__ */ c(r, {
|
|
52
|
+
...M,
|
|
53
|
+
appearance: p,
|
|
54
|
+
size: m,
|
|
55
|
+
disabled: !P && (h || !!M.disabled),
|
|
56
|
+
disabledFocusable: P,
|
|
57
|
+
icon: L ? F : /* @__PURE__ */ c(i, {}),
|
|
58
|
+
className: e(f, u[m], "rounded-s-none", d[p], M.className)
|
|
59
|
+
})]
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
p.displayName = "SplitButton";
|
|
63
|
+
//#endregion
|
|
64
|
+
export { p as SplitButton };
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=SplitButton.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SplitButton.mjs","names":["React","menuButtonSizeClasses","separatorClasses","halfClasses","SplitButton","ariaDescribedBy","props","primary","mergeProps","primaryActionButtonProps","menu","menuButtonLabel","onMenuClick","menuButtonProps","primaryFocusable","disabledFocusable","menuFocusable","menuGlyph","menuIconButton","unwrapButtonGlyph","menuIcon","menuIconRenders","slotRendersContent","menuIconEmpty","warnOnce","role","cn","className","Button","disabled","ChevronDownIcon","size","appearance"],"sources":["../../../src/components/button/SplitButton.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { warnOnce } from '../../lib/dev';\nimport { ChevronDownIcon } from '../../lib/icons';\nimport { mergeProps } from '../../lib/mergeProps';\nimport { slotRendersContent } from '../../lib/slot';\nimport type { Size, Appearance, IconPosition, Slot } from '../../lib/types';\nimport { Button } from './Button';\nimport { unwrapButtonGlyph } from './Button.slots';\n\n/**\n * Props for one half of a SplitButton (`menuButtonProps`, `primaryActionButtonProps`): native\n * `<button>` attributes, `data-*` attributes and `ref`. They are merged onto the built-in props\n * of that half: handlers are composed (yours run first), `className` is merged, id lists are\n * joined and any other value you pass wins.\n */\nexport interface SplitButtonMenuButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /**\n * Makes only this half unavailable but focusable (see `SplitButton.disabledFocusable`, which\n * affects both halves). For each half, focusable-disabled wins over natively disabled.\n * @default false\n */\n disabledFocusable?: boolean;\n /** Ref to the `<button>` element of this half. */\n ref?: React.Ref<HTMLButtonElement>;\n /** Any `data-*` attribute. */\n [dataAttribute: `data-${string}`]: string | number | boolean | undefined;\n}\n\n/** Props for the primary action half of a SplitButton (same shape as the menu half). */\nexport type SplitButtonPrimaryActionButtonProps = SplitButtonMenuButtonProps;\n\n/** Properties for the SplitButton component. */\nexport interface SplitButtonProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onClick'> {\n /**\n * Disables both buttons. A half's own `disabled` (`primaryActionButtonProps`,\n * `menuButtonProps`) disables only that half.\n * @default false\n */\n disabled?: boolean;\n /**\n * Makes both halves unavailable but focusable (see `Button.disabledFocusable`): each half\n * renders `aria-disabled=\"true\"`, `data-disabled` and `data-disabled-focusable`, stays in the tab\n * order, and neither `onClick` nor the menu opens. A half's own `disabledFocusable` (in\n * `primaryActionButtonProps`/`menuButtonProps`) affects only that half. For each half,\n * focusable-disabled wins over natively disabled: the half is focusable-disabled when the root's\n * or its own `disabledFocusable` is set; otherwise it is natively disabled when the root's or its\n * own `disabled` is set.\n * @default false\n */\n disabledFocusable?: boolean;\n /**\n * Icon of the primary action, decorative (`aria-hidden`). For an icon-only primary action pass\n * `primaryActionButtonProps={{ 'aria-label': '…' }}`.\n */\n icon?: Slot<'span'>;\n /**\n * Where the primary action's icon renders: before its label (the inline start) or after it.\n * Has no effect on an icon-only primary action. The menu half is not affected.\n * @default 'before'\n */\n iconPosition?: IconPosition;\n /**\n * Replaces the chevron of the menu half (decorative, `aria-hidden`). The menu half always shows\n * an indicator: `null` and `undefined` keep the default chevron, and so does a value that renders\n * nothing (`false`, `''`, an empty array), which also logs a development warning. Unlike\n * `MenuButton.menuIcon`, a value that renders nothing does not hide the indicator. A `<button>`\n * or `Button` element, or a slot object whose `as` is one, is not nested inside the menu half:\n * its children become the glyph (the chevron when they render nothing), its props (`icon`\n * included) are dropped, and a development warning says so.\n */\n menuIcon?: Slot<'span'>;\n /** Visual style variant.\n * @default 'outline'\n */\n appearance?: Appearance;\n /** Size affecting height, padding and font size.\n * @default 'medium'\n */\n size?: Size;\n /** Click handler for the primary action button. */\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n /** Click handler for the menu (chevron) button. */\n onMenuClick?: React.MouseEventHandler<HTMLButtonElement>;\n /**\n * Accessible name of the menu button (it shows only a chevron). Localize it.\n * @default 'More options'\n */\n menuButtonLabel?: string;\n /**\n * Props for the menu button: `aria-expanded`, `aria-controls`, `id`, handlers (`onKeyDown` for\n * ArrowDown/ArrowUp), `ref` for focus restoration, … Pass the render-prop props of\n * `Menu.Trigger` here to open a Menu from the chevron.\n */\n menuButtonProps?: SplitButtonMenuButtonProps;\n /** Props for the primary action button (`ref`, `title`, handlers, …). */\n primaryActionButtonProps?: SplitButtonPrimaryActionButtonProps;\n /** Ref to the wrapping `role=\"group\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/**\n * Menu button size per SplitButton size: at least 24×24 CSS px at every size (WCAG 2.5.8 target\n * size; the chevron shares an edge with the primary button, so the spacing exception does not\n * apply). Overrides the square icon-only sizing of `Button` (`w-*`, `px-0`).\n */\nconst menuButtonSizeClasses: Record<Size, string> = {\n 'extra-small': 'w-auto min-w-6 min-h-6 px-1.5',\n small: 'w-auto min-w-6 min-h-6 px-1.5',\n medium: 'w-auto min-w-6 min-h-6 px-2',\n large: 'w-auto min-w-6 min-h-6 px-2',\n 'extra-large': 'w-auto min-w-6 min-h-6 px-3',\n};\n\n/** The separator is the menu button's start border (logical, so it mirrors in RTL). */\nconst separatorClasses: Record<Appearance, string> = {\n primary: 'border-s-primary-foreground/30',\n outline: 'border-s-stroke',\n subtle: 'border-s-stroke',\n transparent: 'border-s-stroke',\n};\n\n/**\n * Keeps each half's focus ring above its neighbour. `min-h-6` keeps both halves as tall as the\n * 24px menu button target at the extra-small size.\n */\nconst halfClasses = 'relative min-h-6 focus-visible:z-10';\n\n/**\n * A primary action button joined to a menu button (chevron), e.g. Save + \"Save as…\" options.\n * Both halves are {@link Button}s with the shared appearances and sizes, inside a\n * `role=\"group\"` wrapper.\n *\n * - `ref`, `className`, `style`, `aria-label` and other props go to the group; `aria-describedby`\n * is routed to the primary button (so a Tooltip around the SplitButton describes the action).\n * - `primaryActionButtonProps` / `menuButtonProps` reach the two buttons; the menu button is\n * named by `menuButtonLabel` (default `'More options'`).\n * - The menu button is at least 24×24 px at every size, so an extra-small SplitButton is 24px tall.\n * - `icon`/`iconPosition` belong to the primary action; `menuIcon` replaces the chevron, which the\n * menu half always shows (a `menuIcon` that renders nothing keeps it).\n * - `disabledFocusable` keeps both halves focusable while unavailable; `Menu.Trigger` does not open\n * its menu from an `aria-disabled` menu half.\n *\n * @example\n * <Menu>\n * <Menu.Trigger>\n * {(triggerProps) => (\n * <SplitButton menuButtonProps={triggerProps} onClick={save}>Save</SplitButton>\n * )}\n * </Menu.Trigger>\n * <Menu.Popover>…</Menu.Popover>\n * </Menu>\n */\nexport const SplitButton = ({\n appearance = 'outline',\n size = 'medium',\n disabled = false,\n disabledFocusable = false,\n icon,\n iconPosition,\n menuIcon,\n className,\n children,\n onClick,\n onMenuClick,\n menuButtonLabel = 'More options',\n menuButtonProps,\n primaryActionButtonProps,\n 'aria-describedby': ariaDescribedBy,\n role,\n ref,\n ...props\n}: SplitButtonProps) => {\n const primary = mergeProps(\n { 'aria-describedby': ariaDescribedBy, onClick } as SplitButtonMenuButtonProps,\n primaryActionButtonProps,\n );\n const menu = mergeProps(\n {\n 'aria-label': menuButtonLabel,\n 'aria-haspopup': 'menu',\n onClick: onMenuClick,\n } as SplitButtonMenuButtonProps,\n menuButtonProps,\n );\n\n // Per half: focusable-disabled (the root's or its own) wins over natively disabled.\n const primaryFocusable = disabledFocusable || Boolean(primary.disabledFocusable);\n const menuFocusable = disabledFocusable || Boolean(menu.disabledFocusable);\n\n // The glyph sits inside the menu half's button: a button passed as `menuIcon` is unwrapped (its\n // children are the glyph), never nested (C-SLOTS).\n const { glyph: menuGlyph, button: menuIconButton } = unwrapButtonGlyph(menuIcon);\n // The menu half always shows an indicator: a `menuIcon` that renders nothing keeps the chevron.\n const menuIconRenders = slotRendersContent(menuGlyph);\n // An unwrapped button reports its own warning only.\n const menuIconEmpty = menuIconButton === null && menuIcon != null && !menuIconRenders;\n React.useEffect(() => {\n if (menuIconEmpty) {\n warnOnce(\n 'SplitButton:menuIcon-empty',\n 'SplitButton: `menuIcon` renders nothing, so the menu button shows the default chevron. Unlike `MenuButton`, a SplitButton always shows a menu indicator: pass an icon, or leave `menuIcon` unset.',\n );\n }\n }, [menuIconEmpty]);\n React.useEffect(() => {\n if (menuIconButton) {\n warnOnce(\n 'SplitButton:menuIcon-button',\n `SplitButton: \\`menuIcon\\` received ${menuIconButton}; its children render as the glyph of the menu button and its props were dropped (buttons cannot be nested). Pass icon content instead, e.g. \\`menuIcon={<MyIcon />}\\`.`,\n );\n }\n }, [menuIconButton]);\n\n // `role=\"group\"` applies wherever the consumer's role is `undefined` or `null` (as in Button).\n return (\n <div\n ref={ref}\n {...props}\n role={role ?? 'group'}\n className={cn('inline-flex items-stretch', className)}\n >\n <Button\n {...primary}\n appearance={appearance}\n size={size}\n disabled={!primaryFocusable && (disabled || Boolean(primary.disabled))}\n disabledFocusable={primaryFocusable}\n icon={icon}\n iconPosition={iconPosition}\n className={cn(halfClasses, 'rounded-e-none border-e-0', primary.className)}\n >\n {children}\n </Button>\n <Button\n {...menu}\n appearance={appearance}\n size={size}\n disabled={!menuFocusable && (disabled || Boolean(menu.disabled))}\n disabledFocusable={menuFocusable}\n icon={menuIconRenders ? menuGlyph : <ChevronDownIcon />}\n className={cn(\n halfClasses,\n menuButtonSizeClasses[size],\n 'rounded-s-none',\n separatorClasses[appearance],\n menu.className,\n )}\n />\n </div>\n );\n};\n\nSplitButton.displayName = 'SplitButton';\n"],"mappings":";;;;;;;;;;;AA0GA,IAAMC,IAA8C;CAClD,eAAe;CACf,OAAO;CACP,QAAQ;CACR,OAAO;CACP,eAAe;AACjB,GAGMC,IAA+C;CACnD,SAAS;CACT,SAAS;CACT,QAAQ;CACR,aAAa;AACf,GAMMC,IAAc,uCA2BPC,KAAe,EAC1B,gBAAa,WACb,UAAO,UACP,cAAW,IACX,uBAAoB,IACpB,SACA,iBACA,aACA,cACA,aACA,YACA,gBACA,qBAAkB,gBAClB,oBACA,6BACA,oBAAoBC,GACpB,SACA,QACA,GAAGC,QACmB;CACtB,IAAMC,IAAUC,EACd;EAAE,oBAAoBH;EAAiB;CAAQ,GAC/CI,CACF,GACMC,IAAOF,EACX;EACE,cAAcG;EACd,iBAAiB;EACjB,SAASC;CACX,GACAC,CACF,GAGMC,IAAmBC,KAAqB,EAAQR,EAAQ,mBACxDS,IAAgBD,KAAqB,EAAQL,EAAK,mBAIlD,EAAE,OAAOO,GAAW,QAAQC,MAAmBC,EAAkBC,CAAQ,GAEzEC,IAAkBC,EAAmBL,CAAS,GAE9CM,IAAgBL,MAAmB,QAAQE,KAAY,QAAQ,CAACC;CAmBtE,OAlBArB,EAAM,gBAAgB;EACpB,AAAIuB,KACFC,EACE,8BACA,mMACF;CAEJ,GAAG,CAACD,CAAa,CAAC,GAClBvB,EAAM,gBAAgB;EACpB,AAAIkB,KACFM,EACE,+BACA,sCAAsCN,EAAe,wKACvD;CAEJ,GAAG,CAACA,CAAc,CAAC,GAIjB,kBAAC,OAAD;EACO;EACL,GAAIZ;EACJ,MAAMmB,KAAQ;EACd,WAAWC,EAAG,6BAA6BC,CAAS;EAJtD,UAAA,CAME,kBAACC,GAAD;GACE,GAAIrB;GACQ;GACN;GACN,UAAU,CAACO,MAAqBe,KAAY,EAAQtB,EAAQ;GAC5D,mBAAmBO;GACb;GACQ;GACd,WAAWY,EAAGvB,GAAa,6BAA6BI,EAAQ,SAAS;GAExE;EACK,CAAA,GACR,kBAACqB,GAAD;GACE,GAAIlB;GACQ;GACN;GACN,UAAU,CAACM,MAAkBa,KAAY,EAAQnB,EAAK;GACtD,mBAAmBM;GACnB,MAAMK,IAAkBJ,IAAY,kBAACa,GAAD,CAAkB,CAAA;GACtD,WAAWJ,EACTvB,GACAF,EAAsB8B,IACtB,kBACA7B,EAAiB8B,IACjBtB,EAAK,SACP;EACD,CAAA,CACE;;AAET;AAEA,EAAY,cAAc"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/composeEventHandlers.cjs"),i=require("../../hooks/useControllable.cjs"),a=require("./buttonStyles.cjs"),o=require("./Button.cjs");let s=require("react");s=e.__toESM(s,1);let c=require("react/jsx-runtime");var l=new Map;function u(e,t,n){let r=`${e}:${String(t)}:${String(n)}`,i=l.get(r);if(i===void 0){let o=new Set(a.buttonClassName({appearance:e,disabled:t}).split(/\s+/));i=a.buttonClassName({appearance:e,disabled:t,pressed:!0,accessible:n}).split(/\s+/).filter(e=>e!==``&&!o.has(e)).join(` `),l.set(r,i)}return i}var d=new Set([`checkbox`,`radio`,`switch`,`menuitemcheckbox`,`menuitemradio`,`option`,`treeitem`]);function f(e){let t=e?.trim().split(/\s+/)[0]?.toLowerCase()??``;return t===``||t===`button`?`pressed`:d.has(t)?`checked`:`none`}var p=({pressed:e,defaultPressed:a=!1,onPressedChange:l,appearance:d=`outline`,size:p=`medium`,disabled:m=!1,disabledFocusable:h=!1,isAccessible:g=!1,className:_,onClick:v,...y})=>{let[b,x]=i.useControllable(e,a,l),S=r.composeEventHandlers(v,()=>x(e=>!e)),C=y[`aria-disabled`],w=m||h||C===!0||C===`true`,T=y.role,E=f(T);return s.useEffect(()=>{E===`none`&&n.warnOnce(`ToggleButton:role-state`,`ToggleButton: \`role="${String(T).trim()}"\` allows neither \`aria-pressed\` nor \`aria-checked\`, so the pressed state is not exposed to assistive technology. Leave the role out (or use \`button\`), or use a role that has a checked state: \`checkbox\`, \`radio\`, \`switch\`, \`menuitemcheckbox\`, \`menuitemradio\`, \`option\` or \`treeitem\`.`)},[E,T]),(0,c.jsx)(o.Button,{...y,appearance:d,size:p,disabled:m,disabledFocusable:h,"aria-pressed":E===`pressed`?b:void 0,...E===`checked`&&{"aria-checked":b,"data-checked":b?``:void 0},"data-pressed":b?``:void 0,onClick:S,className:t.cn(b&&u(d,w,g),_)})};p.displayName=`ToggleButton`,exports.ToggleButton=p;
|
|
2
|
+
//# sourceMappingURL=ToggleButton.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToggleButton.cjs","names":["buttonClassName","useControllable","composeEventHandlers","Button","cn","require_runtime","require_cn","require_dev","require_composeEventHandlers","require_useControllable","require_buttonStyles","require_Button","react","react_jsx_runtime","pressedLayerCache","getPressedLayer","key","appearance","disabled","accessible","layer","unpressed","cls","CHECKED_ROLES","stateAttributeFor","token","role","ToggleButton","props","isPressed","setPressed","pressed","defaultPressed","onPressedChange","handleClick","onClick","current","ariaDisabled","disabledLook","disabledFocusable","stateAttribute","isAccessible","className"],"sources":["../../../src/components/button/ToggleButton.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnOnce } from '../../lib/dev';\nimport { useControllable } from '../../hooks/useControllable';\nimport type { Size, Appearance, IconPosition, Slot } from '../../lib/types';\nimport { Button } from './Button';\nimport { buttonClassName } from './buttonStyles';\n\n/** Properties for the ToggleButton component. */\nexport interface ToggleButtonProps extends Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n 'onChange'\n> {\n /** Controlled pressed state. */\n pressed?: boolean;\n /** Initial pressed state for uncontrolled usage.\n * @default false\n */\n defaultPressed?: boolean;\n /**\n * Called with the new pressed state when the user toggles the button. Fires only when the state\n * changes (once per click, also in StrictMode). In controlled mode the button keeps showing\n * `pressed` until the parent passes the new value.\n */\n onPressedChange?: (pressed: boolean) => void;\n /** Visual style variant.\n * @default 'outline'\n */\n appearance?: Appearance;\n /** Size affecting height, padding and font size.\n * @default 'medium'\n */\n size?: Size;\n /**\n * Icon slot rendered before the label (after it with `iconPosition=\"after\"`). Decorative: it\n * renders with `aria-hidden=\"true\"` (a slot object can override it). An icon-only toggle needs\n * `aria-label`, `aria-labelledby` or `title`.\n */\n icon?: Slot<'span'>;\n /**\n * Where the icon renders: before the label (the inline start) or after it (the inline end).\n * Follows the writing direction through DOM order. Has no effect on an icon-only toggle.\n * @default 'before'\n */\n iconPosition?: IconPosition;\n /**\n * Marks the toggle unavailable but keeps it focusable and in the tab order (see\n * `Button.disabledFocusable`): `aria-disabled=\"true\"`, `data-disabled` and\n * `data-disabled-focusable` instead of the native `disabled` attribute. Clicks, Enter and Space\n * neither toggle it nor call `onClick` or `onPressedChange`; a pressed toggle shows the pressed\n * and disabled look. Wins over `disabled` when both are set. In a `Toolbar` it stays in the\n * arrow-key order.\n * @default false\n */\n disabledFocusable?: boolean;\n /**\n * Draws the pressed state as a brand fill with on-brand text (on `primary`, the pressed fill with\n * an inset on-brand stroke), so the state never depends on a light tint (Fluent's\n * `isAccessible`). Recommended for icon-only toggles in toolbars. Forced colors are unchanged.\n * @default false\n */\n isAccessible?: boolean;\n /** Ref to the rendered `<button>`. */\n ref?: React.Ref<HTMLButtonElement>;\n}\n\n/**\n * The classes `buttonClassName({ pressed: true, accessible })` adds on top of the unpressed button,\n * per appearance, disabled state and `isAccessible`. Derived from the shared maps (never re-typed),\n * so ToggleButton's pressed look is exactly the button family's: `Button` merges them after its own\n * classes with `cn()`, which replaces the conflicting unpressed colors. Size classes are not\n * involved.\n */\nconst pressedLayerCache = new Map<string, string>();\nfunction getPressedLayer(appearance: Appearance, disabled: boolean, accessible: boolean): string {\n const key = `${appearance}:${String(disabled)}:${String(accessible)}`;\n let layer = pressedLayerCache.get(key);\n if (layer === undefined) {\n const unpressed = new Set(buttonClassName({ appearance, disabled }).split(/\\s+/));\n layer = buttonClassName({ appearance, disabled, pressed: true, accessible })\n .split(/\\s+/)\n .filter((cls) => cls !== '' && !unpressed.has(cls))\n .join(' ');\n pressedLayerCache.set(key, layer);\n }\n return layer;\n}\n\n/**\n * The roles that report a toggle's state with `aria-checked` (`aria-pressed` is allowed only on\n * `button`).\n */\nconst CHECKED_ROLES: ReadonlySet<string> = new Set([\n 'checkbox',\n 'radio',\n 'switch',\n 'menuitemcheckbox',\n 'menuitemradio',\n 'option',\n 'treeitem',\n]);\n\n/**\n * Which attribute reports the pressed state for `role` (its first token, ASCII case-insensitive):\n * `'pressed'` (no role or `button`), `'checked'` (a checked role) or `'none'` (any other role).\n */\nfunction stateAttributeFor(role: string | undefined): 'pressed' | 'checked' | 'none' {\n const token = role?.trim().split(/\\s+/)[0]?.toLowerCase() ?? '';\n if (token === '' || token === 'button') return 'pressed';\n return CHECKED_ROLES.has(token) ? 'checked' : 'none';\n}\n\n/**\n * A button that switches between pressed and unpressed, e.g. Bold in a text toolbar. Built on\n * {@link Button}: same appearances, sizes, `type=\"button\"` default, decorative icon slot and\n * icon-only warning. The pressed look uses the shared pressed colors (selected tokens; a Highlight\n * outline in forced colors), or a brand fill with `isAccessible`.\n *\n * - Uncontrolled: `defaultPressed`; controlled: `pressed` + `onPressedChange`.\n * - A consumer `onClick` runs first; calling `event.preventDefault()` in it cancels the toggle.\n * - It reports its state with `aria-pressed` without a `role` or with `role=\"button\"`. With `role`\n * `checkbox`, `radio`, `switch`, `menuitemcheckbox`, `menuitemradio`, `option` or `treeitem` it\n * reports it with `aria-checked` (and `data-checked` while pressed) instead; with any other role\n * it renders neither (development warning), because `aria-pressed` is allowed only on buttons.\n * `data-pressed` is present while pressed in every case.\n *\n * @example\n * <ToggleButton icon={<BoldIcon />} aria-label=\"Bold\" />\n * <ToggleButton pressed={bold} onPressedChange={setBold}>Bold</ToggleButton>\n * <ToggleButton role=\"checkbox\" isAccessible icon={<GridIcon />} aria-label=\"Grid\" />\n */\nexport const ToggleButton = ({\n pressed,\n defaultPressed = false,\n onPressedChange,\n appearance = 'outline',\n size = 'medium',\n disabled = false,\n disabledFocusable = false,\n isAccessible = false,\n className,\n onClick,\n ...props\n}: ToggleButtonProps) => {\n const [isPressed, setPressed] = useControllable(pressed, defaultPressed, onPressedChange);\n\n // With `disabledFocusable`, Button replaces this handler, so the toggle never runs.\n const handleClick = composeEventHandlers(onClick, () => setPressed((current) => !current));\n\n // Button shows the disabled look for `disabled`, `disabledFocusable` and a consumer\n // `aria-disabled` alike.\n const ariaDisabled = props['aria-disabled'];\n const disabledLook =\n disabled || disabledFocusable || ariaDisabled === true || ariaDisabled === 'true';\n\n const role = props.role;\n const stateAttribute = stateAttributeFor(role);\n React.useEffect(() => {\n if (stateAttribute !== 'none') return;\n warnOnce(\n 'ToggleButton:role-state',\n `ToggleButton: \\`role=\"${String(role).trim()}\"\\` allows neither \\`aria-pressed\\` nor \\`aria-checked\\`, so the pressed state is not exposed to assistive technology. Leave the role out (or use \\`button\\`), or use a role that has a checked state: \\`checkbox\\`, \\`radio\\`, \\`switch\\`, \\`menuitemcheckbox\\`, \\`menuitemradio\\`, \\`option\\` or \\`treeitem\\`.`,\n );\n }, [stateAttribute, role]);\n\n return (\n <Button\n {...props}\n appearance={appearance}\n size={size}\n disabled={disabled}\n disabledFocusable={disabledFocusable}\n // After the consumer's props: the attribute the role allows reports the state, and a\n // consumer `aria-pressed` never survives where it is not allowed.\n aria-pressed={stateAttribute === 'pressed' ? isPressed : undefined}\n {...(stateAttribute === 'checked' && {\n 'aria-checked': isPressed,\n 'data-checked': isPressed ? '' : undefined,\n })}\n data-pressed={isPressed ? '' : undefined}\n onClick={handleClick}\n className={cn(\n isPressed && getPressedLayer(appearance, disabledLook, isAccessible),\n className,\n )}\n />\n );\n};\n\nToggleButton.displayName = 'ToggleButton';\n"],"mappings":"oWA0EA,IAAMc,EAAoB,IAAI,IAC9B,SAASC,EAAgB,EAAwB,EAAmB,EAA6B,CAC/F,IAAMC,EAAM,GAAGC,EAAW,GAAG,OAAOC,CAAQ,EAAE,GAAG,OAAOC,CAAU,IAC9DC,EAAQN,EAAkB,IAAIE,CAAG,EACrC,GAAII,IAAU,IAAA,GAAW,CACvB,IAAMC,EAAY,IAAI,IAAIrB,EAAAA,gBAAgB,CAAE,aAAY,UAAS,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,EAChF,EAAQA,EAAAA,gBAAgB,CAAE,aAAY,WAAU,QAAS,GAAM,YAAW,CAAC,CAAC,CACzE,MAAM,KAAK,CAAC,CACZ,OAAQ,GAAQsB,IAAQ,IAAM,CAACD,EAAU,IAAIC,CAAG,CAAC,CAAC,CAClD,KAAK,GAAG,EACXR,EAAkB,IAAIE,EAAKI,CAAK,CAClC,CACA,OAAOA,CACT,CAMA,IAAMG,EAAqC,IAAI,IAAI,CACjD,WACA,QACA,SACA,mBACA,gBACA,SACA,UACF,CAAC,EAMD,SAASC,EAAkB,EAA0D,CACnF,IAAMC,EAAQC,GAAM,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,EAAE,YAAY,GAAK,GAE7D,OADID,IAAU,IAAMA,IAAU,SAAiB,UACxCF,EAAc,IAAIE,CAAK,EAAI,UAAY,MAChD,CAqBA,IAAaE,GAAgB,CAC3B,UACA,iBAAiB,GACjB,kBACA,aAAa,UACb,OAAO,SACP,WAAW,GACX,oBAAoB,GACpB,eAAe,GACf,YACA,UACA,GAAGC,KACoB,CACvB,GAAM,CAACC,EAAWC,GAAc7B,EAAAA,gBAAgB8B,EAASC,EAAgBC,CAAe,EAGlFC,EAAchC,EAAAA,qBAAqBiC,MAAeL,EAAY,GAAY,CAACM,CAAO,CAAC,EAInFC,EAAeT,EAAM,iBACrBU,EACJpB,GAAYqB,GAAqBF,IAAiB,IAAQA,IAAiB,OAEvEX,EAAOE,EAAM,KACbY,EAAiBhB,EAAkBE,CAAI,EAS7C,OARAd,EAAM,cAAgB,CAChB4B,IAAmB,QACvBjC,EAAA,SACE,0BACA,yBAAyB,OAAOmB,CAAI,CAAC,CAAC,KAAK,EAAE,iTAC/C,CACF,EAAG,CAACc,EAAgBd,CAAI,CAAC,GAGvB,EAAAb,EAAA,IAAA,CAACV,EAAAA,OAAD,CACE,GAAIyB,EACQ,aACN,OACI,WACS,oBAGnB,eAAcY,IAAmB,UAAYX,EAAY,IAAA,GACzD,GAAKW,IAAmB,WAAa,CACnC,eAAgBX,EAChB,eAAgBA,EAAY,GAAK,IAAA,EACnC,EACA,eAAcA,EAAY,GAAK,IAAA,GAC/B,QAASK,EACT,UAAW9B,EAAAA,GACTyB,GAAad,EAAgBE,EAAYqB,EAAcG,CAAY,EACnEC,CACF,CACD,CAAA,CAEL,EAEA,EAAa,YAAc"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../../lib/cn.mjs";
|
|
3
|
+
import { warnOnce as t } from "../../lib/dev.mjs";
|
|
4
|
+
import { composeEventHandlers as n } from "../../lib/composeEventHandlers.mjs";
|
|
5
|
+
import { useControllable as r } from "../../hooks/useControllable.mjs";
|
|
6
|
+
import { buttonClassName as i } from "./buttonStyles.mjs";
|
|
7
|
+
import { Button as a } from "./Button.mjs";
|
|
8
|
+
import * as o from "react";
|
|
9
|
+
import { jsx as s } from "react/jsx-runtime";
|
|
10
|
+
//#region src/components/button/ToggleButton.tsx
|
|
11
|
+
var c = /* @__PURE__ */ new Map();
|
|
12
|
+
function l(e, t, n) {
|
|
13
|
+
let r = `${e}:${String(t)}:${String(n)}`, a = c.get(r);
|
|
14
|
+
if (a === void 0) {
|
|
15
|
+
let o = new Set(i({
|
|
16
|
+
appearance: e,
|
|
17
|
+
disabled: t
|
|
18
|
+
}).split(/\s+/));
|
|
19
|
+
a = i({
|
|
20
|
+
appearance: e,
|
|
21
|
+
disabled: t,
|
|
22
|
+
pressed: !0,
|
|
23
|
+
accessible: n
|
|
24
|
+
}).split(/\s+/).filter((e) => e !== "" && !o.has(e)).join(" "), c.set(r, a);
|
|
25
|
+
}
|
|
26
|
+
return a;
|
|
27
|
+
}
|
|
28
|
+
var u = /* @__PURE__ */ new Set([
|
|
29
|
+
"checkbox",
|
|
30
|
+
"radio",
|
|
31
|
+
"switch",
|
|
32
|
+
"menuitemcheckbox",
|
|
33
|
+
"menuitemradio",
|
|
34
|
+
"option",
|
|
35
|
+
"treeitem"
|
|
36
|
+
]);
|
|
37
|
+
function d(e) {
|
|
38
|
+
let t = e?.trim().split(/\s+/)[0]?.toLowerCase() ?? "";
|
|
39
|
+
return t === "" || t === "button" ? "pressed" : u.has(t) ? "checked" : "none";
|
|
40
|
+
}
|
|
41
|
+
var f = ({ pressed: i, defaultPressed: c = !1, onPressedChange: u, appearance: f = "outline", size: p = "medium", disabled: m = !1, disabledFocusable: h = !1, isAccessible: g = !1, className: _, onClick: v, ...y }) => {
|
|
42
|
+
let [b, x] = r(i, c, u), S = n(v, () => x((e) => !e)), C = y["aria-disabled"], w = m || h || C === !0 || C === "true", T = y.role, E = d(T);
|
|
43
|
+
return o.useEffect(() => {
|
|
44
|
+
E === "none" && t("ToggleButton:role-state", `ToggleButton: \`role="${String(T).trim()}"\` allows neither \`aria-pressed\` nor \`aria-checked\`, so the pressed state is not exposed to assistive technology. Leave the role out (or use \`button\`), or use a role that has a checked state: \`checkbox\`, \`radio\`, \`switch\`, \`menuitemcheckbox\`, \`menuitemradio\`, \`option\` or \`treeitem\`.`);
|
|
45
|
+
}, [E, T]), /* @__PURE__ */ s(a, {
|
|
46
|
+
...y,
|
|
47
|
+
appearance: f,
|
|
48
|
+
size: p,
|
|
49
|
+
disabled: m,
|
|
50
|
+
disabledFocusable: h,
|
|
51
|
+
"aria-pressed": E === "pressed" ? b : void 0,
|
|
52
|
+
...E === "checked" && {
|
|
53
|
+
"aria-checked": b,
|
|
54
|
+
"data-checked": b ? "" : void 0
|
|
55
|
+
},
|
|
56
|
+
"data-pressed": b ? "" : void 0,
|
|
57
|
+
onClick: S,
|
|
58
|
+
className: e(b && l(f, w, g), _)
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
f.displayName = "ToggleButton";
|
|
62
|
+
//#endregion
|
|
63
|
+
export { f as ToggleButton };
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=ToggleButton.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToggleButton.mjs","names":["React","pressedLayerCache","getPressedLayer","key","appearance","disabled","accessible","layer","unpressed","buttonClassName","cls","CHECKED_ROLES","stateAttributeFor","token","role","ToggleButton","props","isPressed","setPressed","useControllable","pressed","defaultPressed","onPressedChange","handleClick","composeEventHandlers","onClick","current","ariaDisabled","disabledLook","disabledFocusable","stateAttribute","warnOnce","Button","cn","isAccessible","className"],"sources":["../../../src/components/button/ToggleButton.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnOnce } from '../../lib/dev';\nimport { useControllable } from '../../hooks/useControllable';\nimport type { Size, Appearance, IconPosition, Slot } from '../../lib/types';\nimport { Button } from './Button';\nimport { buttonClassName } from './buttonStyles';\n\n/** Properties for the ToggleButton component. */\nexport interface ToggleButtonProps extends Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n 'onChange'\n> {\n /** Controlled pressed state. */\n pressed?: boolean;\n /** Initial pressed state for uncontrolled usage.\n * @default false\n */\n defaultPressed?: boolean;\n /**\n * Called with the new pressed state when the user toggles the button. Fires only when the state\n * changes (once per click, also in StrictMode). In controlled mode the button keeps showing\n * `pressed` until the parent passes the new value.\n */\n onPressedChange?: (pressed: boolean) => void;\n /** Visual style variant.\n * @default 'outline'\n */\n appearance?: Appearance;\n /** Size affecting height, padding and font size.\n * @default 'medium'\n */\n size?: Size;\n /**\n * Icon slot rendered before the label (after it with `iconPosition=\"after\"`). Decorative: it\n * renders with `aria-hidden=\"true\"` (a slot object can override it). An icon-only toggle needs\n * `aria-label`, `aria-labelledby` or `title`.\n */\n icon?: Slot<'span'>;\n /**\n * Where the icon renders: before the label (the inline start) or after it (the inline end).\n * Follows the writing direction through DOM order. Has no effect on an icon-only toggle.\n * @default 'before'\n */\n iconPosition?: IconPosition;\n /**\n * Marks the toggle unavailable but keeps it focusable and in the tab order (see\n * `Button.disabledFocusable`): `aria-disabled=\"true\"`, `data-disabled` and\n * `data-disabled-focusable` instead of the native `disabled` attribute. Clicks, Enter and Space\n * neither toggle it nor call `onClick` or `onPressedChange`; a pressed toggle shows the pressed\n * and disabled look. Wins over `disabled` when both are set. In a `Toolbar` it stays in the\n * arrow-key order.\n * @default false\n */\n disabledFocusable?: boolean;\n /**\n * Draws the pressed state as a brand fill with on-brand text (on `primary`, the pressed fill with\n * an inset on-brand stroke), so the state never depends on a light tint (Fluent's\n * `isAccessible`). Recommended for icon-only toggles in toolbars. Forced colors are unchanged.\n * @default false\n */\n isAccessible?: boolean;\n /** Ref to the rendered `<button>`. */\n ref?: React.Ref<HTMLButtonElement>;\n}\n\n/**\n * The classes `buttonClassName({ pressed: true, accessible })` adds on top of the unpressed button,\n * per appearance, disabled state and `isAccessible`. Derived from the shared maps (never re-typed),\n * so ToggleButton's pressed look is exactly the button family's: `Button` merges them after its own\n * classes with `cn()`, which replaces the conflicting unpressed colors. Size classes are not\n * involved.\n */\nconst pressedLayerCache = new Map<string, string>();\nfunction getPressedLayer(appearance: Appearance, disabled: boolean, accessible: boolean): string {\n const key = `${appearance}:${String(disabled)}:${String(accessible)}`;\n let layer = pressedLayerCache.get(key);\n if (layer === undefined) {\n const unpressed = new Set(buttonClassName({ appearance, disabled }).split(/\\s+/));\n layer = buttonClassName({ appearance, disabled, pressed: true, accessible })\n .split(/\\s+/)\n .filter((cls) => cls !== '' && !unpressed.has(cls))\n .join(' ');\n pressedLayerCache.set(key, layer);\n }\n return layer;\n}\n\n/**\n * The roles that report a toggle's state with `aria-checked` (`aria-pressed` is allowed only on\n * `button`).\n */\nconst CHECKED_ROLES: ReadonlySet<string> = new Set([\n 'checkbox',\n 'radio',\n 'switch',\n 'menuitemcheckbox',\n 'menuitemradio',\n 'option',\n 'treeitem',\n]);\n\n/**\n * Which attribute reports the pressed state for `role` (its first token, ASCII case-insensitive):\n * `'pressed'` (no role or `button`), `'checked'` (a checked role) or `'none'` (any other role).\n */\nfunction stateAttributeFor(role: string | undefined): 'pressed' | 'checked' | 'none' {\n const token = role?.trim().split(/\\s+/)[0]?.toLowerCase() ?? '';\n if (token === '' || token === 'button') return 'pressed';\n return CHECKED_ROLES.has(token) ? 'checked' : 'none';\n}\n\n/**\n * A button that switches between pressed and unpressed, e.g. Bold in a text toolbar. Built on\n * {@link Button}: same appearances, sizes, `type=\"button\"` default, decorative icon slot and\n * icon-only warning. The pressed look uses the shared pressed colors (selected tokens; a Highlight\n * outline in forced colors), or a brand fill with `isAccessible`.\n *\n * - Uncontrolled: `defaultPressed`; controlled: `pressed` + `onPressedChange`.\n * - A consumer `onClick` runs first; calling `event.preventDefault()` in it cancels the toggle.\n * - It reports its state with `aria-pressed` without a `role` or with `role=\"button\"`. With `role`\n * `checkbox`, `radio`, `switch`, `menuitemcheckbox`, `menuitemradio`, `option` or `treeitem` it\n * reports it with `aria-checked` (and `data-checked` while pressed) instead; with any other role\n * it renders neither (development warning), because `aria-pressed` is allowed only on buttons.\n * `data-pressed` is present while pressed in every case.\n *\n * @example\n * <ToggleButton icon={<BoldIcon />} aria-label=\"Bold\" />\n * <ToggleButton pressed={bold} onPressedChange={setBold}>Bold</ToggleButton>\n * <ToggleButton role=\"checkbox\" isAccessible icon={<GridIcon />} aria-label=\"Grid\" />\n */\nexport const ToggleButton = ({\n pressed,\n defaultPressed = false,\n onPressedChange,\n appearance = 'outline',\n size = 'medium',\n disabled = false,\n disabledFocusable = false,\n isAccessible = false,\n className,\n onClick,\n ...props\n}: ToggleButtonProps) => {\n const [isPressed, setPressed] = useControllable(pressed, defaultPressed, onPressedChange);\n\n // With `disabledFocusable`, Button replaces this handler, so the toggle never runs.\n const handleClick = composeEventHandlers(onClick, () => setPressed((current) => !current));\n\n // Button shows the disabled look for `disabled`, `disabledFocusable` and a consumer\n // `aria-disabled` alike.\n const ariaDisabled = props['aria-disabled'];\n const disabledLook =\n disabled || disabledFocusable || ariaDisabled === true || ariaDisabled === 'true';\n\n const role = props.role;\n const stateAttribute = stateAttributeFor(role);\n React.useEffect(() => {\n if (stateAttribute !== 'none') return;\n warnOnce(\n 'ToggleButton:role-state',\n `ToggleButton: \\`role=\"${String(role).trim()}\"\\` allows neither \\`aria-pressed\\` nor \\`aria-checked\\`, so the pressed state is not exposed to assistive technology. Leave the role out (or use \\`button\\`), or use a role that has a checked state: \\`checkbox\\`, \\`radio\\`, \\`switch\\`, \\`menuitemcheckbox\\`, \\`menuitemradio\\`, \\`option\\` or \\`treeitem\\`.`,\n );\n }, [stateAttribute, role]);\n\n return (\n <Button\n {...props}\n appearance={appearance}\n size={size}\n disabled={disabled}\n disabledFocusable={disabledFocusable}\n // After the consumer's props: the attribute the role allows reports the state, and a\n // consumer `aria-pressed` never survives where it is not allowed.\n aria-pressed={stateAttribute === 'pressed' ? isPressed : undefined}\n {...(stateAttribute === 'checked' && {\n 'aria-checked': isPressed,\n 'data-checked': isPressed ? '' : undefined,\n })}\n data-pressed={isPressed ? '' : undefined}\n onClick={handleClick}\n className={cn(\n isPressed && getPressedLayer(appearance, disabledLook, isAccessible),\n className,\n )}\n />\n );\n};\n\nToggleButton.displayName = 'ToggleButton';\n"],"mappings":";;;;;;;;;;AA0EA,IAAMC,oBAAoB,IAAI,IAAoB;AAClD,SAASC,EAAgB,GAAwB,GAAmB,GAA6B;CAC/F,IAAMC,IAAM,GAAGC,EAAW,GAAG,OAAOC,CAAQ,EAAE,GAAG,OAAOC,CAAU,KAC9DC,IAAQN,EAAkB,IAAIE,CAAG;CACrC,IAAII,MAAU,KAAA,GAAW;EACvB,IAAMC,IAAY,IAAI,IAAIC,EAAgB;GAAE;GAAY;EAAS,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC;EAKhF,AAJA,IAAQA,EAAgB;GAAE;GAAY;GAAU,SAAS;GAAM;EAAW,CAAC,CAAC,CACzE,MAAM,KAAK,CAAC,CACZ,QAAQ,MAAQC,MAAQ,MAAM,CAACF,EAAU,IAAIE,CAAG,CAAC,CAAC,CAClD,KAAK,GAAG,GACXT,EAAkB,IAAIE,GAAKI,CAAK;CAClC;CACA,OAAOA;AACT;AAMA,IAAMI,oBAAqC,IAAI,IAAI;CACjD;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAMD,SAASC,EAAkB,GAA0D;CACnF,IAAMC,IAAQC,GAAM,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,EAAE,YAAY,KAAK;CAE7D,OADID,MAAU,MAAMA,MAAU,WAAiB,YACxCF,EAAc,IAAIE,CAAK,IAAI,YAAY;AAChD;AAqBA,IAAaE,KAAgB,EAC3B,YACA,oBAAiB,IACjB,oBACA,gBAAa,WACb,UAAO,UACP,cAAW,IACX,uBAAoB,IACpB,kBAAe,IACf,cACA,YACA,GAAGC,QACoB;CACvB,IAAM,CAACC,GAAWC,KAAcC,EAAgBC,GAASC,GAAgBC,CAAe,GAGlFC,IAAcC,EAAqBC,SAAeP,GAAY,MAAY,CAACQ,CAAO,CAAC,GAInFC,IAAeX,EAAM,kBACrBY,IACJvB,KAAYwB,KAAqBF,MAAiB,MAAQA,MAAiB,QAEvEb,IAAOE,EAAM,MACbc,IAAiBlB,EAAkBE,CAAI;CAS7C,OARAd,EAAM,gBAAgB;EACpB,AAAI8B,MAAmB,UACvBC,EACE,2BACA,yBAAyB,OAAOjB,CAAI,CAAC,CAAC,KAAK,EAAE,iTAC/C;CACF,GAAG,CAACgB,GAAgBhB,CAAI,CAAC,GAGvB,kBAACkB,GAAD;EACE,GAAIhB;EACQ;EACN;EACI;EACS;EAGnB,gBAAcc,MAAmB,YAAYb,IAAY,KAAA;EACzD,GAAKa,MAAmB,aAAa;GACnC,gBAAgBb;GAChB,gBAAgBA,IAAY,KAAK,KAAA;EACnC;EACA,gBAAcA,IAAY,KAAK,KAAA;EAC/B,SAASM;EACT,WAAWU,EACThB,KAAaf,EAAgBE,GAAYwB,GAAcM,CAAY,GACnEC,CACF;CACD,CAAA;AAEL;AAEA,EAAa,cAAc"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/composeEventHandlers.cjs"),r=require("../../hooks/useRovingTabIndex.cjs"),i=require("../../hooks/useMergedRefs.cjs"),a=require("../../hooks/useCheckedValues.cjs"),o=require("./Toolbar.context.cjs"),s=require("./Toolbar.parts.cjs");let c=require("react");c=e.__toESM(c,1);let l=require("react/jsx-runtime");var u=`button, [href], input, select, textarea, [role="button"], [tabindex]`,d={"extra-small":`p-0.5`,small:`p-0.5`,medium:`p-1`,large:`p-1.5`,"extra-large":`p-2`},f=e=>{let{as:s,orientation:f=`horizontal`,size:p=`medium`,checkedValues:m,defaultCheckedValues:h,onCheckedValuesChange:g,className:_,ref:v,onKeyDown:y,onFocus:b,role:x,"aria-orientation":S,...C}=e,{containerProps:w}=r.useRovingTabIndex({itemSelector:u,manageTabIndex:!0,tabStop:`last-focused`,orientation:f}),T=i.useMergedRefs(w.ref,v),E=a.useCheckedValues(m,h,g),D=o.useToolbarCheckableRegistry(),O=c.useMemo(()=>({orientation:f,size:p,checked:E,registerCheckable:D}),[f,p,E,D]),k=s??`div`;return(0,l.jsx)(o.ToolbarContext.Provider,{value:O,children:(0,l.jsx)(k,{"data-size":p,"data-orientation":f,...C,role:x??`toolbar`,"aria-orientation":S??f,ref:T,"data-roving-container":``,onKeyDown:n.composeEventHandlers(y,w.onKeyDown),onFocus:n.composeEventHandlers(b,w.onFocus,{checkDefaultPrevented:!1}),className:t.cn(`inline-flex items-center gap-1 rounded border border-border`,d[p],f===`vertical`&&`flex-col items-stretch`,_)})})};f.displayName=`Toolbar`;var p=Object.assign(f,{Button:s.ToolbarButton,ToggleButton:s.ToolbarToggleButton,RadioGroup:s.ToolbarRadioGroup,RadioButton:s.ToolbarRadioButton,Group:s.ToolbarGroup,Divider:s.ToolbarDivider});exports.Toolbar=p,exports.ToolbarButton=s.ToolbarButton,exports.ToolbarDivider=s.ToolbarDivider,exports.ToolbarGroup=s.ToolbarGroup,exports.ToolbarRadioButton=s.ToolbarRadioButton,exports.ToolbarRadioGroup=s.ToolbarRadioGroup,exports.ToolbarToggleButton=s.ToolbarToggleButton;
|
|
2
|
+
//# sourceMappingURL=Toolbar.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toolbar.cjs","names":["useRovingTabIndex","useMergedRefs","useCheckedValues","useToolbarCheckableRegistry","React","ToolbarContext","composeEventHandlers","cn","ToolbarButton","ToolbarToggleButton","ToolbarRadioGroup","ToolbarRadioButton","ToolbarGroup","ToolbarDivider","require_runtime","require_cn","require_composeEventHandlers","require_useRovingTabIndex","require_useMergedRefs","require_useCheckedValues","require_Toolbar_context","require_Toolbar_parts","react","react_jsx_runtime","TOOLBAR_ITEM_SELECTOR","toolbarPaddingClasses","ToolbarRoot","ariaOrientation","rest","props","mergedRef","containerProps","ref","checked","checkedValues","defaultCheckedValues","onCheckedValuesChange","registerCheckable","context","orientation","size","Component","as","role","onKeyDown","onFocus","className","Toolbar"],"sources":["../../../src/components/button/Toolbar.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport type { PolymorphicComponent, PolymorphicProps } from '../../lib/polymorphic';\nimport type { CheckedValues, CheckedValuesChangeHandler, Orientation, Size } from '../../lib/types';\nimport { useCheckedValues } from '../../hooks/useCheckedValues';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useRovingTabIndex } from '../../hooks/useRovingTabIndex';\nimport { ToolbarContext, useToolbarCheckableRegistry } from './Toolbar.context';\nimport type { ToolbarContextValue } from './Toolbar.context';\nimport {\n ToolbarButton,\n ToolbarDivider,\n ToolbarGroup,\n ToolbarRadioButton,\n ToolbarRadioGroup,\n ToolbarToggleButton,\n} from './Toolbar.parts';\n\nexport {\n ToolbarButton,\n ToolbarDivider,\n ToolbarGroup,\n ToolbarRadioButton,\n ToolbarRadioGroup,\n ToolbarToggleButton,\n};\nexport type {\n ToolbarButtonOwnProps,\n ToolbarButtonProps,\n ToolbarDividerProps,\n ToolbarGroupProps,\n ToolbarRadioButtonProps,\n ToolbarRadioGroupProps,\n ToolbarToggleButtonProps,\n} from './Toolbar.parts';\n\n/**\n * The Toolbar's own props (the XOwnProps rule of `PolymorphicProps`: component-specific props\n * only). Every other prop comes from the rendered element (`as`, default `'div'`). Give the\n * toolbar an `aria-label` (or `aria-labelledby`) that describes its purpose, e.g. \"Formatting\".\n */\nexport interface ToolbarOwnProps {\n /**\n * Layout and arrow-key axis: Left/Right move between items when horizontal (mirrored in RTL),\n * Up/Down when vertical. Exposed as `aria-orientation` and `data-orientation`.\n * @default 'horizontal'\n */\n orientation?: Orientation;\n /**\n * Default size of `Toolbar.Button`, `Toolbar.ToggleButton` and `Toolbar.RadioButton` (their\n * own `size` wins), and the toolbar's padding. Plain Buttons inside keep their own default.\n * Exposed as `data-size`.\n * @default 'medium'\n */\n size?: Size;\n /**\n * Pressed `Toolbar.ToggleButton`s and checked `Toolbar.RadioButton`s, per group `name`\n * (controlled): `{ format: ['bold'], align: ['center'] }`.\n */\n checkedValues?: CheckedValues;\n /** Initial checked values for uncontrolled usage. @default {} */\n defaultCheckedValues?: CheckedValues;\n /**\n * Called when a toggle or radio changes them (only on change): the new checked values first,\n * then `details` with the group's `name`, its `checkedItems` and the `event` (Fluent's\n * `onCheckedValueChange(event, { name, checkedItems })`; always passed, typed optional until 1.0).\n */\n onCheckedValuesChange?: CheckedValuesChangeHandler;\n}\n\n/**\n * Props of {@link Toolbar} rendered as `C` (default `'div'`). `ToolbarProps` without a type\n * argument is the 0.4 name: the props of a Toolbar rendered as a `<div>`, including `ref`.\n */\nexport type ToolbarProps<C extends React.ElementType = 'div'> = PolymorphicProps<\n C,\n ToolbarOwnProps\n>;\n\n/** The props the implementation reads, for any `as`. */\ntype ToolbarImplProps = ToolbarOwnProps &\n React.HTMLAttributes<HTMLElement> & {\n as?: React.ElementType;\n ref?: React.Ref<HTMLElement>;\n };\n\n/**\n * Every focusable control a toolbar can contain, whatever component renders it. Matches that\n * cannot take focus (a `type=\"hidden\"` input, a control CSS hides) are dropped by the roving hook.\n */\nconst TOOLBAR_ITEM_SELECTOR =\n 'button, [href], input, select, textarea, [role=\"button\"], [tabindex]';\n\n/** The toolbar's padding per size. */\nconst toolbarPaddingClasses: Record<Size, string> = {\n 'extra-small': 'p-0.5',\n small: 'p-0.5',\n medium: 'p-1',\n large: 'p-1.5',\n 'extra-large': 'p-2',\n};\n\n// The root of the Toolbar compound; its component JSDoc is on the `Toolbar` export below (C-DOCS).\nconst ToolbarRoot: PolymorphicComponent<'div', ToolbarOwnProps> = (props) => {\n const {\n as,\n orientation = 'horizontal',\n size = 'medium',\n checkedValues,\n defaultCheckedValues,\n onCheckedValuesChange,\n className,\n ref,\n onKeyDown,\n onFocus,\n role,\n 'aria-orientation': ariaOrientation,\n ...rest\n } = props as ToolbarImplProps;\n\n const { containerProps } = useRovingTabIndex({\n itemSelector: TOOLBAR_ITEM_SELECTOR,\n manageTabIndex: true,\n tabStop: 'last-focused',\n orientation,\n });\n const mergedRef = useMergedRefs<HTMLElement>(containerProps.ref, ref);\n\n const checked = useCheckedValues(checkedValues, defaultCheckedValues, onCheckedValuesChange);\n const registerCheckable = useToolbarCheckableRegistry();\n const context = React.useMemo<ToolbarContextValue>(\n () => ({ orientation, size, checked, registerCheckable }),\n [orientation, size, checked, registerCheckable],\n );\n\n const Component: React.ElementType = as ?? 'div';\n // The role and `aria-orientation` defaults apply wherever the consumer's value is `undefined` or\n // `null` (as in Button), so a wrapper forwarding its own unset props keeps them.\n return (\n <ToolbarContext.Provider value={context}>\n <Component\n data-size={size}\n data-orientation={orientation}\n {...rest}\n role={role ?? 'toolbar'}\n aria-orientation={ariaOrientation ?? orientation}\n ref={mergedRef}\n data-roving-container=\"\"\n onKeyDown={composeEventHandlers(onKeyDown, containerProps.onKeyDown)}\n onFocus={composeEventHandlers(onFocus, containerProps.onFocus, {\n checkDefaultPrevented: false,\n })}\n className={cn(\n 'inline-flex items-center gap-1 rounded border border-border',\n toolbarPaddingClasses[size],\n orientation === 'vertical' && 'flex-col items-stretch',\n className,\n )}\n />\n </ToolbarContext.Provider>\n );\n};\nToolbarRoot.displayName = 'Toolbar';\n\n/**\n * A container for a set of controls (APG Toolbar pattern): `role=\"toolbar\"`, one Tab stop, and\n * arrow-key navigation between its controls.\n *\n * - Works with any children (Buttons, ToggleButtons, links, inputs, value controls such as\n * Checkbox or Dropdown): the focusable controls are found in the DOM, and the Toolbar sets their\n * `tabIndex` itself (one `0`, the rest `-1`). The `type=\"hidden\"` input that a named value\n * control renders never counts as a control, and controls that CSS hides are skipped.\n * - Parts: `Toolbar.Button`, `Toolbar.ToggleButton` and `Toolbar.RadioButton` take the toolbar's\n * `size` (default `'medium'`) and the `subtle` appearance by default; `Toolbar.RadioGroup`,\n * `Toolbar.Group` and `Toolbar.Divider` lay them out. Plain Buttons keep their own defaults.\n * - State: the pressed `Toolbar.ToggleButton`s and the checked `Toolbar.RadioButton` of each\n * group live in `checkedValues`/`defaultCheckedValues`, per group `name`, and every change calls\n * `onCheckedValuesChange(checkedValues, details)`. The state is in the server HTML.\n * - Left/Right (Up/Down when `orientation=\"vertical\"`) move focus and wrap; Home/End jump to the\n * first/last control; Left/Right are mirrored in RTL. Natively disabled controls are skipped,\n * also when a child disables them on its own; `disabledFocusable` ones stay in the arrow-key\n * order (APG), so a Tooltip can explain why they are unavailable. The arrows never press a\n * toggle or check a radio: Space, Enter or a click does.\n * - The radios of a `Toolbar.RadioGroup` are part of that arrow-key order, and Up/Down (Left/Right\n * in a vertical toolbar) also move among them, wrapping inside the group.\n * - Tab returns to the last focused control. Focusing a nested composite (radio group, tab list)\n * or a text field, select, slider or spin button keeps the Tab stop where it was.\n * - Text fields, selects, sliders, spin buttons and editable comboboxes keep their own arrow keys\n * (the caret moves). A Dropdown (select-only combobox) does not: Left/Right move past it. It\n * keeps Up/Down, Home and End for its list, so in a vertical toolbar the arrows cannot leave it.\n * - Elements with their own `tabIndex={-1}` are left alone, and a nested composite widget (a\n * RadioGroup, a tab list, …; not `Toolbar.RadioGroup`) counts as one control that keeps its own\n * Tab stop and arrow keys.\n * - A Menu or Popover opened from a control keeps its own keys: arrows, Home and End pressed in\n * the popup never move focus back to the toolbar's controls.\n * - A consumer `onKeyDown` runs first; `event.preventDefault()` in it cancels the navigation.\n * - Renders `data-size` and `data-orientation`.\n *\n * React Server Components cannot dot into a client module: import the flat names\n * `ToolbarButton`, `ToolbarToggleButton`, `ToolbarRadioGroup`, `ToolbarRadioButton`,\n * `ToolbarGroup` and `ToolbarDivider` there; `Toolbar.Button` etc. work in client files.\n *\n * @example\n * <Toolbar aria-label=\"Formatting\" defaultCheckedValues={{ format: ['bold'], align: ['left'] }}>\n * <Toolbar.ToggleButton name=\"format\" value=\"bold\" icon={<BoldIcon />} aria-label=\"Bold\" />\n * <Toolbar.ToggleButton name=\"format\" value=\"code\" icon={<CodeIcon />} aria-label=\"Code\" />\n * <Toolbar.Divider />\n * <Toolbar.RadioGroup aria-label=\"Text alignment\">\n * <Toolbar.RadioButton name=\"align\" value=\"left\" icon={<AlignLeftIcon />} aria-label=\"Left\" />\n * <Toolbar.RadioButton name=\"align\" value=\"center\" icon={<AlignCenterIcon />} aria-label=\"Center\" />\n * </Toolbar.RadioGroup>\n * </Toolbar>\n */\nexport const Toolbar = /* @__PURE__ */ Object.assign(ToolbarRoot, {\n Button: ToolbarButton,\n ToggleButton: ToolbarToggleButton,\n RadioGroup: ToolbarRadioGroup,\n RadioButton: ToolbarRadioButton,\n Group: ToolbarGroup,\n Divider: ToolbarDivider,\n});\n"],"mappings":"0aA2FA,IAAMwB,EACJ,uEAGIC,EAA8C,CAClD,cAAe,QACf,MAAO,QACP,OAAQ,MACR,MAAO,QACP,cAAe,KACjB,EAGMC,EAA6D,GAAU,CAC3E,GAAM,CACJ,KACA,cAAc,aACd,OAAO,SACP,gBACA,uBACA,wBACA,YACA,MACA,YACA,UACA,OACA,mBAAoBC,EACpB,GAAGC,GACDC,EAEE,CAAE,kBAAmB7B,EAAAA,kBAAkB,CAC3C,aAAcwB,EACd,eAAgB,GAChB,QAAS,eACT,aACF,CAAC,EACKM,EAAY7B,EAAAA,cAA2B8B,EAAe,IAAKC,CAAG,EAE9DC,EAAU/B,EAAAA,iBAAiBgC,EAAeC,EAAsBC,CAAqB,EACrFC,EAAoBlC,EAAAA,4BAA4B,EAChDmC,EAAUlC,EAAM,aACb,CAAE,cAAa,OAAM,UAAS,mBAAkB,GACvD,CAACmC,EAAaC,EAAMP,EAASI,CAAiB,CAChD,EAEMI,EAA+BC,GAAM,MAG3C,OACE,EAAAnB,EAAA,IAAA,CAAClB,EAAAA,eAAe,SAAhB,CAAyB,MAAOiC,EAC9B,UAAA,EAAAf,EAAA,IAAA,CAACkB,EAAD,CACE,YAAWD,EACX,mBAAkBD,EAClB,GAAIX,EACJ,KAAMe,GAAQ,UACd,mBAAkBhB,GAAmBY,EACrC,IAAKT,EACL,wBAAsB,GACtB,UAAWxB,EAAAA,qBAAqBsC,EAAWb,EAAe,SAAS,EACnE,QAASzB,EAAAA,qBAAqBuC,EAASd,EAAe,QAAS,CAC7D,sBAAuB,EACzB,CAAC,EACD,UAAWxB,EAAAA,GACT,8DACAkB,EAAsBe,GACtBD,IAAgB,YAAc,yBAC9BO,CACF,CACD,CAAA,CACsB,CAAA,CAE7B,EACA,EAAY,YAAc,UAmD1B,IAAaC,EAA0B,OAAO,OAAOrB,EAAa,CAChE,OAAQlB,EAAAA,cACR,aAAcC,EAAAA,oBACd,WAAYC,EAAAA,kBACZ,YAAaC,EAAAA,mBACb,MAAOC,EAAAA,aACP,QAASC,EAAAA,cACX,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/dev.cjs"),n=require("../../hooks/useCheckedValues.cjs");let r=require("react");r=e.__toESM(r,1);var i=r.createContext(null);i.displayName=`ToolbarContext`;var a=()=>{},o={orientation:`horizontal`,size:`medium`,checked:{values:Object.freeze({}),isChecked:()=>!1,toggle:a,select:a},registerCheckable:()=>a};function s(e){return r.useContext(i)||(t.reportMissingContext(e,`Toolbar`),o)}function c(e,t){return`Toolbar: two toggle or radio buttons of one toolbar have the name "${e}" and the value "${t}", so both show as pressed. Give every part of a group its own value.`}function l(){return n.useDuplicatePairRegistry(`Toolbar:duplicate-value`,c)}exports.ToolbarContext=i,exports.useToolbarCheckableRegistry=l,exports.useToolbarContext=s;
|
|
2
|
+
//# sourceMappingURL=Toolbar.context.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toolbar.context.cjs","names":["React","useDuplicatePairRegistry","require_runtime","require_dev","require_useCheckedValues","react","ToolbarContext","noop","INERT_TOOLBAR_CONTEXT","useToolbarContext","componentName","duplicateValueMessage","name","value","useToolbarCheckableRegistry"],"sources":["../../../src/components/button/Toolbar.context.ts"],"sourcesContent":["import * as React from 'react';\nimport { useDuplicatePairRegistry, type CheckedValuesApi } from '../../hooks/useCheckedValues';\nimport { reportMissingContext } from '../../lib/dev';\nimport type { Orientation, Size } from '../../lib/types';\n\n/*\n * The context a Toolbar gives its parts (`Toolbar.Button`, `Toolbar.ToggleButton`, …): the\n * orientation, the default size and the checked-values state. Internal; imports no component.\n */\n\n/** What a Toolbar shares with its parts. */\nexport interface ToolbarContextValue {\n /** The toolbar's orientation (the arrow-key axis and the layout direction of groups). */\n orientation: Orientation;\n /** The default size of `Toolbar.Button`, `Toolbar.ToggleButton` and `Toolbar.RadioButton`. */\n size: Size;\n /** The pressed toggles and checked radios, per group `name`. */\n checked: CheckedValuesApi;\n /**\n * Development only (a no-op in production): a toggle or radio button registers its\n * `name`/`value` from an effect and unregisters on cleanup; a second registration of the same\n * pair in one toolbar warns once (`Toolbar:duplicate-value`), since both would show as pressed.\n */\n registerCheckable: (name: string, value: string) => () => void;\n}\n\nexport const ToolbarContext = React.createContext<ToolbarContextValue | null>(null);\nToolbarContext.displayName = 'ToolbarContext';\n\nconst noop = () => {};\n\n/** The context a misplaced part renders with in production (C-CONTEXT). */\nconst INERT_TOOLBAR_CONTEXT: ToolbarContextValue = {\n orientation: 'horizontal',\n size: 'medium',\n checked: {\n values: Object.freeze({}),\n isChecked: () => false,\n toggle: noop,\n select: noop,\n },\n registerCheckable: () => noop,\n};\n\n/** C-CONTEXT: throws in development, logs once and returns an inert value in production. */\nexport function useToolbarContext(componentName: string): ToolbarContextValue {\n const context = React.useContext(ToolbarContext);\n if (context) return context;\n reportMissingContext(componentName, 'Toolbar');\n return INERT_TOOLBAR_CONTEXT;\n}\n\n/** The warning for two toggle or radio buttons of one toolbar with the same `name`/`value` pair. */\nfunction duplicateValueMessage(name: string, value: string): string {\n return `Toolbar: two toggle or radio buttons of one toolbar have the name \"${name}\" and the value \"${value}\", so both show as pressed. Give every part of a group its own value.`;\n}\n\n/**\n * The `registerCheckable` of one toolbar: a count per `name`/`value` pair, kept for the toolbar's\n * lifetime. A second registration of a pair warns once (development only).\n */\nexport function useToolbarCheckableRegistry(): ToolbarContextValue['registerCheckable'] {\n return useDuplicatePairRegistry('Toolbar:duplicate-value', duplicateValueMessage);\n}\n"],"mappings":"0LA0BA,IAAaM,EAAiBN,EAAM,cAA0C,IAAI,EAClF,EAAe,YAAc,iBAE7B,IAAMO,MAAa,CAAC,EAGdC,EAA6C,CACjD,YAAa,aACb,KAAM,SACN,QAAS,CACP,OAAQ,OAAO,OAAO,CAAC,CAAC,EACxB,cAAiB,GACjB,OAAQD,EACR,OAAQA,CACV,EACA,sBAAyBA,CAC3B,EAGA,SAAgBE,EAAkB,EAA4C,CAI5E,OAHgBT,EAAM,WAAWM,CAC7B,IACJH,EAAA,qBAAqBO,EAAe,SAAS,EACtCF,EACT,CAGA,SAASG,EAAsB,EAAc,EAAuB,CAClE,MAAO,sEAAsEC,EAAK,mBAAmBC,EAAM,sEAC7G,CAMA,SAAgBC,GAAwE,CACtF,OAAOb,EAAAA,yBAAyB,0BAA2BU,CAAqB,CAClF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { reportMissingContext as e } from "../../lib/dev.mjs";
|
|
3
|
+
import { useDuplicatePairRegistry as t } from "../../hooks/useCheckedValues.mjs";
|
|
4
|
+
import * as n from "react";
|
|
5
|
+
//#region src/components/button/Toolbar.context.ts
|
|
6
|
+
var r = n.createContext(null);
|
|
7
|
+
r.displayName = "ToolbarContext";
|
|
8
|
+
var i = () => {}, a = {
|
|
9
|
+
orientation: "horizontal",
|
|
10
|
+
size: "medium",
|
|
11
|
+
checked: {
|
|
12
|
+
values: Object.freeze({}),
|
|
13
|
+
isChecked: () => !1,
|
|
14
|
+
toggle: i,
|
|
15
|
+
select: i
|
|
16
|
+
},
|
|
17
|
+
registerCheckable: () => i
|
|
18
|
+
};
|
|
19
|
+
function o(t) {
|
|
20
|
+
return n.useContext(r) || (e(t, "Toolbar"), a);
|
|
21
|
+
}
|
|
22
|
+
function s(e, t) {
|
|
23
|
+
return `Toolbar: two toggle or radio buttons of one toolbar have the name "${e}" and the value "${t}", so both show as pressed. Give every part of a group its own value.`;
|
|
24
|
+
}
|
|
25
|
+
function c() {
|
|
26
|
+
return t("Toolbar:duplicate-value", s);
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { r as ToolbarContext, c as useToolbarCheckableRegistry, o as useToolbarContext };
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=Toolbar.context.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toolbar.context.mjs","names":["React","ToolbarContext","noop","INERT_TOOLBAR_CONTEXT","useToolbarContext","reportMissingContext","componentName","duplicateValueMessage","name","value","useToolbarCheckableRegistry","useDuplicatePairRegistry"],"sources":["../../../src/components/button/Toolbar.context.ts"],"sourcesContent":["import * as React from 'react';\nimport { useDuplicatePairRegistry, type CheckedValuesApi } from '../../hooks/useCheckedValues';\nimport { reportMissingContext } from '../../lib/dev';\nimport type { Orientation, Size } from '../../lib/types';\n\n/*\n * The context a Toolbar gives its parts (`Toolbar.Button`, `Toolbar.ToggleButton`, …): the\n * orientation, the default size and the checked-values state. Internal; imports no component.\n */\n\n/** What a Toolbar shares with its parts. */\nexport interface ToolbarContextValue {\n /** The toolbar's orientation (the arrow-key axis and the layout direction of groups). */\n orientation: Orientation;\n /** The default size of `Toolbar.Button`, `Toolbar.ToggleButton` and `Toolbar.RadioButton`. */\n size: Size;\n /** The pressed toggles and checked radios, per group `name`. */\n checked: CheckedValuesApi;\n /**\n * Development only (a no-op in production): a toggle or radio button registers its\n * `name`/`value` from an effect and unregisters on cleanup; a second registration of the same\n * pair in one toolbar warns once (`Toolbar:duplicate-value`), since both would show as pressed.\n */\n registerCheckable: (name: string, value: string) => () => void;\n}\n\nexport const ToolbarContext = React.createContext<ToolbarContextValue | null>(null);\nToolbarContext.displayName = 'ToolbarContext';\n\nconst noop = () => {};\n\n/** The context a misplaced part renders with in production (C-CONTEXT). */\nconst INERT_TOOLBAR_CONTEXT: ToolbarContextValue = {\n orientation: 'horizontal',\n size: 'medium',\n checked: {\n values: Object.freeze({}),\n isChecked: () => false,\n toggle: noop,\n select: noop,\n },\n registerCheckable: () => noop,\n};\n\n/** C-CONTEXT: throws in development, logs once and returns an inert value in production. */\nexport function useToolbarContext(componentName: string): ToolbarContextValue {\n const context = React.useContext(ToolbarContext);\n if (context) return context;\n reportMissingContext(componentName, 'Toolbar');\n return INERT_TOOLBAR_CONTEXT;\n}\n\n/** The warning for two toggle or radio buttons of one toolbar with the same `name`/`value` pair. */\nfunction duplicateValueMessage(name: string, value: string): string {\n return `Toolbar: two toggle or radio buttons of one toolbar have the name \"${name}\" and the value \"${value}\", so both show as pressed. Give every part of a group its own value.`;\n}\n\n/**\n * The `registerCheckable` of one toolbar: a count per `name`/`value` pair, kept for the toolbar's\n * lifetime. A second registration of a pair warns once (development only).\n */\nexport function useToolbarCheckableRegistry(): ToolbarContextValue['registerCheckable'] {\n return useDuplicatePairRegistry('Toolbar:duplicate-value', duplicateValueMessage);\n}\n"],"mappings":";;;;;AA0BA,IAAaC,IAAiBD,EAAM,cAA0C,IAAI;AAClF,EAAe,cAAc;AAE7B,IAAME,UAAa,CAAC,GAGdC,IAA6C;CACjD,aAAa;CACb,MAAM;CACN,SAAS;EACP,QAAQ,OAAO,OAAO,CAAC,CAAC;EACxB,iBAAiB;EACjB,QAAQD;EACR,QAAQA;CACV;CACA,yBAAyBA;AAC3B;AAGA,SAAgBE,EAAkB,GAA4C;CAI5E,OAHgBJ,EAAM,WAAWC,CAC7B,MACJI,EAAqBC,GAAe,SAAS,GACtCH;AACT;AAGA,SAASI,EAAsB,GAAc,GAAuB;CAClE,OAAO,sEAAsEC,EAAK,mBAAmBC,EAAM;AAC7G;AAMA,SAAgBC,IAAwE;CACtF,OAAOC,EAAyB,2BAA2BJ,CAAqB;AAClF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../../lib/cn.mjs";
|
|
3
|
+
import { composeEventHandlers as t } from "../../lib/composeEventHandlers.mjs";
|
|
4
|
+
import { useRovingTabIndex as n } from "../../hooks/useRovingTabIndex.mjs";
|
|
5
|
+
import { useMergedRefs as r } from "../../hooks/useMergedRefs.mjs";
|
|
6
|
+
import { useCheckedValues as i } from "../../hooks/useCheckedValues.mjs";
|
|
7
|
+
import { ToolbarContext as a, useToolbarCheckableRegistry as o } from "./Toolbar.context.mjs";
|
|
8
|
+
import { ToolbarButton as s, ToolbarDivider as c, ToolbarGroup as l, ToolbarRadioButton as u, ToolbarRadioGroup as d, ToolbarToggleButton as f } from "./Toolbar.parts.mjs";
|
|
9
|
+
import * as p from "react";
|
|
10
|
+
import { jsx as m } from "react/jsx-runtime";
|
|
11
|
+
//#region src/components/button/Toolbar.tsx
|
|
12
|
+
var h = "button, [href], input, select, textarea, [role=\"button\"], [tabindex]", g = {
|
|
13
|
+
"extra-small": "p-0.5",
|
|
14
|
+
small: "p-0.5",
|
|
15
|
+
medium: "p-1",
|
|
16
|
+
large: "p-1.5",
|
|
17
|
+
"extra-large": "p-2"
|
|
18
|
+
}, _ = (s) => {
|
|
19
|
+
let { as: c, orientation: l = "horizontal", size: u = "medium", checkedValues: d, defaultCheckedValues: f, onCheckedValuesChange: _, className: v, ref: y, onKeyDown: b, onFocus: x, role: S, "aria-orientation": C, ...w } = s, { containerProps: T } = n({
|
|
20
|
+
itemSelector: h,
|
|
21
|
+
manageTabIndex: !0,
|
|
22
|
+
tabStop: "last-focused",
|
|
23
|
+
orientation: l
|
|
24
|
+
}), E = r(T.ref, y), D = i(d, f, _), O = o(), k = p.useMemo(() => ({
|
|
25
|
+
orientation: l,
|
|
26
|
+
size: u,
|
|
27
|
+
checked: D,
|
|
28
|
+
registerCheckable: O
|
|
29
|
+
}), [
|
|
30
|
+
l,
|
|
31
|
+
u,
|
|
32
|
+
D,
|
|
33
|
+
O
|
|
34
|
+
]), A = c ?? "div";
|
|
35
|
+
return /* @__PURE__ */ m(a.Provider, {
|
|
36
|
+
value: k,
|
|
37
|
+
children: /* @__PURE__ */ m(A, {
|
|
38
|
+
"data-size": u,
|
|
39
|
+
"data-orientation": l,
|
|
40
|
+
...w,
|
|
41
|
+
role: S ?? "toolbar",
|
|
42
|
+
"aria-orientation": C ?? l,
|
|
43
|
+
ref: E,
|
|
44
|
+
"data-roving-container": "",
|
|
45
|
+
onKeyDown: t(b, T.onKeyDown),
|
|
46
|
+
onFocus: t(x, T.onFocus, { checkDefaultPrevented: !1 }),
|
|
47
|
+
className: e("inline-flex items-center gap-1 rounded border border-border", g[u], l === "vertical" && "flex-col items-stretch", v)
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
_.displayName = "Toolbar";
|
|
52
|
+
var v = /* @__PURE__ */ Object.assign(_, {
|
|
53
|
+
Button: s,
|
|
54
|
+
ToggleButton: f,
|
|
55
|
+
RadioGroup: d,
|
|
56
|
+
RadioButton: u,
|
|
57
|
+
Group: l,
|
|
58
|
+
Divider: c
|
|
59
|
+
});
|
|
60
|
+
//#endregion
|
|
61
|
+
export { v as Toolbar, s as ToolbarButton, c as ToolbarDivider, l as ToolbarGroup, u as ToolbarRadioButton, d as ToolbarRadioGroup, f as ToolbarToggleButton };
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=Toolbar.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toolbar.mjs","names":["React","TOOLBAR_ITEM_SELECTOR","toolbarPaddingClasses","ToolbarRoot","ariaOrientation","rest","props","useRovingTabIndex","mergedRef","useMergedRefs","containerProps","ref","checked","useCheckedValues","checkedValues","defaultCheckedValues","onCheckedValuesChange","registerCheckable","useToolbarCheckableRegistry","context","orientation","size","Component","as","ToolbarContext","role","composeEventHandlers","onKeyDown","onFocus","cn","className","Toolbar","ToolbarButton","ToolbarToggleButton","ToolbarRadioGroup","ToolbarRadioButton","ToolbarGroup","ToolbarDivider"],"sources":["../../../src/components/button/Toolbar.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport type { PolymorphicComponent, PolymorphicProps } from '../../lib/polymorphic';\nimport type { CheckedValues, CheckedValuesChangeHandler, Orientation, Size } from '../../lib/types';\nimport { useCheckedValues } from '../../hooks/useCheckedValues';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useRovingTabIndex } from '../../hooks/useRovingTabIndex';\nimport { ToolbarContext, useToolbarCheckableRegistry } from './Toolbar.context';\nimport type { ToolbarContextValue } from './Toolbar.context';\nimport {\n ToolbarButton,\n ToolbarDivider,\n ToolbarGroup,\n ToolbarRadioButton,\n ToolbarRadioGroup,\n ToolbarToggleButton,\n} from './Toolbar.parts';\n\nexport {\n ToolbarButton,\n ToolbarDivider,\n ToolbarGroup,\n ToolbarRadioButton,\n ToolbarRadioGroup,\n ToolbarToggleButton,\n};\nexport type {\n ToolbarButtonOwnProps,\n ToolbarButtonProps,\n ToolbarDividerProps,\n ToolbarGroupProps,\n ToolbarRadioButtonProps,\n ToolbarRadioGroupProps,\n ToolbarToggleButtonProps,\n} from './Toolbar.parts';\n\n/**\n * The Toolbar's own props (the XOwnProps rule of `PolymorphicProps`: component-specific props\n * only). Every other prop comes from the rendered element (`as`, default `'div'`). Give the\n * toolbar an `aria-label` (or `aria-labelledby`) that describes its purpose, e.g. \"Formatting\".\n */\nexport interface ToolbarOwnProps {\n /**\n * Layout and arrow-key axis: Left/Right move between items when horizontal (mirrored in RTL),\n * Up/Down when vertical. Exposed as `aria-orientation` and `data-orientation`.\n * @default 'horizontal'\n */\n orientation?: Orientation;\n /**\n * Default size of `Toolbar.Button`, `Toolbar.ToggleButton` and `Toolbar.RadioButton` (their\n * own `size` wins), and the toolbar's padding. Plain Buttons inside keep their own default.\n * Exposed as `data-size`.\n * @default 'medium'\n */\n size?: Size;\n /**\n * Pressed `Toolbar.ToggleButton`s and checked `Toolbar.RadioButton`s, per group `name`\n * (controlled): `{ format: ['bold'], align: ['center'] }`.\n */\n checkedValues?: CheckedValues;\n /** Initial checked values for uncontrolled usage. @default {} */\n defaultCheckedValues?: CheckedValues;\n /**\n * Called when a toggle or radio changes them (only on change): the new checked values first,\n * then `details` with the group's `name`, its `checkedItems` and the `event` (Fluent's\n * `onCheckedValueChange(event, { name, checkedItems })`; always passed, typed optional until 1.0).\n */\n onCheckedValuesChange?: CheckedValuesChangeHandler;\n}\n\n/**\n * Props of {@link Toolbar} rendered as `C` (default `'div'`). `ToolbarProps` without a type\n * argument is the 0.4 name: the props of a Toolbar rendered as a `<div>`, including `ref`.\n */\nexport type ToolbarProps<C extends React.ElementType = 'div'> = PolymorphicProps<\n C,\n ToolbarOwnProps\n>;\n\n/** The props the implementation reads, for any `as`. */\ntype ToolbarImplProps = ToolbarOwnProps &\n React.HTMLAttributes<HTMLElement> & {\n as?: React.ElementType;\n ref?: React.Ref<HTMLElement>;\n };\n\n/**\n * Every focusable control a toolbar can contain, whatever component renders it. Matches that\n * cannot take focus (a `type=\"hidden\"` input, a control CSS hides) are dropped by the roving hook.\n */\nconst TOOLBAR_ITEM_SELECTOR =\n 'button, [href], input, select, textarea, [role=\"button\"], [tabindex]';\n\n/** The toolbar's padding per size. */\nconst toolbarPaddingClasses: Record<Size, string> = {\n 'extra-small': 'p-0.5',\n small: 'p-0.5',\n medium: 'p-1',\n large: 'p-1.5',\n 'extra-large': 'p-2',\n};\n\n// The root of the Toolbar compound; its component JSDoc is on the `Toolbar` export below (C-DOCS).\nconst ToolbarRoot: PolymorphicComponent<'div', ToolbarOwnProps> = (props) => {\n const {\n as,\n orientation = 'horizontal',\n size = 'medium',\n checkedValues,\n defaultCheckedValues,\n onCheckedValuesChange,\n className,\n ref,\n onKeyDown,\n onFocus,\n role,\n 'aria-orientation': ariaOrientation,\n ...rest\n } = props as ToolbarImplProps;\n\n const { containerProps } = useRovingTabIndex({\n itemSelector: TOOLBAR_ITEM_SELECTOR,\n manageTabIndex: true,\n tabStop: 'last-focused',\n orientation,\n });\n const mergedRef = useMergedRefs<HTMLElement>(containerProps.ref, ref);\n\n const checked = useCheckedValues(checkedValues, defaultCheckedValues, onCheckedValuesChange);\n const registerCheckable = useToolbarCheckableRegistry();\n const context = React.useMemo<ToolbarContextValue>(\n () => ({ orientation, size, checked, registerCheckable }),\n [orientation, size, checked, registerCheckable],\n );\n\n const Component: React.ElementType = as ?? 'div';\n // The role and `aria-orientation` defaults apply wherever the consumer's value is `undefined` or\n // `null` (as in Button), so a wrapper forwarding its own unset props keeps them.\n return (\n <ToolbarContext.Provider value={context}>\n <Component\n data-size={size}\n data-orientation={orientation}\n {...rest}\n role={role ?? 'toolbar'}\n aria-orientation={ariaOrientation ?? orientation}\n ref={mergedRef}\n data-roving-container=\"\"\n onKeyDown={composeEventHandlers(onKeyDown, containerProps.onKeyDown)}\n onFocus={composeEventHandlers(onFocus, containerProps.onFocus, {\n checkDefaultPrevented: false,\n })}\n className={cn(\n 'inline-flex items-center gap-1 rounded border border-border',\n toolbarPaddingClasses[size],\n orientation === 'vertical' && 'flex-col items-stretch',\n className,\n )}\n />\n </ToolbarContext.Provider>\n );\n};\nToolbarRoot.displayName = 'Toolbar';\n\n/**\n * A container for a set of controls (APG Toolbar pattern): `role=\"toolbar\"`, one Tab stop, and\n * arrow-key navigation between its controls.\n *\n * - Works with any children (Buttons, ToggleButtons, links, inputs, value controls such as\n * Checkbox or Dropdown): the focusable controls are found in the DOM, and the Toolbar sets their\n * `tabIndex` itself (one `0`, the rest `-1`). The `type=\"hidden\"` input that a named value\n * control renders never counts as a control, and controls that CSS hides are skipped.\n * - Parts: `Toolbar.Button`, `Toolbar.ToggleButton` and `Toolbar.RadioButton` take the toolbar's\n * `size` (default `'medium'`) and the `subtle` appearance by default; `Toolbar.RadioGroup`,\n * `Toolbar.Group` and `Toolbar.Divider` lay them out. Plain Buttons keep their own defaults.\n * - State: the pressed `Toolbar.ToggleButton`s and the checked `Toolbar.RadioButton` of each\n * group live in `checkedValues`/`defaultCheckedValues`, per group `name`, and every change calls\n * `onCheckedValuesChange(checkedValues, details)`. The state is in the server HTML.\n * - Left/Right (Up/Down when `orientation=\"vertical\"`) move focus and wrap; Home/End jump to the\n * first/last control; Left/Right are mirrored in RTL. Natively disabled controls are skipped,\n * also when a child disables them on its own; `disabledFocusable` ones stay in the arrow-key\n * order (APG), so a Tooltip can explain why they are unavailable. The arrows never press a\n * toggle or check a radio: Space, Enter or a click does.\n * - The radios of a `Toolbar.RadioGroup` are part of that arrow-key order, and Up/Down (Left/Right\n * in a vertical toolbar) also move among them, wrapping inside the group.\n * - Tab returns to the last focused control. Focusing a nested composite (radio group, tab list)\n * or a text field, select, slider or spin button keeps the Tab stop where it was.\n * - Text fields, selects, sliders, spin buttons and editable comboboxes keep their own arrow keys\n * (the caret moves). A Dropdown (select-only combobox) does not: Left/Right move past it. It\n * keeps Up/Down, Home and End for its list, so in a vertical toolbar the arrows cannot leave it.\n * - Elements with their own `tabIndex={-1}` are left alone, and a nested composite widget (a\n * RadioGroup, a tab list, …; not `Toolbar.RadioGroup`) counts as one control that keeps its own\n * Tab stop and arrow keys.\n * - A Menu or Popover opened from a control keeps its own keys: arrows, Home and End pressed in\n * the popup never move focus back to the toolbar's controls.\n * - A consumer `onKeyDown` runs first; `event.preventDefault()` in it cancels the navigation.\n * - Renders `data-size` and `data-orientation`.\n *\n * React Server Components cannot dot into a client module: import the flat names\n * `ToolbarButton`, `ToolbarToggleButton`, `ToolbarRadioGroup`, `ToolbarRadioButton`,\n * `ToolbarGroup` and `ToolbarDivider` there; `Toolbar.Button` etc. work in client files.\n *\n * @example\n * <Toolbar aria-label=\"Formatting\" defaultCheckedValues={{ format: ['bold'], align: ['left'] }}>\n * <Toolbar.ToggleButton name=\"format\" value=\"bold\" icon={<BoldIcon />} aria-label=\"Bold\" />\n * <Toolbar.ToggleButton name=\"format\" value=\"code\" icon={<CodeIcon />} aria-label=\"Code\" />\n * <Toolbar.Divider />\n * <Toolbar.RadioGroup aria-label=\"Text alignment\">\n * <Toolbar.RadioButton name=\"align\" value=\"left\" icon={<AlignLeftIcon />} aria-label=\"Left\" />\n * <Toolbar.RadioButton name=\"align\" value=\"center\" icon={<AlignCenterIcon />} aria-label=\"Center\" />\n * </Toolbar.RadioGroup>\n * </Toolbar>\n */\nexport const Toolbar = /* @__PURE__ */ Object.assign(ToolbarRoot, {\n Button: ToolbarButton,\n ToggleButton: ToolbarToggleButton,\n RadioGroup: ToolbarRadioGroup,\n RadioButton: ToolbarRadioButton,\n Group: ToolbarGroup,\n Divider: ToolbarDivider,\n});\n"],"mappings":";;;;;;;;;;;AA2FA,IAAMC,IACJ,0EAGIC,IAA8C;CAClD,eAAe;CACf,OAAO;CACP,QAAQ;CACR,OAAO;CACP,eAAe;AACjB,GAGMC,KAA6D,MAAU;CAC3E,IAAM,EACJ,OACA,iBAAc,cACd,UAAO,UACP,kBACA,yBACA,0BACA,cACA,QACA,cACA,YACA,SACA,oBAAoBC,GACpB,GAAGC,MACDC,GAEE,EAAE,sBAAmBC,EAAkB;EAC3C,cAAcN;EACd,gBAAgB;EAChB,SAAS;EACT;CACF,CAAC,GACKO,IAAYC,EAA2BC,EAAe,KAAKC,CAAG,GAE9DC,IAAUC,EAAiBC,GAAeC,GAAsBC,CAAqB,GACrFC,IAAoBC,EAA4B,GAChDC,IAAUnB,EAAM,eACb;EAAE;EAAa;EAAM;EAAS;CAAkB,IACvD;EAACoB;EAAaC;EAAMT;EAASK;CAAiB,CAChD,GAEMK,IAA+BC,KAAM;CAG3C,OACE,kBAACC,EAAe,UAAhB;EAAyB,OAAOL;EAC9B,UAAA,kBAACG,GAAD;GACE,aAAWD;GACX,oBAAkBD;GAClB,GAAIf;GACJ,MAAMoB,KAAQ;GACd,oBAAkBrB,KAAmBgB;GACrC,KAAKZ;GACL,yBAAsB;GACtB,WAAWkB,EAAqBC,GAAWjB,EAAe,SAAS;GACnE,SAASgB,EAAqBE,GAASlB,EAAe,SAAS,EAC7D,uBAAuB,GACzB,CAAC;GACD,WAAWmB,EACT,+DACA3B,EAAsBmB,IACtBD,MAAgB,cAAc,0BAC9BU,CACF;EACD,CAAA;CACsB,CAAA;AAE7B;AACA,EAAY,cAAc;AAmD1B,IAAaC,IAA0B,uBAAO,OAAO5B,GAAa;CAChE,QAAQ6B;CACR,cAAcC;CACd,YAAYC;CACZ,aAAaC;CACb,OAAOC;CACP,SAASC;AACX,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/slot.cjs"),i=require("../../lib/composeEventHandlers.cjs"),a=require("../../lib/direction.cjs"),o=require("../../lib/styles.cjs"),s=require("./Button.cjs"),c=require("./ToggleButton.cjs"),l=require("./Toolbar.context.cjs");let u=require("react");u=e.__toESM(u,1);let d=require("react/jsx-runtime");var f=s.Button,p=`h-auto min-w-0 flex-col gap-0.5 px-2 py-1 text-caption-1`,m={"extra-small":`size-5 justify-center [&>svg]:size-full`,small:`size-5 justify-center [&>svg]:size-full`,medium:`size-6 justify-center [&>svg]:size-full`,large:`size-6 justify-center [&>svg]:size-full`,"extra-large":`size-6 justify-center [&>svg]:size-full`};function h(e,t){if(!r.slotRendersContent(e))return e;let n=r.resolveSlot(e,`span`,t);return n?{...n.props,as:n.Component,children:n.children}:e}var g=e=>{let{vertical:n=!1,appearance:r=`subtle`,size:i,icon:a,className:o,...s}=e,c=l.useToolbarContext(`Toolbar.Button`),u=i??c.size;return(0,d.jsx)(f,{...s,appearance:r,size:u,icon:n?h(a,m[u]):a,"data-vertical":n?``:void 0,className:t.cn(n&&p,o)})};g.displayName=`ToolbarButton`;function _(e,t,n){u.useEffect(()=>e(t,n),[e,t,n])}var v=({name:e,value:t,appearance:n=`subtle`,size:r,onClick:a,...o})=>{let s=l.useToolbarContext(`Toolbar.ToggleButton`),{checked:u}=s;return _(s.registerCheckable,e,t),(0,d.jsx)(c.ToggleButton,{...o,appearance:n,size:r??s.size,pressed:u.isChecked(e,t),onClick:i.composeEventHandlers(a,n=>u.toggle(e,t,n.nativeEvent))})};v.displayName=`ToolbarToggleButton`;var y=({name:e,value:t,appearance:n=`subtle`,size:r,onClick:a,...o})=>{let s=l.useToolbarContext(`Toolbar.RadioButton`),{checked:u}=s;return _(s.registerCheckable,e,t),(0,d.jsx)(c.ToggleButton,{...o,role:`radio`,appearance:n,size:r??s.size,pressed:u.isChecked(e,t),onClick:i.composeEventHandlers(a,n=>u.select(e,t,n.nativeEvent))})};y.displayName=`ToolbarRadioButton`;var b=({className:e,onKeyDown:r,ref:o,...s})=>{let{orientation:c}=l.useToolbarContext(`Toolbar.RadioGroup`),f=s[`aria-label`],p=s[`aria-labelledby`];u.useEffect(()=>{f||p||n.warnOnce(`Toolbar.RadioGroup:name`,'Toolbar.RadioGroup: a radio group needs an accessible name that says what it chooses (e.g. "Text alignment"). Pass `aria-label` or `aria-labelledby`.')},[f,p]);let m=e=>{if(e.metaKey||e.ctrlKey||e.altKey)return;let t=e.currentTarget,n=c===`vertical`?a.getArrowIntent(e.key,{orientation:`horizontal`,dir:a.getDirection(t)}):a.getArrowIntent(e.key,{orientation:`vertical`,dir:`ltr`});if(!n)return;let r=Array.from(t.querySelectorAll(`[role="radio"]`)),i=r.findIndex(t=>t.contains(e.target));if(i===-1)return;e.preventDefault();let o=n===`next`?1:-1,s=r.length;for(let e=1;e<s;e++){let t=r[((i+o*e)%s+s)%s];if(!t.matches(`:disabled`)&&(t.focus(),t.ownerDocument.activeElement===t))return}};return(0,d.jsx)(`div`,{...s,ref:o,role:`radiogroup`,"data-roving-transparent":``,onKeyDown:i.composeEventHandlers(r,m),className:t.cn(`flex gap-1`,c===`vertical`&&`flex-col`,e)})};b.displayName=`ToolbarRadioGroup`;var x=({role:e,className:n,ref:r,...i})=>{let{orientation:a}=l.useToolbarContext(`Toolbar.Group`),o=!!(i[`aria-label`]||i[`aria-labelledby`]);return(0,d.jsx)(`div`,{role:e??(o?`group`:`presentation`),"data-orientation":a,...i,ref:r,className:t.cn(`flex gap-1`,a===`vertical`&&`flex-col`,n)})};x.displayName=`ToolbarGroup`;var S=({className:e,ref:n,...r})=>{let{orientation:i}=l.useToolbarContext(`Toolbar.Divider`),a=i===`vertical`;return(0,d.jsx)(`div`,{role:`separator`,"aria-orientation":a?`horizontal`:`vertical`,...r,ref:n,className:t.cn(a?`my-1 h-0 shrink-0 self-stretch border-t border-border`:`mx-1 w-0 shrink-0 self-stretch border-s border-border`,o.forcedColors.border,e)})};S.displayName=`ToolbarDivider`,exports.ToolbarButton=g,exports.ToolbarDivider=S,exports.ToolbarGroup=x,exports.ToolbarRadioButton=y,exports.ToolbarRadioGroup=b,exports.ToolbarToggleButton=v;
|
|
2
|
+
//# sourceMappingURL=Toolbar.parts.cjs.map
|