@primitiv-ui/react 0.1.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 +79 -0
- package/package.json +59 -0
- package/src/AccessibleIcon/AccessibleIcon.tsx +40 -0
- package/src/AccessibleIcon/README.md +42 -0
- package/src/AccessibleIcon/__tests__/AccessibleIcon.test.tsx +47 -0
- package/src/AccessibleIcon/index.ts +2 -0
- package/src/AccessibleIcon/types.ts +8 -0
- package/src/Accordion/Accordion.tsx +412 -0
- package/src/Accordion/AccordionContext.ts +12 -0
- package/src/Accordion/README.md +202 -0
- package/src/Accordion/__tests__/Accordion.asChild.test.tsx +237 -0
- package/src/Accordion/__tests__/Accordion.basic-rendering.test.tsx +333 -0
- package/src/Accordion/__tests__/Accordion.controlled-state.test.tsx +175 -0
- package/src/Accordion/__tests__/Accordion.data-attributes.test.tsx +272 -0
- package/src/Accordion/__tests__/Accordion.disabled-items.test.tsx +311 -0
- package/src/Accordion/__tests__/Accordion.error-handling.test.tsx +119 -0
- package/src/Accordion/__tests__/Accordion.forceMount.test.tsx +119 -0
- package/src/Accordion/__tests__/Accordion.keyboard-interaction.test.tsx +736 -0
- package/src/Accordion/__tests__/Accordion.mouse-interaction.test.tsx +212 -0
- package/src/Accordion/__tests__/Accordion.multiple-mode.test.tsx +90 -0
- package/src/Accordion/__tests__/Accordion.reading-direction.test.tsx +139 -0
- package/src/Accordion/__tests__/Accordion.uncontrolled-state.test.tsx +154 -0
- package/src/Accordion/hooks/index.ts +6 -0
- package/src/Accordion/hooks/useAccordionContext.ts +1 -0
- package/src/Accordion/hooks/useAccordionHeaderContext.ts +10 -0
- package/src/Accordion/hooks/useAccordionItem.ts +22 -0
- package/src/Accordion/hooks/useAccordionItemContext.ts +1 -0
- package/src/Accordion/hooks/useAccordionRoot.ts +151 -0
- package/src/Accordion/hooks/useAccordionTrigger.ts +90 -0
- package/src/Accordion/index.ts +1 -0
- package/src/Accordion/types.ts +81 -0
- package/src/Alert/Alert.tsx +43 -0
- package/src/Alert/README.md +54 -0
- package/src/Alert/__tests__/Alert.test.tsx +28 -0
- package/src/Alert/index.ts +2 -0
- package/src/Alert/types.ts +5 -0
- package/src/Avatar/Avatar.tsx +149 -0
- package/src/Avatar/AvatarContext.ts +20 -0
- package/src/Avatar/README.md +116 -0
- package/src/Avatar/__tests__/Avatar.asChild.test.tsx +53 -0
- package/src/Avatar/__tests__/Avatar.basic-rendering.test.tsx +14 -0
- package/src/Avatar/__tests__/Avatar.error-handling.test.tsx +30 -0
- package/src/Avatar/__tests__/Avatar.fallback.test.tsx +75 -0
- package/src/Avatar/__tests__/Avatar.image-loading.test.tsx +81 -0
- package/src/Avatar/hooks/index.ts +2 -0
- package/src/Avatar/hooks/useAvatarContext.ts +1 -0
- package/src/Avatar/hooks/useAvatarImage.ts +40 -0
- package/src/Avatar/index.ts +3 -0
- package/src/Avatar/types.ts +44 -0
- package/src/Breadcrumb/Breadcrumb.tsx +234 -0
- package/src/Breadcrumb/README.md +111 -0
- package/src/Breadcrumb/__tests__/Breadcrumb.asChild.test.tsx +33 -0
- package/src/Breadcrumb/__tests__/Breadcrumb.basic-rendering.test.tsx +132 -0
- package/src/Breadcrumb/index.ts +2 -0
- package/src/Breadcrumb/types.ts +22 -0
- package/src/Button/Button.tsx +95 -0
- package/src/Button/README.md +112 -0
- package/src/Button/__tests__/Button.asChild.test.tsx +91 -0
- package/src/Button/__tests__/Button.basic-rendering.test.tsx +126 -0
- package/src/Button/__tests__/Button.contract.test.tsx +72 -0
- package/src/Button/__tests__/Button.disabled.test.tsx +52 -0
- package/src/Button/__tests__/Button.icon-usage.test.tsx +57 -0
- package/src/Button/__tests__/Button.keyboard-interaction.test.tsx +70 -0
- package/src/Button/index.ts +2 -0
- package/src/Button/types.ts +8 -0
- package/src/Carousel/Carousel.tsx +708 -0
- package/src/Carousel/CarouselContext.ts +11 -0
- package/src/Carousel/README.md +848 -0
- package/src/Carousel/__tests__/Carousel.asChild.test.tsx +178 -0
- package/src/Carousel/__tests__/Carousel.auto-play.test.tsx +617 -0
- package/src/Carousel/__tests__/Carousel.basic-rendering.test.tsx +569 -0
- package/src/Carousel/__tests__/Carousel.controlled-state.test.tsx +137 -0
- package/src/Carousel/__tests__/Carousel.error-handling.test.tsx +81 -0
- package/src/Carousel/__tests__/Carousel.ids.test.tsx +111 -0
- package/src/Carousel/__tests__/Carousel.imperative-api.test.tsx +213 -0
- package/src/Carousel/__tests__/Carousel.indicators.test.tsx +560 -0
- package/src/Carousel/__tests__/Carousel.intersection-observer.test.tsx +276 -0
- package/src/Carousel/__tests__/Carousel.keyboard-navigation.test.tsx +158 -0
- package/src/Carousel/__tests__/Carousel.play-pause.test.tsx +232 -0
- package/src/Carousel/__tests__/Carousel.prev-next.test.tsx +68 -0
- package/src/Carousel/__tests__/Carousel.reduced-motion.test.tsx +49 -0
- package/src/Carousel/__tests__/Carousel.refresh-progress.test.tsx +87 -0
- package/src/Carousel/__tests__/Carousel.scroll-snap-change.test.tsx +179 -0
- package/src/Carousel/__tests__/Carousel.scroll-sync.test.tsx +109 -0
- package/src/Carousel/__tests__/Carousel.slides-per-move.test.tsx +151 -0
- package/src/Carousel/__tests__/Carousel.slides-per-page.test.tsx +183 -0
- package/src/Carousel/__tests__/Carousel.touch-interaction.test.tsx +96 -0
- package/src/Carousel/__tests__/Carousel.transition-modes.test.tsx +70 -0
- package/src/Carousel/__tests__/Carousel.translations.test.tsx +157 -0
- package/src/Carousel/__tests__/Carousel.uncontrolled-state.test.tsx +146 -0
- package/src/Carousel/hooks/index.ts +4 -0
- package/src/Carousel/hooks/useCarouselContext.ts +13 -0
- package/src/Carousel/hooks/useCarouselRoot.ts +450 -0
- package/src/Carousel/hooks/useCarouselSlide.ts +45 -0
- package/src/Carousel/hooks/useCarouselViewport.ts +290 -0
- package/src/Carousel/index.ts +3 -0
- package/src/Carousel/types.ts +400 -0
- package/src/Checkbox/Checkbox.tsx +228 -0
- package/src/Checkbox/CheckboxContext.ts +12 -0
- package/src/Checkbox/README.md +156 -0
- package/src/Checkbox/__tests__/Checkbox.asChild.test.tsx +69 -0
- package/src/Checkbox/__tests__/Checkbox.basic-rendering.test.tsx +41 -0
- package/src/Checkbox/__tests__/Checkbox.controlled-state.test.tsx +82 -0
- package/src/Checkbox/__tests__/Checkbox.disabled.test.tsx +15 -0
- package/src/Checkbox/__tests__/Checkbox.indeterminate.test.tsx +82 -0
- package/src/Checkbox/__tests__/Checkbox.indicator.test.tsx +117 -0
- package/src/Checkbox/__tests__/Checkbox.uncontrolled-state.test.tsx +89 -0
- package/src/Checkbox/hooks/index.ts +2 -0
- package/src/Checkbox/hooks/useCheckboxContext.ts +1 -0
- package/src/Checkbox/hooks/useCheckboxRoot.ts +32 -0
- package/src/Checkbox/index.ts +1 -0
- package/src/Checkbox/types.ts +33 -0
- package/src/CheckboxCard/CheckboxCard.tsx +208 -0
- package/src/CheckboxCard/CheckboxCardContext.ts +12 -0
- package/src/CheckboxCard/README.md +114 -0
- package/src/CheckboxCard/__tests__/CheckboxCard.asChild.test.tsx +54 -0
- package/src/CheckboxCard/__tests__/CheckboxCard.basic-rendering.test.tsx +58 -0
- package/src/CheckboxCard/__tests__/CheckboxCard.controlled-state.test.tsx +77 -0
- package/src/CheckboxCard/__tests__/CheckboxCard.disabled.test.tsx +55 -0
- package/src/CheckboxCard/__tests__/CheckboxCard.error-handling.test.tsx +20 -0
- package/src/CheckboxCard/__tests__/CheckboxCard.indeterminate.test.tsx +60 -0
- package/src/CheckboxCard/__tests__/CheckboxCard.indicator.test.tsx +136 -0
- package/src/CheckboxCard/__tests__/CheckboxCard.uncontrolled-state.test.tsx +73 -0
- package/src/CheckboxCard/hooks/index.ts +2 -0
- package/src/CheckboxCard/hooks/useCheckboxCardContext.ts +1 -0
- package/src/CheckboxCard/hooks/useCheckboxCardRoot.ts +30 -0
- package/src/CheckboxCard/index.ts +3 -0
- package/src/CheckboxCard/types.ts +33 -0
- package/src/Collapsible/Collapsible.tsx +316 -0
- package/src/Collapsible/CollapsibleContext.ts +7 -0
- package/src/Collapsible/README.md +174 -0
- package/src/Collapsible/__tests__/Collapsible.asChild.test.tsx +240 -0
- package/src/Collapsible/__tests__/Collapsible.basic-rendering.test.tsx +118 -0
- package/src/Collapsible/__tests__/Collapsible.controlled-state.test.tsx +134 -0
- package/src/Collapsible/__tests__/Collapsible.disabled.test.tsx +132 -0
- package/src/Collapsible/__tests__/Collapsible.error-handling.test.tsx +40 -0
- package/src/Collapsible/__tests__/Collapsible.forceMount.test.tsx +111 -0
- package/src/Collapsible/__tests__/Collapsible.triggerIcon.test.tsx +93 -0
- package/src/Collapsible/__tests__/Collapsible.uncontrolled-state.test.tsx +125 -0
- package/src/Collapsible/hooks/index.ts +2 -0
- package/src/Collapsible/hooks/useCollapsibleRoot.ts +34 -0
- package/src/Collapsible/hooks/useCollapsibleTrigger.ts +49 -0
- package/src/Collapsible/index.ts +1 -0
- package/src/Collapsible/types.ts +48 -0
- package/src/ContextMenu/ContextMenu.tsx +1004 -0
- package/src/ContextMenu/ContextMenuContentContext.ts +15 -0
- package/src/ContextMenu/ContextMenuContext.ts +21 -0
- package/src/ContextMenu/ContextMenuGroupContext.ts +8 -0
- package/src/ContextMenu/ContextMenuItemIndicatorContext.ts +8 -0
- package/src/ContextMenu/ContextMenuRadioGroupContext.ts +9 -0
- package/src/ContextMenu/ContextMenuSubContext.ts +15 -0
- package/src/ContextMenu/README.md +275 -0
- package/src/ContextMenu/__tests__/ContextMenu.asChild.test.tsx +186 -0
- package/src/ContextMenu/__tests__/ContextMenu.basic-rendering.test.tsx +39 -0
- package/src/ContextMenu/__tests__/ContextMenu.checkbox-item.test.tsx +145 -0
- package/src/ContextMenu/__tests__/ContextMenu.error-handling.test.tsx +113 -0
- package/src/ContextMenu/__tests__/ContextMenu.group-label.test.tsx +48 -0
- package/src/ContextMenu/__tests__/ContextMenu.item-indicator.test.tsx +88 -0
- package/src/ContextMenu/__tests__/ContextMenu.item.test.tsx +106 -0
- package/src/ContextMenu/__tests__/ContextMenu.keyboard-interaction.test.tsx +172 -0
- package/src/ContextMenu/__tests__/ContextMenu.mouse-interaction.test.tsx +227 -0
- package/src/ContextMenu/__tests__/ContextMenu.radio-item.test.tsx +127 -0
- package/src/ContextMenu/__tests__/ContextMenu.reading-direction.test.tsx +152 -0
- package/src/ContextMenu/__tests__/ContextMenu.separator.test.tsx +47 -0
- package/src/ContextMenu/__tests__/ContextMenu.state-modes.test.tsx +119 -0
- package/src/ContextMenu/__tests__/ContextMenu.sub.test.tsx +262 -0
- package/src/ContextMenu/__tests__/ContextMenu.typeahead.test.tsx +89 -0
- package/src/ContextMenu/constants.ts +4 -0
- package/src/ContextMenu/index.ts +1 -0
- package/src/ContextMenu/types.ts +199 -0
- package/src/DirectionProvider/DirectionContext.ts +21 -0
- package/src/DirectionProvider/DirectionProvider.tsx +31 -0
- package/src/DirectionProvider/README.md +62 -0
- package/src/DirectionProvider/__tests__/DirectionProvider.test.tsx +29 -0
- package/src/DirectionProvider/index.ts +3 -0
- package/src/DirectionProvider/types.ts +10 -0
- package/src/Divider/Divider.tsx +57 -0
- package/src/Divider/README.md +57 -0
- package/src/Divider/__tests__/Divider.test.tsx +41 -0
- package/src/Divider/index.ts +1 -0
- package/src/Divider/types.ts +5 -0
- package/src/Dropdown/Dropdown.tsx +842 -0
- package/src/Dropdown/DropdownContentContext.ts +15 -0
- package/src/Dropdown/DropdownContext.ts +17 -0
- package/src/Dropdown/DropdownGroupContext.ts +8 -0
- package/src/Dropdown/DropdownItemIndicatorContext.ts +13 -0
- package/src/Dropdown/DropdownRadioGroupContext.ts +9 -0
- package/src/Dropdown/DropdownSubContext.ts +15 -0
- package/src/Dropdown/README.md +284 -0
- package/src/Dropdown/__tests__/Dropdown.asChild.test.tsx +286 -0
- package/src/Dropdown/__tests__/Dropdown.basic-rendering.test.tsx +43 -0
- package/src/Dropdown/__tests__/Dropdown.checkbox-item.test.tsx +121 -0
- package/src/Dropdown/__tests__/Dropdown.disabled.test.tsx +143 -0
- package/src/Dropdown/__tests__/Dropdown.error-handling.test.tsx +85 -0
- package/src/Dropdown/__tests__/Dropdown.group-label.test.tsx +68 -0
- package/src/Dropdown/__tests__/Dropdown.item-indicator.test.tsx +260 -0
- package/src/Dropdown/__tests__/Dropdown.item.test.tsx +72 -0
- package/src/Dropdown/__tests__/Dropdown.keyboard-edge-cases.test.tsx +77 -0
- package/src/Dropdown/__tests__/Dropdown.keyboard-interaction.test.tsx +310 -0
- package/src/Dropdown/__tests__/Dropdown.mouse-interaction.test.tsx +347 -0
- package/src/Dropdown/__tests__/Dropdown.radio-item.test.tsx +134 -0
- package/src/Dropdown/__tests__/Dropdown.reading-direction.test.tsx +153 -0
- package/src/Dropdown/__tests__/Dropdown.separator.test.tsx +46 -0
- package/src/Dropdown/__tests__/Dropdown.state-modes.test.tsx +100 -0
- package/src/Dropdown/__tests__/Dropdown.sub.test.tsx +185 -0
- package/src/Dropdown/__tests__/Dropdown.trigger.test.tsx +110 -0
- package/src/Dropdown/__tests__/Dropdown.typeahead.test.tsx +133 -0
- package/src/Dropdown/constants.ts +4 -0
- package/src/Dropdown/hooks/index.ts +9 -0
- package/src/Dropdown/hooks/useCloseSiblingSub.ts +13 -0
- package/src/Dropdown/hooks/useDropdownContent.ts +162 -0
- package/src/Dropdown/hooks/useDropdownContext.ts +1 -0
- package/src/Dropdown/hooks/useDropdownGroup.ts +18 -0
- package/src/Dropdown/hooks/useDropdownItem.ts +49 -0
- package/src/Dropdown/hooks/useDropdownLabel.ts +15 -0
- package/src/Dropdown/hooks/useDropdownRoot.ts +57 -0
- package/src/Dropdown/hooks/useDropdownSubContext.ts +1 -0
- package/src/Dropdown/hooks/useDropdownTrigger.ts +31 -0
- package/src/Dropdown/index.ts +1 -0
- package/src/Dropdown/types.ts +200 -0
- package/src/EmptyState/EmptyState.tsx +245 -0
- package/src/EmptyState/README.md +129 -0
- package/src/EmptyState/__tests__/EmptyState.Actions.test.tsx +32 -0
- package/src/EmptyState/__tests__/EmptyState.Description.test.tsx +30 -0
- package/src/EmptyState/__tests__/EmptyState.Media.test.tsx +34 -0
- package/src/EmptyState/__tests__/EmptyState.Root.test.tsx +28 -0
- package/src/EmptyState/__tests__/EmptyState.Title.test.tsx +26 -0
- package/src/EmptyState/index.ts +2 -0
- package/src/EmptyState/types.ts +21 -0
- package/src/Field/Field.tsx +239 -0
- package/src/Field/FieldContext.ts +22 -0
- package/src/Field/README.md +167 -0
- package/src/Field/__tests__/Field.asChild.test.tsx +83 -0
- package/src/Field/__tests__/Field.basic-rendering.test.tsx +104 -0
- package/src/Field/__tests__/Field.state-cascade.test.tsx +75 -0
- package/src/Field/hooks/index.ts +2 -0
- package/src/Field/hooks/useFieldContext.ts +1 -0
- package/src/Field/hooks/useFieldProps.ts +57 -0
- package/src/Field/index.ts +2 -0
- package/src/Field/types.ts +33 -0
- package/src/Fieldset/Fieldset.tsx +104 -0
- package/src/Fieldset/README.md +74 -0
- package/src/Fieldset/__tests__/Fieldset.basic-rendering.test.tsx +81 -0
- package/src/Fieldset/__tests__/Fieldset.disabled.test.tsx +41 -0
- package/src/Fieldset/index.ts +2 -0
- package/src/Fieldset/types.ts +5 -0
- package/src/Input/Input.tsx +120 -0
- package/src/Input/README.md +180 -0
- package/src/Input/__tests__/Input.asChild.test.tsx +85 -0
- package/src/Input/__tests__/Input.basic-rendering.test.tsx +118 -0
- package/src/Input/__tests__/Input.disabled.test.tsx +49 -0
- package/src/Input/__tests__/Input.field-integration.test.tsx +148 -0
- package/src/Input/index.ts +2 -0
- package/src/Input/types.ts +7 -0
- package/src/InputGroup/InputGroup.tsx +228 -0
- package/src/InputGroup/README.md +178 -0
- package/src/InputGroup/__tests__/InputGroup.asChild.test.tsx +109 -0
- package/src/InputGroup/__tests__/InputGroup.basic-rendering.test.tsx +106 -0
- package/src/InputGroup/index.ts +2 -0
- package/src/InputGroup/types.ts +13 -0
- package/src/MillerColumns/MillerColumns.tsx +329 -0
- package/src/MillerColumns/MillerColumnsContext.ts +25 -0
- package/src/MillerColumns/README.md +278 -0
- package/src/MillerColumns/__tests__/MillerColumns.aria.test.tsx +82 -0
- package/src/MillerColumns/__tests__/MillerColumns.asChild.test.tsx +106 -0
- package/src/MillerColumns/__tests__/MillerColumns.auto-scroll.test.tsx +68 -0
- package/src/MillerColumns/__tests__/MillerColumns.basic-rendering.test.tsx +52 -0
- package/src/MillerColumns/__tests__/MillerColumns.column-projection.test.tsx +161 -0
- package/src/MillerColumns/__tests__/MillerColumns.controlled-state.test.tsx +90 -0
- package/src/MillerColumns/__tests__/MillerColumns.data-attributes.test.tsx +77 -0
- package/src/MillerColumns/__tests__/MillerColumns.disabled-items.test.tsx +65 -0
- package/src/MillerColumns/__tests__/MillerColumns.error-handling.test.tsx +57 -0
- package/src/MillerColumns/__tests__/MillerColumns.fixtures.ts +15 -0
- package/src/MillerColumns/__tests__/MillerColumns.item-indicator.test.tsx +57 -0
- package/src/MillerColumns/__tests__/MillerColumns.keyboard-interaction.test.tsx +181 -0
- package/src/MillerColumns/__tests__/MillerColumns.preview-panel.test.tsx +47 -0
- package/src/MillerColumns/__tests__/MillerColumns.resize.test.tsx +137 -0
- package/src/MillerColumns/__tests__/MillerColumns.roving-tabindex.test.tsx +91 -0
- package/src/MillerColumns/__tests__/MillerColumns.selection.test.tsx +54 -0
- package/src/MillerColumns/__tests__/MillerColumns.uncontrolled-state.test.tsx +70 -0
- package/src/MillerColumns/hooks/index.ts +7 -0
- package/src/MillerColumns/hooks/useMillerColumnsColumn.ts +23 -0
- package/src/MillerColumns/hooks/useMillerColumnsColumnContext.ts +1 -0
- package/src/MillerColumns/hooks/useMillerColumnsContext.ts +1 -0
- package/src/MillerColumns/hooks/useMillerColumnsItem.ts +157 -0
- package/src/MillerColumns/hooks/useMillerColumnsItemContext.ts +1 -0
- package/src/MillerColumns/hooks/useMillerColumnsResizeHandle.ts +76 -0
- package/src/MillerColumns/hooks/useMillerColumnsRoot.ts +0 -0
- package/src/MillerColumns/index.ts +3 -0
- package/src/MillerColumns/types.ts +93 -0
- package/src/MillerColumns/useMillerColumnsSelection.ts +31 -0
- package/src/MillerColumns/utils.ts +75 -0
- package/src/Modal/Modal.tsx +474 -0
- package/src/Modal/ModalContext.ts +13 -0
- package/src/Modal/README.md +207 -0
- package/src/Modal/__tests__/Modal.accessibility.test.tsx +167 -0
- package/src/Modal/__tests__/Modal.asChild.test.tsx +162 -0
- package/src/Modal/__tests__/Modal.click-outside.test.tsx +115 -0
- package/src/Modal/__tests__/Modal.content.test.tsx +193 -0
- package/src/Modal/__tests__/Modal.controlled-state.test.tsx +120 -0
- package/src/Modal/__tests__/Modal.error-handling.test.tsx +30 -0
- package/src/Modal/__tests__/Modal.escape-hatches.test.tsx +99 -0
- package/src/Modal/__tests__/Modal.imperative-api.test.tsx +119 -0
- package/src/Modal/__tests__/Modal.nested.test.tsx +106 -0
- package/src/Modal/__tests__/Modal.overlay.test.tsx +99 -0
- package/src/Modal/__tests__/Modal.portal.test.tsx +90 -0
- package/src/Modal/__tests__/Modal.presence.test.tsx +111 -0
- package/src/Modal/__tests__/Modal.trigger.test.tsx +70 -0
- package/src/Modal/__tests__/Modal.uncontrolled-state.test.tsx +72 -0
- package/src/Modal/__tests__/dialog-polyfill.ts +40 -0
- package/src/Modal/hooks/index.ts +4 -0
- package/src/Modal/hooks/useModalContent.ts +62 -0
- package/src/Modal/hooks/useModalContext.ts +1 -0
- package/src/Modal/hooks/useModalRoot.ts +81 -0
- package/src/Modal/hooks/useModalTrigger.ts +25 -0
- package/src/Modal/index.ts +3 -0
- package/src/Modal/types.ts +76 -0
- package/src/Portal/Portal.tsx +28 -0
- package/src/Portal/README.md +70 -0
- package/src/Portal/__tests__/Portal.basic-rendering.test.tsx +17 -0
- package/src/Portal/index.ts +2 -0
- package/src/Portal/types.ts +6 -0
- package/src/Progress/Progress.tsx +178 -0
- package/src/Progress/ProgressContext.ts +15 -0
- package/src/Progress/README.md +112 -0
- package/src/Progress/__tests__/Progress.asChild.test.tsx +37 -0
- package/src/Progress/__tests__/Progress.basic-rendering.test.tsx +65 -0
- package/src/Progress/__tests__/Progress.error-handling.test.tsx +40 -0
- package/src/Progress/__tests__/Progress.fixtures.ts +7 -0
- package/src/Progress/__tests__/Progress.value.test.tsx +83 -0
- package/src/Progress/hooks/index.ts +2 -0
- package/src/Progress/hooks/useProgressContext.ts +1 -0
- package/src/Progress/hooks/useProgressRoot.ts +45 -0
- package/src/Progress/index.ts +3 -0
- package/src/Progress/types.ts +43 -0
- package/src/RadioCard/README.md +133 -0
- package/src/RadioCard/RadioCard.tsx +334 -0
- package/src/RadioCard/RadioCardContext.ts +23 -0
- package/src/RadioCard/RadioCardItemContext.ts +10 -0
- package/src/RadioCard/__tests__/RadioCard.asChild.test.tsx +76 -0
- package/src/RadioCard/__tests__/RadioCard.basic-rendering.test.tsx +87 -0
- package/src/RadioCard/__tests__/RadioCard.controlled-state.test.tsx +107 -0
- package/src/RadioCard/__tests__/RadioCard.disabled-items.test.tsx +61 -0
- package/src/RadioCard/__tests__/RadioCard.error-handling.test.tsx +35 -0
- package/src/RadioCard/__tests__/RadioCard.indicator.test.tsx +119 -0
- package/src/RadioCard/__tests__/RadioCard.keyboard-interaction.test.tsx +158 -0
- package/src/RadioCard/__tests__/RadioCard.orientation.test.tsx +90 -0
- package/src/RadioCard/__tests__/RadioCard.reading-direction.test.tsx +65 -0
- package/src/RadioCard/__tests__/RadioCard.uncontrolled-state.test.tsx +108 -0
- package/src/RadioCard/hooks/index.ts +3 -0
- package/src/RadioCard/hooks/useRadioCardContext.ts +1 -0
- package/src/RadioCard/hooks/useRadioCardItemContext.ts +1 -0
- package/src/RadioCard/hooks/useRadioCardRoot.ts +77 -0
- package/src/RadioCard/index.ts +4 -0
- package/src/RadioCard/types.ts +51 -0
- package/src/RadioGroup/README.md +185 -0
- package/src/RadioGroup/RadioGroup.tsx +353 -0
- package/src/RadioGroup/RadioGroupContext.ts +23 -0
- package/src/RadioGroup/RadioGroupItemContext.ts +10 -0
- package/src/RadioGroup/__tests__/RadioGroup.asChild.test.tsx +105 -0
- package/src/RadioGroup/__tests__/RadioGroup.basic-rendering.test.tsx +72 -0
- package/src/RadioGroup/__tests__/RadioGroup.controlled-state.test.tsx +109 -0
- package/src/RadioGroup/__tests__/RadioGroup.disabled-keydown-guards.test.tsx +68 -0
- package/src/RadioGroup/__tests__/RadioGroup.disabled.test.tsx +79 -0
- package/src/RadioGroup/__tests__/RadioGroup.error-handling.test.tsx +33 -0
- package/src/RadioGroup/__tests__/RadioGroup.indicator.test.tsx +85 -0
- package/src/RadioGroup/__tests__/RadioGroup.keyboard-interaction.test.tsx +135 -0
- package/src/RadioGroup/__tests__/RadioGroup.orientation.test.tsx +90 -0
- package/src/RadioGroup/__tests__/RadioGroup.reading-direction.test.tsx +65 -0
- package/src/RadioGroup/__tests__/RadioGroup.ref-forwarding.test.tsx +45 -0
- package/src/RadioGroup/__tests__/RadioGroup.roving-tabindex.test.tsx +105 -0
- package/src/RadioGroup/__tests__/RadioGroup.uncontrolled-state.test.tsx +96 -0
- package/src/RadioGroup/hooks/index.ts +3 -0
- package/src/RadioGroup/hooks/useRadioGroupContext.ts +1 -0
- package/src/RadioGroup/hooks/useRadioGroupItemContext.ts +1 -0
- package/src/RadioGroup/hooks/useRadioGroupRoot.ts +87 -0
- package/src/RadioGroup/index.ts +1 -0
- package/src/RadioGroup/types.ts +51 -0
- package/src/Select/README.md +203 -0
- package/src/Select/Select.tsx +204 -0
- package/src/Select/__tests__/Select.asChild.test.tsx +36 -0
- package/src/Select/__tests__/Select.basic-rendering.test.tsx +17 -0
- package/src/Select/__tests__/Select.controlled-state.test.tsx +69 -0
- package/src/Select/__tests__/Select.data-attributes.test.tsx +29 -0
- package/src/Select/__tests__/Select.field-integration.test.tsx +150 -0
- package/src/Select/__tests__/Select.group.test.tsx +42 -0
- package/src/Select/__tests__/Select.placeholder.test.tsx +32 -0
- package/src/Select/index.ts +2 -0
- package/src/Select/types.ts +89 -0
- package/src/SkipNav/README.md +87 -0
- package/src/SkipNav/SkipNav.tsx +116 -0
- package/src/SkipNav/__tests__/SkipNav.basic-rendering.test.tsx +23 -0
- package/src/SkipNav/__tests__/SkipNav.ids.test.tsx +19 -0
- package/src/SkipNav/index.ts +1 -0
- package/src/SkipNav/types.ts +26 -0
- package/src/Slider/README.md +215 -0
- package/src/Slider/Slider.tsx +308 -0
- package/src/Slider/SliderContext.ts +24 -0
- package/src/Slider/__tests__/Slider.asChild.test.tsx +119 -0
- package/src/Slider/__tests__/Slider.basic-rendering.test.tsx +157 -0
- package/src/Slider/__tests__/Slider.controlled-state.test.tsx +78 -0
- package/src/Slider/__tests__/Slider.disabled.test.tsx +82 -0
- package/src/Slider/__tests__/Slider.error-handling.test.tsx +45 -0
- package/src/Slider/__tests__/Slider.fixtures.ts +53 -0
- package/src/Slider/__tests__/Slider.form.test.tsx +67 -0
- package/src/Slider/__tests__/Slider.inverted.test.tsx +112 -0
- package/src/Slider/__tests__/Slider.keyboard-interaction.test.tsx +118 -0
- package/src/Slider/__tests__/Slider.multiple-thumbs.test.tsx +84 -0
- package/src/Slider/__tests__/Slider.orientation.test.tsx +101 -0
- package/src/Slider/__tests__/Slider.pointer-interaction.test.tsx +205 -0
- package/src/Slider/__tests__/Slider.reading-direction.test.tsx +99 -0
- package/src/Slider/__tests__/Slider.uncontrolled-state.test.tsx +69 -0
- package/src/Slider/__tests__/Slider.value-commit.test.tsx +103 -0
- package/src/Slider/hooks/index.ts +3 -0
- package/src/Slider/hooks/useSliderContext.ts +1 -0
- package/src/Slider/hooks/useSliderRoot.ts +197 -0
- package/src/Slider/hooks/useSliderThumb.ts +77 -0
- package/src/Slider/index.ts +3 -0
- package/src/Slider/types.ts +48 -0
- package/src/Slider/utils.ts +155 -0
- package/src/Slot/Slot.tsx +158 -0
- package/src/Slot/__tests__/Slot.test.tsx +163 -0
- package/src/Slot/__tests__/composeEventHandlers.test.ts +74 -0
- package/src/Slot/composeEventHandlers.ts +38 -0
- package/src/Slot/index.ts +3 -0
- package/src/Slot/types.ts +5 -0
- package/src/Status/README.md +50 -0
- package/src/Status/Status.tsx +44 -0
- package/src/Status/__tests__/Status.test.tsx +28 -0
- package/src/Status/index.ts +2 -0
- package/src/Status/types.ts +5 -0
- package/src/Switch/README.md +121 -0
- package/src/Switch/Switch.tsx +167 -0
- package/src/Switch/SwitchContext.ts +10 -0
- package/src/Switch/__tests__/Switch.asChild.test.tsx +56 -0
- package/src/Switch/__tests__/Switch.basic-rendering.test.tsx +76 -0
- package/src/Switch/__tests__/Switch.contract.test.tsx +109 -0
- package/src/Switch/__tests__/Switch.controlled-state.test.tsx +79 -0
- package/src/Switch/__tests__/Switch.disabled.test.tsx +60 -0
- package/src/Switch/__tests__/Switch.error-handling.test.tsx +20 -0
- package/src/Switch/__tests__/Switch.keyboard-interaction.test.tsx +56 -0
- package/src/Switch/__tests__/Switch.thumb.test.tsx +84 -0
- package/src/Switch/__tests__/Switch.uncontrolled-state.test.tsx +83 -0
- package/src/Switch/hooks/index.ts +2 -0
- package/src/Switch/hooks/useSwitchContext.ts +1 -0
- package/src/Switch/hooks/useSwitchRoot.ts +28 -0
- package/src/Switch/index.ts +3 -0
- package/src/Switch/types.ts +37 -0
- package/src/Table/README.md +205 -0
- package/src/Table/Table.tsx +380 -0
- package/src/Table/__tests__/Table.Body.test.tsx +61 -0
- package/src/Table/__tests__/Table.Caption.test.tsx +70 -0
- package/src/Table/__tests__/Table.Cell.test.tsx +73 -0
- package/src/Table/__tests__/Table.Footer.test.tsx +61 -0
- package/src/Table/__tests__/Table.Head.test.tsx +61 -0
- package/src/Table/__tests__/Table.Header.test.tsx +73 -0
- package/src/Table/__tests__/Table.Root.test.tsx +49 -0
- package/src/Table/__tests__/Table.Row.test.tsx +67 -0
- package/src/Table/__tests__/Table.ScrollArea.test.tsx +83 -0
- package/src/Table/index.ts +1 -0
- package/src/Table/types.ts +63 -0
- package/src/Tabs/README.md +110 -0
- package/src/Tabs/Tabs.tsx +434 -0
- package/src/Tabs/TabsContext.ts +13 -0
- package/src/Tabs/__tests__/Tabs.activation-mode.test.tsx +114 -0
- package/src/Tabs/__tests__/Tabs.asChild.test.tsx +91 -0
- package/src/Tabs/__tests__/Tabs.basic-rendering.test.tsx +483 -0
- package/src/Tabs/__tests__/Tabs.change-event-callbacks.test.tsx +133 -0
- package/src/Tabs/__tests__/Tabs.controlled-state.test.tsx +152 -0
- package/src/Tabs/__tests__/Tabs.disabled-tabs.test.tsx +203 -0
- package/src/Tabs/__tests__/Tabs.error-handling.test.tsx +82 -0
- package/src/Tabs/__tests__/Tabs.fixtures.ts +171 -0
- package/src/Tabs/__tests__/Tabs.imperative-api.test.tsx +118 -0
- package/src/Tabs/__tests__/Tabs.keyboard-interaction.test.tsx +192 -0
- package/src/Tabs/__tests__/Tabs.lazy-mount.test.tsx +61 -0
- package/src/Tabs/__tests__/Tabs.mouse-interaction.test.tsx +216 -0
- package/src/Tabs/__tests__/Tabs.reading-direction.test.tsx +58 -0
- package/src/Tabs/__tests__/Tabs.uncontrolled-state.test.tsx +197 -0
- package/src/Tabs/hooks/index.ts +4 -0
- package/src/Tabs/hooks/useTabsContent.ts +27 -0
- package/src/Tabs/hooks/useTabsContext.ts +1 -0
- package/src/Tabs/hooks/useTabsRoot.ts +148 -0
- package/src/Tabs/hooks/useTabsTrigger.ts +111 -0
- package/src/Tabs/index.ts +3 -0
- package/src/Tabs/types.ts +99 -0
- package/src/Tabs/utils.ts +8 -0
- package/src/Textarea/README.md +98 -0
- package/src/Textarea/Textarea.tsx +93 -0
- package/src/Textarea/__tests__/Textarea.asChild.test.tsx +85 -0
- package/src/Textarea/__tests__/Textarea.basic-rendering.test.tsx +107 -0
- package/src/Textarea/__tests__/Textarea.disabled.test.tsx +49 -0
- package/src/Textarea/__tests__/Textarea.field-integration.test.tsx +134 -0
- package/src/Textarea/index.ts +2 -0
- package/src/Textarea/types.ts +7 -0
- package/src/Toggle/README.md +97 -0
- package/src/Toggle/Toggle.tsx +81 -0
- package/src/Toggle/__tests__/Toggle.asChild.test.tsx +42 -0
- package/src/Toggle/__tests__/Toggle.basic-rendering.test.tsx +28 -0
- package/src/Toggle/__tests__/Toggle.controlled-state.test.tsx +60 -0
- package/src/Toggle/__tests__/Toggle.disabled.test.tsx +34 -0
- package/src/Toggle/__tests__/Toggle.keyboard-interaction.test.tsx +42 -0
- package/src/Toggle/__tests__/Toggle.uncontrolled-state.test.tsx +40 -0
- package/src/Toggle/index.ts +2 -0
- package/src/Toggle/types.ts +23 -0
- package/src/ToggleGroup/README.md +137 -0
- package/src/ToggleGroup/ToggleGroup.tsx +298 -0
- package/src/ToggleGroup/ToggleGroupContext.ts +9 -0
- package/src/ToggleGroup/__tests__/ToggleGroup.asChild.test.tsx +65 -0
- package/src/ToggleGroup/__tests__/ToggleGroup.basic-rendering.test.tsx +50 -0
- package/src/ToggleGroup/__tests__/ToggleGroup.disabled.test.tsx +54 -0
- package/src/ToggleGroup/__tests__/ToggleGroup.keyboard-interaction.test.tsx +151 -0
- package/src/ToggleGroup/__tests__/ToggleGroup.multiple-mode.test.tsx +144 -0
- package/src/ToggleGroup/__tests__/ToggleGroup.reading-direction.test.tsx +28 -0
- package/src/ToggleGroup/__tests__/ToggleGroup.single-mode.test.tsx +139 -0
- package/src/ToggleGroup/hooks/index.ts +2 -0
- package/src/ToggleGroup/hooks/useToggleGroupContext.ts +1 -0
- package/src/ToggleGroup/hooks/useToggleGroupRoot.ts +110 -0
- package/src/ToggleGroup/index.ts +2 -0
- package/src/ToggleGroup/types.ts +72 -0
- package/src/Tooltip/README.md +214 -0
- package/src/Tooltip/Tooltip.tsx +260 -0
- package/src/Tooltip/TooltipContext.ts +20 -0
- package/src/Tooltip/__tests__/Tooltip.asChild.test.tsx +77 -0
- package/src/Tooltip/__tests__/Tooltip.basic-rendering.test.tsx +180 -0
- package/src/Tooltip/__tests__/Tooltip.controlled-state.test.tsx +128 -0
- package/src/Tooltip/__tests__/Tooltip.escape-hatches.test.tsx +73 -0
- package/src/Tooltip/__tests__/Tooltip.focus-interaction.test.tsx +88 -0
- package/src/Tooltip/__tests__/Tooltip.hover-interaction.test.tsx +179 -0
- package/src/Tooltip/__tests__/Tooltip.keyboard-interaction.test.tsx +85 -0
- package/src/Tooltip/__tests__/Tooltip.uncontrolled-state.test.tsx +67 -0
- package/src/Tooltip/hooks/index.ts +4 -0
- package/src/Tooltip/hooks/useTooltipContent.ts +53 -0
- package/src/Tooltip/hooks/useTooltipProvider.ts +41 -0
- package/src/Tooltip/hooks/useTooltipRoot.ts +106 -0
- package/src/Tooltip/hooks/useTooltipTrigger.ts +44 -0
- package/src/Tooltip/index.ts +1 -0
- package/src/Tooltip/types.ts +64 -0
- package/src/Tree/README.md +339 -0
- package/src/Tree/Tree.tsx +571 -0
- package/src/Tree/TreeContext.ts +24 -0
- package/src/Tree/__tests__/Tree.aria.test.tsx +53 -0
- package/src/Tree/__tests__/Tree.asChild.test.tsx +134 -0
- package/src/Tree/__tests__/Tree.basic-rendering.test.tsx +111 -0
- package/src/Tree/__tests__/Tree.branch-behaviour.test.tsx +87 -0
- package/src/Tree/__tests__/Tree.controlled-expansion.test.tsx +92 -0
- package/src/Tree/__tests__/Tree.data-attributes.test.tsx +88 -0
- package/src/Tree/__tests__/Tree.disabled-items.test.tsx +196 -0
- package/src/Tree/__tests__/Tree.error-handling.test.tsx +71 -0
- package/src/Tree/__tests__/Tree.forceMount.test.tsx +72 -0
- package/src/Tree/__tests__/Tree.keyboard-interaction.test.tsx +150 -0
- package/src/Tree/__tests__/Tree.multiple-selection.test.tsx +151 -0
- package/src/Tree/__tests__/Tree.range-selection.test.tsx +200 -0
- package/src/Tree/__tests__/Tree.recursion-depth.test.tsx +73 -0
- package/src/Tree/__tests__/Tree.roving-tabindex.test.tsx +117 -0
- package/src/Tree/__tests__/Tree.selection-path.test.tsx +404 -0
- package/src/Tree/__tests__/Tree.single-selection.test.tsx +108 -0
- package/src/Tree/__tests__/Tree.uncontrolled-expansion.test.tsx +69 -0
- package/src/Tree/hooks/index.ts +3 -0
- package/src/Tree/hooks/useTreeItemKeyboard.ts +86 -0
- package/src/Tree/hooks/useTreePath.ts +68 -0
- package/src/Tree/hooks/useTreeRoot.ts +279 -0
- package/src/Tree/index.ts +3 -0
- package/src/Tree/types.ts +224 -0
- package/src/Tree/utils.ts +59 -0
- package/src/VisuallyHidden/README.md +58 -0
- package/src/VisuallyHidden/VisuallyHidden.tsx +67 -0
- package/src/VisuallyHidden/__tests__/VisuallyHidden.test.tsx +59 -0
- package/src/VisuallyHidden/index.ts +2 -0
- package/src/VisuallyHidden/types.ts +5 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useCollection.ts +74 -0
- package/src/hooks/useControllableState.ts +81 -0
- package/src/hooks/useRovingTabindex.ts +178 -0
- package/src/index.ts +38 -0
- package/src/test/intersectionObserverPolyfill.ts +83 -0
- package/src/test/popoverPolyfill.ts +86 -0
- package/src/test/scrollPolyfill.ts +23 -0
- package/src/types.ts +13 -0
- package/src/utils/__tests__/createStrictContext.test.tsx +69 -0
- package/src/utils/__tests__/deriveId.test.ts +28 -0
- package/src/utils/__tests__/getKeyToActionMap.test.ts +106 -0
- package/src/utils/createStrictContext.ts +49 -0
- package/src/utils/deriveId.ts +31 -0
- package/src/utils/getKeyToActionMap.ts +95 -0
- package/src/utils/index.ts +3 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# Tree
|
|
2
|
+
|
|
3
|
+
A compound component for a **hierarchical tree view** β nested
|
|
4
|
+
collapsible groups of selectable rows, modelled on the WAI-ARIA tree
|
|
5
|
+
pattern.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Tree } from "@primitiv-ui/react";
|
|
9
|
+
|
|
10
|
+
<Tree.Root defaultExpandedValues={["src"]}>
|
|
11
|
+
<Tree.Item value="readme">readme</Tree.Item>
|
|
12
|
+
<Tree.Branch value="src">
|
|
13
|
+
<Tree.BranchControl>
|
|
14
|
+
<Tree.BranchIndicator>βΈ</Tree.BranchIndicator>
|
|
15
|
+
src
|
|
16
|
+
</Tree.BranchControl>
|
|
17
|
+
<Tree.BranchContent>
|
|
18
|
+
<Tree.Item value="index">index.ts</Tree.Item>
|
|
19
|
+
<Tree.Item value="button">button.tsx</Tree.Item>
|
|
20
|
+
</Tree.BranchContent>
|
|
21
|
+
</Tree.Branch>
|
|
22
|
+
</Tree.Root>;
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Authoring model
|
|
26
|
+
|
|
27
|
+
The tree is authored by **recursive composition** β there is no `data`
|
|
28
|
+
prop. An `Item` is a leaf; a `Branch` is a parent that pairs a
|
|
29
|
+
`<Tree.BranchControl>` (its clickable row) with a `<Tree.BranchContent>`
|
|
30
|
+
(the nested group). Each `BranchContent` renders its children one
|
|
31
|
+
nesting level deeper, so a `Branch` placed inside a `BranchContent`
|
|
32
|
+
automatically reports `aria-level={depth + 1}` and `data-depth={depth}`.
|
|
33
|
+
|
|
34
|
+
Depth and parent value ride a context β the components don't traverse
|
|
35
|
+
the React tree to figure out where they are.
|
|
36
|
+
|
|
37
|
+
## Sub-components
|
|
38
|
+
|
|
39
|
+
| Export | Role | Notes |
|
|
40
|
+
| ---------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
|
|
41
|
+
| `Tree.Root` | State owner | Owns expansion + selection, the collection, and the roving tabstop. `role="tree"`, `data-selection-mode`, `aria-multiselectable` in multiple mode |
|
|
42
|
+
| `Tree.Item` | Leaf treeitem | `role="treeitem"`. Supports `label`, `disabled`, `asChild` |
|
|
43
|
+
| `Tree.Branch` | Branch treeitem | `role="treeitem"` containing the control row and (when expanded) the content group. Supports `label`, `disabled` |
|
|
44
|
+
| `Tree.BranchControl` | Branch row | The clickable row inside a `Branch`. Click toggles expansion **and** selects. Supports `asChild` |
|
|
45
|
+
| `Tree.BranchContent` | Branch group | `role="group"`. Mount/unmount with the branch, or stay mounted via `forceMount` for CSS animation |
|
|
46
|
+
| `Tree.BranchIndicator` | Chevron / glyph | Decorative `aria-hidden` span with `data-state="open" | "closed"`. Supports `asChild` |
|
|
47
|
+
| `Tree.SelectionPath` | Selection breadcrumbs | Renders one breadcrumb trail per currently-selected value. See [Selection path](#selection-path) |
|
|
48
|
+
|
|
49
|
+
## State model
|
|
50
|
+
|
|
51
|
+
The Root carries two independent state axes β expansion and selection β
|
|
52
|
+
each statically discriminated into controlled and uncontrolled forms.
|
|
53
|
+
Passing both `default*` and the controlled prop is a type error.
|
|
54
|
+
|
|
55
|
+
### Expansion
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
// Uncontrolled
|
|
59
|
+
<Tree.Root defaultExpandedValues={["src"]} onExpandedChange={(v) => β¦}>
|
|
60
|
+
|
|
61
|
+
// Controlled
|
|
62
|
+
<Tree.Root expandedValues={values} onExpandedChange={setValues}>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`onExpandedChange` fires in both modes.
|
|
66
|
+
|
|
67
|
+
### Selection
|
|
68
|
+
|
|
69
|
+
The selection shape depends on `selectionMode`:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
// Single (default) β selectedValue is `string | null`
|
|
73
|
+
<Tree.Root defaultSelectedValue="readme" onSelectedValueChange={(v) => β¦}>
|
|
74
|
+
<Tree.Root selectedValue={v} onSelectedValueChange={setV}>
|
|
75
|
+
|
|
76
|
+
// Multiple β selectedValues is `string[]`
|
|
77
|
+
<Tree.Root
|
|
78
|
+
selectionMode="multiple"
|
|
79
|
+
defaultSelectedValues={["readme", "index"]}
|
|
80
|
+
onSelectedValuesChange={(v) => β¦}
|
|
81
|
+
>
|
|
82
|
+
<Tree.Root
|
|
83
|
+
selectionMode="multiple"
|
|
84
|
+
selectedValues={v}
|
|
85
|
+
onSelectedValuesChange={setV}
|
|
86
|
+
>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
In **multiple** mode:
|
|
90
|
+
|
|
91
|
+
- Plain click replaces selection with the clicked item.
|
|
92
|
+
- `Ctrl` / `Cmd` + click toggles the item in or out.
|
|
93
|
+
- `Shift` + click selects the contiguous range of visible items
|
|
94
|
+
between the previous click (the _anchor_) and the clicked item,
|
|
95
|
+
skipping disabled items. The anchor stays put across Shift+clicks,
|
|
96
|
+
matching the listbox convention.
|
|
97
|
+
|
|
98
|
+
In **single** mode modifier keys are ignored β clicks always replace.
|
|
99
|
+
|
|
100
|
+
## `forceMount` (animating branches in and out)
|
|
101
|
+
|
|
102
|
+
By default a collapsed branch's content is unmounted. Pass `forceMount`
|
|
103
|
+
to `BranchContent` to keep it in the DOM with `aria-hidden="true"` and
|
|
104
|
+
`data-state="closed"` so CSS transitions can play:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
<Tree.Branch value="src">
|
|
108
|
+
<Tree.BranchControl>src</Tree.BranchControl>
|
|
109
|
+
<Tree.BranchContent forceMount>
|
|
110
|
+
<Tree.Item value="index">index.ts</Tree.Item>
|
|
111
|
+
</Tree.BranchContent>
|
|
112
|
+
</Tree.Branch>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The default form mirrors the rest of the library; `forceMount` mirrors
|
|
116
|
+
`Collapsible.Content`. Choose based on whether your styling needs an
|
|
117
|
+
enter/exit animation.
|
|
118
|
+
|
|
119
|
+
## Keyboard interaction
|
|
120
|
+
|
|
121
|
+
The whole tree is a single roving-tabindex widget β exactly one item
|
|
122
|
+
is tabbable at a time. The tabstop follows the last-focused item and
|
|
123
|
+
defaults to the first enabled visible item.
|
|
124
|
+
|
|
125
|
+
| Key | Leaf `Item` | `Branch` |
|
|
126
|
+
| ----------------------- | ----------------------- | ---------------------------------------------------------- |
|
|
127
|
+
| `ArrowUp` / `ArrowDown` | Previous / next visible | Previous / next visible |
|
|
128
|
+
| `Home` / `End` | First / last visible | First / last visible |
|
|
129
|
+
| `ArrowRight` | No-op | Collapsed: expand. Expanded: focus the first child |
|
|
130
|
+
| `ArrowLeft` | Focus the parent branch | Expanded: collapse. Collapsed: focus the parent branch |
|
|
131
|
+
| `Enter` / `Space` | Select | Toggle expansion **and** select (same as clicking the row) |
|
|
132
|
+
|
|
133
|
+
Arrow keys skip disabled items. Home / End and direct focus still land
|
|
134
|
+
on them so they remain discoverable.
|
|
135
|
+
|
|
136
|
+
## ARIA
|
|
137
|
+
|
|
138
|
+
- The root is `role="tree"` with `aria-multiselectable="true"` in
|
|
139
|
+
multiple mode.
|
|
140
|
+
- Items and branches are `role="treeitem"` with `aria-level` (1-based),
|
|
141
|
+
`aria-selected`, and β on branches β `aria-expanded` and
|
|
142
|
+
`aria-labelledby` pointing at the `BranchControl` (so the branch's
|
|
143
|
+
accessible name is just the row's content, not all descendant text).
|
|
144
|
+
- The nested content group is `role="group"`.
|
|
145
|
+
- Indicators are `aria-hidden="true"`.
|
|
146
|
+
|
|
147
|
+
## Styling hooks
|
|
148
|
+
|
|
149
|
+
The component ships **no CSS**. Style with the data attributes:
|
|
150
|
+
|
|
151
|
+
| Attribute | Where | Meaning |
|
|
152
|
+
| -------------------------------- | --------------------------------- | --------------------------------------------------------- | ------------------------- |
|
|
153
|
+
| `data-selection-mode="single | multiple"` | `Root` | The active selection mode |
|
|
154
|
+
| `data-depth="N"` | `Item`, `Branch`, `BranchContent` | Zero-based nesting depth |
|
|
155
|
+
| `data-leaf=""` | `Item` | Marks a leaf treeitem |
|
|
156
|
+
| `data-branch=""` | `Branch` | Marks a branch treeitem |
|
|
157
|
+
| `data-state="open | closed"` | `Branch`, `BranchContent`, indicators | Branch expansion state |
|
|
158
|
+
| `data-selected=""` | `Item`, `Branch` | Set when the treeitem is selected |
|
|
159
|
+
| `data-disabled=""` | `Item`, `Branch`, segments | Set when the treeitem (or breadcrumb segment) is disabled |
|
|
160
|
+
| `data-tree-selection-path=""` | `SelectionPath` wrapper | Identifies the breadcrumb trail container |
|
|
161
|
+
| `data-empty=""` | `SelectionPath` wrapper | Set when no item is selected |
|
|
162
|
+
| `data-tree-selection-segment=""` | `SelectionPath` segments | One per crumb in the trail; carries `data-value` |
|
|
163
|
+
|
|
164
|
+
Indentation, guide lines, focus rings, and the chevron rotation are
|
|
165
|
+
the consumer's job. The `data-depth` attribute combined with modern
|
|
166
|
+
CSS (`attr(data-depth type(<integer>))` or `[data-depth="N"]`
|
|
167
|
+
selectors) is enough to drive an indented hierarchy without inline
|
|
168
|
+
styles.
|
|
169
|
+
|
|
170
|
+
> **Browser support note.** Reading a typed attribute through
|
|
171
|
+
> `attr(data-depth type(<integer>))` inside `calc()` requires Chrome
|
|
172
|
+
> 133+ or Safari 18.2+. Firefox does not yet ship the advanced
|
|
173
|
+
> `attr()` syntax β it will fall back to the default value supplied
|
|
174
|
+
> as the second argument (or `0` if omitted). Two cross-browser
|
|
175
|
+
> workarounds:
|
|
176
|
+
>
|
|
177
|
+
> **1. Enumerate per-depth rules** β pick a sensible cap for your UI
|
|
178
|
+
> and write one selector per level:
|
|
179
|
+
>
|
|
180
|
+
> ```css
|
|
181
|
+
> [role="treeitem"][data-depth="0"] > .row {
|
|
182
|
+
> padding-inline-start: 0.5rem;
|
|
183
|
+
> }
|
|
184
|
+
> [role="treeitem"][data-depth="1"] > .row {
|
|
185
|
+
> padding-inline-start: 1.75rem;
|
|
186
|
+
> }
|
|
187
|
+
> [role="treeitem"][data-depth="2"] > .row {
|
|
188
|
+
> padding-inline-start: 3rem;
|
|
189
|
+
> }
|
|
190
|
+
> /* β¦extend as deep as your tree can go */
|
|
191
|
+
> ```
|
|
192
|
+
>
|
|
193
|
+
> **2. Set a CSS variable inline from the render layer** β the
|
|
194
|
+
> consumer already knows the depth when authoring the tree
|
|
195
|
+
> recursively, so it can be threaded through as a prop:
|
|
196
|
+
>
|
|
197
|
+
> ```tsx
|
|
198
|
+
> function Node({ node, depth }: { node: FileNode; depth: number }) {
|
|
199
|
+
> const indent = { "--tree-indent": depth } as React.CSSProperties;
|
|
200
|
+
> if (node.children) {
|
|
201
|
+
> return (
|
|
202
|
+
> <Tree.Branch value={node.id}>
|
|
203
|
+
> <Tree.BranchControl style={indent}>{node.label}</Tree.BranchControl>
|
|
204
|
+
> <Tree.BranchContent>
|
|
205
|
+
> {node.children.map((child) => (
|
|
206
|
+
> <Node key={child.id} node={child} depth={depth + 1} />
|
|
207
|
+
> ))}
|
|
208
|
+
> </Tree.BranchContent>
|
|
209
|
+
> </Tree.Branch>
|
|
210
|
+
> );
|
|
211
|
+
> }
|
|
212
|
+
> return (
|
|
213
|
+
> <Tree.Item value={node.id} style={indent}>
|
|
214
|
+
> {node.label}
|
|
215
|
+
> </Tree.Item>
|
|
216
|
+
> );
|
|
217
|
+
> }
|
|
218
|
+
> ```
|
|
219
|
+
>
|
|
220
|
+
> ```css
|
|
221
|
+
> [role="treeitem"] > .row {
|
|
222
|
+
> padding-inline-start: calc(var(--tree-indent, 0) * 1.25rem + 0.5rem);
|
|
223
|
+
> }
|
|
224
|
+
> ```
|
|
225
|
+
|
|
226
|
+
## Selection path
|
|
227
|
+
|
|
228
|
+
`Tree.Item` and `Tree.Branch` accept an optional `label` prop. It does
|
|
229
|
+
**not** affect what's rendered for the row β the children still do β
|
|
230
|
+
but it is stored alongside the value in Tree's node registry so the
|
|
231
|
+
tree can surface a human-readable breadcrumb trail of the current
|
|
232
|
+
selection.
|
|
233
|
+
|
|
234
|
+
```tsx
|
|
235
|
+
<Tree.Branch value="src" label="src">
|
|
236
|
+
<Tree.BranchControl>π src</Tree.BranchControl>
|
|
237
|
+
<Tree.BranchContent>
|
|
238
|
+
<Tree.Item value="index" label="index.ts">
|
|
239
|
+
π index.ts
|
|
240
|
+
</Tree.Item>
|
|
241
|
+
</Tree.BranchContent>
|
|
242
|
+
</Tree.Branch>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### `Tree.SelectionPath`
|
|
246
|
+
|
|
247
|
+
The out-of-box subcomponent renders one breadcrumb trail per
|
|
248
|
+
currently-selected value, composing the package's `Breadcrumb`
|
|
249
|
+
primitive: a `<nav aria-label="Breadcrumb"><ol>` per path, with
|
|
250
|
+
non-final segments as plain `<li>` text and the leaf as a
|
|
251
|
+
`Breadcrumb.Page` (`aria-current="page"`). Segments without a
|
|
252
|
+
`label` prop fall back to their `value`.
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
import { Tree } from "@primitiv-ui/react";
|
|
256
|
+
import { ChevronRight } from "@primitiv-ui/icons";
|
|
257
|
+
|
|
258
|
+
<Tree.Root defaultSelectedValue="index">
|
|
259
|
+
β¦
|
|
260
|
+
<Tree.SelectionPath separator={<ChevronRight />} />
|
|
261
|
+
</Tree.Root>;
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
When no item is selected, the wrapper still renders with
|
|
265
|
+
`data-empty=""` so consumers can style a placeholder (e.g. an em-dash
|
|
266
|
+
via `::before`) without scoping the path bar conditionally.
|
|
267
|
+
|
|
268
|
+
For full control over the markup β wiring router links, custom
|
|
269
|
+
ordering, or grouping multiple selections β pass a function as
|
|
270
|
+
`children`. It receives the resolved paths and replaces the default
|
|
271
|
+
rendering entirely:
|
|
272
|
+
|
|
273
|
+
```tsx
|
|
274
|
+
<Tree.SelectionPath>
|
|
275
|
+
{({ paths }) =>
|
|
276
|
+
paths.map((path, i) => (
|
|
277
|
+
<Breadcrumb.Root key={i}>
|
|
278
|
+
<Breadcrumb.List>
|
|
279
|
+
{path.map((seg) => (
|
|
280
|
+
<Breadcrumb.Item key={seg.value}>
|
|
281
|
+
<Breadcrumb.Link asChild>
|
|
282
|
+
<RouterLink to={`/files/${seg.value}`}>
|
|
283
|
+
{seg.label ?? seg.value}
|
|
284
|
+
</RouterLink>
|
|
285
|
+
</Breadcrumb.Link>
|
|
286
|
+
</Breadcrumb.Item>
|
|
287
|
+
))}
|
|
288
|
+
</Breadcrumb.List>
|
|
289
|
+
</Breadcrumb.Root>
|
|
290
|
+
))
|
|
291
|
+
}
|
|
292
|
+
</Tree.SelectionPath>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### `useTreePath` / `useTreeSelectionPaths`
|
|
296
|
+
|
|
297
|
+
For UIs that don't fit the breadcrumb shape, two hooks expose the raw
|
|
298
|
+
path data:
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
import { useTreePath, useTreeSelectionPaths } from "@primitiv-ui/react";
|
|
302
|
+
|
|
303
|
+
const path = useTreePath(value); // root β leaf for one value
|
|
304
|
+
const paths = useTreeSelectionPaths(); // one path per selected value, in selection order
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Both return arrays of `TreePathSegment`:
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
type TreePathSegment = {
|
|
311
|
+
value: string;
|
|
312
|
+
label: string | null; // falls back to `null` when no `label` prop was supplied
|
|
313
|
+
isBranch: boolean;
|
|
314
|
+
disabled: boolean;
|
|
315
|
+
depth: number;
|
|
316
|
+
};
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Paths survive a branch collapsing without `forceMount`: Tree keeps a
|
|
320
|
+
durable copy of every node's metadata so ancestry remains resolvable
|
|
321
|
+
even after descendants unmount. A value that has never mounted (e.g.
|
|
322
|
+
a pre-selected item whose branch has not yet opened) returns an empty
|
|
323
|
+
array.
|
|
324
|
+
|
|
325
|
+
## Disabled items
|
|
326
|
+
|
|
327
|
+
Pass `disabled` on an `Item` or `Branch` to render `aria-disabled` and
|
|
328
|
+
`data-disabled`, ignore clicks and activation keys, and skip the item
|
|
329
|
+
during arrow-key navigation and range selection. Disabled items remain
|
|
330
|
+
in the DOM and focusable for discovery; `Home` / `End` still reach
|
|
331
|
+
them.
|
|
332
|
+
|
|
333
|
+
## Deferred past v1
|
|
334
|
+
|
|
335
|
+
- Type-ahead (printable-character focus search).
|
|
336
|
+
- Keyboard multi-select chords (`Ctrl+Enter`, `Shift+Arrow`, `Ctrl+A`).
|
|
337
|
+
- Drag-to-reorder.
|
|
338
|
+
- Imperative `expandAll` / `collapseAll` ref API.
|
|
339
|
+
- Lazy / async children loading.
|