@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,75 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
|
|
3
|
+
import { Field } from "../Field";
|
|
4
|
+
|
|
5
|
+
describe("Field state cascade", () => {
|
|
6
|
+
it("sets data-field-invalid='' on the root when invalid", () => {
|
|
7
|
+
// Arrange & Act
|
|
8
|
+
render(<Field.Root data-testid="field" invalid />);
|
|
9
|
+
|
|
10
|
+
// Assert
|
|
11
|
+
expect(screen.getByTestId("field")).toHaveAttribute(
|
|
12
|
+
"data-field-invalid",
|
|
13
|
+
"",
|
|
14
|
+
);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("sets data-field-disabled='' on the root when disabled", () => {
|
|
18
|
+
// Arrange & Act
|
|
19
|
+
render(<Field.Root data-testid="field" disabled />);
|
|
20
|
+
|
|
21
|
+
// Assert
|
|
22
|
+
expect(screen.getByTestId("field")).toHaveAttribute(
|
|
23
|
+
"data-field-disabled",
|
|
24
|
+
"",
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("sets data-field-required='' on the root when required", () => {
|
|
29
|
+
// Arrange & Act
|
|
30
|
+
render(<Field.Root data-testid="field" required />);
|
|
31
|
+
|
|
32
|
+
// Assert
|
|
33
|
+
expect(screen.getByTestId("field")).toHaveAttribute(
|
|
34
|
+
"data-field-required",
|
|
35
|
+
"",
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("does not set state data-* attributes when the corresponding flag is false", () => {
|
|
40
|
+
// Arrange & Act
|
|
41
|
+
render(<Field.Root data-testid="field" />);
|
|
42
|
+
const root = screen.getByTestId("field");
|
|
43
|
+
|
|
44
|
+
// Assert
|
|
45
|
+
expect(root).not.toHaveAttribute("data-field-invalid");
|
|
46
|
+
expect(root).not.toHaveAttribute("data-field-disabled");
|
|
47
|
+
expect(root).not.toHaveAttribute("data-field-required");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("Field.ErrorText returns null when invalid=false", () => {
|
|
51
|
+
// Arrange & Act
|
|
52
|
+
render(
|
|
53
|
+
<Field.Root>
|
|
54
|
+
<Field.ErrorText>You should not see this.</Field.ErrorText>
|
|
55
|
+
</Field.Root>,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// Assert
|
|
59
|
+
expect(
|
|
60
|
+
screen.queryByText("You should not see this."),
|
|
61
|
+
).not.toBeInTheDocument();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("Field.ErrorText renders when invalid=true", () => {
|
|
65
|
+
// Arrange & Act
|
|
66
|
+
render(
|
|
67
|
+
<Field.Root invalid>
|
|
68
|
+
<Field.ErrorText>Required.</Field.ErrorText>
|
|
69
|
+
</Field.Root>,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// Assert
|
|
73
|
+
expect(screen.getByText("Required.")).toBeInTheDocument();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useFieldContext } from "../FieldContext";
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
|
|
3
|
+
import { FieldContext } from "../FieldContext";
|
|
4
|
+
|
|
5
|
+
type FieldAwareProps = {
|
|
6
|
+
id?: string;
|
|
7
|
+
"aria-describedby"?: string;
|
|
8
|
+
"aria-invalid"?:
|
|
9
|
+
| boolean
|
|
10
|
+
| "true"
|
|
11
|
+
| "false"
|
|
12
|
+
| "grammar"
|
|
13
|
+
| "spelling"
|
|
14
|
+
| undefined;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
required?: boolean;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Merges consumer-supplied props with any {@link FieldContext} available
|
|
21
|
+
* higher in the tree. Use it inside form controls (Input, Textarea,
|
|
22
|
+
* Select, …) so they automatically inherit the field's id, aria
|
|
23
|
+
* wiring, and `disabled` / `required` cascade when nested inside
|
|
24
|
+
* `<Field.Root>`.
|
|
25
|
+
*
|
|
26
|
+
* **Merge rules**
|
|
27
|
+
* - `id`, `disabled`, `required`, `aria-invalid`: consumer wins; the
|
|
28
|
+
* field provides the fallback.
|
|
29
|
+
* - `aria-describedby`: composes — consumer-supplied ids come first,
|
|
30
|
+
* then the field's `descriptionId`, then the `errorId` when invalid.
|
|
31
|
+
*
|
|
32
|
+
* When no FieldContext is in scope the consumer props are returned
|
|
33
|
+
* unchanged, so existing usage outside a `<Field.Root>` is unaffected.
|
|
34
|
+
*/
|
|
35
|
+
export function useFieldProps<P extends FieldAwareProps>(consumerProps: P): P {
|
|
36
|
+
const field = useContext(FieldContext);
|
|
37
|
+
if (!field) return consumerProps;
|
|
38
|
+
|
|
39
|
+
const composedDescribedBy =
|
|
40
|
+
[
|
|
41
|
+
consumerProps["aria-describedby"],
|
|
42
|
+
field.descriptionId,
|
|
43
|
+
field.invalid ? field.errorId : null,
|
|
44
|
+
]
|
|
45
|
+
.filter(Boolean)
|
|
46
|
+
.join(" ") || undefined;
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
...consumerProps,
|
|
50
|
+
id: consumerProps.id ?? field.id,
|
|
51
|
+
disabled: consumerProps.disabled ?? field.disabled,
|
|
52
|
+
required: consumerProps.required ?? field.required,
|
|
53
|
+
"aria-invalid":
|
|
54
|
+
consumerProps["aria-invalid"] ?? (field.invalid || undefined),
|
|
55
|
+
"aria-describedby": composedDescribedBy,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ComponentProps, ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
export type FieldRootProps = ComponentProps<"div"> & {
|
|
4
|
+
/** Stable id wired to the control via {@link FieldLabel}'s `htmlFor`. Auto-generated via `useId` when omitted. */
|
|
5
|
+
id?: string;
|
|
6
|
+
/** Marks the field as invalid; cascades to the control via context. */
|
|
7
|
+
invalid?: boolean;
|
|
8
|
+
/** Disables the field; cascades to the control via context. */
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
/** Marks the field as required; cascades to the control via context. */
|
|
11
|
+
required?: boolean;
|
|
12
|
+
/** Renders the consumer element instead of `<div>` via Slot. */
|
|
13
|
+
asChild?: boolean;
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type FieldLabelProps = ComponentProps<"label"> & {
|
|
18
|
+
/** Renders the consumer element instead of `<label>` via Slot. */
|
|
19
|
+
asChild?: boolean;
|
|
20
|
+
children?: ReactNode;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type FieldDescriptionProps = ComponentProps<"div"> & {
|
|
24
|
+
/** Renders the consumer element instead of `<div>` via Slot. */
|
|
25
|
+
asChild?: boolean;
|
|
26
|
+
children?: ReactNode;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type FieldErrorTextProps = ComponentProps<"div"> & {
|
|
30
|
+
/** Renders the consumer element instead of `<div>` via Slot. */
|
|
31
|
+
asChild?: boolean;
|
|
32
|
+
children?: ReactNode;
|
|
33
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { FieldsetLegendProps, FieldsetProps } from "./types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The root of a Fieldset — renders a native `<fieldset>` element.
|
|
5
|
+
*
|
|
6
|
+
* A `<fieldset>` carries an implicit `role="group"` and groups a set of
|
|
7
|
+
* related form controls (radios, checkboxes, inputs). Pair it with a
|
|
8
|
+
* {@link FieldsetLegend} so the group is announced with an accessible
|
|
9
|
+
* name when the user enters any control inside it.
|
|
10
|
+
*
|
|
11
|
+
* **Disabled.** Setting `disabled` forwards the native attribute, which
|
|
12
|
+
* disables *every* form control nested inside the fieldset at once — the
|
|
13
|
+
* standard way to disable a whole section of a form. It also sets
|
|
14
|
+
* `data-disabled=""` so CSS can target the state without the `:disabled`
|
|
15
|
+
* pseudo-class:
|
|
16
|
+
*
|
|
17
|
+
* ```css
|
|
18
|
+
* fieldset[data-disabled] { opacity: 0.5; }
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <Fieldset.Root>
|
|
24
|
+
* <Fieldset.Legend>Notifications</Fieldset.Legend>
|
|
25
|
+
* <label><input type="checkbox" name="email" /> Email</label>
|
|
26
|
+
* <label><input type="checkbox" name="sms" /> SMS</label>
|
|
27
|
+
* </Fieldset.Root>
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
function Fieldset({ disabled, children, ...rest }: FieldsetProps) {
|
|
31
|
+
return (
|
|
32
|
+
<fieldset
|
|
33
|
+
{...rest}
|
|
34
|
+
disabled={disabled}
|
|
35
|
+
data-disabled={disabled ? "" : undefined}
|
|
36
|
+
>
|
|
37
|
+
{children}
|
|
38
|
+
</fieldset>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
Fieldset.displayName = "Fieldset";
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The caption for a {@link Fieldset} — renders a native `<legend>`.
|
|
46
|
+
*
|
|
47
|
+
* The `<legend>` must be the first child of the `<fieldset>`. It supplies
|
|
48
|
+
* the group's accessible name, so assistive technology announces it when
|
|
49
|
+
* the user moves focus into any control within the group.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* <Fieldset.Legend>Shipping address</Fieldset.Legend>
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
function FieldsetLegend({ children, ...rest }: FieldsetLegendProps) {
|
|
57
|
+
return <legend {...rest}>{children}</legend>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
FieldsetLegend.displayName = "FieldsetLegend";
|
|
61
|
+
|
|
62
|
+
type FieldsetCompound = typeof Fieldset & {
|
|
63
|
+
Root: typeof Fieldset;
|
|
64
|
+
Legend: typeof FieldsetLegend;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const FieldsetCompound: FieldsetCompound = Object.assign(Fieldset, {
|
|
68
|
+
Root: Fieldset,
|
|
69
|
+
Legend: FieldsetLegend,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Headless, accessible **Fieldset** — a stateless compound component that
|
|
74
|
+
* groups related form controls, with zero styles.
|
|
75
|
+
*
|
|
76
|
+
* `Fieldset` is both callable (an alias of {@link Fieldset | `Fieldset.Root`})
|
|
77
|
+
* and carries its sub-component as a static property. Prefer the
|
|
78
|
+
* namespaced form in application code:
|
|
79
|
+
*
|
|
80
|
+
* - {@link Fieldset | `Fieldset.Root`} — `<fieldset>`, implicit `role="group"`.
|
|
81
|
+
* - {@link FieldsetLegend | `Fieldset.Legend`} — `<legend>`, the group's accessible name.
|
|
82
|
+
*
|
|
83
|
+
* @example Grouping a set of radios
|
|
84
|
+
* ```tsx
|
|
85
|
+
* import { Fieldset } from "@primitiv-ui/react";
|
|
86
|
+
*
|
|
87
|
+
* <Fieldset.Root>
|
|
88
|
+
* <Fieldset.Legend>Plan</Fieldset.Legend>
|
|
89
|
+
* <label><input type="radio" name="plan" value="free" /> Free</label>
|
|
90
|
+
* <label><input type="radio" name="plan" value="pro" /> Pro</label>
|
|
91
|
+
* </Fieldset.Root>
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @example Disabling a whole section
|
|
95
|
+
* ```tsx
|
|
96
|
+
* <Fieldset.Root disabled>
|
|
97
|
+
* <Fieldset.Legend>Billing</Fieldset.Legend>
|
|
98
|
+
* …every nested control is disabled…
|
|
99
|
+
* </Fieldset.Root>
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
FieldsetCompound.displayName = "Fieldset";
|
|
103
|
+
|
|
104
|
+
export { FieldsetCompound as Fieldset };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Fieldset
|
|
2
|
+
|
|
3
|
+
A headless, accessible grouping for related form controls — a stateless
|
|
4
|
+
compound component wrapping `<fieldset>` and `<legend>`. Zero styles ship.
|
|
5
|
+
|
|
6
|
+
```tsx
|
|
7
|
+
import { Fieldset } from "@primitiv-ui/react";
|
|
8
|
+
|
|
9
|
+
<Fieldset.Root>
|
|
10
|
+
<Fieldset.Legend>Notifications</Fieldset.Legend>
|
|
11
|
+
<label><input type="checkbox" name="email" /> Email</label>
|
|
12
|
+
<label><input type="checkbox" name="sms" /> SMS</label>
|
|
13
|
+
</Fieldset.Root>;
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`Fieldset` is both callable (an alias of `Fieldset.Root`) and carries its
|
|
17
|
+
sub-component as a static property.
|
|
18
|
+
|
|
19
|
+
## Parts
|
|
20
|
+
|
|
21
|
+
| Part | Element | Notes |
|
|
22
|
+
| ----------------- | ------------ | ------------------------------------------------------ |
|
|
23
|
+
| `Fieldset.Root` | `<fieldset>` | Implicit `role="group"`; `disabled` styling hook |
|
|
24
|
+
| `Fieldset.Legend` | `<legend>` | Supplies the group's accessible name |
|
|
25
|
+
|
|
26
|
+
## Props
|
|
27
|
+
|
|
28
|
+
### `Fieldset.Root`
|
|
29
|
+
|
|
30
|
+
| Prop | Type | Default | Notes |
|
|
31
|
+
| ---------- | ---------------------------- | ------- | ----------------------------------------------------------- |
|
|
32
|
+
| `disabled` | `boolean` | — | Native `disabled` + `data-disabled=""` styling hook |
|
|
33
|
+
| `...rest` | `ComponentProps<"fieldset">` | — | All other `<fieldset>` props (`aria-*`, `data-*`, etc.) |
|
|
34
|
+
|
|
35
|
+
### `Fieldset.Legend`
|
|
36
|
+
|
|
37
|
+
| Prop | Type | Default | Notes |
|
|
38
|
+
| --------- | -------------------------- | ------- | -------------------------------- |
|
|
39
|
+
| `...rest` | `ComponentProps<"legend">` | — | All `<legend>` props |
|
|
40
|
+
|
|
41
|
+
## Accessible name
|
|
42
|
+
|
|
43
|
+
A `<fieldset>` has an implicit `role="group"`. Place a `Fieldset.Legend`
|
|
44
|
+
as the first child so the group is announced with a name — assistive
|
|
45
|
+
technology reads the legend when the user moves focus into any control
|
|
46
|
+
within the group.
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
<Fieldset.Root>
|
|
50
|
+
<Fieldset.Legend>Shipping address</Fieldset.Legend>
|
|
51
|
+
…
|
|
52
|
+
</Fieldset.Root>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Disabled
|
|
56
|
+
|
|
57
|
+
Passing `disabled` to `Fieldset.Root` forwards the native `disabled`
|
|
58
|
+
attribute. Natively, this disables **every** form control nested inside
|
|
59
|
+
the fieldset at once — the standard way to disable a whole section of a
|
|
60
|
+
form. It also sets `data-disabled=""` so CSS can target the state
|
|
61
|
+
directly:
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
<Fieldset.Root disabled>
|
|
65
|
+
<Fieldset.Legend>Billing</Fieldset.Legend>
|
|
66
|
+
…every nested control is disabled…
|
|
67
|
+
</Fieldset.Root>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```css
|
|
71
|
+
fieldset[data-disabled] {
|
|
72
|
+
opacity: 0.5;
|
|
73
|
+
}
|
|
74
|
+
```
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
|
|
3
|
+
import { Fieldset } from "../Fieldset";
|
|
4
|
+
|
|
5
|
+
describe("Fieldset basic rendering", () => {
|
|
6
|
+
it("renders a <fieldset> element with an implicit group role", () => {
|
|
7
|
+
// Arrange & Act
|
|
8
|
+
render(<Fieldset.Root />);
|
|
9
|
+
|
|
10
|
+
// Assert
|
|
11
|
+
expect(screen.getByRole("group").tagName).toBe("FIELDSET");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("Fieldset is callable as an alias of Fieldset.Root", () => {
|
|
15
|
+
// Arrange & Act
|
|
16
|
+
render(<Fieldset />);
|
|
17
|
+
|
|
18
|
+
// Assert
|
|
19
|
+
expect(screen.getByRole("group").tagName).toBe("FIELDSET");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("renders Fieldset.Legend as a <legend> element", () => {
|
|
23
|
+
// Arrange & Act
|
|
24
|
+
render(
|
|
25
|
+
<Fieldset.Root>
|
|
26
|
+
<Fieldset.Legend>Shipping address</Fieldset.Legend>
|
|
27
|
+
</Fieldset.Root>,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
// Assert
|
|
31
|
+
expect(screen.getByText("Shipping address").tagName).toBe("LEGEND");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("uses the legend as the group's accessible name", () => {
|
|
35
|
+
// Arrange & Act
|
|
36
|
+
render(
|
|
37
|
+
<Fieldset.Root>
|
|
38
|
+
<Fieldset.Legend>Contact details</Fieldset.Legend>
|
|
39
|
+
</Fieldset.Root>,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// Assert
|
|
43
|
+
expect(
|
|
44
|
+
screen.getByRole("group", { name: "Contact details" }),
|
|
45
|
+
).toBeInTheDocument();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("renders children inside the fieldset", () => {
|
|
49
|
+
// Arrange & Act
|
|
50
|
+
render(
|
|
51
|
+
<Fieldset.Root>
|
|
52
|
+
<input data-testid="field" />
|
|
53
|
+
</Fieldset.Root>,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// Assert
|
|
57
|
+
expect(screen.getByRole("group")).toContainElement(
|
|
58
|
+
screen.getByTestId("field"),
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("passes through className and data-* attributes on the root", () => {
|
|
63
|
+
// Arrange & Act
|
|
64
|
+
render(<Fieldset.Root className="group" data-testid="fs" />);
|
|
65
|
+
|
|
66
|
+
// Assert
|
|
67
|
+
expect(screen.getByTestId("fs")).toHaveClass("group");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("passes through props on the legend", () => {
|
|
71
|
+
// Arrange & Act
|
|
72
|
+
render(
|
|
73
|
+
<Fieldset.Root>
|
|
74
|
+
<Fieldset.Legend className="group__legend">Billing</Fieldset.Legend>
|
|
75
|
+
</Fieldset.Root>,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Assert
|
|
79
|
+
expect(screen.getByText("Billing")).toHaveClass("group__legend");
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
|
|
3
|
+
import { Fieldset } from "../Fieldset";
|
|
4
|
+
|
|
5
|
+
describe("Fieldset disabled state", () => {
|
|
6
|
+
it("sets the native disabled attribute on the fieldset", () => {
|
|
7
|
+
// Arrange & Act
|
|
8
|
+
render(<Fieldset.Root disabled />);
|
|
9
|
+
|
|
10
|
+
// Assert
|
|
11
|
+
expect(screen.getByRole("group")).toBeDisabled();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('sets data-disabled="" as a CSS styling hook', () => {
|
|
15
|
+
// Arrange & Act
|
|
16
|
+
render(<Fieldset.Root disabled data-testid="fs" />);
|
|
17
|
+
|
|
18
|
+
// Assert
|
|
19
|
+
expect(screen.getByTestId("fs")).toHaveAttribute("data-disabled", "");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("does not set data-disabled when not disabled", () => {
|
|
23
|
+
// Arrange & Act
|
|
24
|
+
render(<Fieldset.Root data-testid="fs" />);
|
|
25
|
+
|
|
26
|
+
// Assert
|
|
27
|
+
expect(screen.getByTestId("fs")).not.toHaveAttribute("data-disabled");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("disables form controls nested inside the fieldset", () => {
|
|
31
|
+
// Arrange & Act
|
|
32
|
+
render(
|
|
33
|
+
<Fieldset.Root disabled>
|
|
34
|
+
<input data-testid="field" />
|
|
35
|
+
</Fieldset.Root>,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Assert
|
|
39
|
+
expect(screen.getByTestId("field")).toBeDisabled();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { useFieldProps } from "../Field/hooks";
|
|
2
|
+
import { Slot } from "../Slot";
|
|
3
|
+
import { InputProps } from "./types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A headless, accessible single-line text input.
|
|
7
|
+
*
|
|
8
|
+
* Renders a native `<input>` and passes every standard input attribute
|
|
9
|
+
* straight through to the DOM — `value` / `defaultValue`, `placeholder`,
|
|
10
|
+
* `type`, `name`, `required`, `pattern`, `min`, `max`, `step`,
|
|
11
|
+
* `maxLength`, and so on. No styles ship with the component.
|
|
12
|
+
*
|
|
13
|
+
* **Default type.** `type="text"` is set by default. Override with the
|
|
14
|
+
* `type` prop for any native variant (`"email"`, `"password"`,
|
|
15
|
+
* `"number"`, `"search"`, `"tel"`, `"url"`, `"date"`, …). Future
|
|
16
|
+
* composite primitives (`PasswordInput`, `NumberInput`, `DatePicker`)
|
|
17
|
+
* will layer richer interaction on top of those types.
|
|
18
|
+
*
|
|
19
|
+
* **Labelling.** An `<input>` has no implicit accessible name. Pair it
|
|
20
|
+
* with a `<label>` (`htmlFor` → the input's `id`), or pass `aria-label`
|
|
21
|
+
* / `aria-labelledby` for the control to be announced correctly.
|
|
22
|
+
*
|
|
23
|
+
* **Native validation.** All HTML constraint-validation attributes
|
|
24
|
+
* (`required`, `pattern`, `min`, `max`, `minLength`, `maxLength`,
|
|
25
|
+
* `type="email"` / `"url"` / `"number"`) work as the browser intends —
|
|
26
|
+
* the component does not interfere. CSS can target `input:invalid`
|
|
27
|
+
* directly; for assistive technology, set `aria-invalid` explicitly
|
|
28
|
+
* based on your validation state.
|
|
29
|
+
*
|
|
30
|
+
* **Form library compatibility.** `ref`, `name`, `onChange`, and
|
|
31
|
+
* `onBlur` all pass through, so the spread pattern used by
|
|
32
|
+
* react-hook-form's `register("field")` and similar libraries works
|
|
33
|
+
* directly:
|
|
34
|
+
*
|
|
35
|
+
* ```tsx
|
|
36
|
+
* <Input {...register("email")} type="email" required />
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* **Field integration.** When rendered inside a `<Field.Root>`, Input
|
|
40
|
+
* opts into `FieldContext` and inherits `id`, `aria-describedby`,
|
|
41
|
+
* `aria-invalid`, `disabled`, and `required` from the field. Any prop
|
|
42
|
+
* the consumer passes wins; `aria-describedby` is composed (consumer
|
|
43
|
+
* ids first, then field-supplied description / error ids). Outside a
|
|
44
|
+
* `<Field.Root>`, behaviour is unchanged.
|
|
45
|
+
*
|
|
46
|
+
* **Ref forwarding.** Pass a `ref` prop to access the underlying
|
|
47
|
+
* `HTMLInputElement`:
|
|
48
|
+
*
|
|
49
|
+
* ```tsx
|
|
50
|
+
* const ref = useRef<HTMLInputElement>(null);
|
|
51
|
+
* <Input ref={ref} aria-label="Email" />
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* **Disabled.** Sets native `disabled` (removing the field from the tab
|
|
55
|
+
* order and blocking input) plus `data-disabled=""` so CSS can target
|
|
56
|
+
* `[data-disabled]` without relying on the `:disabled` pseudo-class:
|
|
57
|
+
*
|
|
58
|
+
* ```css
|
|
59
|
+
* input[data-disabled] { opacity: 0.5; cursor: not-allowed; }
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* **`asChild` composition.** Renders the consumer's element instead of
|
|
63
|
+
* `<input>`, merging all props (aria-*, data-*, event handlers, ref)
|
|
64
|
+
* via the {@link Slot} utility. `type` is **not** forwarded in this
|
|
65
|
+
* mode — the child element owns its own type semantics.
|
|
66
|
+
*
|
|
67
|
+
* **Adornments** live in the separate `InputGroup` primitive — leading
|
|
68
|
+
* / trailing icons, currency symbols, clear buttons, password-reveal
|
|
69
|
+
* toggles.
|
|
70
|
+
*
|
|
71
|
+
* @example Basic usage
|
|
72
|
+
* ```tsx
|
|
73
|
+
* <label htmlFor="email">Email</label>
|
|
74
|
+
* <Input id="email" type="email" required />
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @example Inside a Field — id, aria-*, disabled, required all wired automatically
|
|
78
|
+
* ```tsx
|
|
79
|
+
* <Field.Root invalid={!!errors.email}>
|
|
80
|
+
* <Field.Label>Email</Field.Label>
|
|
81
|
+
* <Input type="email" {...register("email")} />
|
|
82
|
+
* <Field.ErrorText>{errors.email?.message}</Field.ErrorText>
|
|
83
|
+
* </Field.Root>
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @example Disabled
|
|
87
|
+
* ```tsx
|
|
88
|
+
* <Input aria-label="Email" disabled />
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* @example asChild — wrap a custom input variant
|
|
92
|
+
* ```tsx
|
|
93
|
+
* <Input asChild aria-label="Email">
|
|
94
|
+
* <MaskedInput mask="email" />
|
|
95
|
+
* </Input>
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export function Input({
|
|
99
|
+
asChild = false,
|
|
100
|
+
type = "text",
|
|
101
|
+
children,
|
|
102
|
+
ref,
|
|
103
|
+
...consumer
|
|
104
|
+
}: InputProps) {
|
|
105
|
+
const merged = useFieldProps(consumer);
|
|
106
|
+
|
|
107
|
+
const rootProps = {
|
|
108
|
+
...merged,
|
|
109
|
+
ref,
|
|
110
|
+
"data-disabled": merged.disabled ? "" : undefined,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
if (asChild) {
|
|
114
|
+
return <Slot {...rootProps}>{children}</Slot>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return <input type={type} {...rootProps} />;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Input.displayName = "Input";
|