@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,200 @@
|
|
|
1
|
+
import { ComponentProps, ReactNode, Ref } from "react";
|
|
2
|
+
|
|
3
|
+
import { CheckedState } from "../Checkbox/types";
|
|
4
|
+
import { Direction } from "../DirectionProvider";
|
|
5
|
+
|
|
6
|
+
type DropdownRootBaseProps = {
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* Reading direction for the menu. Affects which arrow key opens / closes
|
|
10
|
+
* a submenu — `ArrowRight` opens in `"ltr"`, `ArrowLeft` opens in
|
|
11
|
+
* `"rtl"`. Falls back to the inherited {@link DirectionProvider} value,
|
|
12
|
+
* or to `"ltr"` if no provider is present.
|
|
13
|
+
*/
|
|
14
|
+
dir?: Direction;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type DropdownRootUncontrolledProps = DropdownRootBaseProps & {
|
|
18
|
+
defaultOpen?: boolean;
|
|
19
|
+
open?: never;
|
|
20
|
+
onOpenChange?: (open: boolean) => void;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type DropdownRootControlledProps = DropdownRootBaseProps & {
|
|
24
|
+
defaultOpen?: never;
|
|
25
|
+
open: boolean;
|
|
26
|
+
onOpenChange: (open: boolean) => void;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type DropdownRootProps =
|
|
30
|
+
| DropdownRootUncontrolledProps
|
|
31
|
+
| DropdownRootControlledProps;
|
|
32
|
+
|
|
33
|
+
export type DropdownTriggerProps = Omit<
|
|
34
|
+
ComponentProps<"button">,
|
|
35
|
+
"aria-haspopup" | "aria-expanded" | "aria-controls"
|
|
36
|
+
> & {
|
|
37
|
+
children?: ReactNode;
|
|
38
|
+
ref?: Ref<HTMLButtonElement>;
|
|
39
|
+
asChild?: boolean;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type DropdownContentProps = Omit<
|
|
43
|
+
ComponentProps<"menu">,
|
|
44
|
+
"role" | "popover" | "id"
|
|
45
|
+
> & {
|
|
46
|
+
children?: ReactNode;
|
|
47
|
+
ref?: Ref<HTMLMenuElement>;
|
|
48
|
+
asChild?: boolean;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type DropdownItemProps = Omit<
|
|
52
|
+
ComponentProps<"li">,
|
|
53
|
+
"role" | "tabIndex" | "onSelect"
|
|
54
|
+
> & {
|
|
55
|
+
children?: ReactNode;
|
|
56
|
+
ref?: Ref<HTMLLIElement>;
|
|
57
|
+
asChild?: boolean;
|
|
58
|
+
disabled?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Fires when the item is activated (click, Enter, or Space). Called
|
|
61
|
+
* with an event whose `preventDefault()` skips the auto-close that
|
|
62
|
+
* Dropdown performs after selection.
|
|
63
|
+
*/
|
|
64
|
+
onSelect?: (event: Event) => void;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export type DropdownSeparatorProps = Omit<ComponentProps<"li">, "role"> & {
|
|
68
|
+
children?: ReactNode;
|
|
69
|
+
ref?: Ref<HTMLLIElement>;
|
|
70
|
+
asChild?: boolean;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export type DropdownItemIndicatorProps = ComponentProps<"span"> & {
|
|
74
|
+
children?: ReactNode;
|
|
75
|
+
ref?: Ref<HTMLSpanElement>;
|
|
76
|
+
asChild?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Render the indicator even when its parent item is unchecked. The
|
|
79
|
+
* `data-state` attribute still reflects the live state (`"checked"` /
|
|
80
|
+
* `"unchecked"` / `"indeterminate"`), so consumers can animate the
|
|
81
|
+
* indicator in and out instead of mounting / unmounting it.
|
|
82
|
+
*/
|
|
83
|
+
forceMount?: boolean;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export type DropdownGroupProps = Omit<ComponentProps<"li">, "role"> & {
|
|
87
|
+
children?: ReactNode;
|
|
88
|
+
ref?: Ref<HTMLLIElement>;
|
|
89
|
+
asChild?: boolean;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type DropdownLabelProps = ComponentProps<"li"> & {
|
|
93
|
+
children?: ReactNode;
|
|
94
|
+
ref?: Ref<HTMLLIElement>;
|
|
95
|
+
asChild?: boolean;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
type DropdownCheckboxItemBaseProps = Omit<
|
|
99
|
+
ComponentProps<"li">,
|
|
100
|
+
"role" | "tabIndex" | "aria-checked" | "defaultChecked" | "onSelect"
|
|
101
|
+
> & {
|
|
102
|
+
children?: ReactNode;
|
|
103
|
+
ref?: Ref<HTMLLIElement>;
|
|
104
|
+
asChild?: boolean;
|
|
105
|
+
disabled?: boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Fires when activation completes and the close auto-fires. Call
|
|
108
|
+
* `event.preventDefault()` to keep the menu open after toggling.
|
|
109
|
+
*/
|
|
110
|
+
onSelect?: (event: Event) => void;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
type DropdownCheckboxItemUncontrolledProps = DropdownCheckboxItemBaseProps & {
|
|
114
|
+
defaultChecked?: CheckedState;
|
|
115
|
+
checked?: never;
|
|
116
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
type DropdownCheckboxItemControlledProps = DropdownCheckboxItemBaseProps & {
|
|
120
|
+
defaultChecked?: never;
|
|
121
|
+
checked: CheckedState;
|
|
122
|
+
onCheckedChange: (checked: boolean) => void;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export type DropdownCheckboxItemProps =
|
|
126
|
+
| DropdownCheckboxItemUncontrolledProps
|
|
127
|
+
| DropdownCheckboxItemControlledProps;
|
|
128
|
+
|
|
129
|
+
type DropdownRadioGroupBaseProps = Omit<ComponentProps<"li">, "role"> & {
|
|
130
|
+
children?: ReactNode;
|
|
131
|
+
ref?: Ref<HTMLLIElement>;
|
|
132
|
+
asChild?: boolean;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
type DropdownRadioGroupUncontrolledProps = DropdownRadioGroupBaseProps & {
|
|
136
|
+
defaultValue?: string;
|
|
137
|
+
value?: never;
|
|
138
|
+
onValueChange?: (value: string) => void;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
type DropdownRadioGroupControlledProps = DropdownRadioGroupBaseProps & {
|
|
142
|
+
defaultValue?: never;
|
|
143
|
+
value: string;
|
|
144
|
+
onValueChange: (value: string) => void;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export type DropdownRadioGroupProps =
|
|
148
|
+
| DropdownRadioGroupUncontrolledProps
|
|
149
|
+
| DropdownRadioGroupControlledProps;
|
|
150
|
+
|
|
151
|
+
export type DropdownRadioItemProps = Omit<
|
|
152
|
+
ComponentProps<"li">,
|
|
153
|
+
"role" | "tabIndex" | "aria-checked" | "onSelect"
|
|
154
|
+
> & {
|
|
155
|
+
children?: ReactNode;
|
|
156
|
+
ref?: Ref<HTMLLIElement>;
|
|
157
|
+
asChild?: boolean;
|
|
158
|
+
disabled?: boolean;
|
|
159
|
+
value: string;
|
|
160
|
+
onSelect?: (event: Event) => void;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
type DropdownSubBaseProps = {
|
|
164
|
+
children?: ReactNode;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
type DropdownSubUncontrolledProps = DropdownSubBaseProps & {
|
|
168
|
+
defaultOpen?: boolean;
|
|
169
|
+
open?: never;
|
|
170
|
+
onOpenChange?: (open: boolean) => void;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
type DropdownSubControlledProps = DropdownSubBaseProps & {
|
|
174
|
+
defaultOpen?: never;
|
|
175
|
+
open: boolean;
|
|
176
|
+
onOpenChange: (open: boolean) => void;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export type DropdownSubProps =
|
|
180
|
+
| DropdownSubUncontrolledProps
|
|
181
|
+
| DropdownSubControlledProps;
|
|
182
|
+
|
|
183
|
+
export type DropdownSubTriggerProps = Omit<
|
|
184
|
+
ComponentProps<"li">,
|
|
185
|
+
"role" | "tabIndex" | "aria-haspopup" | "aria-expanded" | "aria-controls"
|
|
186
|
+
> & {
|
|
187
|
+
children?: ReactNode;
|
|
188
|
+
ref?: Ref<HTMLLIElement>;
|
|
189
|
+
asChild?: boolean;
|
|
190
|
+
disabled?: boolean;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
export type DropdownSubContentProps = Omit<
|
|
194
|
+
ComponentProps<"menu">,
|
|
195
|
+
"role" | "popover" | "id"
|
|
196
|
+
> & {
|
|
197
|
+
children?: ReactNode;
|
|
198
|
+
ref?: Ref<HTMLMenuElement>;
|
|
199
|
+
asChild?: boolean;
|
|
200
|
+
};
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { Slot } from "../Slot";
|
|
2
|
+
import {
|
|
3
|
+
EmptyStateActionsProps,
|
|
4
|
+
EmptyStateDescriptionProps,
|
|
5
|
+
EmptyStateMediaProps,
|
|
6
|
+
EmptyStateRootProps,
|
|
7
|
+
EmptyStateTitleProps,
|
|
8
|
+
} from "./types";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The root of an Empty State — renders a `<div role="status">` wrapping the
|
|
12
|
+
* placeholder shown when a collection, search, or view has no content.
|
|
13
|
+
*
|
|
14
|
+
* The `status` role makes the root a polite live region (implicit
|
|
15
|
+
* `aria-live="polite"`, `aria-atomic="true"`). Render the `EmptyState`
|
|
16
|
+
* conditionally — in place of the absent content — so that when it appears
|
|
17
|
+
* after a filter or search returns nothing, assistive technology announces
|
|
18
|
+
* it once the user is idle, without interrupting them.
|
|
19
|
+
*
|
|
20
|
+
* Opt out of the live region by passing `role={undefined}` for an empty
|
|
21
|
+
* state that is part of the initial, static page.
|
|
22
|
+
*
|
|
23
|
+
* **`asChild` composition.** Renders the consumer's element instead of a
|
|
24
|
+
* `<div>`, merging `role="status"` and all other props in via the
|
|
25
|
+
* {@link Slot} utility.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* {results.length === 0 && (
|
|
30
|
+
* <EmptyState.Root>
|
|
31
|
+
* <EmptyState.Title>No results</EmptyState.Title>
|
|
32
|
+
* <EmptyState.Description>Try a different search.</EmptyState.Description>
|
|
33
|
+
* </EmptyState.Root>
|
|
34
|
+
* )}
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
function EmptyStateRoot({
|
|
38
|
+
asChild = false,
|
|
39
|
+
children,
|
|
40
|
+
...rest
|
|
41
|
+
}: EmptyStateRootProps) {
|
|
42
|
+
const rootProps = { role: "status", ...rest };
|
|
43
|
+
|
|
44
|
+
if (asChild) {
|
|
45
|
+
return <Slot {...rootProps}>{children}</Slot>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return <div {...rootProps}>{children}</div>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
EmptyStateRoot.displayName = "EmptyStateRoot";
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The illustration slot of an Empty State — renders a `<div aria-hidden="true">`
|
|
55
|
+
* wrapping a decorative icon or illustration.
|
|
56
|
+
*
|
|
57
|
+
* Empty-state artwork is decorative: the {@link EmptyStateTitle | `Title`} and
|
|
58
|
+
* {@link EmptyStateDescription | `Description`} carry the meaning. `Media` is
|
|
59
|
+
* therefore hidden from assistive technology by default, so screen-reader
|
|
60
|
+
* users are not read a redundant or meaningless image. If the artwork is
|
|
61
|
+
* genuinely informative, pass `aria-hidden={false}` and give it an accessible
|
|
62
|
+
* name yourself.
|
|
63
|
+
*
|
|
64
|
+
* **`asChild` composition.** Renders the consumer's element instead of a
|
|
65
|
+
* `<div>`, merging `aria-hidden="true"` and all other props in via the
|
|
66
|
+
* {@link Slot} utility.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```tsx
|
|
70
|
+
* <EmptyState.Media>
|
|
71
|
+
* <InboxIcon />
|
|
72
|
+
* </EmptyState.Media>
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
function EmptyStateMedia({
|
|
76
|
+
asChild = false,
|
|
77
|
+
children,
|
|
78
|
+
...rest
|
|
79
|
+
}: EmptyStateMediaProps) {
|
|
80
|
+
const mediaProps = { "aria-hidden": true, ...rest };
|
|
81
|
+
|
|
82
|
+
if (asChild) {
|
|
83
|
+
return <Slot {...mediaProps}>{children}</Slot>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return <div {...mediaProps}>{children}</div>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
EmptyStateMedia.displayName = "EmptyStateMedia";
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The headline of an Empty State — renders a `<p>` with the short summary of
|
|
93
|
+
* why the view is empty (e.g. "No results found").
|
|
94
|
+
*
|
|
95
|
+
* A `<p>` is the safe default: a headless primitive cannot know the correct
|
|
96
|
+
* heading level for the surrounding document outline. When the empty state
|
|
97
|
+
* stands in for a titled section, promote the title to a real heading with
|
|
98
|
+
* `asChild` so it joins the page's heading hierarchy.
|
|
99
|
+
*
|
|
100
|
+
* **`asChild` composition.** Renders the consumer's element instead of a
|
|
101
|
+
* `<p>`, merging all props in via the {@link Slot} utility.
|
|
102
|
+
*
|
|
103
|
+
* @example Promote to a heading
|
|
104
|
+
* ```tsx
|
|
105
|
+
* <EmptyState.Title asChild>
|
|
106
|
+
* <h2>No results found</h2>
|
|
107
|
+
* </EmptyState.Title>
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
function EmptyStateTitle({
|
|
111
|
+
asChild = false,
|
|
112
|
+
children,
|
|
113
|
+
...rest
|
|
114
|
+
}: EmptyStateTitleProps) {
|
|
115
|
+
if (asChild) {
|
|
116
|
+
return <Slot {...rest}>{children}</Slot>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return <p {...rest}>{children}</p>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
EmptyStateTitle.displayName = "EmptyStateTitle";
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The supporting copy of an Empty State — renders a `<p>` with the secondary
|
|
126
|
+
* text that explains the situation or suggests a next step (e.g. "Try
|
|
127
|
+
* adjusting your filters").
|
|
128
|
+
*
|
|
129
|
+
* Keep it to guidance the user can act on; the actionable controls themselves
|
|
130
|
+
* belong in {@link EmptyStateActions | `Actions`}.
|
|
131
|
+
*
|
|
132
|
+
* **`asChild` composition.** Renders the consumer's element instead of a
|
|
133
|
+
* `<p>`, merging all props in via the {@link Slot} utility.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```tsx
|
|
137
|
+
* <EmptyState.Description>Try adjusting your filters.</EmptyState.Description>
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
function EmptyStateDescription({
|
|
141
|
+
asChild = false,
|
|
142
|
+
children,
|
|
143
|
+
...rest
|
|
144
|
+
}: EmptyStateDescriptionProps) {
|
|
145
|
+
if (asChild) {
|
|
146
|
+
return <Slot {...rest}>{children}</Slot>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return <p {...rest}>{children}</p>;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
EmptyStateDescription.displayName = "EmptyStateDescription";
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* The recovery-action slot of an Empty State — renders a `<div>` grouping the
|
|
156
|
+
* controls that let the user move on from the empty state (e.g. a "Clear
|
|
157
|
+
* filters" button or a "Create your first project" link).
|
|
158
|
+
*
|
|
159
|
+
* It is a plain grouping element with no role of its own, so the buttons and
|
|
160
|
+
* links inside keep their native semantics. As a child of
|
|
161
|
+
* {@link EmptyStateRoot | `Root`}'s live region, the control labels are
|
|
162
|
+
* included when the empty state is announced.
|
|
163
|
+
*
|
|
164
|
+
* **`asChild` composition.** Renders the consumer's element instead of a
|
|
165
|
+
* `<div>`, merging all props in via the {@link Slot} utility.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```tsx
|
|
169
|
+
* <EmptyState.Actions>
|
|
170
|
+
* <button onClick={clearFilters}>Clear filters</button>
|
|
171
|
+
* </EmptyState.Actions>
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
function EmptyStateActions({
|
|
175
|
+
asChild = false,
|
|
176
|
+
children,
|
|
177
|
+
...rest
|
|
178
|
+
}: EmptyStateActionsProps) {
|
|
179
|
+
if (asChild) {
|
|
180
|
+
return <Slot {...rest}>{children}</Slot>;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return <div {...rest}>{children}</div>;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
EmptyStateActions.displayName = "EmptyStateActions";
|
|
187
|
+
|
|
188
|
+
type EmptyStateCompound = typeof EmptyStateRoot & {
|
|
189
|
+
Root: typeof EmptyStateRoot;
|
|
190
|
+
Media: typeof EmptyStateMedia;
|
|
191
|
+
Title: typeof EmptyStateTitle;
|
|
192
|
+
Description: typeof EmptyStateDescription;
|
|
193
|
+
Actions: typeof EmptyStateActions;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const EmptyState: EmptyStateCompound = Object.assign(EmptyStateRoot, {
|
|
197
|
+
Root: EmptyStateRoot,
|
|
198
|
+
Media: EmptyStateMedia,
|
|
199
|
+
Title: EmptyStateTitle,
|
|
200
|
+
Description: EmptyStateDescription,
|
|
201
|
+
Actions: EmptyStateActions,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Headless, accessible **Empty State** — a stateless compound component for
|
|
206
|
+
* the placeholder shown when a collection, search, or view has no content.
|
|
207
|
+
*
|
|
208
|
+
* `EmptyState` is both callable (an alias of {@link EmptyStateRoot |
|
|
209
|
+
* `EmptyState.Root`}) and carries its sub-components as static properties.
|
|
210
|
+
* Prefer the namespaced form in application code:
|
|
211
|
+
*
|
|
212
|
+
* - {@link EmptyStateRoot | `EmptyState.Root`} — `<div role="status">`, the
|
|
213
|
+
* polite live region wrapping the placeholder.
|
|
214
|
+
* - {@link EmptyStateMedia | `EmptyState.Media`} — `<div aria-hidden="true">`,
|
|
215
|
+
* the decorative icon/illustration slot.
|
|
216
|
+
* - {@link EmptyStateTitle | `EmptyState.Title`} — `<p>`, the headline.
|
|
217
|
+
* - {@link EmptyStateDescription | `EmptyState.Description`} — `<p>`, the
|
|
218
|
+
* supporting copy.
|
|
219
|
+
* - {@link EmptyStateActions | `EmptyState.Actions`} — `<div>`, the
|
|
220
|
+
* recovery-action slot.
|
|
221
|
+
*
|
|
222
|
+
* All sub-components are stateless and optional — compose only the parts a
|
|
223
|
+
* given empty state needs.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```tsx
|
|
227
|
+
* import { EmptyState } from "@primitiv-ui/react";
|
|
228
|
+
*
|
|
229
|
+
* {results.length === 0 && (
|
|
230
|
+
* <EmptyState.Root>
|
|
231
|
+
* <EmptyState.Media>
|
|
232
|
+
* <SearchIcon />
|
|
233
|
+
* </EmptyState.Media>
|
|
234
|
+
* <EmptyState.Title>No results found</EmptyState.Title>
|
|
235
|
+
* <EmptyState.Description>Try adjusting your filters.</EmptyState.Description>
|
|
236
|
+
* <EmptyState.Actions>
|
|
237
|
+
* <button onClick={clearFilters}>Clear filters</button>
|
|
238
|
+
* </EmptyState.Actions>
|
|
239
|
+
* </EmptyState.Root>
|
|
240
|
+
* )}
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
EmptyState.displayName = "EmptyState";
|
|
244
|
+
|
|
245
|
+
export { EmptyState };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# EmptyState
|
|
2
|
+
|
|
3
|
+
A stateless compound component for the placeholder shown when a
|
|
4
|
+
collection, search, or view has no content. Renders a polite
|
|
5
|
+
[`status`](https://www.w3.org/TR/wai-aria-1.2/#status) live region so a
|
|
6
|
+
conditionally-mounted empty state is announced. Zero styles ship.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { EmptyState } from "@primitiv-ui/react";
|
|
10
|
+
|
|
11
|
+
{
|
|
12
|
+
results.length === 0 && (
|
|
13
|
+
<EmptyState.Root>
|
|
14
|
+
<EmptyState.Media>
|
|
15
|
+
<SearchIcon />
|
|
16
|
+
</EmptyState.Media>
|
|
17
|
+
<EmptyState.Title>No results found</EmptyState.Title>
|
|
18
|
+
<EmptyState.Description>
|
|
19
|
+
Try adjusting your filters.
|
|
20
|
+
</EmptyState.Description>
|
|
21
|
+
<EmptyState.Actions>
|
|
22
|
+
<button onClick={clearFilters}>Clear filters</button>
|
|
23
|
+
</EmptyState.Actions>
|
|
24
|
+
</EmptyState.Root>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Sub-components
|
|
30
|
+
|
|
31
|
+
All sub-components are stateless and optional — compose only the parts a
|
|
32
|
+
given empty state needs.
|
|
33
|
+
|
|
34
|
+
| Export | Renders | Notes |
|
|
35
|
+
| ------------------------ | ------------------------ | ------------------------------------------------------------------ |
|
|
36
|
+
| `EmptyState.Root` | `<div role="status">` | Polite live region wrapping the placeholder. |
|
|
37
|
+
| `EmptyState.Media` | `<div aria-hidden>` | Decorative icon/illustration slot — see [Media](#media). |
|
|
38
|
+
| `EmptyState.Title` | `<p>` | The headline — see [Title heading level](#title-heading-level). |
|
|
39
|
+
| `EmptyState.Description` | `<p>` | Secondary supporting copy. |
|
|
40
|
+
| `EmptyState.Actions` | `<div>` | Groups recovery controls (buttons/links). |
|
|
41
|
+
|
|
42
|
+
`EmptyState` is also callable directly as an alias of `EmptyState.Root`.
|
|
43
|
+
|
|
44
|
+
## Props
|
|
45
|
+
|
|
46
|
+
Every sub-component accepts `asChild` plus all native props for the
|
|
47
|
+
element it renders:
|
|
48
|
+
|
|
49
|
+
| Prop | Type | Default | Notes |
|
|
50
|
+
| --------- | --------- | ------- | ---------------------------------------------------- |
|
|
51
|
+
| `asChild` | `boolean` | `false` | Render the consumer's own element instead — see below |
|
|
52
|
+
| `...rest` | native | — | All props for the rendered element, including `aria-*` |
|
|
53
|
+
|
|
54
|
+
## Announce on appearance
|
|
55
|
+
|
|
56
|
+
`EmptyState.Root` renders `role="status"` — a polite live region with
|
|
57
|
+
implicit `aria-live="polite"` and `aria-atomic="true"`. Render the empty
|
|
58
|
+
state **conditionally**, in place of the absent content, so that when a
|
|
59
|
+
search or filter returns nothing the message is announced once the user
|
|
60
|
+
is idle:
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
{
|
|
64
|
+
results.length === 0 && <EmptyState.Root>No results found</EmptyState.Root>;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
For an empty state that is part of the initial, static page — and so has
|
|
69
|
+
nothing to announce — opt out of the live region:
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
<EmptyState.Root role={undefined}>…</EmptyState.Root>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Media
|
|
76
|
+
|
|
77
|
+
Empty-state artwork is decorative: the `Title` and `Description` carry
|
|
78
|
+
the meaning. `EmptyState.Media` is therefore `aria-hidden` by default so
|
|
79
|
+
screen-reader users are not read a redundant image. If the artwork is
|
|
80
|
+
genuinely informative, opt back in and give it an accessible name:
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
<EmptyState.Media aria-hidden={false}>
|
|
84
|
+
<img src="/chart.svg" alt="Sales trending to zero" />
|
|
85
|
+
</EmptyState.Media>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Title heading level
|
|
89
|
+
|
|
90
|
+
`EmptyState.Title` renders a `<p>` — a headless primitive cannot know
|
|
91
|
+
the correct heading level for the surrounding document outline. When the
|
|
92
|
+
empty state stands in for a titled section, promote the title to a real
|
|
93
|
+
heading with `asChild` so it joins the page's heading hierarchy:
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
<EmptyState.Title asChild>
|
|
97
|
+
<h2>No results found</h2>
|
|
98
|
+
</EmptyState.Title>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## asChild
|
|
102
|
+
|
|
103
|
+
Pass `asChild` to any sub-component to render the consumer's own element
|
|
104
|
+
instead of the default, merging in the sub-component's props (and, for
|
|
105
|
+
`Root` and `Media`, its `role` / `aria-hidden`) via the `Slot` utility:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
<EmptyState.Root asChild>
|
|
109
|
+
<section>…</section>
|
|
110
|
+
</EmptyState.Root>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Styling hooks
|
|
114
|
+
|
|
115
|
+
`EmptyState` emits no `data-*` attributes — it is a static layout
|
|
116
|
+
component. Style it with whatever system you use, targeting the rendered
|
|
117
|
+
elements directly or via your own `className`s:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
<EmptyState.Root className="empty-state">
|
|
121
|
+
<EmptyState.Title className="empty-state__title">
|
|
122
|
+
No results found
|
|
123
|
+
</EmptyState.Title>
|
|
124
|
+
</EmptyState.Root>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
[Back to @primitiv-ui/react](../../README.md)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { EmptyState } from "..";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
describe("EmptyState.Actions component", () => {
|
|
5
|
+
it("should render a div containing its children", () => {
|
|
6
|
+
// Arrange
|
|
7
|
+
render(
|
|
8
|
+
<EmptyState.Actions>
|
|
9
|
+
<button>Clear filters</button>
|
|
10
|
+
</EmptyState.Actions>,
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
// Assert
|
|
14
|
+
const button = screen.getByRole("button", { name: "Clear filters" });
|
|
15
|
+
expect(button.parentElement?.tagName).toBe("DIV");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should render the consumer element with asChild", () => {
|
|
19
|
+
// Arrange
|
|
20
|
+
render(
|
|
21
|
+
<EmptyState.Actions asChild>
|
|
22
|
+
<nav>
|
|
23
|
+
<button>Clear filters</button>
|
|
24
|
+
</nav>
|
|
25
|
+
</EmptyState.Actions>,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// Assert
|
|
29
|
+
const button = screen.getByRole("button", { name: "Clear filters" });
|
|
30
|
+
expect(button.parentElement?.tagName).toBe("NAV");
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { EmptyState } from "..";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
describe("EmptyState.Description component", () => {
|
|
5
|
+
it("should render a paragraph containing its children", () => {
|
|
6
|
+
// Arrange
|
|
7
|
+
render(
|
|
8
|
+
<EmptyState.Description>
|
|
9
|
+
Try adjusting your filters.
|
|
10
|
+
</EmptyState.Description>,
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
// Assert
|
|
14
|
+
const description = screen.getByText("Try adjusting your filters.");
|
|
15
|
+
expect(description.tagName).toBe("P");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should render the consumer element with asChild", () => {
|
|
19
|
+
// Arrange
|
|
20
|
+
render(
|
|
21
|
+
<EmptyState.Description asChild>
|
|
22
|
+
<span>Try adjusting your filters.</span>
|
|
23
|
+
</EmptyState.Description>,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
// Assert
|
|
27
|
+
const description = screen.getByText("Try adjusting your filters.");
|
|
28
|
+
expect(description.tagName).toBe("SPAN");
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { EmptyState } from "..";
|
|
2
|
+
import { render } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
describe("EmptyState.Media component", () => {
|
|
5
|
+
it("should render a div hidden from assistive technology", () => {
|
|
6
|
+
// Arrange
|
|
7
|
+
const { container } = render(
|
|
8
|
+
<EmptyState.Media>
|
|
9
|
+
<svg />
|
|
10
|
+
</EmptyState.Media>,
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
// Assert
|
|
14
|
+
const media = container.firstChild as HTMLElement;
|
|
15
|
+
expect(media.tagName).toBe("DIV");
|
|
16
|
+
expect(media).toHaveAttribute("aria-hidden", "true");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should render the consumer element with asChild, keeping it hidden", () => {
|
|
20
|
+
// Arrange
|
|
21
|
+
const { container } = render(
|
|
22
|
+
<EmptyState.Media asChild>
|
|
23
|
+
<span>
|
|
24
|
+
<svg />
|
|
25
|
+
</span>
|
|
26
|
+
</EmptyState.Media>,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// Assert
|
|
30
|
+
const media = container.firstChild as HTMLElement;
|
|
31
|
+
expect(media.tagName).toBe("SPAN");
|
|
32
|
+
expect(media).toHaveAttribute("aria-hidden", "true");
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { EmptyState } from "..";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
describe("EmptyState.Root component", () => {
|
|
5
|
+
it("should render a div with role status containing its children", () => {
|
|
6
|
+
// Arrange
|
|
7
|
+
render(<EmptyState.Root>No projects yet</EmptyState.Root>);
|
|
8
|
+
|
|
9
|
+
// Assert
|
|
10
|
+
const root = screen.getByRole("status");
|
|
11
|
+
expect(root.tagName).toBe("DIV");
|
|
12
|
+
expect(root).toHaveTextContent("No projects yet");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should render the consumer element with asChild, keeping role status", () => {
|
|
16
|
+
// Arrange
|
|
17
|
+
render(
|
|
18
|
+
<EmptyState.Root asChild>
|
|
19
|
+
<section>No projects yet</section>
|
|
20
|
+
</EmptyState.Root>,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
// Assert
|
|
24
|
+
const root = screen.getByRole("status");
|
|
25
|
+
expect(root.tagName).toBe("SECTION");
|
|
26
|
+
expect(root).toHaveTextContent("No projects yet");
|
|
27
|
+
});
|
|
28
|
+
});
|