@commercetools/nimbus-mcp 0.1.0 → 2.11.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 +10998 -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-scrollarea.json +428 -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 +179 -0
- package/data/docs/types/ScrollAreaElementIds.json +9 -0
- package/data/docs/types/ScrollAreaProps.json +9 -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 +280 -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,716 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"id": "Components-ModalPage",
|
|
4
|
+
"title": "ModalPage",
|
|
5
|
+
"exportName": "ModalPage",
|
|
6
|
+
"description": "A fullscreen modal overlay for form, info, and tabular page patterns. Provides a structured compound component API for complex editing and detail workflows in Merchant Center.",
|
|
7
|
+
"lifecycleState": "Experimental",
|
|
8
|
+
"order": 999,
|
|
9
|
+
"repoPath": "packages/nimbus/src/components/modal-page/modal-page.mdx",
|
|
10
|
+
"menu": [
|
|
11
|
+
"Components",
|
|
12
|
+
"Layout",
|
|
13
|
+
"ModalPage"
|
|
14
|
+
],
|
|
15
|
+
"route": "components/layout/modalpage",
|
|
16
|
+
"tags": [
|
|
17
|
+
"component",
|
|
18
|
+
"overlay",
|
|
19
|
+
"modal",
|
|
20
|
+
"page",
|
|
21
|
+
"dialog",
|
|
22
|
+
"fullscreen"
|
|
23
|
+
],
|
|
24
|
+
"toc": [
|
|
25
|
+
{
|
|
26
|
+
"value": "Overview",
|
|
27
|
+
"href": "#overview",
|
|
28
|
+
"depth": 2,
|
|
29
|
+
"numbering": [
|
|
30
|
+
1,
|
|
31
|
+
1
|
|
32
|
+
],
|
|
33
|
+
"parent": "root"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"value": "Key features",
|
|
37
|
+
"href": "#key-features",
|
|
38
|
+
"depth": 3,
|
|
39
|
+
"numbering": [
|
|
40
|
+
1,
|
|
41
|
+
1,
|
|
42
|
+
1
|
|
43
|
+
],
|
|
44
|
+
"parent": "root"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"value": "Resources",
|
|
48
|
+
"href": "#resources",
|
|
49
|
+
"depth": 3,
|
|
50
|
+
"numbering": [
|
|
51
|
+
1,
|
|
52
|
+
1,
|
|
53
|
+
2
|
|
54
|
+
],
|
|
55
|
+
"parent": "root"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"value": "Variables",
|
|
59
|
+
"href": "#variables",
|
|
60
|
+
"depth": 2,
|
|
61
|
+
"numbering": [
|
|
62
|
+
1,
|
|
63
|
+
2
|
|
64
|
+
],
|
|
65
|
+
"parent": "root"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"value": "Info page",
|
|
69
|
+
"href": "#info-page",
|
|
70
|
+
"depth": 3,
|
|
71
|
+
"numbering": [
|
|
72
|
+
1,
|
|
73
|
+
2,
|
|
74
|
+
1
|
|
75
|
+
],
|
|
76
|
+
"parent": "root"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"value": "Form page",
|
|
80
|
+
"href": "#form-page",
|
|
81
|
+
"depth": 3,
|
|
82
|
+
"numbering": [
|
|
83
|
+
1,
|
|
84
|
+
2,
|
|
85
|
+
2
|
|
86
|
+
],
|
|
87
|
+
"parent": "root"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"value": "Tabular page",
|
|
91
|
+
"href": "#tabular-page",
|
|
92
|
+
"depth": 3,
|
|
93
|
+
"numbering": [
|
|
94
|
+
1,
|
|
95
|
+
2,
|
|
96
|
+
3
|
|
97
|
+
],
|
|
98
|
+
"parent": "root"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"value": "Multi-column content",
|
|
102
|
+
"href": "#multi-column-content",
|
|
103
|
+
"depth": 3,
|
|
104
|
+
"numbering": [
|
|
105
|
+
1,
|
|
106
|
+
2,
|
|
107
|
+
4
|
|
108
|
+
],
|
|
109
|
+
"parent": "root"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"value": "Stacked pages",
|
|
113
|
+
"href": "#stacked-pages",
|
|
114
|
+
"depth": 3,
|
|
115
|
+
"numbering": [
|
|
116
|
+
1,
|
|
117
|
+
2,
|
|
118
|
+
5
|
|
119
|
+
],
|
|
120
|
+
"parent": "root"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"value": "Guidelines",
|
|
124
|
+
"href": "#guidelines",
|
|
125
|
+
"depth": 2,
|
|
126
|
+
"numbering": [
|
|
127
|
+
1,
|
|
128
|
+
3
|
|
129
|
+
],
|
|
130
|
+
"parent": "root"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"value": "Best practices",
|
|
134
|
+
"href": "#best-practices",
|
|
135
|
+
"depth": 3,
|
|
136
|
+
"numbering": [
|
|
137
|
+
1,
|
|
138
|
+
3,
|
|
139
|
+
1
|
|
140
|
+
],
|
|
141
|
+
"parent": "root"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"value": "Specs",
|
|
145
|
+
"href": "#specs",
|
|
146
|
+
"depth": 2,
|
|
147
|
+
"numbering": [
|
|
148
|
+
1,
|
|
149
|
+
4
|
|
150
|
+
],
|
|
151
|
+
"parent": "root"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"value": "Accessibility",
|
|
155
|
+
"href": "#accessibility",
|
|
156
|
+
"depth": 2,
|
|
157
|
+
"numbering": [
|
|
158
|
+
1,
|
|
159
|
+
5
|
|
160
|
+
],
|
|
161
|
+
"parent": "root"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"value": "Keyboard Navigation",
|
|
165
|
+
"href": "#keyboard-navigation",
|
|
166
|
+
"depth": 3,
|
|
167
|
+
"numbering": [
|
|
168
|
+
1,
|
|
169
|
+
5,
|
|
170
|
+
1
|
|
171
|
+
],
|
|
172
|
+
"parent": "root"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"value": "Screen Reader Support",
|
|
176
|
+
"href": "#screen-reader-support",
|
|
177
|
+
"depth": 3,
|
|
178
|
+
"numbering": [
|
|
179
|
+
1,
|
|
180
|
+
5,
|
|
181
|
+
2
|
|
182
|
+
],
|
|
183
|
+
"parent": "root"
|
|
184
|
+
}
|
|
185
|
+
],
|
|
186
|
+
"layout": "app-frame",
|
|
187
|
+
"tabs": [
|
|
188
|
+
{
|
|
189
|
+
"key": "overview",
|
|
190
|
+
"title": "Overview",
|
|
191
|
+
"order": 0
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"key": "guidelines",
|
|
195
|
+
"title": "Guidelines",
|
|
196
|
+
"order": 2
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"key": "dev",
|
|
200
|
+
"title": "Implementation",
|
|
201
|
+
"order": 3
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"key": "a11y",
|
|
205
|
+
"title": "Accessibility",
|
|
206
|
+
"order": 4
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
},
|
|
210
|
+
"mdx": "\n## Overview\n\nModalPage is a fullscreen overlay that covers nearly the entire viewport,\nproviding a dedicated context for complex workflows. It is the Nimbus\nequivalent of the Merchant Center Application Kit's modal page patterns\n(form, info, and tabular variants).\n\nUnlike a regular Drawer, ModalPage has a fixed, structured layout with a\ntop navigation bar, header, scrollable content area, and optional footer.\nIt is always controlled — consumers manage the open state with `isOpen` and\n`onClose`.\n\n### Key features\n\n- **Controlled-only API**: Explicit `isOpen` + `onClose` — no hidden state\n- **Breadcrumb navigation**: `ModalPage.TopBar` shows previous/current path with an accessible back button\n- **Structured layout**: TopBar / Header / Content (scrollable) / Footer\n- **Tab navigation**: `ModalPage.TabNav` for tabular page patterns\n- **Multi-column content**: Use `PageContent.Root` inside `ModalPage.Content` for column layouts\n- **Accessibility first**: WCAG 2.1 AA compliant with focus management, keyboard navigation, and screen reader support\n\n### Resources\n\n[React Aria Dialog Docs](https://react-spectrum.adobe.com/react-aria/Dialog.html)\n[ARIA Dialog Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/)\n\n## Variables\n\nGet familiar with the features.\n\n### Info page\n\nA read-only detail view. Footer is optional.\n\n```jsx live\nconst App = () => {\n const [isOpen, setIsOpen] = React.useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open Info Page</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Product Details\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Product Details</ModalPage.Title>\n <ModalPage.Subtitle>View the product information</ModalPage.Subtitle>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>Product information goes here.</Text>\n </ModalPage.Content>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Form page\n\nUse when the user needs to create or edit an entity. Always include a Footer\nwith Save/Cancel actions.\n\n```jsx live\nconst App = () => {\n const [isOpen, setIsOpen] = React.useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open Form Page</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Add Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Add Product</ModalPage.Title>\n <ModalPage.Subtitle>Fill in the product details</ModalPage.Subtitle>\n <ModalPage.Actions>\n <Button size=\"sm\" variant=\"outline\">Preview</Button>\n </ModalPage.Actions>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>Form fields go here.</Text>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Tabular page\n\nUse when content is organized into multiple sections via tab navigation.\nPlace `ModalPage.TabNav` inside the header and display the active section\nin the content area.\n\n```jsx live\nconst App = () => {\n const [isOpen, setIsOpen] = React.useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open Tabular Page</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Orders\"\n currentPathLabel=\"Order #12345\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Order #12345</ModalPage.Title>\n <ModalPage.Subtitle>Placed on 2024-01-15</ModalPage.Subtitle>\n <ModalPage.TabNav>\n <TabNav.Root aria-label=\"Order sections\">\n <TabNav.Item href=\"#general\" isCurrent>General</TabNav.Item>\n <TabNav.Item href=\"#items\">Items</TabNav.Item>\n <TabNav.Item href=\"#shipping\">Shipping</TabNav.Item>\n </TabNav.Root>\n </ModalPage.TabNav>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>General information</Text>\n </ModalPage.Content>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Multi-column content\n\nUse `PageContent.Root` with `columns` inside `ModalPage.Content` for\nside-by-side layouts:\n\n```jsx live\nconst App = () => {\n const [isOpen, setIsOpen] = React.useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open Two-Column Page</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n </ModalPage.Header>\n <ModalPage.Content>\n <PageContent.Root variant=\"wide\" columns=\"2/1\">\n <PageContent.Column>\n <Text>Main form area (2/3 width)</Text>\n </PageContent.Column>\n <PageContent.Column sticky>\n <Text>Sidebar summary (1/3 width, sticky)</Text>\n </PageContent.Column>\n </PageContent.Root>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Stacked pages\n\nUse when a workflow requires drilling into a sub-task — for example, opening\n\"Add Variant\" while the \"Edit Product\" page is open. Place the second\n`ModalPage.Root` inside the first `ModalPage.Content`. Each page manages its\nown independent open state.\n\n```jsx live\nconst App = () => {\n const [isFirstOpen, setIsFirstOpen] = React.useState(false);\n const [isSecondOpen, setIsSecondOpen] = React.useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsFirstOpen(true)}>Open Edit Product</Button>\n <ModalPage.Root\n isOpen={isFirstOpen}\n onClose={() => setIsFirstOpen(false)}\n >\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n <ModalPage.Subtitle>Update the product details</ModalPage.Subtitle>\n </ModalPage.Header>\n <ModalPage.Content>\n <Stack>\n <Text>Product form content goes here.</Text>\n <Button onPress={() => setIsSecondOpen(true)}>\n Open Add Variant\n </Button>\n </Stack>\n\n <ModalPage.Root\n isOpen={isSecondOpen}\n onClose={() => setIsSecondOpen(false)}\n >\n <ModalPage.TopBar\n previousPathLabel=\"Edit Product\"\n currentPathLabel=\"Add Variant\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Add Variant</ModalPage.Title>\n <ModalPage.Subtitle>Define a new product variant</ModalPage.Subtitle>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>Variant form content goes here.</Text>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save Variant</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save Product</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n## Guidelines\n\nUse ModalPage strategically to enhance user workflow without disrupting the\nexperience.\n\n### Best practices\n\n- **Always provide a title**: Use `ModalPage.Title` so screen readers can identify the dialog\n- **Use TopBar navigation**: Always supply meaningful `previousPathLabel` and `currentPathLabel`\n- **Footer actions for forms**: Include Save/Cancel in `ModalPage.Footer` for form pages\n- **Prefer Escape key close**: Don't disable keyboard dismissal — it matches OS conventions and WCAG 2.1\n- **Backdrop click is disabled**: Users must close via back button, Cancel, or Escape to prevent accidental data loss\n\n> [!TIP]\\\n> When to use\n\n- **Complex editing workflows**: Creating or editing entities with many fields\n- **Multi-section detail views**: When content is too rich for a standard Drawer\n- **Tabular data workflows**: When content requires tabs (general, items, shipping)\n- **Full-page focused context**: When the user needs to focus entirely on the task\n\n> [!CAUTION]\\\n> When not to use\n\n- **Simple confirmation dialogs**: Use `Dialog` instead\n- **Single-form quick edits**: Use `Drawer` instead — ModalPage is for complex, multi-field scenarios\n- **Navigation overlays**: Use proper routing for section changes\n\n## Specs\n\n<PropsTable id=\"ModalPage\" />\n\n## Accessibility\n\n### Keyboard Navigation\n\n| Key | Action |\n|-----|--------|\n| `Escape` | Closes the modal page |\n| `Tab` / `Shift+Tab` | Moves focus between interactive elements |\n\nFocus is trapped inside the modal while open and returns to the triggering\nelement when the modal closes.\n\n### Screen Reader Support\n\n- The dialog has `role=\"dialog\"` and `aria-modal=\"true\"`\n- `ModalPage.Title` automatically provides the accessible name for the dialog\n- The back button has a localized label referencing the previous path (e.g. \"Go back to Products\")\n- The breadcrumb separator is hidden from assistive technology\n- The current path label is marked as the current page\n",
|
|
211
|
+
"views": {
|
|
212
|
+
"overview": {
|
|
213
|
+
"mdx": "\n## Overview\n\nModalPage is a fullscreen overlay that covers nearly the entire viewport,\nproviding a dedicated context for complex workflows. It is the Nimbus\nequivalent of the Merchant Center Application Kit's modal page patterns\n(form, info, and tabular variants).\n\nUnlike a regular Drawer, ModalPage has a fixed, structured layout with a\ntop navigation bar, header, scrollable content area, and optional footer.\nIt is always controlled — consumers manage the open state with `isOpen` and\n`onClose`.\n\n### Key features\n\n- **Controlled-only API**: Explicit `isOpen` + `onClose` — no hidden state\n- **Breadcrumb navigation**: `ModalPage.TopBar` shows previous/current path with an accessible back button\n- **Structured layout**: TopBar / Header / Content (scrollable) / Footer\n- **Tab navigation**: `ModalPage.TabNav` for tabular page patterns\n- **Multi-column content**: Use `PageContent.Root` inside `ModalPage.Content` for column layouts\n- **Accessibility first**: WCAG 2.1 AA compliant with focus management, keyboard navigation, and screen reader support\n\n### Resources\n\n[React Aria Dialog Docs](https://react-spectrum.adobe.com/react-aria/Dialog.html)\n[ARIA Dialog Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/)\n\n## Variables\n\nGet familiar with the features.\n\n### Info page\n\nA read-only detail view. Footer is optional.\n\n```jsx live\nconst App = () => {\n const [isOpen, setIsOpen] = React.useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open Info Page</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Product Details\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Product Details</ModalPage.Title>\n <ModalPage.Subtitle>View the product information</ModalPage.Subtitle>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>Product information goes here.</Text>\n </ModalPage.Content>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Form page\n\nUse when the user needs to create or edit an entity. Always include a Footer\nwith Save/Cancel actions.\n\n```jsx live\nconst App = () => {\n const [isOpen, setIsOpen] = React.useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open Form Page</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Add Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Add Product</ModalPage.Title>\n <ModalPage.Subtitle>Fill in the product details</ModalPage.Subtitle>\n <ModalPage.Actions>\n <Button size=\"sm\" variant=\"outline\">Preview</Button>\n </ModalPage.Actions>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>Form fields go here.</Text>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Tabular page\n\nUse when content is organized into multiple sections via tab navigation.\nPlace `ModalPage.TabNav` inside the header and display the active section\nin the content area.\n\n```jsx live\nconst App = () => {\n const [isOpen, setIsOpen] = React.useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open Tabular Page</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Orders\"\n currentPathLabel=\"Order #12345\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Order #12345</ModalPage.Title>\n <ModalPage.Subtitle>Placed on 2024-01-15</ModalPage.Subtitle>\n <ModalPage.TabNav>\n <TabNav.Root aria-label=\"Order sections\">\n <TabNav.Item href=\"#general\" isCurrent>General</TabNav.Item>\n <TabNav.Item href=\"#items\">Items</TabNav.Item>\n <TabNav.Item href=\"#shipping\">Shipping</TabNav.Item>\n </TabNav.Root>\n </ModalPage.TabNav>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>General information</Text>\n </ModalPage.Content>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Multi-column content\n\nUse `PageContent.Root` with `columns` inside `ModalPage.Content` for\nside-by-side layouts:\n\n```jsx live\nconst App = () => {\n const [isOpen, setIsOpen] = React.useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open Two-Column Page</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n </ModalPage.Header>\n <ModalPage.Content>\n <PageContent.Root variant=\"wide\" columns=\"2/1\">\n <PageContent.Column>\n <Text>Main form area (2/3 width)</Text>\n </PageContent.Column>\n <PageContent.Column sticky>\n <Text>Sidebar summary (1/3 width, sticky)</Text>\n </PageContent.Column>\n </PageContent.Root>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Stacked pages\n\nUse when a workflow requires drilling into a sub-task — for example, opening\n\"Add Variant\" while the \"Edit Product\" page is open. Place the second\n`ModalPage.Root` inside the first `ModalPage.Content`. Each page manages its\nown independent open state.\n\n```jsx live\nconst App = () => {\n const [isFirstOpen, setIsFirstOpen] = React.useState(false);\n const [isSecondOpen, setIsSecondOpen] = React.useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsFirstOpen(true)}>Open Edit Product</Button>\n <ModalPage.Root\n isOpen={isFirstOpen}\n onClose={() => setIsFirstOpen(false)}\n >\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n <ModalPage.Subtitle>Update the product details</ModalPage.Subtitle>\n </ModalPage.Header>\n <ModalPage.Content>\n <Stack>\n <Text>Product form content goes here.</Text>\n <Button onPress={() => setIsSecondOpen(true)}>\n Open Add Variant\n </Button>\n </Stack>\n\n <ModalPage.Root\n isOpen={isSecondOpen}\n onClose={() => setIsSecondOpen(false)}\n >\n <ModalPage.TopBar\n previousPathLabel=\"Edit Product\"\n currentPathLabel=\"Add Variant\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Add Variant</ModalPage.Title>\n <ModalPage.Subtitle>Define a new product variant</ModalPage.Subtitle>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>Variant form content goes here.</Text>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save Variant</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save Product</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n## Guidelines\n\nUse ModalPage strategically to enhance user workflow without disrupting the\nexperience.\n\n### Best practices\n\n- **Always provide a title**: Use `ModalPage.Title` so screen readers can identify the dialog\n- **Use TopBar navigation**: Always supply meaningful `previousPathLabel` and `currentPathLabel`\n- **Footer actions for forms**: Include Save/Cancel in `ModalPage.Footer` for form pages\n- **Prefer Escape key close**: Don't disable keyboard dismissal — it matches OS conventions and WCAG 2.1\n- **Backdrop click is disabled**: Users must close via back button, Cancel, or Escape to prevent accidental data loss\n\n> [!TIP]\\\n> When to use\n\n- **Complex editing workflows**: Creating or editing entities with many fields\n- **Multi-section detail views**: When content is too rich for a standard Drawer\n- **Tabular data workflows**: When content requires tabs (general, items, shipping)\n- **Full-page focused context**: When the user needs to focus entirely on the task\n\n> [!CAUTION]\\\n> When not to use\n\n- **Simple confirmation dialogs**: Use `Dialog` instead\n- **Single-form quick edits**: Use `Drawer` instead — ModalPage is for complex, multi-field scenarios\n- **Navigation overlays**: Use proper routing for section changes\n\n## Specs\n\n<PropsTable id=\"ModalPage\" />\n\n## Accessibility\n\n### Keyboard Navigation\n\n| Key | Action |\n|-----|--------|\n| `Escape` | Closes the modal page |\n| `Tab` / `Shift+Tab` | Moves focus between interactive elements |\n\nFocus is trapped inside the modal while open and returns to the triggering\nelement when the modal closes.\n\n### Screen Reader Support\n\n- The dialog has `role=\"dialog\"` and `aria-modal=\"true\"`\n- `ModalPage.Title` automatically provides the accessible name for the dialog\n- The back button has a localized label referencing the previous path (e.g. \"Go back to Products\")\n- The breadcrumb separator is hidden from assistive technology\n- The current path label is marked as the current page\n",
|
|
214
|
+
"toc": [
|
|
215
|
+
{
|
|
216
|
+
"value": "Overview",
|
|
217
|
+
"href": "#overview",
|
|
218
|
+
"depth": 2,
|
|
219
|
+
"numbering": [
|
|
220
|
+
1,
|
|
221
|
+
1
|
|
222
|
+
],
|
|
223
|
+
"parent": "root"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"value": "Key features",
|
|
227
|
+
"href": "#key-features",
|
|
228
|
+
"depth": 3,
|
|
229
|
+
"numbering": [
|
|
230
|
+
1,
|
|
231
|
+
1,
|
|
232
|
+
1
|
|
233
|
+
],
|
|
234
|
+
"parent": "root"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"value": "Resources",
|
|
238
|
+
"href": "#resources",
|
|
239
|
+
"depth": 3,
|
|
240
|
+
"numbering": [
|
|
241
|
+
1,
|
|
242
|
+
1,
|
|
243
|
+
2
|
|
244
|
+
],
|
|
245
|
+
"parent": "root"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"value": "Variables",
|
|
249
|
+
"href": "#variables",
|
|
250
|
+
"depth": 2,
|
|
251
|
+
"numbering": [
|
|
252
|
+
1,
|
|
253
|
+
2
|
|
254
|
+
],
|
|
255
|
+
"parent": "root"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"value": "Info page",
|
|
259
|
+
"href": "#info-page",
|
|
260
|
+
"depth": 3,
|
|
261
|
+
"numbering": [
|
|
262
|
+
1,
|
|
263
|
+
2,
|
|
264
|
+
1
|
|
265
|
+
],
|
|
266
|
+
"parent": "root"
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
"value": "Form page",
|
|
270
|
+
"href": "#form-page",
|
|
271
|
+
"depth": 3,
|
|
272
|
+
"numbering": [
|
|
273
|
+
1,
|
|
274
|
+
2,
|
|
275
|
+
2
|
|
276
|
+
],
|
|
277
|
+
"parent": "root"
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
"value": "Tabular page",
|
|
281
|
+
"href": "#tabular-page",
|
|
282
|
+
"depth": 3,
|
|
283
|
+
"numbering": [
|
|
284
|
+
1,
|
|
285
|
+
2,
|
|
286
|
+
3
|
|
287
|
+
],
|
|
288
|
+
"parent": "root"
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"value": "Multi-column content",
|
|
292
|
+
"href": "#multi-column-content",
|
|
293
|
+
"depth": 3,
|
|
294
|
+
"numbering": [
|
|
295
|
+
1,
|
|
296
|
+
2,
|
|
297
|
+
4
|
|
298
|
+
],
|
|
299
|
+
"parent": "root"
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"value": "Stacked pages",
|
|
303
|
+
"href": "#stacked-pages",
|
|
304
|
+
"depth": 3,
|
|
305
|
+
"numbering": [
|
|
306
|
+
1,
|
|
307
|
+
2,
|
|
308
|
+
5
|
|
309
|
+
],
|
|
310
|
+
"parent": "root"
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"value": "Guidelines",
|
|
314
|
+
"href": "#guidelines",
|
|
315
|
+
"depth": 2,
|
|
316
|
+
"numbering": [
|
|
317
|
+
1,
|
|
318
|
+
3
|
|
319
|
+
],
|
|
320
|
+
"parent": "root"
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"value": "Best practices",
|
|
324
|
+
"href": "#best-practices",
|
|
325
|
+
"depth": 3,
|
|
326
|
+
"numbering": [
|
|
327
|
+
1,
|
|
328
|
+
3,
|
|
329
|
+
1
|
|
330
|
+
],
|
|
331
|
+
"parent": "root"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"value": "Specs",
|
|
335
|
+
"href": "#specs",
|
|
336
|
+
"depth": 2,
|
|
337
|
+
"numbering": [
|
|
338
|
+
1,
|
|
339
|
+
4
|
|
340
|
+
],
|
|
341
|
+
"parent": "root"
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"value": "Accessibility",
|
|
345
|
+
"href": "#accessibility",
|
|
346
|
+
"depth": 2,
|
|
347
|
+
"numbering": [
|
|
348
|
+
1,
|
|
349
|
+
5
|
|
350
|
+
],
|
|
351
|
+
"parent": "root"
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
"value": "Keyboard Navigation",
|
|
355
|
+
"href": "#keyboard-navigation",
|
|
356
|
+
"depth": 3,
|
|
357
|
+
"numbering": [
|
|
358
|
+
1,
|
|
359
|
+
5,
|
|
360
|
+
1
|
|
361
|
+
],
|
|
362
|
+
"parent": "root"
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
"value": "Screen Reader Support",
|
|
366
|
+
"href": "#screen-reader-support",
|
|
367
|
+
"depth": 3,
|
|
368
|
+
"numbering": [
|
|
369
|
+
1,
|
|
370
|
+
5,
|
|
371
|
+
2
|
|
372
|
+
],
|
|
373
|
+
"parent": "root"
|
|
374
|
+
}
|
|
375
|
+
]
|
|
376
|
+
},
|
|
377
|
+
"a11y": {
|
|
378
|
+
"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 const [isOpen, setIsOpen] = React.useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open Modal Page</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n <ModalPage.Subtitle>Update the product details</ModalPage.Subtitle>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>\n This modal page demonstrates accessibility features: dialog role,\n focus trap, Escape key dismissal, and breadcrumb navigation.\n </Text>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Accessibility standards\n\n- **Role identification**: ModalPage has `role=\"dialog\"` with proper labeling via `ModalPage.Title`.\n- **Focus management**: Focus moves to the back button on open and returns to the trigger on close.\n- **Focus containment**: Tab navigation stays within the modal while it is open.\n- **Accessible names**: `ModalPage.Title` automatically provides the dialog's accessible name via `aria-labelledby`.\n- **Accessible description**: `ModalPage.Subtitle`, when present, automatically provides the dialog's accessible description via `aria-describedby`.\n- **Modal indication**: `aria-modal=\"true\"` is set, blocking screen reader interaction with the background.\n- **State announcements**: Screen readers announce when the dialog opens and closes.\n- **Breadcrumb accessibility**: The `/` separator is `aria-hidden=\"true\"`; the current path has `aria-current=\"page\"`.\n- **Back button label**: The back button in `ModalPage.TopBar` uses a localized `aria-label` referencing the `previousPathLabel`.\n- **Breadcrumb previous path**: The `previousPathLabel` text is `aria-hidden=\"true\"` since the back button's label already conveys this information.\n- **Keyboard dismissal**: Escape key always closes the modal (WCAG 2.1 SC 2.1.2 — No Keyboard Trap).\n- **No keyboard trap**: Focus is contained but always escapable via Escape key.\n- **Focus order**: Logical focus progression through all interactive elements.\n- **Focus visible**: Clear focus indicators on all interactive elements.\n- **Contrast**: All text meets minimum contrast requirements.\n- **Non-text contrast**: Focus indicators and UI components meet contrast standards.\n- **Name, role, value**: Proper semantic markup and ARIA attributes throughout.\n\n### Resources\n\n- [W3C ARIA Authoring Practices Guide (APG) - Dialog](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/)\n- [WCAG 2.1 Guidelines](https://www.w3.org/WAI/WCAG21/quickref/)\n- [WCAG 2.1 SC 2.1.2 - No Keyboard Trap](https://www.w3.org/WAI/WCAG21/Understanding/no-keyboard-trap.html)\n",
|
|
379
|
+
"toc": [
|
|
380
|
+
{
|
|
381
|
+
"value": "Accessibility",
|
|
382
|
+
"href": "#accessibility",
|
|
383
|
+
"depth": 2,
|
|
384
|
+
"numbering": [
|
|
385
|
+
1,
|
|
386
|
+
1
|
|
387
|
+
],
|
|
388
|
+
"parent": "root"
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
"value": "Accessibility standards",
|
|
392
|
+
"href": "#accessibility-standards",
|
|
393
|
+
"depth": 3,
|
|
394
|
+
"numbering": [
|
|
395
|
+
1,
|
|
396
|
+
1,
|
|
397
|
+
1
|
|
398
|
+
],
|
|
399
|
+
"parent": "root"
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
"value": "Resources",
|
|
403
|
+
"href": "#resources",
|
|
404
|
+
"depth": 3,
|
|
405
|
+
"numbering": [
|
|
406
|
+
1,
|
|
407
|
+
1,
|
|
408
|
+
2
|
|
409
|
+
],
|
|
410
|
+
"parent": "root"
|
|
411
|
+
}
|
|
412
|
+
]
|
|
413
|
+
},
|
|
414
|
+
"dev": {
|
|
415
|
+
"mdx": "\n## Getting started\n\n### Import\n\n```tsx\nimport { ModalPage } from '@commercetools/nimbus';\n```\n\n### Basic usage\n\nModalPage is a controlled compound component. The basic implementation shows\nhow to manage open state and compose the required sub-components:\n\n```jsx live-dev\nconst App = () => {\n const [isOpen, setIsOpen] = useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open Modal Page</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n <ModalPage.Subtitle>Update the product details</ModalPage.Subtitle>\n <ModalPage.Actions>\n <Button size=\"sm\" variant=\"outline\">Preview</Button>\n </ModalPage.Actions>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>Form content goes here.</Text>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n## Usage examples\n\n### Closing the modal page\n\nThere are three ways to close a ModalPage — all route through the same\n`onClose` callback:\n\n1. **Back button in TopBar** — acts as a close trigger, calling `onClose`\n2. **Any button with `slot=\"close\"`** — automatically triggers `onClose`\n3. **Escape key** — always enabled; matches browser/OS convention and WCAG 2.1\n\n```jsx live-dev\nconst App = () => {\n const [isOpen, setIsOpen] = useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>\n Close via: back button in TopBar, slot=\"close\" button, or Escape key.\n </Text>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Multi-column content\n\nUse `PageContent.Root` with `columns` inside `ModalPage.Content` for\nside-by-side layouts:\n\n```jsx live-dev\nconst App = () => {\n const [isOpen, setIsOpen] = useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open Two-Column Page</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n </ModalPage.Header>\n <ModalPage.Content>\n <PageContent.Root variant=\"wide\" columns=\"2/1\">\n <PageContent.Column>\n <Text>Main form (2/3 width)</Text>\n </PageContent.Column>\n <PageContent.Column sticky>\n <Text>Summary sidebar (1/3 width, sticky)</Text>\n </PageContent.Column>\n </PageContent.Root>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Header actions\n\nUse `ModalPage.Actions` to place secondary actions (e.g. Preview, Export) in\nthe right column of the header grid:\n\n```jsx live-dev\nconst App = () => {\n const [isOpen, setIsOpen] = useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open with Header Actions</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n <ModalPage.Subtitle>Last saved 2 minutes ago</ModalPage.Subtitle>\n <ModalPage.Actions>\n <Button size=\"sm\" variant=\"ghost\">Preview</Button>\n <Button size=\"sm\" variant=\"outline\">Export</Button>\n </ModalPage.Actions>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>Content area</Text>\n </ModalPage.Content>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Tabular page with TabNav\n\nUse `ModalPage.TabNav` inside the header for tabular page patterns with\nroute-based tab navigation:\n\n```jsx live-dev\nconst App = () => {\n const [isOpen, setIsOpen] = useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsOpen(true)}>Open Tabular Page</Button>\n <ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <ModalPage.TopBar\n previousPathLabel=\"Orders\"\n currentPathLabel=\"Order #12345\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Order #12345</ModalPage.Title>\n <ModalPage.Subtitle>Placed on 2024-01-15</ModalPage.Subtitle>\n <ModalPage.TabNav>\n <TabNav.Root aria-label=\"Order sections\">\n <TabNav.Item href=\"#general\" isCurrent>General</TabNav.Item>\n <TabNav.Item href=\"#items\">Items</TabNav.Item>\n <TabNav.Item href=\"#shipping\">Shipping</TabNav.Item>\n </TabNav.Root>\n </ModalPage.TabNav>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>General information</Text>\n </ModalPage.Content>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n### Stacked modal pages\n\nWhen a workflow requires drilling into a sub-task (e.g. adding a variant\nwhile editing a product), place a second `ModalPage.Root` inside the first\n`ModalPage.Content`. Each modal page manages its own independent state.\n\nThe breadcrumb in `ModalPage.TopBar` naturally reflects the depth:\nset `previousPathLabel` to the parent page's title so the back button\nreads contextually.\n\nBehaviour that works automatically:\n- Escape closes only the topmost page\n- Focus is trapped in the topmost page; previous page is inert\n- When the second page closes, focus returns to its trigger inside the first page\n- When the first page closes, focus returns to the original page trigger\n\n```jsx live-dev\nconst App = () => {\n const [isFirstOpen, setIsFirstOpen] = useState(false);\n const [isSecondOpen, setIsSecondOpen] = useState(false);\n return (\n <Stack>\n <Button onPress={() => setIsFirstOpen(true)}>Open Edit Product</Button>\n <ModalPage.Root\n isOpen={isFirstOpen}\n onClose={() => setIsFirstOpen(false)}\n >\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n <ModalPage.Subtitle>Update the product details</ModalPage.Subtitle>\n </ModalPage.Header>\n <ModalPage.Content>\n <Stack>\n <Text>Product form content goes here.</Text>\n <Button onPress={() => setIsSecondOpen(true)}>\n Open Add Variant\n </Button>\n </Stack>\n\n <ModalPage.Root\n isOpen={isSecondOpen}\n onClose={() => setIsSecondOpen(false)}\n >\n <ModalPage.TopBar\n previousPathLabel=\"Edit Product\"\n currentPathLabel=\"Add Variant\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Add Variant</ModalPage.Title>\n <ModalPage.Subtitle>Define a new product variant</ModalPage.Subtitle>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>Variant form content goes here.</Text>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save Variant</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save Product</Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </Stack>\n );\n}\n```\n\n## Component requirements\n\n### Accessible dialog label\n\nThe dialog must have an accessible name. Use `ModalPage.Title` (recommended):\n\n```tsx\n<ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n</ModalPage.Header>\n```\n\n`ModalPage.Title` automatically provides the accessible name for the dialog.\nScreen readers will announce the title text when the dialog opens.\n\n### Custom page width\n\nThe default width is near-fullscreen. Pass a `width` prop to\n`ModalPage.Root` to override:\n\n```tsx\n<ModalPage.Root isOpen={isOpen} onClose={handleClose} width=\"xl\">\n ...\n</ModalPage.Root>\n```\n\n### Footer button spacing\n\n`ModalPage.Footer` automatically spaces its children — place buttons directly\nwithout a layout wrapper:\n\n```tsx\n<ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">Cancel</Button>\n <Button colorPalette=\"primary\" variant=\"solid\">Save</Button>\n</ModalPage.Footer>\n```\n\n### Controlled state\n\nModalPage is controlled-only. You must always supply both `isOpen` and\n`onClose`:\n\n```tsx\nconst [isOpen, setIsOpen] = useState(false);\n\n<ModalPage.Root isOpen={isOpen} onClose={() => setIsOpen(false)}>\n ...\n</ModalPage.Root>\n```\n\n## Accessibility\n\nModalPage handles most accessibility requirements internally:\n\n- The dialog has `role=\"dialog\"` and `aria-modal=\"true\"`\n- Focus is trapped inside the modal while open\n- Focus moves to the back button on open and returns to the trigger on close\n- Escape key dismissal is always active\n- Backdrop click is disabled — full-page forms should not close accidentally\n\n#### Keyboard navigation\n\n| Key | Action |\n|-----|--------|\n| `Escape` | Closes the modal page |\n| `Tab` / `Shift+Tab` | Navigate focusable elements within the modal |\n\n#### ARIA attributes\n\n- `role=\"dialog\"`: Applied to the dialog container\n- `aria-labelledby`: Automatically linked to `ModalPage.Title`\n- `aria-modal=\"true\"`: Marks the overlay as modal to screen readers\n- `aria-current=\"page\"`: Applied to the current path label in `ModalPage.TopBar`\n- `aria-hidden=\"true\"`: Applied to the breadcrumb separator\n\n## API reference\n\n<PropsTable id=\"ModalPage\" />\n\n## Testing your implementation\n\nThese examples demonstrate how to test your implementation when using ModalPage\nin your application. As the component's internal functionality is already tested\nby Nimbus, these patterns help you verify your integration and application-specific\nlogic.\n\n### Basic usage\n\n```tsx\nimport { useState } from \"react\";\nimport { render, screen, fireEvent } from \"@testing-library/react\";\nimport { describe, it, expect, vi } from \"vitest\";\nimport {\n Button,\n ModalPage,\n NimbusProvider,\n PageContent,\n Stack,\n TabNav,\n Text,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"ModalPage - Basic usage\", () => {\n it(\"opens and closes via controlled state\", () => {\n const onClose = vi.fn();\n\n const Example = () => {\n const [isOpen, setIsOpen] = useState(false);\n return (\n <NimbusProvider>\n <Button onPress={() => setIsOpen(true)}>Open</Button>\n <ModalPage.Root\n isOpen={isOpen}\n onClose={() => {\n onClose();\n setIsOpen(false);\n }}\n >\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n <ModalPage.Subtitle>\n Update the product details\n </ModalPage.Subtitle>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>Form content</Text>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">\n Cancel\n </Button>\n <Button colorPalette=\"primary\" variant=\"solid\">\n Save\n </Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </NimbusProvider>\n );\n };\n\n render(<Example />);\n\n // Dialog is not in DOM before opening\n expect(screen.queryByRole(\"dialog\")).not.toBeInTheDocument();\n\n // Open the modal\n fireEvent.click(screen.getByRole(\"button\", { name: \"Open\" }));\n expect(screen.getByRole(\"dialog\")).toBeInTheDocument();\n expect(\n screen.getByRole(\"heading\", { name: \"Edit Product\" })\n ).toBeInTheDocument();\n\n // Close via slot=\"close\" button\n fireEvent.click(screen.getByRole(\"button\", { name: \"Cancel\" }));\n expect(onClose).toHaveBeenCalledOnce();\n });\n});\n```\n\n### Form page with header actions and footer\n\n```tsx\nimport { useState } from \"react\";\nimport { render, screen, fireEvent } from \"@testing-library/react\";\nimport { describe, it, expect, vi } from \"vitest\";\nimport {\n Button,\n ModalPage,\n NimbusProvider,\n PageContent,\n Stack,\n TabNav,\n Text,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"ModalPage - Form page\", () => {\n it(\"renders header actions and footer buttons\", () => {\n render(\n <NimbusProvider>\n <ModalPage.Root isOpen onClose={() => {}}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Add Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Add Product</ModalPage.Title>\n <ModalPage.Subtitle>Fill in the product details</ModalPage.Subtitle>\n <ModalPage.Actions>\n <Button size=\"sm\" variant=\"outline\">\n Preview\n </Button>\n </ModalPage.Actions>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>Form fields go here</Text>\n </ModalPage.Content>\n <ModalPage.Footer>\n <Button slot=\"close\" variant=\"outline\">\n Cancel\n </Button>\n <Button colorPalette=\"primary\" variant=\"solid\">\n Save\n </Button>\n </ModalPage.Footer>\n </ModalPage.Root>\n </NimbusProvider>\n );\n\n expect(screen.getByRole(\"button\", { name: \"Preview\" })).toBeInTheDocument();\n expect(screen.getByRole(\"button\", { name: \"Cancel\" })).toBeInTheDocument();\n expect(screen.getByRole(\"button\", { name: \"Save\" })).toBeInTheDocument();\n });\n});\n```\n\n### Multi-column layout\n\n```tsx\nimport { useState } from \"react\";\nimport { render, screen, fireEvent } from \"@testing-library/react\";\nimport { describe, it, expect, vi } from \"vitest\";\nimport {\n Button,\n ModalPage,\n NimbusProvider,\n PageContent,\n Stack,\n TabNav,\n Text,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"ModalPage - Multi-column layout\", () => {\n it(\"renders a 2/1 column layout\", () => {\n render(\n <NimbusProvider>\n <ModalPage.Root isOpen onClose={() => {}}>\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n </ModalPage.Header>\n <ModalPage.Content>\n <PageContent.Root variant=\"wide\" columns=\"2/1\">\n <PageContent.Column>\n <Text>Main form area</Text>\n </PageContent.Column>\n <PageContent.Column sticky>\n <Text>Summary sidebar</Text>\n </PageContent.Column>\n </PageContent.Root>\n </ModalPage.Content>\n </ModalPage.Root>\n </NimbusProvider>\n );\n\n expect(screen.getByText(\"Main form area\")).toBeInTheDocument();\n expect(screen.getByText(\"Summary sidebar\")).toBeInTheDocument();\n });\n});\n```\n\n### Tabular page with TabNav\n\n```tsx\nimport { useState } from \"react\";\nimport { render, screen, fireEvent } from \"@testing-library/react\";\nimport { describe, it, expect, vi } from \"vitest\";\nimport {\n Button,\n ModalPage,\n NimbusProvider,\n PageContent,\n Stack,\n TabNav,\n Text,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"ModalPage - Tabular page\", () => {\n it(\"renders tab navigation inside the header\", () => {\n render(\n <NimbusProvider>\n <ModalPage.Root isOpen onClose={() => {}}>\n <ModalPage.TopBar\n previousPathLabel=\"Orders\"\n currentPathLabel=\"Order #12345\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Order #12345</ModalPage.Title>\n <ModalPage.Subtitle>Placed on 2024-01-15</ModalPage.Subtitle>\n <ModalPage.TabNav>\n <TabNav.Root aria-label=\"Order sections\">\n <TabNav.Item href=\"#general\" isCurrent>\n General\n </TabNav.Item>\n <TabNav.Item href=\"#items\">Items</TabNav.Item>\n <TabNav.Item href=\"#shipping\">Shipping</TabNav.Item>\n </TabNav.Root>\n </ModalPage.TabNav>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>General information</Text>\n </ModalPage.Content>\n </ModalPage.Root>\n </NimbusProvider>\n );\n\n expect(\n screen.getByRole(\"heading\", { name: \"Order #12345\" })\n ).toBeInTheDocument();\n expect(screen.getByText(\"General\")).toBeInTheDocument();\n expect(screen.getByText(\"Items\")).toBeInTheDocument();\n expect(screen.getByText(\"Shipping\")).toBeInTheDocument();\n });\n});\n```\n\n### Stacked modal pages\n\n```tsx\nimport { useState } from \"react\";\nimport { render, screen, fireEvent } from \"@testing-library/react\";\nimport { describe, it, expect, vi } from \"vitest\";\nimport {\n Button,\n ModalPage,\n NimbusProvider,\n PageContent,\n Stack,\n TabNav,\n Text,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"ModalPage - Stacked pages\", () => {\n it(\"renders nested modal pages independently\", () => {\n const Example = () => {\n const [isFirstOpen, setIsFirstOpen] = useState(true);\n const [isSecondOpen, setIsSecondOpen] = useState(false);\n return (\n <NimbusProvider>\n <ModalPage.Root\n isOpen={isFirstOpen}\n onClose={() => setIsFirstOpen(false)}\n >\n <ModalPage.TopBar\n previousPathLabel=\"Products\"\n currentPathLabel=\"Edit Product\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Edit Product</ModalPage.Title>\n </ModalPage.Header>\n <ModalPage.Content>\n <Stack>\n <Text>Product form content</Text>\n <Button onPress={() => setIsSecondOpen(true)}>\n Add Variant\n </Button>\n </Stack>\n <ModalPage.Root\n isOpen={isSecondOpen}\n onClose={() => setIsSecondOpen(false)}\n >\n <ModalPage.TopBar\n previousPathLabel=\"Edit Product\"\n currentPathLabel=\"Add Variant\"\n />\n <ModalPage.Header>\n <ModalPage.Title>Add Variant</ModalPage.Title>\n </ModalPage.Header>\n <ModalPage.Content>\n <Text>Variant form content</Text>\n </ModalPage.Content>\n </ModalPage.Root>\n </ModalPage.Content>\n </ModalPage.Root>\n </NimbusProvider>\n );\n };\n\n render(<Example />);\n\n expect(screen.getByText(\"Product form content\")).toBeInTheDocument();\n\n // Open stacked page\n fireEvent.click(screen.getByRole(\"button\", { name: \"Add Variant\" }));\n expect(screen.getByText(\"Variant form content\")).toBeInTheDocument();\n });\n});\n```\n\n\n## Resources\n\n- [Storybook](https://nimbus-storybook.vercel.app/?path=/docs/components-layout-modalpage--docs)\n- [React Aria Dialog](https://react-spectrum.adobe.com/react-aria/Dialog.html)\n- [ARIA Dialog Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/)\n",
|
|
416
|
+
"toc": [
|
|
417
|
+
{
|
|
418
|
+
"value": "Getting started",
|
|
419
|
+
"href": "#getting-started",
|
|
420
|
+
"depth": 2,
|
|
421
|
+
"numbering": [
|
|
422
|
+
1,
|
|
423
|
+
1
|
|
424
|
+
],
|
|
425
|
+
"parent": "root"
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"value": "Import",
|
|
429
|
+
"href": "#import",
|
|
430
|
+
"depth": 3,
|
|
431
|
+
"numbering": [
|
|
432
|
+
1,
|
|
433
|
+
1,
|
|
434
|
+
1
|
|
435
|
+
],
|
|
436
|
+
"parent": "root"
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
"value": "Basic usage",
|
|
440
|
+
"href": "#basic-usage",
|
|
441
|
+
"depth": 3,
|
|
442
|
+
"numbering": [
|
|
443
|
+
1,
|
|
444
|
+
1,
|
|
445
|
+
2
|
|
446
|
+
],
|
|
447
|
+
"parent": "root"
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
"value": "Usage examples",
|
|
451
|
+
"href": "#usage-examples",
|
|
452
|
+
"depth": 2,
|
|
453
|
+
"numbering": [
|
|
454
|
+
1,
|
|
455
|
+
2
|
|
456
|
+
],
|
|
457
|
+
"parent": "root"
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
"value": "Closing the modal page",
|
|
461
|
+
"href": "#closing-the-modal-page",
|
|
462
|
+
"depth": 3,
|
|
463
|
+
"numbering": [
|
|
464
|
+
1,
|
|
465
|
+
2,
|
|
466
|
+
1
|
|
467
|
+
],
|
|
468
|
+
"parent": "root"
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
"value": "Multi-column content",
|
|
472
|
+
"href": "#multi-column-content",
|
|
473
|
+
"depth": 3,
|
|
474
|
+
"numbering": [
|
|
475
|
+
1,
|
|
476
|
+
2,
|
|
477
|
+
2
|
|
478
|
+
],
|
|
479
|
+
"parent": "root"
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
"value": "Header actions",
|
|
483
|
+
"href": "#header-actions",
|
|
484
|
+
"depth": 3,
|
|
485
|
+
"numbering": [
|
|
486
|
+
1,
|
|
487
|
+
2,
|
|
488
|
+
3
|
|
489
|
+
],
|
|
490
|
+
"parent": "root"
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
"value": "Tabular page with TabNav",
|
|
494
|
+
"href": "#tabular-page-with-tabnav",
|
|
495
|
+
"depth": 3,
|
|
496
|
+
"numbering": [
|
|
497
|
+
1,
|
|
498
|
+
2,
|
|
499
|
+
4
|
|
500
|
+
],
|
|
501
|
+
"parent": "root"
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
"value": "Stacked modal pages",
|
|
505
|
+
"href": "#stacked-modal-pages",
|
|
506
|
+
"depth": 3,
|
|
507
|
+
"numbering": [
|
|
508
|
+
1,
|
|
509
|
+
2,
|
|
510
|
+
5
|
|
511
|
+
],
|
|
512
|
+
"parent": "root"
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
"value": "Component requirements",
|
|
516
|
+
"href": "#component-requirements",
|
|
517
|
+
"depth": 2,
|
|
518
|
+
"numbering": [
|
|
519
|
+
1,
|
|
520
|
+
3
|
|
521
|
+
],
|
|
522
|
+
"parent": "root"
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
"value": "Accessible dialog label",
|
|
526
|
+
"href": "#accessible-dialog-label",
|
|
527
|
+
"depth": 3,
|
|
528
|
+
"numbering": [
|
|
529
|
+
1,
|
|
530
|
+
3,
|
|
531
|
+
1
|
|
532
|
+
],
|
|
533
|
+
"parent": "root"
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
"value": "Custom page width",
|
|
537
|
+
"href": "#custom-page-width",
|
|
538
|
+
"depth": 3,
|
|
539
|
+
"numbering": [
|
|
540
|
+
1,
|
|
541
|
+
3,
|
|
542
|
+
2
|
|
543
|
+
],
|
|
544
|
+
"parent": "root"
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
"value": "Footer button spacing",
|
|
548
|
+
"href": "#footer-button-spacing",
|
|
549
|
+
"depth": 3,
|
|
550
|
+
"numbering": [
|
|
551
|
+
1,
|
|
552
|
+
3,
|
|
553
|
+
3
|
|
554
|
+
],
|
|
555
|
+
"parent": "root"
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
"value": "Controlled state",
|
|
559
|
+
"href": "#controlled-state",
|
|
560
|
+
"depth": 3,
|
|
561
|
+
"numbering": [
|
|
562
|
+
1,
|
|
563
|
+
3,
|
|
564
|
+
4
|
|
565
|
+
],
|
|
566
|
+
"parent": "root"
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
"value": "Accessibility",
|
|
570
|
+
"href": "#accessibility",
|
|
571
|
+
"depth": 2,
|
|
572
|
+
"numbering": [
|
|
573
|
+
1,
|
|
574
|
+
4
|
|
575
|
+
],
|
|
576
|
+
"parent": "root"
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
"value": "Keyboard navigation",
|
|
580
|
+
"href": "#keyboard-navigation",
|
|
581
|
+
"depth": 4,
|
|
582
|
+
"numbering": [
|
|
583
|
+
1,
|
|
584
|
+
4,
|
|
585
|
+
1,
|
|
586
|
+
1
|
|
587
|
+
],
|
|
588
|
+
"parent": "root"
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
"value": "ARIA attributes",
|
|
592
|
+
"href": "#aria-attributes",
|
|
593
|
+
"depth": 4,
|
|
594
|
+
"numbering": [
|
|
595
|
+
1,
|
|
596
|
+
4,
|
|
597
|
+
1,
|
|
598
|
+
2
|
|
599
|
+
],
|
|
600
|
+
"parent": "root"
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
"value": "API reference",
|
|
604
|
+
"href": "#api-reference",
|
|
605
|
+
"depth": 2,
|
|
606
|
+
"numbering": [
|
|
607
|
+
1,
|
|
608
|
+
5
|
|
609
|
+
],
|
|
610
|
+
"parent": "root"
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
"value": "Testing your implementation",
|
|
614
|
+
"href": "#testing-your-implementation",
|
|
615
|
+
"depth": 2,
|
|
616
|
+
"numbering": [
|
|
617
|
+
1,
|
|
618
|
+
6
|
|
619
|
+
],
|
|
620
|
+
"parent": "root"
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
"value": "Basic usage",
|
|
624
|
+
"href": "#basic-usage-1",
|
|
625
|
+
"depth": 3,
|
|
626
|
+
"numbering": [
|
|
627
|
+
1,
|
|
628
|
+
6,
|
|
629
|
+
1
|
|
630
|
+
],
|
|
631
|
+
"parent": "root"
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
"value": "Form page with header actions and footer",
|
|
635
|
+
"href": "#form-page-with-header-actions-and-footer",
|
|
636
|
+
"depth": 3,
|
|
637
|
+
"numbering": [
|
|
638
|
+
1,
|
|
639
|
+
6,
|
|
640
|
+
2
|
|
641
|
+
],
|
|
642
|
+
"parent": "root"
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
"value": "Multi-column layout",
|
|
646
|
+
"href": "#multi-column-layout",
|
|
647
|
+
"depth": 3,
|
|
648
|
+
"numbering": [
|
|
649
|
+
1,
|
|
650
|
+
6,
|
|
651
|
+
3
|
|
652
|
+
],
|
|
653
|
+
"parent": "root"
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
"value": "Tabular page with TabNav",
|
|
657
|
+
"href": "#tabular-page-with-tabnav-1",
|
|
658
|
+
"depth": 3,
|
|
659
|
+
"numbering": [
|
|
660
|
+
1,
|
|
661
|
+
6,
|
|
662
|
+
4
|
|
663
|
+
],
|
|
664
|
+
"parent": "root"
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
"value": "Stacked modal pages",
|
|
668
|
+
"href": "#stacked-modal-pages-1",
|
|
669
|
+
"depth": 3,
|
|
670
|
+
"numbering": [
|
|
671
|
+
1,
|
|
672
|
+
6,
|
|
673
|
+
5
|
|
674
|
+
],
|
|
675
|
+
"parent": "root"
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
"value": "Resources",
|
|
679
|
+
"href": "#resources",
|
|
680
|
+
"depth": 2,
|
|
681
|
+
"numbering": [
|
|
682
|
+
1,
|
|
683
|
+
7
|
|
684
|
+
],
|
|
685
|
+
"parent": "root"
|
|
686
|
+
}
|
|
687
|
+
]
|
|
688
|
+
},
|
|
689
|
+
"guidelines": {
|
|
690
|
+
"mdx": "\n## Guidelines\n\nUse ModalPage strategically to enhance user workflow without disrupting the\nexperience.\n\n### Best practices\n\n- **Always provide a title**: Use `ModalPage.Title` so screen readers can identify the dialog\n- **Use meaningful navigation labels**: `previousPathLabel` and `currentPathLabel` orient the user within the application\n- **Include footer actions for forms**: Form pages should always have Save/Cancel in `ModalPage.Footer`\n- **Avoid disabling Escape key**: Keyboard dismissal is always active — it matches OS conventions and WCAG 2.1\n- **Keep content focused**: ModalPage should have a single, clear purpose — a form, a detail view, or a tabular view\n- **Use the right variant**: Choose the content variant that matches your data (`wide`, `narrow`, or `full`)\n\n> [!TIP]\\\n> When to use\n\n- **Complex editing workflows**: Creating or editing entities with many fields (product forms, order details)\n- **Multi-section detail views**: When content is too rich for a standard Drawer\n- **Tabular data workflows**: When the content is organized into tabs (General, Items, Shipping)\n- **Full-page focused context**: When the user must focus entirely on the task before returning to the list\n\n> [!CAUTION]\\\n> When not to use\n\n- **Simple confirmation dialogs**: Use `Dialog` instead — ModalPage is for content-rich workflows\n- **Single-form quick edits**: Use `Drawer` instead — reserve ModalPage for complex, multi-field scenarios\n- **Navigation overlays**: Use proper routing for moving between application sections\n- **Informational banners or toasts**: Use `Alert` or `Toast` for non-blocking messages\n",
|
|
691
|
+
"toc": [
|
|
692
|
+
{
|
|
693
|
+
"value": "Guidelines",
|
|
694
|
+
"href": "#guidelines",
|
|
695
|
+
"depth": 2,
|
|
696
|
+
"numbering": [
|
|
697
|
+
1,
|
|
698
|
+
1
|
|
699
|
+
],
|
|
700
|
+
"parent": "root"
|
|
701
|
+
},
|
|
702
|
+
{
|
|
703
|
+
"value": "Best practices",
|
|
704
|
+
"href": "#best-practices",
|
|
705
|
+
"depth": 3,
|
|
706
|
+
"numbering": [
|
|
707
|
+
1,
|
|
708
|
+
1,
|
|
709
|
+
1
|
|
710
|
+
],
|
|
711
|
+
"parent": "root"
|
|
712
|
+
}
|
|
713
|
+
]
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|