@commercetools/nimbus-mcp 0.1.0 → 2.10.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 +63 -14
- package/data/docs/route-manifest.json +10913 -0
- package/data/docs/routes/components-accessibility-visually-hidden.json +388 -0
- package/data/docs/routes/components-accessibility.json +34 -0
- package/data/docs/routes/components-buttons-button.json +715 -0
- package/data/docs/routes/components-buttons-icon-button.json +852 -0
- package/data/docs/routes/components-buttons-icon-toggle-button.json +594 -0
- package/data/docs/routes/components-buttons-split-button.json +670 -0
- package/data/docs/routes/components-buttons-toggle-button-group.json +722 -0
- package/data/docs/routes/components-buttons-toggle-button.json +689 -0
- package/data/docs/routes/components-buttons.json +36 -0
- package/data/docs/routes/components-data-display-badge.json +555 -0
- package/data/docs/routes/components-data-display-card.json +338 -0
- package/data/docs/routes/components-data-display-data-table.json +855 -0
- package/data/docs/routes/components-data-display-draggable-list.json +596 -0
- package/data/docs/routes/components-data-display-table.json +472 -0
- package/data/docs/routes/components-data-display-tag-group.json +535 -0
- package/data/docs/routes/components-data-display.json +34 -0
- package/data/docs/routes/components-feedback-alert.json +696 -0
- package/data/docs/routes/components-feedback-dialog.json +682 -0
- package/data/docs/routes/components-feedback-drawer.json +600 -0
- package/data/docs/routes/components-feedback-loading-spinner.json +415 -0
- package/data/docs/routes/components-feedback-progress-bar.json +661 -0
- package/data/docs/routes/components-feedback-toast.json +1040 -0
- package/data/docs/routes/components-feedback-tooltip.json +510 -0
- package/data/docs/routes/components-feedback.json +34 -0
- package/data/docs/routes/components-forms-field-errors.json +557 -0
- package/data/docs/routes/components-forms-form-field.json +848 -0
- package/data/docs/routes/components-forms-group.json +427 -0
- package/data/docs/routes/components-forms-localized-field.json +770 -0
- package/data/docs/routes/components-forms.json +37 -0
- package/data/docs/routes/components-inputs-calendar.json +611 -0
- package/data/docs/routes/components-inputs-checkbox.json +774 -0
- package/data/docs/routes/components-inputs-combo-box.json +761 -0
- package/data/docs/routes/components-inputs-date-input.json +628 -0
- package/data/docs/routes/components-inputs-date-picker.json +709 -0
- package/data/docs/routes/components-inputs-date-range-picker.json +599 -0
- package/data/docs/routes/components-inputs-money-input.json +721 -0
- package/data/docs/routes/components-inputs-multiline-text-input.json +611 -0
- package/data/docs/routes/components-inputs-number-input.json +647 -0
- package/data/docs/routes/components-inputs-password-input.json +576 -0
- package/data/docs/routes/components-inputs-radio-input.json +583 -0
- package/data/docs/routes/components-inputs-range-calendar.json +607 -0
- package/data/docs/routes/components-inputs-rich-text-input.json +599 -0
- package/data/docs/routes/components-inputs-scoped-search-input.json +570 -0
- package/data/docs/routes/components-inputs-search-input.json +588 -0
- package/data/docs/routes/components-inputs-select-input.json +960 -0
- package/data/docs/routes/components-inputs-switch.json +720 -0
- package/data/docs/routes/components-inputs-text-input.json +566 -0
- package/data/docs/routes/components-inputs-time-input.json +775 -0
- package/data/docs/routes/components-inputs.json +34 -0
- package/data/docs/routes/components-layout-box.json +501 -0
- package/data/docs/routes/components-layout-defaultpage.json +748 -0
- package/data/docs/routes/components-layout-flex.json +587 -0
- package/data/docs/routes/components-layout-grid.json +393 -0
- package/data/docs/routes/components-layout-modalpage.json +716 -0
- package/data/docs/routes/components-layout-pagecontent.json +673 -0
- package/data/docs/routes/components-layout-separator.json +461 -0
- package/data/docs/routes/components-layout-simple-grid.json +519 -0
- package/data/docs/routes/components-layout-spacer.json +573 -0
- package/data/docs/routes/components-layout-stack.json +481 -0
- package/data/docs/routes/components-layout.json +34 -0
- package/data/docs/routes/components-media-avatar.json +427 -0
- package/data/docs/routes/components-media-icon.json +663 -0
- package/data/docs/routes/components-media-image.json +511 -0
- package/data/docs/routes/components-media-inline-svg.json +586 -0
- package/data/docs/routes/components-media.json +34 -0
- package/data/docs/routes/components-navigation-accordion.json +643 -0
- package/data/docs/routes/components-navigation-collapsible-motion.json +628 -0
- package/data/docs/routes/components-navigation-link.json +554 -0
- package/data/docs/routes/components-navigation-menu.json +546 -0
- package/data/docs/routes/components-navigation-pagination.json +502 -0
- package/data/docs/routes/components-navigation-steps.json +629 -0
- package/data/docs/routes/components-navigation-tabnav.json +546 -0
- package/data/docs/routes/components-navigation-tabs.json +635 -0
- package/data/docs/routes/components-navigation-toolbar.json +549 -0
- package/data/docs/routes/components-navigation.json +34 -0
- package/data/docs/routes/components-typography-code.json +39 -0
- package/data/docs/routes/components-typography-heading.json +402 -0
- package/data/docs/routes/components-typography-kbd.json +399 -0
- package/data/docs/routes/components-typography-list.json +593 -0
- package/data/docs/routes/components-typography-text.json +444 -0
- package/data/docs/routes/components-typography.json +34 -0
- package/data/docs/routes/components-utilities-nimbus-i18n-provider.json +295 -0
- package/data/docs/routes/components-utilities-nimbus-provider.json +663 -0
- package/data/docs/routes/components-utilities.json +34 -0
- package/data/docs/routes/components.json +33 -0
- package/data/docs/routes/home-contribute-adrs-adr0001-consumer-component-apis.json +314 -0
- package/data/docs/routes/home-contribute-adrs-adr0002-compound-component-extraction.json +160 -0
- package/data/docs/routes/home-contribute-adrs-adr0003-component-lifecycle-states.json +460 -0
- package/data/docs/routes/home-contribute-adrs.json +205 -0
- package/data/docs/routes/home-contribute-development-setup.json +213 -0
- package/data/docs/routes/home-contribute-stats.json +36 -0
- package/data/docs/routes/home-contribute.json +36 -0
- package/data/docs/routes/home-design-tokens-aspect-ratios.json +36 -0
- package/data/docs/routes/home-design-tokens-borders.json +35 -0
- package/data/docs/routes/home-design-tokens-colors.json +157 -0
- package/data/docs/routes/home-design-tokens-other-animations.json +119 -0
- package/data/docs/routes/home-design-tokens-other-blurs.json +36 -0
- package/data/docs/routes/home-design-tokens-other-breakpoints.json +61 -0
- package/data/docs/routes/home-design-tokens-other-cursors.json +36 -0
- package/data/docs/routes/home-design-tokens-other-z-indices.json +39 -0
- package/data/docs/routes/home-design-tokens-other.json +35 -0
- package/data/docs/routes/home-design-tokens-radii.json +59 -0
- package/data/docs/routes/home-design-tokens-shadows.json +57 -0
- package/data/docs/routes/home-design-tokens-sizes.json +137 -0
- package/data/docs/routes/home-design-tokens-spacing.json +36 -0
- package/data/docs/routes/home-design-tokens-typography.json +184 -0
- package/data/docs/routes/home-design-tokens.json +34 -0
- package/data/docs/routes/home-getting-started-core-concepts.json +301 -0
- package/data/docs/routes/home-getting-started-installation.json +621 -0
- package/data/docs/routes/home-getting-started-mcp-server-overview.json +139 -0
- package/data/docs/routes/home-getting-started-mcp-server-setup.json +316 -0
- package/data/docs/routes/home-getting-started-release-process.json +294 -0
- package/data/docs/routes/home-getting-started-testing-setup.json +296 -0
- package/data/docs/routes/home-playground-markdown.json +638 -0
- package/data/docs/routes/home-playground-toc.json +169 -0
- package/data/docs/routes/home-playground.json +34 -0
- package/data/docs/routes/home-style-props-background.json +236 -0
- package/data/docs/routes/home-style-props-border.json +310 -0
- package/data/docs/routes/home-style-props-display.json +120 -0
- package/data/docs/routes/home-style-props-effects.json +116 -0
- package/data/docs/routes/home-style-props-filters.json +396 -0
- package/data/docs/routes/home-style-props-flex-and-grid.json +496 -0
- package/data/docs/routes/home-style-props-interactivity.json +356 -0
- package/data/docs/routes/home-style-props-layout.json +422 -0
- package/data/docs/routes/home-style-props-list.json +116 -0
- package/data/docs/routes/home-style-props-sizing.json +244 -0
- package/data/docs/routes/home-style-props-spacing.json +228 -0
- package/data/docs/routes/home-style-props-svg.json +96 -0
- package/data/docs/routes/home-style-props-tables.json +116 -0
- package/data/docs/routes/home-style-props-transforms.json +216 -0
- package/data/docs/routes/home-style-props-transitions.json +216 -0
- package/data/docs/routes/home-style-props-typography.json +536 -0
- package/data/docs/routes/home-style-props.json +33 -0
- package/data/docs/routes/home.json +32 -0
- package/data/docs/routes/hooks-usecopytoclipboard.json +76 -0
- package/data/docs/routes/hooks-usehotkeys.json +117 -0
- package/data/docs/routes/hooks.json +33 -0
- package/data/docs/routes/icons.json +32 -0
- package/data/docs/routes/patterns-fields-date-range-picker-field.json +393 -0
- package/data/docs/routes/patterns-fields-money-input-field.json +415 -0
- package/data/docs/routes/patterns-fields-multiline-text-input-field.json +404 -0
- package/data/docs/routes/patterns-fields-number-input-field.json +470 -0
- package/data/docs/routes/patterns-fields-password-input-field.json +319 -0
- package/data/docs/routes/patterns-fields-search-input-field.json +382 -0
- package/data/docs/routes/patterns-fields-text-input-field.json +404 -0
- package/data/docs/routes/patterns-fields.json +78 -0
- package/data/docs/routes/patterns.json +34 -0
- package/data/docs/search-index.json +1 -0
- package/data/docs/types/Accordion.json +12 -0
- package/data/docs/types/AccordionContent.json +286 -0
- package/data/docs/types/AccordionHeader.json +891 -0
- package/data/docs/types/AccordionHeaderRightContent.json +27 -0
- package/data/docs/types/AccordionItem.json +242 -0
- package/data/docs/types/AccordionRoot.json +162 -0
- package/data/docs/types/Alert.json +12 -0
- package/data/docs/types/AlertActions.json +11 -0
- package/data/docs/types/AlertDescription.json +118 -0
- package/data/docs/types/AlertDismissButton.json +937 -0
- package/data/docs/types/AlertRoot.json +42 -0
- package/data/docs/types/AlertTitle.json +118 -0
- package/data/docs/types/Avatar.json +125 -0
- package/data/docs/types/Badge.json +64 -0
- package/data/docs/types/Body.json +67 -0
- package/data/docs/types/Box.json +85 -0
- package/data/docs/types/Button.json +1015 -0
- package/data/docs/types/Calendar.json +565 -0
- package/data/docs/types/Caption.json +67 -0
- package/data/docs/types/Card.json +12 -0
- package/data/docs/types/CardContent.json +27 -0
- package/data/docs/types/CardHeader.json +27 -0
- package/data/docs/types/CardRoot.json +106 -0
- package/data/docs/types/Cell.json +227 -0
- package/data/docs/types/Checkbox.json +897 -0
- package/data/docs/types/Code.json +112 -0
- package/data/docs/types/CollapsibleMotionContent.json +35 -0
- package/data/docs/types/CollapsibleMotionRoot.json +99 -0
- package/data/docs/types/CollapsibleMotionTrigger.json +71 -0
- package/data/docs/types/Column.json +101 -0
- package/data/docs/types/ColumnGroup.json +101 -0
- package/data/docs/types/ColumnHeader.json +193 -0
- package/data/docs/types/ComboBoxListBox.json +751 -0
- package/data/docs/types/ComboBoxOption.json +672 -0
- package/data/docs/types/ComboBoxPopover.json +786 -0
- package/data/docs/types/ComboBoxRoot.json +747 -0
- package/data/docs/types/ComboBoxSection.json +277 -0
- package/data/docs/types/ComboBoxTrigger.json +70 -0
- package/data/docs/types/Content.json +33 -0
- package/data/docs/types/DataTable.json +596 -0
- package/data/docs/types/DataTableBody.json +223 -0
- package/data/docs/types/DataTableFooter.json +27 -0
- package/data/docs/types/DataTableHeader.json +269 -0
- package/data/docs/types/DataTableManager.json +11 -0
- package/data/docs/types/DataTableRoot.json +590 -0
- package/data/docs/types/DataTableTable.json +271 -0
- package/data/docs/types/DateInput.json +792 -0
- package/data/docs/types/DatePicker.json +700 -0
- package/data/docs/types/DateRangePicker.json +936 -0
- package/data/docs/types/DateRangePickerField.json +1047 -0
- package/data/docs/types/DefaultPage.json +12 -0
- package/data/docs/types/DefaultPageActions.json +27 -0
- package/data/docs/types/DefaultPageBackLink.json +213 -0
- package/data/docs/types/DefaultPageContent.json +27 -0
- package/data/docs/types/DefaultPageFooter.json +27 -0
- package/data/docs/types/DefaultPageHeader.json +27 -0
- package/data/docs/types/DefaultPageRoot.json +106 -0
- package/data/docs/types/DefaultPageSubtitle.json +27 -0
- package/data/docs/types/DefaultPageTabNav.json +28 -0
- package/data/docs/types/DefaultPageTitle.json +27 -0
- package/data/docs/types/DialogBody.json +27 -0
- package/data/docs/types/DialogCloseTrigger.json +939 -0
- package/data/docs/types/DialogContent.json +27 -0
- package/data/docs/types/DialogFooter.json +27 -0
- package/data/docs/types/DialogHeader.json +27 -0
- package/data/docs/types/DialogRoot.json +138 -0
- package/data/docs/types/DialogTitle.json +27 -0
- package/data/docs/types/DialogTrigger.json +80 -0
- package/data/docs/types/DraggableList.json +12 -0
- package/data/docs/types/DraggableListField.json +894 -0
- package/data/docs/types/DraggableListItem.json +574 -0
- package/data/docs/types/DraggableListRoot.json +745 -0
- package/data/docs/types/Drawer.json +12 -0
- package/data/docs/types/DrawerBody.json +27 -0
- package/data/docs/types/DrawerCloseTrigger.json +939 -0
- package/data/docs/types/DrawerContent.json +27 -0
- package/data/docs/types/DrawerFooter.json +27 -0
- package/data/docs/types/DrawerHeader.json +27 -0
- package/data/docs/types/DrawerRoot.json +142 -0
- package/data/docs/types/DrawerTitle.json +27 -0
- package/data/docs/types/DrawerTrigger.json +80 -0
- package/data/docs/types/FieldErrors.getBuiltInMessage.json +11 -0
- package/data/docs/types/FieldErrors.getCustomMessage.json +9 -0
- package/data/docs/types/FieldErrors.json +109 -0
- package/data/docs/types/Flex.json +238 -0
- package/data/docs/types/Footer.json +67 -0
- package/data/docs/types/FormFieldDescription.json +11 -0
- package/data/docs/types/FormFieldError.json +11 -0
- package/data/docs/types/FormFieldInfoBox.json +27 -0
- package/data/docs/types/FormFieldInput.json +11 -0
- package/data/docs/types/FormFieldLabel.json +11 -0
- package/data/docs/types/FormFieldRoot.json +148 -0
- package/data/docs/types/Grid.json +253 -0
- package/data/docs/types/GridProps.json +11 -0
- package/data/docs/types/Group.json +143 -0
- package/data/docs/types/Header.json +67 -0
- package/data/docs/types/Heading.json +109 -0
- package/data/docs/types/Icon.json +112 -0
- package/data/docs/types/IconButton.json +1019 -0
- package/data/docs/types/IconToggleButton.json +787 -0
- package/data/docs/types/Image.json +373 -0
- package/data/docs/types/Indicator.json +67 -0
- package/data/docs/types/InlineSvg.json +98 -0
- package/data/docs/types/Item.json +67 -0
- package/data/docs/types/Kbd.json +118 -0
- package/data/docs/types/Link.json +380 -0
- package/data/docs/types/List.json +12 -0
- package/data/docs/types/ListIndicator.json +70 -0
- package/data/docs/types/ListItem.json +70 -0
- package/data/docs/types/ListRoot.json +124 -0
- package/data/docs/types/LoadingSpinner.json +87 -0
- package/data/docs/types/LocalizedField.json +460 -0
- package/data/docs/types/LocalizedStringFormatter.json +9 -0
- package/data/docs/types/MakeElementFocusable.json +196 -0
- package/data/docs/types/MenuContent.json +111 -0
- package/data/docs/types/MenuItem.json +671 -0
- package/data/docs/types/MenuRoot.json +670 -0
- package/data/docs/types/MenuSection.json +364 -0
- package/data/docs/types/MenuSubmenu.json +111 -0
- package/data/docs/types/MenuSubmenuTrigger.json +67 -0
- package/data/docs/types/MenuTrigger.json +906 -0
- package/data/docs/types/ModalPage.json +12 -0
- package/data/docs/types/ModalPageActions.json +27 -0
- package/data/docs/types/ModalPageContent.json +27 -0
- package/data/docs/types/ModalPageFooter.json +27 -0
- package/data/docs/types/ModalPageHeader.json +27 -0
- package/data/docs/types/ModalPageRoot.json +87 -0
- package/data/docs/types/ModalPageSubtitle.json +27 -0
- package/data/docs/types/ModalPageTabNav.json +28 -0
- package/data/docs/types/ModalPageTitle.json +27 -0
- package/data/docs/types/ModalPageTopBar.json +57 -0
- package/data/docs/types/MoneyInput.isEmpty.json +40 -0
- package/data/docs/types/MoneyInput.json +282 -0
- package/data/docs/types/MoneyInputField.json +379 -0
- package/data/docs/types/MoneyInputFieldProps.json +9 -0
- package/data/docs/types/MultilineTextInput.json +1194 -0
- package/data/docs/types/MultilineTextInputField.json +1269 -0
- package/data/docs/types/MultilineTextInputFieldProps.json +9 -0
- package/data/docs/types/NimbusI18nProvider.json +42 -0
- package/data/docs/types/NimbusI18nProviderProps.json +9 -0
- package/data/docs/types/NimbusProvider.json +270 -0
- package/data/docs/types/NumberInput.json +952 -0
- package/data/docs/types/NumberInputField.json +1004 -0
- package/data/docs/types/NumberInputFieldProps.json +9 -0
- package/data/docs/types/PageContent.json +11 -0
- package/data/docs/types/PageContentColumn.json +99 -0
- package/data/docs/types/PageContentRoot.json +114 -0
- package/data/docs/types/Pagination.json +159 -0
- package/data/docs/types/PasswordInput.json +1120 -0
- package/data/docs/types/PasswordInputField.json +1216 -0
- package/data/docs/types/PasswordInputFieldProps.json +9 -0
- package/data/docs/types/ProgressBar.json +280 -0
- package/data/docs/types/RadioInputOption.json +550 -0
- package/data/docs/types/RadioInputRoot.json +514 -0
- package/data/docs/types/RangeCalendar.json +618 -0
- package/data/docs/types/RichTextInput.json +134 -0
- package/data/docs/types/Root.json +122 -0
- package/data/docs/types/Row.json +67 -0
- package/data/docs/types/ScopedSearchInput.isEmpty.json +40 -0
- package/data/docs/types/ScopedSearchInput.json +253 -0
- package/data/docs/types/ScrollArea.json +82 -0
- package/data/docs/types/SearchInput.json +1165 -0
- package/data/docs/types/SearchInputField.json +1240 -0
- package/data/docs/types/Select.json +12 -0
- package/data/docs/types/SelectOption.json +572 -0
- package/data/docs/types/SelectOptionGroup.json +215 -0
- package/data/docs/types/SelectOptions.json +693 -0
- package/data/docs/types/SelectRoot.json +926 -0
- package/data/docs/types/Separator.json +65 -0
- package/data/docs/types/SimpleGrid.json +291 -0
- package/data/docs/types/Spacer.json +27 -0
- package/data/docs/types/SpacerProps.json +9 -0
- package/data/docs/types/SplitButton.json +203 -0
- package/data/docs/types/Stack.json +144 -0
- package/data/docs/types/Steps.json +12 -0
- package/data/docs/types/StepsChangeDetails.json +9 -0
- package/data/docs/types/StepsCompletedContent.json +28 -0
- package/data/docs/types/StepsCompletedContentProps.json +9 -0
- package/data/docs/types/StepsContent.json +43 -0
- package/data/docs/types/StepsContentProps.json +9 -0
- package/data/docs/types/StepsDescription.json +28 -0
- package/data/docs/types/StepsDescriptionProps.json +9 -0
- package/data/docs/types/StepsIndicator.json +28 -0
- package/data/docs/types/StepsIndicatorProps.json +9 -0
- package/data/docs/types/StepsItem.json +43 -0
- package/data/docs/types/StepsItemProps.json +9 -0
- package/data/docs/types/StepsList.json +28 -0
- package/data/docs/types/StepsListProps.json +9 -0
- package/data/docs/types/StepsNextTrigger.json +62 -0
- package/data/docs/types/StepsNextTriggerProps.json +9 -0
- package/data/docs/types/StepsNumber.json +28 -0
- package/data/docs/types/StepsNumberProps.json +9 -0
- package/data/docs/types/StepsPrevTrigger.json +62 -0
- package/data/docs/types/StepsPrevTriggerProps.json +9 -0
- package/data/docs/types/StepsRoot.json +183 -0
- package/data/docs/types/StepsRootProps.json +11 -0
- package/data/docs/types/StepsSeparator.json +28 -0
- package/data/docs/types/StepsSeparatorProps.json +9 -0
- package/data/docs/types/StepsStatus.json +57 -0
- package/data/docs/types/StepsStatusProps.json +9 -0
- package/data/docs/types/StepsTitle.json +28 -0
- package/data/docs/types/StepsTitleProps.json +9 -0
- package/data/docs/types/StepsTrigger.json +47 -0
- package/data/docs/types/StepsTriggerProps.json +9 -0
- package/data/docs/types/Switch.json +371 -0
- package/data/docs/types/TabListProps.json +9 -0
- package/data/docs/types/TabNav.json +12 -0
- package/data/docs/types/TabNavItem.json +300 -0
- package/data/docs/types/TabNavItemProps.json +9 -0
- package/data/docs/types/TabNavProps.json +9 -0
- package/data/docs/types/TabNavRoot.json +80 -0
- package/data/docs/types/TabPanelProps.json +9 -0
- package/data/docs/types/TabPanelsProps.json +9 -0
- package/data/docs/types/TabProps.json +9 -0
- package/data/docs/types/Table.json +9 -0
- package/data/docs/types/TableBody.json +67 -0
- package/data/docs/types/TableBodyProps.json +9 -0
- package/data/docs/types/TableCaption.json +67 -0
- package/data/docs/types/TableCaptionProps.json +9 -0
- package/data/docs/types/TableCell.json +227 -0
- package/data/docs/types/TableCellProps.json +9 -0
- package/data/docs/types/TableColumn.json +101 -0
- package/data/docs/types/TableColumnGroup.json +101 -0
- package/data/docs/types/TableColumnGroupProps.json +9 -0
- package/data/docs/types/TableColumnHeader.json +193 -0
- package/data/docs/types/TableColumnHeaderProps.json +9 -0
- package/data/docs/types/TableColumnProps.json +9 -0
- package/data/docs/types/TableFooter.json +67 -0
- package/data/docs/types/TableFooterProps.json +9 -0
- package/data/docs/types/TableHeader.json +67 -0
- package/data/docs/types/TableHeaderProps.json +9 -0
- package/data/docs/types/TableRoot.json +365 -0
- package/data/docs/types/TableRootProps.json +12 -0
- package/data/docs/types/TableRow.json +67 -0
- package/data/docs/types/TableRowProps.json +9 -0
- package/data/docs/types/TableScrollArea.json +82 -0
- package/data/docs/types/TableScrollAreaProps.json +9 -0
- package/data/docs/types/Tabs.json +12 -0
- package/data/docs/types/TabsList.json +110 -0
- package/data/docs/types/TabsPanel.json +112 -0
- package/data/docs/types/TabsPanels.json +108 -0
- package/data/docs/types/TabsRoot.json +211 -0
- package/data/docs/types/TabsTab.json +174 -0
- package/data/docs/types/TagGroup.json +12 -0
- package/data/docs/types/TagGroupRoot.json +306 -0
- package/data/docs/types/TagGroupTag.json +595 -0
- package/data/docs/types/TagGroupTagList.json +166 -0
- package/data/docs/types/Text.json +119 -0
- package/data/docs/types/TextInput.json +1156 -0
- package/data/docs/types/TextInputField.json +1263 -0
- package/data/docs/types/TimeInput.json +752 -0
- package/data/docs/types/ToastAction.json +9 -0
- package/data/docs/types/ToastManagerApi.json +9 -0
- package/data/docs/types/ToastOptions.json +9 -0
- package/data/docs/types/ToastOutlet.json +12 -0
- package/data/docs/types/ToastPlacement.json +9 -0
- package/data/docs/types/ToastPromiseOptions.json +9 -0
- package/data/docs/types/ToastType.json +9 -0
- package/data/docs/types/ToastVariant.json +9 -0
- package/data/docs/types/ToggleButton.json +789 -0
- package/data/docs/types/ToggleButtonGroup.json +9 -0
- package/data/docs/types/ToggleButtonGroupButton.json +331 -0
- package/data/docs/types/ToggleButtonGroupRoot.json +269 -0
- package/data/docs/types/Toolbar.json +176 -0
- package/data/docs/types/Tooltip.json +12 -0
- package/data/docs/types/TooltipContent.json +372 -0
- package/data/docs/types/TooltipRoot.json +179 -0
- package/data/docs/types/Trigger.json +69 -0
- package/data/docs/types/VisuallyHidden.json +93 -0
- package/data/docs/types/__object.json +12 -0
- package/data/docs/types/filters.json +11 -0
- package/data/docs/types/manifest.json +278 -0
- package/data/docs/types/toast.json +234 -0
- package/data/docs/types/useColorMode.json +13 -0
- package/data/docs/types/useColorModeValue.json +13 -0
- package/data/docs/types/useColorScheme.json +12 -0
- package/data/docs/types/useLocalizedStringFormatter.json +14 -0
- package/data/icons.json +21940 -0
- package/data/tokens.json +40061 -0
- package/dist/index.js +2516 -17
- package/package.json +25 -6
- package/dist/data-loader.d.ts +0 -102
- package/dist/data-loader.js +0 -104
- package/dist/index.d.ts +0 -13
- package/dist/server.d.ts +0 -9
- package/dist/server.js +0 -22
- package/dist/server.spec.d.ts +0 -1
- package/dist/server.spec.js +0 -69
- package/dist/tools/list-components.d.ts +0 -9
- package/dist/tools/list-components.js +0 -42
- package/dist/types.d.ts +0 -28
- package/dist/types.js +0 -4
- package/src/data-loader.ts +0 -226
- package/src/index.ts +0 -29
- package/src/server.spec.ts +0 -86
- package/src/server.ts +0 -28
- package/src/tools/list-components.ts +0 -49
- package/src/types.ts +0 -31
- package/tsconfig.json +0 -14
- package/vitest.config.ts +0 -9
|
@@ -0,0 +1,775 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"id": "Components-TimeInput",
|
|
4
|
+
"title": "Time input",
|
|
5
|
+
"exportName": "TimeInput",
|
|
6
|
+
"description": "A time input allows users to enter and select a specific time. It supports flexible input methods while ensuring accuracy and ease of use.",
|
|
7
|
+
"lifecycleState": "Stable",
|
|
8
|
+
"order": 999,
|
|
9
|
+
"repoPath": "packages/nimbus/src/components/time-input/time-input.mdx",
|
|
10
|
+
"menu": [
|
|
11
|
+
"Components",
|
|
12
|
+
"Inputs",
|
|
13
|
+
"Time input"
|
|
14
|
+
],
|
|
15
|
+
"route": "components/inputs/time-input",
|
|
16
|
+
"tags": [
|
|
17
|
+
"component",
|
|
18
|
+
"time",
|
|
19
|
+
"date"
|
|
20
|
+
],
|
|
21
|
+
"toc": [
|
|
22
|
+
{
|
|
23
|
+
"value": "Overview",
|
|
24
|
+
"href": "#overview",
|
|
25
|
+
"depth": 2,
|
|
26
|
+
"numbering": [
|
|
27
|
+
1,
|
|
28
|
+
1
|
|
29
|
+
],
|
|
30
|
+
"parent": "root"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"value": "Resources",
|
|
34
|
+
"href": "#resources",
|
|
35
|
+
"depth": 3,
|
|
36
|
+
"numbering": [
|
|
37
|
+
1,
|
|
38
|
+
1,
|
|
39
|
+
1
|
|
40
|
+
],
|
|
41
|
+
"parent": "root"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"value": "Variables",
|
|
45
|
+
"href": "#variables",
|
|
46
|
+
"depth": 2,
|
|
47
|
+
"numbering": [
|
|
48
|
+
1,
|
|
49
|
+
2
|
|
50
|
+
],
|
|
51
|
+
"parent": "root"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"value": "Visual options",
|
|
55
|
+
"href": "#visual-options",
|
|
56
|
+
"depth": 3,
|
|
57
|
+
"numbering": [
|
|
58
|
+
1,
|
|
59
|
+
2,
|
|
60
|
+
1
|
|
61
|
+
],
|
|
62
|
+
"parent": "root"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"value": "Size",
|
|
66
|
+
"href": "#size",
|
|
67
|
+
"depth": 4,
|
|
68
|
+
"numbering": [
|
|
69
|
+
1,
|
|
70
|
+
2,
|
|
71
|
+
1,
|
|
72
|
+
1
|
|
73
|
+
],
|
|
74
|
+
"parent": "root"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"value": "Solid appearance",
|
|
78
|
+
"href": "#solid-appearance",
|
|
79
|
+
"depth": 4,
|
|
80
|
+
"numbering": [
|
|
81
|
+
1,
|
|
82
|
+
2,
|
|
83
|
+
1,
|
|
84
|
+
2
|
|
85
|
+
],
|
|
86
|
+
"parent": "root"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"value": "Ghost appearance",
|
|
90
|
+
"href": "#ghost-appearance",
|
|
91
|
+
"depth": 4,
|
|
92
|
+
"numbering": [
|
|
93
|
+
1,
|
|
94
|
+
2,
|
|
95
|
+
1,
|
|
96
|
+
3
|
|
97
|
+
],
|
|
98
|
+
"parent": "root"
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
"layout": "app-frame",
|
|
102
|
+
"tabs": [
|
|
103
|
+
{
|
|
104
|
+
"key": "overview",
|
|
105
|
+
"title": "Overview",
|
|
106
|
+
"order": 0
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"key": "guidelines",
|
|
110
|
+
"title": "Guidelines",
|
|
111
|
+
"order": 2
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"key": "dev",
|
|
115
|
+
"title": "Implementation",
|
|
116
|
+
"order": 3
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"key": "a11y",
|
|
120
|
+
"title": "Accessibility",
|
|
121
|
+
"order": 4
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
"mdx": "\n## Overview\n\nA time input enables users to enter and select a specific time. It offers\nflexible input methods while maintaining accuracy and usability.\n\n### Resources\n\nDeep dive into implementation details and access the Nimbus design library.\n\n[React ARIA](https://react-spectrum.adobe.com/react-aria/TimeField.html)\n[Figma library](https://www.figma.com/design/AvtPX6g7OGGCRvNlatGOIY/NIMBUS-design-system?node-id=3047-46447&m=dev)\n\n## Variables\n\nGet familiar with the features.\n\n### Visual options\n\n#### Size\n\nMedium size is the default sizing used most commonly, with a small size for\ncompact use cases.\n\n```jsx live\nconst App = () => (\n <Grid templateColumns=\"repeat(2, 1fr)\" gap=\"400\">\n <TimeInput\n size=\"md\"\n hourCycle={24}\n defaultValue={new Time(20, 0)}\n />\n <TimeInput\n size=\"sm\"\n hourCycle={12}\n defaultValue={new Time(9, 30)}\n />\n </Grid>\n);\n```\n\n#### Solid appearance\n\nThis is the default styling, it provides a more prominent, filled style for\nstandard form usage where the input needs to stand out clearly.\n\n```jsx live\nconst App = () => (\n <TimeInput\n size=\"md\"\n hourCycle={12}\n defaultValue={new Time(15, 45)}\n width=\"50%\"\n />\n);\n```\n\n#### Ghost appearance\n\nOffers a minimalist style (e.g., no background fill, just a border) for\nintegration into uncluttered interfaces or specific contexts.\n\n```jsx live\nconst App = () => (\n <TimeInput\n size=\"md\"\n variant=\"ghost\"\n hourCycle={24}\n defaultValue={new Time(7, 0)}\n width=\"50%\"\n />\n);\n```\n",
|
|
126
|
+
"views": {
|
|
127
|
+
"overview": {
|
|
128
|
+
"mdx": "\n## Overview\n\nA time input enables users to enter and select a specific time. It offers\nflexible input methods while maintaining accuracy and usability.\n\n### Resources\n\nDeep dive into implementation details and access the Nimbus design library.\n\n[React ARIA](https://react-spectrum.adobe.com/react-aria/TimeField.html)\n[Figma library](https://www.figma.com/design/AvtPX6g7OGGCRvNlatGOIY/NIMBUS-design-system?node-id=3047-46447&m=dev)\n\n## Variables\n\nGet familiar with the features.\n\n### Visual options\n\n#### Size\n\nMedium size is the default sizing used most commonly, with a small size for\ncompact use cases.\n\n```jsx live\nconst App = () => (\n <Grid templateColumns=\"repeat(2, 1fr)\" gap=\"400\">\n <TimeInput\n size=\"md\"\n hourCycle={24}\n defaultValue={new Time(20, 0)}\n />\n <TimeInput\n size=\"sm\"\n hourCycle={12}\n defaultValue={new Time(9, 30)}\n />\n </Grid>\n);\n```\n\n#### Solid appearance\n\nThis is the default styling, it provides a more prominent, filled style for\nstandard form usage where the input needs to stand out clearly.\n\n```jsx live\nconst App = () => (\n <TimeInput\n size=\"md\"\n hourCycle={12}\n defaultValue={new Time(15, 45)}\n width=\"50%\"\n />\n);\n```\n\n#### Ghost appearance\n\nOffers a minimalist style (e.g., no background fill, just a border) for\nintegration into uncluttered interfaces or specific contexts.\n\n```jsx live\nconst App = () => (\n <TimeInput\n size=\"md\"\n variant=\"ghost\"\n hourCycle={24}\n defaultValue={new Time(7, 0)}\n width=\"50%\"\n />\n);\n```\n",
|
|
129
|
+
"toc": [
|
|
130
|
+
{
|
|
131
|
+
"value": "Overview",
|
|
132
|
+
"href": "#overview",
|
|
133
|
+
"depth": 2,
|
|
134
|
+
"numbering": [
|
|
135
|
+
1,
|
|
136
|
+
1
|
|
137
|
+
],
|
|
138
|
+
"parent": "root"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"value": "Resources",
|
|
142
|
+
"href": "#resources",
|
|
143
|
+
"depth": 3,
|
|
144
|
+
"numbering": [
|
|
145
|
+
1,
|
|
146
|
+
1,
|
|
147
|
+
1
|
|
148
|
+
],
|
|
149
|
+
"parent": "root"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"value": "Variables",
|
|
153
|
+
"href": "#variables",
|
|
154
|
+
"depth": 2,
|
|
155
|
+
"numbering": [
|
|
156
|
+
1,
|
|
157
|
+
2
|
|
158
|
+
],
|
|
159
|
+
"parent": "root"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"value": "Visual options",
|
|
163
|
+
"href": "#visual-options",
|
|
164
|
+
"depth": 3,
|
|
165
|
+
"numbering": [
|
|
166
|
+
1,
|
|
167
|
+
2,
|
|
168
|
+
1
|
|
169
|
+
],
|
|
170
|
+
"parent": "root"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"value": "Size",
|
|
174
|
+
"href": "#size",
|
|
175
|
+
"depth": 4,
|
|
176
|
+
"numbering": [
|
|
177
|
+
1,
|
|
178
|
+
2,
|
|
179
|
+
1,
|
|
180
|
+
1
|
|
181
|
+
],
|
|
182
|
+
"parent": "root"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"value": "Solid appearance",
|
|
186
|
+
"href": "#solid-appearance",
|
|
187
|
+
"depth": 4,
|
|
188
|
+
"numbering": [
|
|
189
|
+
1,
|
|
190
|
+
2,
|
|
191
|
+
1,
|
|
192
|
+
2
|
|
193
|
+
],
|
|
194
|
+
"parent": "root"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"value": "Ghost appearance",
|
|
198
|
+
"href": "#ghost-appearance",
|
|
199
|
+
"depth": 4,
|
|
200
|
+
"numbering": [
|
|
201
|
+
1,
|
|
202
|
+
2,
|
|
203
|
+
1,
|
|
204
|
+
3
|
|
205
|
+
],
|
|
206
|
+
"parent": "root"
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
},
|
|
210
|
+
"a11y": {
|
|
211
|
+
"mdx": "\n## Accessibility\n\nAccessibility ensures that digital content and functionality are usable by\neveryone, including people with disabilities, by addressing visual, auditory,\ncognitive, and physical limitations.\n\n```jsx live\nconst App = () => (\n <TimeInput\n size=\"md\"\n hourCycle={24}\n defaultValue={new Time(10, 10)}\n width=\"50%\"\n />\n);\n```\n\n### Accessibility standards\n\n- **Provide clear labeling:** Use a `<label>` element that is programmatically\n associated with the input field.\n- **Indicate required fields:** Visually mark required fields (e.g., with an\n asterisk) and programmatically denote them using `aria-required=\"true\"`.\n- **Set an appropriate input type:** Use `type=\"time\"` for native browser\n accessibility features and keyboard support.\n- **Include helpful instructions:** Offer clear instructions or formatting\n guidance for the expected time format.\n- **Enable keyboard navigation:** Ensure users can tab through the input and\n select times using only a keyboard.\n- **Support screen reader announcements:** Verify that screen readers announce\n the input's purpose, current value, and any validation errors.\n- **Manage focus:** Maintain logical focus order when users interact with the\n time input, especially with custom pickers.\n- **Provide accessible error messages:** Display validation errors clearly and\n associate them with the input using `aria-describedby`.\n- **Use sufficient color contrast:** Ensure all text and interactive elements\n have adequate color contrast against their background.\n- **Design for different input methods:** Consider touch targets for mobile\n users and ensure compatibility with assistive technologies.\n- **Test with assistive technologies:** Validate accessibility with screen\n readers and keyboard-only navigation.\n",
|
|
212
|
+
"toc": [
|
|
213
|
+
{
|
|
214
|
+
"value": "Accessibility",
|
|
215
|
+
"href": "#accessibility",
|
|
216
|
+
"depth": 2,
|
|
217
|
+
"numbering": [
|
|
218
|
+
1,
|
|
219
|
+
1
|
|
220
|
+
],
|
|
221
|
+
"parent": "root"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"value": "Accessibility standards",
|
|
225
|
+
"href": "#accessibility-standards",
|
|
226
|
+
"depth": 3,
|
|
227
|
+
"numbering": [
|
|
228
|
+
1,
|
|
229
|
+
1,
|
|
230
|
+
1
|
|
231
|
+
],
|
|
232
|
+
"parent": "root"
|
|
233
|
+
}
|
|
234
|
+
]
|
|
235
|
+
},
|
|
236
|
+
"dev": {
|
|
237
|
+
"mdx": "\n## Getting started\n\n### Import\n\n```tsx\nimport { TimeInput, type TimeInputProps } from '@commercetools/nimbus';\nimport { Time, type TimeValue } from '@internationalized/date';\n```\n\n### Basic usage\n\nThe simplest implementation uses uncontrolled mode:\n\n```jsx live-dev\nconst App = () => (\n <TimeInput aria-label=\"Enter a time\" />\n)\n```\n\n## Working with @internationalized/date\n\nThe TimeInput component relies on `@internationalized/date`'s time value types for representing times. This library provides timezone-aware time handling and locale-specific formatting.\n\n### TimeValue types\n\nThe component accepts and returns `TimeValue` objects, which can be one of several types:\n\n```tsx\nimport { Time, ZonedDateTime } from '@internationalized/date';\n\n// A simple time without date or timezone\nconst simpleTime = new Time(14, 30); // 2:30 PM\n\n// A time with timezone from a full date-time\nconst zonedTime = parseZonedDateTime('2024-12-04T14:30[America/New_York]');\n```\n\n### Creating Time values\n\nUse the `Time` constructor to create time values:\n\n```tsx\nimport { Time } from '@internationalized/date';\n\n// Create a time: 9:30 AM\nconst morningTime = new Time(9, 30);\n\n// Create a time with seconds: 3:45:15 PM\nconst afternoonTime = new Time(15, 45, 15);\n```\n\n### Converting time values\n\nUse `toString()` to convert Time objects for display or storage:\n\n```tsx\nconst time = new Time(14, 30);\ntime.toString(); // \"14:30:00\"\n\n// Access individual components\ntime.hour; // 14\ntime.minute; // 30\ntime.second; // 0\n```\n\n> [!TIP]\\\n> See [@internationalized/date documentation](https://react-spectrum.adobe.com/internationalized/date/) for complete API reference and advanced usage.\n\n## Usage examples\n\n### Size options\n\nThe `sm` and `md` size variants are available to match your interface density:\n\n```jsx live-dev\nconst App = () => (\n <Stack direction=\"column\" gap=\"400\">\n <TimeInput size=\"sm\" aria-label=\"Small time input\" defaultValue={new Time(9, 30)} />\n <TimeInput size=\"md\" aria-label=\"Medium time input\" defaultValue={new Time(15, 45)} />\n </Stack>\n)\n```\n\n### Visual variants\n\nChoose between `solid` (default) and `ghost` variants to match your design context:\n\n```jsx live-dev\nconst App = () => (\n <Stack direction=\"column\" gap=\"400\">\n <TimeInput variant=\"solid\" aria-label=\"Solid variant\" defaultValue={new Time(10, 0)} />\n <TimeInput variant=\"ghost\" aria-label=\"Ghost variant\" defaultValue={new Time(14, 30)} />\n </Stack>\n)\n```\n\n### Leading and trailing elements\n\nAdd icons or interactive elements before or after the time segments:\n\n```jsx live-dev\nconst App = () => (\n <Stack direction=\"column\" gap=\"400\">\n <TimeInput\n leadingElement={<Icon as={Icons.AccessTime} />}\n aria-label=\"Time with leading icon\"\n defaultValue={new Time(9, 0)}\n />\n <TimeInput\n trailingElement={<Icon as={Icons.CalendarMonth} />}\n aria-label=\"Time with trailing icon\"\n defaultValue={new Time(17, 0)}\n />\n <TimeInput\n leadingElement={<Icon as={Icons.AccessTime} />}\n trailingElement={<Icon as={Icons.CalendarMonth} />}\n aria-label=\"Time with both icons\"\n defaultValue={new Time(12, 30)}\n />\n </Stack>\n)\n```\n\n### Hour cycle\n\nControl whether the time displays in 12-hour or 24-hour format using the `hourCycle` prop:\n\n```jsx live-dev\nconst App = () => (\n <Stack direction=\"column\" gap=\"400\">\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">12-hour format</Text>\n <TimeInput\n hourCycle={12}\n aria-label=\"12-hour format\"\n defaultValue={new Time(14, 30)}\n />\n </Stack>\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">24-hour format</Text>\n <TimeInput\n hourCycle={24}\n aria-label=\"24-hour format\"\n defaultValue={new Time(14, 30)}\n />\n </Stack>\n </Stack>\n)\n```\n\n**Behavioral differences:**\n- `hourCycle={12}`: Displays time with AM/PM indicator (e.g., 2:30 PM)\n- `hourCycle={24}`: Displays time in 24-hour format (e.g., 14:30)\n\n### Granularity\n\nThe `granularity` prop controls which time segments are displayed and editable:\n\n```jsx live-dev\nconst App = () => (\n <Stack direction=\"column\" gap=\"400\">\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">Hour only</Text>\n <TimeInput\n granularity=\"hour\"\n aria-label=\"Hour granularity\"\n defaultValue={new Time(14, 30, 45)}\n />\n </Stack>\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">Hour and minute (default)</Text>\n <TimeInput\n granularity=\"minute\"\n aria-label=\"Minute granularity\"\n defaultValue={new Time(14, 30, 45)}\n />\n </Stack>\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">Hour, minute, and second</Text>\n <TimeInput\n granularity=\"second\"\n aria-label=\"Second granularity\"\n defaultValue={new Time(14, 30, 45)}\n />\n </Stack>\n </Stack>\n)\n```\n\n**Available granularities:**\n- `\"hour\"`: Only hour segment\n- `\"minute\"`: Hour and minute segments (default)\n- `\"second\"`: Hour, minute, and second segments\n\n### Hide timezone\n\nControl timezone visibility when using ZonedDateTime values:\n\n```jsx live-dev\nconst App = () => {\n const zonedTime = parseZonedDateTime('2024-12-04T14:30[America/New_York]');\n \n return (\n <Stack direction=\"column\" gap=\"400\">\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">With timezone</Text>\n <TimeInput\n aria-label=\"With timezone\"\n defaultValue={zonedTime}\n hideTimeZone={false}\n />\n </Stack>\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">Without timezone</Text>\n <TimeInput\n aria-label=\"Without timezone\"\n defaultValue={zonedTime}\n hideTimeZone={true}\n />\n </Stack>\n </Stack>\n );\n}\n```\n\n### Force leading zeros\n\nDisplay single-digit hours and minutes with leading zeros:\n\n```jsx live-dev\nconst App = () => (\n <Stack direction=\"column\" gap=\"400\">\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">Without leading zeros</Text>\n <TimeInput\n aria-label=\"Without leading zeros\"\n defaultValue={new Time(9, 5)}\n shouldForceLeadingZeros={false}\n />\n </Stack>\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">With leading zeros</Text>\n <TimeInput\n aria-label=\"With leading zeros\"\n defaultValue={new Time(9, 5)}\n shouldForceLeadingZeros={true}\n />\n </Stack>\n </Stack>\n)\n```\n\n### Placeholder value\n\nThe `placeholderValue` sets the default values when a user first interacts with empty segments:\n\n```jsx live-dev\nconst App = () => (\n <Stack direction=\"column\" gap=\"400\">\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">With placeholder (starts at 9:00 AM)</Text>\n <TimeInput\n aria-label=\"With placeholder value\"\n placeholderValue={new Time(9, 0)}\n />\n </Stack>\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">Without placeholder (default behavior)</Text>\n <TimeInput\n aria-label=\"Without placeholder value\"\n />\n </Stack>\n </Stack>\n)\n```\n\n### Min and max values\n\nRestrict selectable times using `minValue` and `maxValue`:\n\n```jsx live-dev\nconst App = () => {\n const [time, setTime] = useState<TimeValue | null>(new Time(10, 0));\n const minTime = new Time(9, 0);\n const maxTime = new Time(17, 0);\n \n const isInvalid = time\n ? (time.compare(minTime) < 0 || time.compare(maxTime) > 0)\n : false;\n \n return (\n <Stack direction=\"column\" gap=\"400\">\n <TimeInput\n aria-label=\"Business hours only\"\n value={time}\n onChange={setTime}\n minValue={minTime}\n maxValue={maxTime}\n isInvalid={isInvalid}\n />\n <Text fontSize=\"sm\" color={isInvalid ? \"critical.11\" : \"neutral.11\"}>\n {isInvalid \n ? \"Time must be between 9:00 AM and 5:00 PM\"\n : \"Valid time range: 9:00 AM - 5:00 PM\"}\n </Text>\n </Stack>\n );\n}\n```\n\n### Disabled state\n\nPrevent user interaction with the `isDisabled` prop:\n\n```jsx live-dev\nconst App = () => (\n <TimeInput\n isDisabled\n aria-label=\"Disabled time input\"\n defaultValue={new Time(10, 30)}\n />\n)\n```\n\n### Invalid state\n\nIndicate validation errors with the `isInvalid` prop:\n\n```jsx live-dev\nconst App = () => (\n <Stack direction=\"column\" gap=\"400\">\n <TimeInput\n isInvalid\n aria-label=\"Invalid time\"\n defaultValue={new Time(8, 0)}\n />\n <Text fontSize=\"sm\" color=\"critical.11\">\n Selected time is outside business hours\n </Text>\n </Stack>\n)\n```\n\n### Read-only state\n\nDisplay time values without allowing edits:\n\n```jsx live-dev\nconst App = () => (\n <TimeInput\n isReadOnly\n aria-label=\"Read-only time\"\n defaultValue={new Time(14, 30)}\n />\n)\n```\n\n### Required state\n\nMark the input as required for form validation:\n\n```jsx live-dev\nconst App = () => (\n <TimeInput\n isRequired\n aria-label=\"Required time input\"\n />\n)\n```\n\n### Uncontrolled mode\n\nFor simpler use cases, use uncontrolled mode with `defaultValue` and `onChange`:\n\n```jsx live-dev\nconst App = () => {\n const [displayValue, setDisplayValue] = useState<string>('No time selected');\n\n return (\n <Stack direction=\"column\" gap=\"400\">\n <TimeInput\n defaultValue={new Time(9, 30)}\n onChange={(value) => {\n if (value) {\n setDisplayValue(`Selected: ${value.toString()}`);\n } else {\n setDisplayValue('No time selected');\n }\n }}\n aria-label=\"Uncontrolled time input\"\n />\n <Text fontSize=\"sm\">{displayValue}</Text>\n </Stack>\n );\n}\n```\n\nUse uncontrolled mode when you need to capture the selected time without managing state yourself.\n\n### Controlled mode\n\nFor scenarios requiring programmatic control or coordination with other components, use controlled mode:\n\n```jsx live-dev\nconst App = () => {\n const [value, setValue] = useState<TimeInputProps[\"value\"]>(new Time(12, 0));\n\n return (\n <Stack direction=\"column\" gap=\"400\">\n <TimeInput\n value={value}\n onChange={setValue}\n aria-label=\"Controlled time input\"\n />\n <Stack direction=\"row\" gap=\"300\">\n <Button onPress={() => setValue(new Time(9, 0))}>\n Set to 9:00 AM\n </Button>\n <Button onPress={() => setValue(new Time(17, 0))}>\n Set to 5:00 PM\n </Button>\n <Button variant=\"secondary\" onPress={() => setValue(null)}>\n Clear\n </Button>\n </Stack>\n <Text fontSize=\"sm\">\n {value ? `Current time: ${value.toString()}` : 'No time selected'}\n </Text>\n </Stack>\n );\n}\n```\n\nUse controlled mode when you need to:\n- Synchronize the time with external state\n- Validate or transform time selections\n- Clear or programmatically set the time value\n\n### Different locales\n\nThe TimeInput automatically formats times according to the current locale:\n\n```jsx live-dev\nconst App = () => {\n const sampleTime = new Time(14, 30);\n \n return (\n <Stack direction=\"column\" gap=\"600\">\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">US (en-US)</Text>\n <NimbusI18nProvider locale=\"en-US\">\n <TimeInput\n aria-label=\"US locale\"\n defaultValue={sampleTime}\n />\n </NimbusI18nProvider>\n </Stack>\n <Stack direction=\"column\" gap=\"200\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">German (de-DE)</Text>\n <NimbusI18nProvider locale=\"de-DE\">\n <TimeInput\n aria-label=\"German locale\"\n defaultValue={sampleTime}\n />\n </NimbusI18nProvider>\n </Stack>\n </Stack>\n );\n}\n```\n\n### Form integration\n\nIntegrate TimeInput with FormField for complete form layouts:\n\n```jsx live-dev\nconst App = () => {\n const [time, setTime] = useState<TimeValue | null>(new Time(10, 30));\n const minTime = new Time(9, 0);\n const maxTime = new Time(17, 0);\n \n const isInvalid = time\n ? (time.compare(minTime) < 0 || time.compare(maxTime) > 0)\n : true;\n\n return (\n <FormField.Root isInvalid={isInvalid} isRequired>\n <FormField.Label>Appointment Time</FormField.Label>\n <FormField.Input>\n <TimeInput\n value={time}\n onChange={setTime}\n minValue={minTime}\n maxValue={maxTime}\n width=\"full\"\n />\n </FormField.Input>\n <FormField.Description>\n Select a time between 9:00 AM and 5:00 PM\n </FormField.Description>\n <FormField.Error>\n The selected time must be between 9:00 AM and 5:00 PM\n </FormField.Error>\n </FormField.Root>\n );\n}\n```\n\n## Component requirements\n\n### TimeValue requirements\n\nAll time values **must** use `@internationalized/date` types:\n- `Time` for simple time values without timezone\n- `ZonedDateTime` for times with timezone information\n- `TimeValue` as the union type for component props\n\n## Accessibility\n\nThe TimeInput handles most accessibility requirements internally. However, you must always associate an internationalized label with the component. Visual labels are preferable, and can be set by:\n\n- Using FormField with FormField.Label (recommended for forms)\n- Associating a `<label>` element with the TimeInput using `aria-labelledby`:\n\n```tsx\n<label id=\"time-label\">\n {msg.format(labelMessage)}\n</label>\n<TimeInput aria-labelledby=\"time-label\" />\n```\n\n- Associating a `<label>` element with the TimeInput using `htmlFor`:\n\n```tsx\n<label htmlFor=\"time-input-id\">\n {msg.format(labelMessage)}\n</label>\n<TimeInput id=\"time-input-id\" />\n```\n\nIf your design requires that the label should not be visible, the label should be set using the `aria-label` prop:\n\n```tsx\n<TimeInput aria-label={msg.format(labelMessage)} />\n```\n\nIf your use case requires tracking and analytics for this component, it is good practice to add a **persistent**, **unique** id to the component:\n\n```tsx\nconst PERSISTENT_ID = \"appointment-time-input\";\n\nexport const AppointmentForm = () => (\n <TimeInput id={PERSISTENT_ID} aria-label=\"Appointment time\" />\n);\n```\n\n#### Keyboard navigation\n\nThe component supports full keyboard interaction:\n- `Tab` / `Shift+Tab`: Move focus between segments and out of the component\n- `Arrow Up` / `Arrow Down`: Increment or decrement the focused segment\n- `Arrow Left` / `Arrow Right`: Move between time segments\n- `Number keys`: Directly type numeric values into segments\n- `A` / `P` (in 12-hour mode): Type \"A\" or \"P\" to set AM/PM\n\n## API reference\n\n<PropsTable id=\"TimeInput\" />\n\n## Common patterns\n\n### Business hours restriction\n\nLimit time selection to standard business hours:\n\n```jsx live-dev\nconst App = () => {\n const [time, setTime] = useState<TimeValue | null>(new Time(9, 0));\n const businessStart = new Time(9, 0);\n const businessEnd = new Time(17, 0);\n \n const isOutsideBusinessHours = time\n ? (time.compare(businessStart) < 0 || time.compare(businessEnd) > 0)\n : false;\n\n return (\n <Stack direction=\"column\" gap=\"400\">\n <TimeInput\n value={time}\n onChange={setTime}\n minValue={businessStart}\n maxValue={businessEnd}\n isInvalid={isOutsideBusinessHours}\n aria-label=\"Business hours\"\n />\n <Text fontSize=\"sm\" color=\"neutral.11\">\n Business hours: 9:00 AM - 5:00 PM\n </Text>\n {isOutsideBusinessHours && (\n <Text fontSize=\"sm\" color=\"critical.11\">\n ⚠ Selected time is outside business hours\n </Text>\n )}\n </Stack>\n );\n}\n```\n\n### Time range selector\n\nCreate start and end time inputs with validation:\n\n```jsx live-dev\nconst App = () => {\n const [startTime, setStartTime] = useState<TimeValue | null>(new Time(9, 0));\n const [endTime, setEndTime] = useState<TimeValue | null>(new Time(17, 0));\n \n const hasError = startTime && endTime && endTime.compare(startTime) <= 0;\n\n return (\n <Stack direction=\"column\" gap=\"400\">\n <Stack direction=\"row\" gap=\"300\" alignItems=\"end\">\n <Stack direction=\"column\" gap=\"200\" flex=\"1\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">Start Time</Text>\n <TimeInput\n value={startTime}\n onChange={setStartTime}\n isInvalid={hasError}\n aria-label=\"Start time\"\n />\n </Stack>\n <Text fontSize=\"sm\" color=\"neutral.11\">to</Text>\n <Stack direction=\"column\" gap=\"200\" flex=\"1\">\n <Text fontSize=\"sm\" fontWeight=\"semibold\">End Time</Text>\n <TimeInput\n value={endTime}\n onChange={setEndTime}\n minValue={startTime ?? undefined}\n isInvalid={hasError}\n aria-label=\"End time\"\n />\n </Stack>\n </Stack>\n {hasError && (\n <Text fontSize=\"sm\" color=\"critical.11\">\n End time must be after start time\n </Text>\n )}\n {!hasError && startTime && endTime && (\n <Text fontSize=\"sm\" color=\"neutral.11\">\n Duration: {endTime.hour - startTime.hour} hours\n </Text>\n )}\n </Stack>\n );\n}\n```\n\n## Testing your implementation\n\nThese examples demonstrate how to test your implementation when using TimeInput within your application. As the component's internal functionality is already tested by Nimbus, these patterns help you verify your integration and application-specific logic.\n\n### Basic Rendering Tests\n\nVerify the TimeInput component renders with expected elements and structure\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport { TimeInput, NimbusProvider } from \"@commercetools/nimbus\";\nimport { Time } from \"@internationalized/date\";\n\ndescribe(\"TimeInput - Basic rendering\", () => {\n it(\"renders time input with accessible structure\", () => {\n render(\n <NimbusProvider>\n <TimeInput aria-label=\"Enter a time\" />\n </NimbusProvider>\n );\n\n const timeInput = screen.getByRole(\"group\", { name: /Enter a time/i });\n expect(timeInput).toBeInTheDocument();\n });\n\n it(\"renders with default value\", () => {\n render(\n <NimbusProvider>\n <TimeInput aria-label=\"Time input\" defaultValue={new Time(14, 30)} />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n expect(segments.length).toBe(3);\n });\n\n it(\"renders with different sizes\", () => {\n const { rerender } = render(\n <NimbusProvider>\n <TimeInput aria-label=\"Small time\" size=\"sm\" />\n </NimbusProvider>\n );\n\n expect(screen.getByRole(\"group\")).toBeInTheDocument();\n\n rerender(\n <NimbusProvider>\n <TimeInput aria-label=\"Medium time\" size=\"md\" />\n </NimbusProvider>\n );\n\n expect(screen.getByRole(\"group\")).toBeInTheDocument();\n });\n\n it(\"renders with different variants\", () => {\n const { rerender } = render(\n <NimbusProvider>\n <TimeInput aria-label=\"Solid variant\" variant=\"solid\" />\n </NimbusProvider>\n );\n\n expect(screen.getByRole(\"group\")).toBeInTheDocument();\n\n rerender(\n <NimbusProvider>\n <TimeInput aria-label=\"Ghost variant\" variant=\"ghost\" />\n </NimbusProvider>\n );\n\n expect(screen.getByRole(\"group\")).toBeInTheDocument();\n });\n});\n```\n\n### Interaction Tests\n\nTest user interactions with time segments using keyboard\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport { TimeInput, NimbusProvider } from \"@commercetools/nimbus\";\nimport { Time } from \"@internationalized/date\";\n\ndescribe(\"TimeInput - Interactions\", () => {\n it(\"can focus and navigate between segments\", async () => {\n const user = userEvent.setup();\n render(\n <NimbusProvider>\n <TimeInput aria-label=\"Time input\" />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n const firstSegment = segments[0];\n\n // Tab to focus first segment\n await user.tab();\n expect(firstSegment).toHaveFocus();\n\n // Navigate to next segment\n await user.keyboard(\"{ArrowRight}\");\n expect(segments[1]).toHaveFocus();\n });\n\n it(\"increments and decrements segment values with arrow keys\", async () => {\n const user = userEvent.setup();\n render(\n <NimbusProvider>\n <TimeInput aria-label=\"Time input\" defaultValue={new Time(10, 30)} />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n const hourSegment = segments[0];\n\n await user.tab();\n expect(hourSegment).toHaveFocus();\n\n // Increment hour\n await user.keyboard(\"{ArrowUp}\");\n expect(hourSegment.textContent).toBe(\"11\");\n\n // Decrement hour\n await user.keyboard(\"{ArrowDown}\");\n expect(hourSegment.textContent).toBe(\"10\");\n });\n\n it(\"calls onChange when time value changes\", async () => {\n const user = userEvent.setup();\n const handleChange = vi.fn();\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Time input\"\n defaultValue={new Time(10, 0)}\n onChange={handleChange}\n />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n\n await user.tab();\n expect(segments[0]).toHaveFocus();\n\n await user.keyboard(\"{ArrowUp}\");\n\n expect(handleChange).toHaveBeenCalled();\n const newTime = handleChange.mock.calls[0][0];\n expect(newTime).toHaveProperty(\"hour\");\n expect(newTime).toHaveProperty(\"minute\");\n });\n\n it(\"allows direct numeric input\", async () => {\n const user = userEvent.setup();\n render(\n <NimbusProvider>\n <TimeInput aria-label=\"Time input\" />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n const hourSegment = segments[0];\n\n await user.tab();\n expect(hourSegment).toHaveFocus();\n\n // Type a number\n await user.keyboard(\"09\");\n expect(hourSegment.textContent).toBe(\"9\");\n });\n});\n```\n\n### Controlled Mode Tests\n\nTest controlled component behavior with value prop\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport { TimeInput, NimbusProvider } from \"@commercetools/nimbus\";\nimport { Time } from \"@internationalized/date\";\n\ndescribe(\"TimeInput - Controlled mode\", () => {\n it(\"respects controlled value prop\", () => {\n const controlledTime = new Time(14, 30);\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Controlled time\"\n value={controlledTime}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n expect(segments[0].textContent).toBe(\"2\");\n expect(segments[1].textContent).toBe(\"30\");\n });\n\n it(\"calls onChange with new Time value when user interacts\", async () => {\n const user = userEvent.setup();\n const handleChange = vi.fn();\n const controlledTime = new Time(10, 0);\n\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Controlled time\"\n value={controlledTime}\n onChange={handleChange}\n />\n </NimbusProvider>\n );\n\n await user.tab();\n await user.keyboard(\"{ArrowUp}\");\n\n expect(handleChange).toHaveBeenCalled();\n const newValue = handleChange.mock.calls[0][0] as Time;\n expect(newValue.hour).toBe(11);\n });\n\n it(\"updates display when controlled value changes\", () => {\n const { rerender } = render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Controlled time\"\n value={new Time(10, 0)}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n let segments = screen.getAllByRole(\"spinbutton\");\n expect(segments[0].textContent).toBe(\"10\");\n\n rerender(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Controlled time\"\n value={new Time(15, 30)}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n segments = screen.getAllByRole(\"spinbutton\");\n expect(segments[0].textContent).toBe(\"3\");\n expect(segments[1].textContent).toBe(\"30\");\n });\n});\n```\n\n### Uncontrolled Mode Tests\n\nTest uncontrolled component behavior with defaultValue prop\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport { TimeInput, NimbusProvider } from \"@commercetools/nimbus\";\nimport { Time } from \"@internationalized/date\";\n\ndescribe(\"TimeInput - Uncontrolled mode\", () => {\n it(\"uses defaultValue for initial display\", () => {\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Uncontrolled time\"\n defaultValue={new Time(9, 30)}\n />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n expect(segments[0].textContent).toBe(\"9\");\n expect(segments[1].textContent).toBe(\"30\");\n });\n\n it(\"manages internal state after user interaction\", async () => {\n const user = userEvent.setup();\n const handleChange = vi.fn();\n\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Uncontrolled time\"\n defaultValue={new Time(10, 0)}\n onChange={handleChange}\n />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n\n await user.tab();\n await user.keyboard(\"{ArrowUp}\");\n\n expect(segments[0].textContent).toBe(\"11\");\n expect(handleChange).toHaveBeenCalled();\n const newTime = handleChange.mock.calls[0][0];\n expect(newTime).toHaveProperty(\"hour\");\n expect(newTime).toHaveProperty(\"minute\");\n });\n});\n```\n\n### Hour Cycle Tests\n\nTest 12-hour and 24-hour format behavior\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport { TimeInput, NimbusProvider } from \"@commercetools/nimbus\";\nimport { Time } from \"@internationalized/date\";\n\ndescribe(\"TimeInput - Hour cycle\", () => {\n it(\"displays time in 12-hour format with AM/PM\", () => {\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"12-hour format\"\n hourCycle={12}\n defaultValue={new Time(14, 30)}\n />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n expect(segments[0].textContent).toBe(\"2\"); // 2 PM\n\n // Last segment should be AM/PM\n const lastSegment = segments[segments.length - 1];\n expect(lastSegment.textContent).toBe(\"PM\");\n });\n\n it(\"displays time in 24-hour format without AM/PM\", () => {\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"24-hour format\"\n hourCycle={24}\n defaultValue={new Time(14, 30)}\n />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n expect(segments[0].textContent).toBe(\"14\");\n\n // Should have hour and minute segments only (no AM/PM)\n expect(segments.length).toBe(2);\n });\n}); /**\n```\n\n### Granularity Tests\n\nTest different time granularity levels (hour, minute, second)\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport { TimeInput, NimbusProvider } from \"@commercetools/nimbus\";\nimport { Time } from \"@internationalized/date\";\n\ndescribe(\"TimeInput - Granularity\", () => {\n it(\"shows only hour segment when granularity is hour\", () => {\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Hour granularity\"\n granularity=\"hour\"\n defaultValue={new Time(14, 30, 45)}\n />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n // Should have hour and AM/PM segments only (in 12-hour format)\n expect(segments.length).toBeLessThanOrEqual(2);\n });\n\n it(\"shows hour and minute segments when granularity is minute\", () => {\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Minute granularity\"\n granularity=\"minute\"\n defaultValue={new Time(14, 30, 45)}\n />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n expect(segments.length).toBeGreaterThanOrEqual(2);\n });\n\n it(\"shows hour, minute, and second segments when granularity is second\", () => {\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Second granularity\"\n granularity=\"second\"\n defaultValue={new Time(14, 30, 45)}\n />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n expect(segments.length).toBeGreaterThanOrEqual(3);\n });\n});\n```\n\n### Validation Tests\n\nTest min/max value validation behavior\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport { TimeInput, NimbusProvider } from \"@commercetools/nimbus\";\nimport { Time } from \"@internationalized/date\";\n\ndescribe(\"TimeInput - Validation\", () => {\n it(\"accepts minValue prop\", () => {\n const minTime = new Time(9, 0);\n\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Time with min\"\n minValue={minTime}\n defaultValue={new Time(10, 0)}\n />\n </NimbusProvider>\n );\n\n const timeInput = screen.getByRole(\"group\");\n expect(timeInput).toBeInTheDocument();\n });\n\n it(\"accepts maxValue prop\", () => {\n const maxTime = new Time(17, 0);\n\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Time with max\"\n maxValue={maxTime}\n defaultValue={new Time(16, 0)}\n />\n </NimbusProvider>\n );\n\n const timeInput = screen.getByRole(\"group\");\n expect(timeInput).toBeInTheDocument();\n });\n}); /**\n```\n\n### State Tests\n\nTest different component states (disabled, invalid, readonly, required)\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport { TimeInput, NimbusProvider } from \"@commercetools/nimbus\";\nimport { Time } from \"@internationalized/date\";\n\ndescribe(\"TimeInput - States\", () => {\n it(\"renders disabled state\", () => {\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Disabled time\"\n isDisabled\n defaultValue={new Time(10, 30)}\n />\n </NimbusProvider>\n );\n\n const timeInput = screen.getByRole(\"group\");\n expect(timeInput).toHaveAttribute(\"aria-disabled\", \"true\");\n\n const segments = screen.getAllByRole(\"spinbutton\");\n segments.forEach((segment) => {\n expect(segment).toHaveAttribute(\"aria-disabled\", \"true\");\n });\n });\n\n it(\"prevents interaction when disabled\", async () => {\n const user = userEvent.setup();\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Disabled time\"\n isDisabled\n defaultValue={new Time(10, 30)}\n />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n const hourSegment = segments[0];\n\n await user.tab();\n\n // Disabled segments should not receive focus\n expect(hourSegment).not.toHaveFocus();\n });\n\n it(\"renders invalid state\", () => {\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Invalid time\"\n isInvalid\n defaultValue={new Time(10, 30)}\n />\n </NimbusProvider>\n );\n\n const timeInput = screen.getByRole(\"group\");\n expect(timeInput).toHaveAttribute(\"data-invalid\", \"true\");\n });\n\n it(\"renders readonly state\", () => {\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Readonly time\"\n isReadOnly\n defaultValue={new Time(10, 30)}\n />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n segments.forEach((segment) => {\n expect(segment).toHaveAttribute(\"aria-readonly\", \"true\");\n });\n });\n\n it(\"prevents editing when readonly\", async () => {\n const user = userEvent.setup();\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Readonly time\"\n isReadOnly\n defaultValue={new Time(10, 30)}\n />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n const hourSegment = segments[0];\n const initialValue = hourSegment.textContent;\n\n await user.tab();\n expect(hourSegment).toHaveFocus();\n\n // Try to change value\n await user.keyboard(\"{ArrowUp}\");\n\n // Value should not change\n expect(hourSegment.textContent).toBe(initialValue);\n });\n\n it(\"accepts isRequired prop\", () => {\n render(\n <NimbusProvider>\n <TimeInput aria-label=\"Required time\" isRequired />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n segments.forEach((segment) => {\n expect(segment).toHaveAttribute(\"aria-required\", \"true\");\n });\n });\n});\n```\n\n### Accessibility Tests\n\nVerify ARIA attributes and keyboard navigation\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport { TimeInput, NimbusProvider } from \"@commercetools/nimbus\";\nimport { Time } from \"@internationalized/date\";\n\ndescribe(\"TimeInput - Accessibility\", () => {\n it(\"has proper ARIA role\", () => {\n render(\n <NimbusProvider>\n <TimeInput aria-label=\"Time input\" />\n </NimbusProvider>\n );\n\n const timeInput = screen.getByRole(\"group\", { name: /Time input/i });\n expect(timeInput).toBeInTheDocument();\n });\n\n it(\"supports aria-label\", () => {\n render(\n <NimbusProvider>\n <TimeInput aria-label=\"Appointment time\" />\n </NimbusProvider>\n );\n\n expect(\n screen.getByRole(\"group\", { name: /Appointment time/i })\n ).toBeInTheDocument();\n });\n\n it(\"supports aria-labelledby\", () => {\n render(\n <NimbusProvider>\n <div>\n <span id=\"time-label\">Select time</span>\n <TimeInput aria-labelledby=\"time-label\" />\n </div>\n </NimbusProvider>\n );\n\n expect(\n screen.getByRole(\"group\", { name: /Select time/i })\n ).toBeInTheDocument();\n });\n\n it(\"time segments have spinbutton role\", () => {\n render(\n <NimbusProvider>\n <TimeInput aria-label=\"Time input\" defaultValue={new Time(10, 30)} />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n expect(segments.length).toBeGreaterThan(0);\n });\n\n it(\"supports keyboard navigation between segments\", async () => {\n const user = userEvent.setup();\n render(\n <NimbusProvider>\n <TimeInput aria-label=\"Time input\" />\n </NimbusProvider>\n );\n\n const segments = screen.getAllByRole(\"spinbutton\");\n\n await user.tab();\n expect(segments[0]).toHaveFocus();\n\n await user.keyboard(\"{ArrowRight}\");\n expect(segments[1]).toHaveFocus();\n\n await user.keyboard(\"{ArrowLeft}\");\n expect(segments[0]).toHaveFocus();\n });\n});\n```\n\n### Form Integration Tests\n\nTest TimeInput integration with FormField component\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport { TimeInput, NimbusProvider } from \"@commercetools/nimbus\";\nimport { Time } from \"@internationalized/date\";\n\ndescribe(\"TimeInput - Form integration\", () => {\n it(\"integrates with FormField\", () => {\n render(\n <NimbusProvider>\n <div>\n <label htmlFor=\"time-field\">Meeting time</label>\n <TimeInput\n aria-label=\"Meeting time\"\n id=\"time-field\"\n defaultValue={new Time(10, 0)}\n />\n </div>\n </NimbusProvider>\n );\n\n const label = screen.getByText(\"Meeting time\");\n expect(label).toBeInTheDocument();\n\n const timeInput = screen.getByRole(\"group\");\n expect(timeInput).toBeInTheDocument();\n });\n\n it(\"displays validation errors in FormField context\", () => {\n render(\n <NimbusProvider>\n <TimeInput\n aria-label=\"Invalid time\"\n isInvalid\n defaultValue={new Time(10, 0)}\n />\n </NimbusProvider>\n );\n\n const timeInput = screen.getByRole(\"group\");\n expect(timeInput).toHaveAttribute(\"data-invalid\", \"true\");\n });\n\n it(\"calls onBlur when focus leaves the component\", async () => {\n const user = userEvent.setup();\n const handleBlur = vi.fn();\n\n render(\n <NimbusProvider>\n <TimeInput aria-label=\"Time input\" onBlur={handleBlur} />\n </NimbusProvider>\n );\n\n await user.tab();\n await user.tab();\n await user.tab();\n await user.tab(); // Tab through all segments and out\n\n expect(handleBlur).toHaveBeenCalled();\n });\n});\n```\n\n\n## Resources\n\n- [Storybook](https://nimbus-storybook.vercel.app/?path=/docs/components-timeinput--docs)\n- [React Aria TimeField](https://react-spectrum.adobe.com/react-aria/TimeField.html)\n- [@internationalized/date documentation](https://react-spectrum.adobe.com/internationalized/date/)\n",
|
|
238
|
+
"toc": [
|
|
239
|
+
{
|
|
240
|
+
"value": "Getting started",
|
|
241
|
+
"href": "#getting-started",
|
|
242
|
+
"depth": 2,
|
|
243
|
+
"numbering": [
|
|
244
|
+
1,
|
|
245
|
+
1
|
|
246
|
+
],
|
|
247
|
+
"parent": "root"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"value": "Import",
|
|
251
|
+
"href": "#import",
|
|
252
|
+
"depth": 3,
|
|
253
|
+
"numbering": [
|
|
254
|
+
1,
|
|
255
|
+
1,
|
|
256
|
+
1
|
|
257
|
+
],
|
|
258
|
+
"parent": "root"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"value": "Basic usage",
|
|
262
|
+
"href": "#basic-usage",
|
|
263
|
+
"depth": 3,
|
|
264
|
+
"numbering": [
|
|
265
|
+
1,
|
|
266
|
+
1,
|
|
267
|
+
2
|
|
268
|
+
],
|
|
269
|
+
"parent": "root"
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
"value": "Working with @internationalized/date",
|
|
273
|
+
"href": "#working-with-internationalizeddate",
|
|
274
|
+
"depth": 2,
|
|
275
|
+
"numbering": [
|
|
276
|
+
1,
|
|
277
|
+
2
|
|
278
|
+
],
|
|
279
|
+
"parent": "root"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"value": "TimeValue types",
|
|
283
|
+
"href": "#timevalue-types",
|
|
284
|
+
"depth": 3,
|
|
285
|
+
"numbering": [
|
|
286
|
+
1,
|
|
287
|
+
2,
|
|
288
|
+
1
|
|
289
|
+
],
|
|
290
|
+
"parent": "root"
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"value": "Creating Time values",
|
|
294
|
+
"href": "#creating-time-values",
|
|
295
|
+
"depth": 3,
|
|
296
|
+
"numbering": [
|
|
297
|
+
1,
|
|
298
|
+
2,
|
|
299
|
+
2
|
|
300
|
+
],
|
|
301
|
+
"parent": "root"
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
"value": "Converting time values",
|
|
305
|
+
"href": "#converting-time-values",
|
|
306
|
+
"depth": 3,
|
|
307
|
+
"numbering": [
|
|
308
|
+
1,
|
|
309
|
+
2,
|
|
310
|
+
3
|
|
311
|
+
],
|
|
312
|
+
"parent": "root"
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
"value": "Usage examples",
|
|
316
|
+
"href": "#usage-examples",
|
|
317
|
+
"depth": 2,
|
|
318
|
+
"numbering": [
|
|
319
|
+
1,
|
|
320
|
+
3
|
|
321
|
+
],
|
|
322
|
+
"parent": "root"
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
"value": "Size options",
|
|
326
|
+
"href": "#size-options",
|
|
327
|
+
"depth": 3,
|
|
328
|
+
"numbering": [
|
|
329
|
+
1,
|
|
330
|
+
3,
|
|
331
|
+
1
|
|
332
|
+
],
|
|
333
|
+
"parent": "root"
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
"value": "Visual variants",
|
|
337
|
+
"href": "#visual-variants",
|
|
338
|
+
"depth": 3,
|
|
339
|
+
"numbering": [
|
|
340
|
+
1,
|
|
341
|
+
3,
|
|
342
|
+
2
|
|
343
|
+
],
|
|
344
|
+
"parent": "root"
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
"value": "Leading and trailing elements",
|
|
348
|
+
"href": "#leading-and-trailing-elements",
|
|
349
|
+
"depth": 3,
|
|
350
|
+
"numbering": [
|
|
351
|
+
1,
|
|
352
|
+
3,
|
|
353
|
+
3
|
|
354
|
+
],
|
|
355
|
+
"parent": "root"
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
"value": "Hour cycle",
|
|
359
|
+
"href": "#hour-cycle",
|
|
360
|
+
"depth": 3,
|
|
361
|
+
"numbering": [
|
|
362
|
+
1,
|
|
363
|
+
3,
|
|
364
|
+
4
|
|
365
|
+
],
|
|
366
|
+
"parent": "root"
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
"value": "Granularity",
|
|
370
|
+
"href": "#granularity",
|
|
371
|
+
"depth": 3,
|
|
372
|
+
"numbering": [
|
|
373
|
+
1,
|
|
374
|
+
3,
|
|
375
|
+
5
|
|
376
|
+
],
|
|
377
|
+
"parent": "root"
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"value": "Hide timezone",
|
|
381
|
+
"href": "#hide-timezone",
|
|
382
|
+
"depth": 3,
|
|
383
|
+
"numbering": [
|
|
384
|
+
1,
|
|
385
|
+
3,
|
|
386
|
+
6
|
|
387
|
+
],
|
|
388
|
+
"parent": "root"
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
"value": "Force leading zeros",
|
|
392
|
+
"href": "#force-leading-zeros",
|
|
393
|
+
"depth": 3,
|
|
394
|
+
"numbering": [
|
|
395
|
+
1,
|
|
396
|
+
3,
|
|
397
|
+
7
|
|
398
|
+
],
|
|
399
|
+
"parent": "root"
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
"value": "Placeholder value",
|
|
403
|
+
"href": "#placeholder-value",
|
|
404
|
+
"depth": 3,
|
|
405
|
+
"numbering": [
|
|
406
|
+
1,
|
|
407
|
+
3,
|
|
408
|
+
8
|
|
409
|
+
],
|
|
410
|
+
"parent": "root"
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
"value": "Min and max values",
|
|
414
|
+
"href": "#min-and-max-values",
|
|
415
|
+
"depth": 3,
|
|
416
|
+
"numbering": [
|
|
417
|
+
1,
|
|
418
|
+
3,
|
|
419
|
+
9
|
|
420
|
+
],
|
|
421
|
+
"parent": "root"
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
"value": "Disabled state",
|
|
425
|
+
"href": "#disabled-state",
|
|
426
|
+
"depth": 3,
|
|
427
|
+
"numbering": [
|
|
428
|
+
1,
|
|
429
|
+
3,
|
|
430
|
+
10
|
|
431
|
+
],
|
|
432
|
+
"parent": "root"
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
"value": "Invalid state",
|
|
436
|
+
"href": "#invalid-state",
|
|
437
|
+
"depth": 3,
|
|
438
|
+
"numbering": [
|
|
439
|
+
1,
|
|
440
|
+
3,
|
|
441
|
+
11
|
|
442
|
+
],
|
|
443
|
+
"parent": "root"
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"value": "Read-only state",
|
|
447
|
+
"href": "#read-only-state",
|
|
448
|
+
"depth": 3,
|
|
449
|
+
"numbering": [
|
|
450
|
+
1,
|
|
451
|
+
3,
|
|
452
|
+
12
|
|
453
|
+
],
|
|
454
|
+
"parent": "root"
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
"value": "Required state",
|
|
458
|
+
"href": "#required-state",
|
|
459
|
+
"depth": 3,
|
|
460
|
+
"numbering": [
|
|
461
|
+
1,
|
|
462
|
+
3,
|
|
463
|
+
13
|
|
464
|
+
],
|
|
465
|
+
"parent": "root"
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
"value": "Uncontrolled mode",
|
|
469
|
+
"href": "#uncontrolled-mode",
|
|
470
|
+
"depth": 3,
|
|
471
|
+
"numbering": [
|
|
472
|
+
1,
|
|
473
|
+
3,
|
|
474
|
+
14
|
|
475
|
+
],
|
|
476
|
+
"parent": "root"
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
"value": "Controlled mode",
|
|
480
|
+
"href": "#controlled-mode",
|
|
481
|
+
"depth": 3,
|
|
482
|
+
"numbering": [
|
|
483
|
+
1,
|
|
484
|
+
3,
|
|
485
|
+
15
|
|
486
|
+
],
|
|
487
|
+
"parent": "root"
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
"value": "Different locales",
|
|
491
|
+
"href": "#different-locales",
|
|
492
|
+
"depth": 3,
|
|
493
|
+
"numbering": [
|
|
494
|
+
1,
|
|
495
|
+
3,
|
|
496
|
+
16
|
|
497
|
+
],
|
|
498
|
+
"parent": "root"
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
"value": "Form integration",
|
|
502
|
+
"href": "#form-integration",
|
|
503
|
+
"depth": 3,
|
|
504
|
+
"numbering": [
|
|
505
|
+
1,
|
|
506
|
+
3,
|
|
507
|
+
17
|
|
508
|
+
],
|
|
509
|
+
"parent": "root"
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
"value": "Component requirements",
|
|
513
|
+
"href": "#component-requirements",
|
|
514
|
+
"depth": 2,
|
|
515
|
+
"numbering": [
|
|
516
|
+
1,
|
|
517
|
+
4
|
|
518
|
+
],
|
|
519
|
+
"parent": "root"
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
"value": "TimeValue requirements",
|
|
523
|
+
"href": "#timevalue-requirements",
|
|
524
|
+
"depth": 3,
|
|
525
|
+
"numbering": [
|
|
526
|
+
1,
|
|
527
|
+
4,
|
|
528
|
+
1
|
|
529
|
+
],
|
|
530
|
+
"parent": "root"
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
"value": "Accessibility",
|
|
534
|
+
"href": "#accessibility",
|
|
535
|
+
"depth": 2,
|
|
536
|
+
"numbering": [
|
|
537
|
+
1,
|
|
538
|
+
5
|
|
539
|
+
],
|
|
540
|
+
"parent": "root"
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
"value": "Keyboard navigation",
|
|
544
|
+
"href": "#keyboard-navigation",
|
|
545
|
+
"depth": 4,
|
|
546
|
+
"numbering": [
|
|
547
|
+
1,
|
|
548
|
+
5,
|
|
549
|
+
1,
|
|
550
|
+
1
|
|
551
|
+
],
|
|
552
|
+
"parent": "root"
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
"value": "API reference",
|
|
556
|
+
"href": "#api-reference",
|
|
557
|
+
"depth": 2,
|
|
558
|
+
"numbering": [
|
|
559
|
+
1,
|
|
560
|
+
6
|
|
561
|
+
],
|
|
562
|
+
"parent": "root"
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
"value": "Common patterns",
|
|
566
|
+
"href": "#common-patterns",
|
|
567
|
+
"depth": 2,
|
|
568
|
+
"numbering": [
|
|
569
|
+
1,
|
|
570
|
+
7
|
|
571
|
+
],
|
|
572
|
+
"parent": "root"
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
"value": "Business hours restriction",
|
|
576
|
+
"href": "#business-hours-restriction",
|
|
577
|
+
"depth": 3,
|
|
578
|
+
"numbering": [
|
|
579
|
+
1,
|
|
580
|
+
7,
|
|
581
|
+
1
|
|
582
|
+
],
|
|
583
|
+
"parent": "root"
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
"value": "Time range selector",
|
|
587
|
+
"href": "#time-range-selector",
|
|
588
|
+
"depth": 3,
|
|
589
|
+
"numbering": [
|
|
590
|
+
1,
|
|
591
|
+
7,
|
|
592
|
+
2
|
|
593
|
+
],
|
|
594
|
+
"parent": "root"
|
|
595
|
+
},
|
|
596
|
+
{
|
|
597
|
+
"value": "Testing your implementation",
|
|
598
|
+
"href": "#testing-your-implementation",
|
|
599
|
+
"depth": 2,
|
|
600
|
+
"numbering": [
|
|
601
|
+
1,
|
|
602
|
+
8
|
|
603
|
+
],
|
|
604
|
+
"parent": "root"
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
"value": "Basic Rendering Tests",
|
|
608
|
+
"href": "#basic-rendering-tests",
|
|
609
|
+
"depth": 3,
|
|
610
|
+
"numbering": [
|
|
611
|
+
1,
|
|
612
|
+
8,
|
|
613
|
+
1
|
|
614
|
+
],
|
|
615
|
+
"parent": "root"
|
|
616
|
+
},
|
|
617
|
+
{
|
|
618
|
+
"value": "Interaction Tests",
|
|
619
|
+
"href": "#interaction-tests",
|
|
620
|
+
"depth": 3,
|
|
621
|
+
"numbering": [
|
|
622
|
+
1,
|
|
623
|
+
8,
|
|
624
|
+
2
|
|
625
|
+
],
|
|
626
|
+
"parent": "root"
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
"value": "Controlled Mode Tests",
|
|
630
|
+
"href": "#controlled-mode-tests",
|
|
631
|
+
"depth": 3,
|
|
632
|
+
"numbering": [
|
|
633
|
+
1,
|
|
634
|
+
8,
|
|
635
|
+
3
|
|
636
|
+
],
|
|
637
|
+
"parent": "root"
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
"value": "Uncontrolled Mode Tests",
|
|
641
|
+
"href": "#uncontrolled-mode-tests",
|
|
642
|
+
"depth": 3,
|
|
643
|
+
"numbering": [
|
|
644
|
+
1,
|
|
645
|
+
8,
|
|
646
|
+
4
|
|
647
|
+
],
|
|
648
|
+
"parent": "root"
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
"value": "Hour Cycle Tests",
|
|
652
|
+
"href": "#hour-cycle-tests",
|
|
653
|
+
"depth": 3,
|
|
654
|
+
"numbering": [
|
|
655
|
+
1,
|
|
656
|
+
8,
|
|
657
|
+
5
|
|
658
|
+
],
|
|
659
|
+
"parent": "root"
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
"value": "Granularity Tests",
|
|
663
|
+
"href": "#granularity-tests",
|
|
664
|
+
"depth": 3,
|
|
665
|
+
"numbering": [
|
|
666
|
+
1,
|
|
667
|
+
8,
|
|
668
|
+
6
|
|
669
|
+
],
|
|
670
|
+
"parent": "root"
|
|
671
|
+
},
|
|
672
|
+
{
|
|
673
|
+
"value": "Validation Tests",
|
|
674
|
+
"href": "#validation-tests",
|
|
675
|
+
"depth": 3,
|
|
676
|
+
"numbering": [
|
|
677
|
+
1,
|
|
678
|
+
8,
|
|
679
|
+
7
|
|
680
|
+
],
|
|
681
|
+
"parent": "root"
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
"value": "State Tests",
|
|
685
|
+
"href": "#state-tests",
|
|
686
|
+
"depth": 3,
|
|
687
|
+
"numbering": [
|
|
688
|
+
1,
|
|
689
|
+
8,
|
|
690
|
+
8
|
|
691
|
+
],
|
|
692
|
+
"parent": "root"
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
"value": "Accessibility Tests",
|
|
696
|
+
"href": "#accessibility-tests",
|
|
697
|
+
"depth": 3,
|
|
698
|
+
"numbering": [
|
|
699
|
+
1,
|
|
700
|
+
8,
|
|
701
|
+
9
|
|
702
|
+
],
|
|
703
|
+
"parent": "root"
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
"value": "Form Integration Tests",
|
|
707
|
+
"href": "#form-integration-tests",
|
|
708
|
+
"depth": 3,
|
|
709
|
+
"numbering": [
|
|
710
|
+
1,
|
|
711
|
+
8,
|
|
712
|
+
10
|
|
713
|
+
],
|
|
714
|
+
"parent": "root"
|
|
715
|
+
},
|
|
716
|
+
{
|
|
717
|
+
"value": "Resources",
|
|
718
|
+
"href": "#resources",
|
|
719
|
+
"depth": 2,
|
|
720
|
+
"numbering": [
|
|
721
|
+
1,
|
|
722
|
+
9
|
|
723
|
+
],
|
|
724
|
+
"parent": "root"
|
|
725
|
+
}
|
|
726
|
+
]
|
|
727
|
+
},
|
|
728
|
+
"guidelines": {
|
|
729
|
+
"mdx": "\n## Guidelines\n\nNumber input guidelines focus on clear labels, suitable ranges, easy interaction\nvia keyboard and buttons, and strong error handling, all while following WCAG\naccessibility rules.\n\n### Best practices\n\n- **Labels:** Always include a concise and clear label using sentence case.\n Labels should not be hidden. In the rare case where context is sufficient and\n label can be absent, review the design with an accessibility expert.\n- **Default values:** Provide a clear and logical default time when possible\n (e.g., current time, a common start time like 9:00 AM). Avoid leaving the\n input blank.\n- **Helper text:** Use helper text to indicate the expected time format (e.g.,\n \"HH:MM AM/PM\", \"24-hour format\") or other constraints like valid time ranges.\n It is optional and is replaced by error messages during validation.\n- **Validation:**\n - Provide clear and concise error messages below the input field, replacing\n any helper text.\n - Highlight errors visually, for example, with a red border and an error icon.\n - Validate the entered time against any defined constraints (e.g., valid time\n format, time within allowed range).\n\n## Usage\n\nA time input enables users to enter or select a specific time, offering\nflexibility while maintaining precision.\n\n> [!TIP]\\\n> When to use\n\n- Inputting a specific time of day (e.g., appointment times, event schedules).\n- When time is a discrete data point rather than a duration.\n- When users need to select from a predefined set of time slots.\n\n> [!CAUTION]\\\n> When not to use\n\n- For durations (e.g., \"5 hours 30 minutes\"); use a separate duration input or a\n set of number inputs.\n- When a broad range of continuous times is needed and exact entry is less\n critical; a simple text input with a time format mask might suffice.\n- When users need to select a time zone along with the time; use a dedicated\n time and time zone selector.\n\n## Keeping interactions simple\n\nTime inputs should be straightforward and require minimal effort from the user.\nThis includes clear labeling and error states, and aiding the user with\ndefaults.\n\n> [!TIP]\\\n> **Do**\n>\n> - Always include a label.\n> - Set a clear default time when relevant.\n> - Provide helper text for format or range constraints.\n> - Offer clear error messages and visual indicators.\n\n```jsx live\nconst App = () => (\n <FormField.Root isInvalid>\n <FormField.Label>Start time</FormField.Label>\n <FormField.Input>\n <TimeInput\n size=\"md\"\n hourCycle={24}\n defaultValue={new Time(20, 15)}\n width=\"50%\"\n />\n </FormField.Input>\n <FormField.Error>\n Start time can only be :30, :45, or :00.\n </FormField.Error>\n </FormField.Root>\n);\n```\n\n> [!CAUTION]\\\n> **Don't**\n>\n> - You cannot use a time input for durations, instead use a date range input.\n> - Do not rely solely on color to indicate errors.\n> - Never hide labels.\n\n```jsx live\nconst App = () => (\n <TimeInput\n size=\"md\"\n hourCycle={24}\n defaultValue={new Time(20, 15)}\n width=\"50%\"\n />\n);\n```\n",
|
|
730
|
+
"toc": [
|
|
731
|
+
{
|
|
732
|
+
"value": "Guidelines",
|
|
733
|
+
"href": "#guidelines",
|
|
734
|
+
"depth": 2,
|
|
735
|
+
"numbering": [
|
|
736
|
+
1,
|
|
737
|
+
1
|
|
738
|
+
],
|
|
739
|
+
"parent": "root"
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
"value": "Best practices",
|
|
743
|
+
"href": "#best-practices",
|
|
744
|
+
"depth": 3,
|
|
745
|
+
"numbering": [
|
|
746
|
+
1,
|
|
747
|
+
1,
|
|
748
|
+
1
|
|
749
|
+
],
|
|
750
|
+
"parent": "root"
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
"value": "Usage",
|
|
754
|
+
"href": "#usage",
|
|
755
|
+
"depth": 2,
|
|
756
|
+
"numbering": [
|
|
757
|
+
1,
|
|
758
|
+
2
|
|
759
|
+
],
|
|
760
|
+
"parent": "root"
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
"value": "Keeping interactions simple",
|
|
764
|
+
"href": "#keeping-interactions-simple",
|
|
765
|
+
"depth": 2,
|
|
766
|
+
"numbering": [
|
|
767
|
+
1,
|
|
768
|
+
3
|
|
769
|
+
],
|
|
770
|
+
"parent": "root"
|
|
771
|
+
}
|
|
772
|
+
]
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|