@eocrm/design-system 0.0.0-stage → 0.6.18
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/AI-PRIMER.md +341 -0
- package/LICENSE +202 -0
- package/README.md +266 -2
- package/docs/components/Accordion.md +114 -0
- package/docs/components/AgentAvatar.md +58 -0
- package/docs/components/Alert.md +81 -0
- package/docs/components/AppLayout.md +70 -0
- package/docs/components/Avatar.md +49 -0
- package/docs/components/AvatarGroup.md +47 -0
- package/docs/components/Badge.md +60 -0
- package/docs/components/Banner.md +89 -0
- package/docs/components/BrandIcon.md +32 -0
- package/docs/components/Breadcrumb.md +72 -0
- package/docs/components/Button.md +107 -0
- package/docs/components/ButtonGroup.md +78 -0
- package/docs/components/Calendar.md +158 -0
- package/docs/components/Card.md +165 -0
- package/docs/components/CatalogPicker.md +83 -0
- package/docs/components/Chart.md +114 -0
- package/docs/components/ChatBubble.md +55 -0
- package/docs/components/ChatLauncher.md +97 -0
- package/docs/components/Checkbox.md +55 -0
- package/docs/components/CircularProgress.md +53 -0
- package/docs/components/Cluster.md +96 -0
- package/docs/components/Code.md +35 -0
- package/docs/components/CodeBlock.md +67 -0
- package/docs/components/ColorPicker.md +115 -0
- package/docs/components/ConfirmationPopover.md +70 -0
- package/docs/components/Constrain.md +39 -0
- package/docs/components/CurrencySelect.md +57 -0
- package/docs/components/CursorPagination.md +43 -0
- package/docs/components/DashboardCanvas.md +79 -0
- package/docs/components/DashboardWidget.md +131 -0
- package/docs/components/DataTable.md +88 -0
- package/docs/components/DatePicker.md +68 -0
- package/docs/components/DateRangePicker.md +71 -0
- package/docs/components/DateStrip.md +56 -0
- package/docs/components/DefinitionList.md +82 -0
- package/docs/components/Divider.md +57 -0
- package/docs/components/Dot.md +26 -0
- package/docs/components/Drawer.md +94 -0
- package/docs/components/DropdownMenu.md +299 -0
- package/docs/components/EmojiPicker.md +84 -0
- package/docs/components/EmptyState.md +55 -0
- package/docs/components/EntityChip.md +102 -0
- package/docs/components/ErrorState.md +72 -0
- package/docs/components/Field.md +91 -0
- package/docs/components/FileUpload.md +109 -0
- package/docs/components/FilterChip.md +88 -0
- package/docs/components/FlowCanvas.md +108 -0
- package/docs/components/FormRow.md +31 -0
- package/docs/components/FormSection.md +37 -0
- package/docs/components/Grid.md +103 -0
- package/docs/components/Highlight.md +75 -0
- package/docs/components/HighlightedText.md +50 -0
- package/docs/components/IconPicker.md +134 -0
- package/docs/components/IconTile.md +30 -0
- package/docs/components/Image.md +84 -0
- package/docs/components/ImageCrop.md +163 -0
- package/docs/components/Indent.md +31 -0
- package/docs/components/InlineDatePicker.md +58 -0
- package/docs/components/InlineDateRangePicker.md +57 -0
- package/docs/components/Input.md +54 -0
- package/docs/components/Kanban.md +122 -0
- package/docs/components/Kbd.md +41 -0
- package/docs/components/Lightbox.md +105 -0
- package/docs/components/Link.md +65 -0
- package/docs/components/LinkCard.md +41 -0
- package/docs/components/LiquidEditor.md +84 -0
- package/docs/components/List.md +68 -0
- package/docs/components/LiveRegion.md +29 -0
- package/docs/components/LocaleProvider.md +25 -0
- package/docs/components/Logo.md +41 -0
- package/docs/components/Masonry.md +48 -0
- package/docs/components/MediaTile.md +95 -0
- package/docs/components/Modal.md +107 -0
- package/docs/components/MoneyInput.md +62 -0
- package/docs/components/OptionsPicker.md +123 -0
- package/docs/components/OtpInput.md +65 -0
- package/docs/components/Page.md +35 -0
- package/docs/components/PageHeader.md +133 -0
- package/docs/components/Pagination.md +44 -0
- package/docs/components/Palette.md +32 -0
- package/docs/components/PasswordInput.md +45 -0
- package/docs/components/PasswordStrengthMeter.md +27 -0
- package/docs/components/PersonDisplay.md +153 -0
- package/docs/components/PhoneInput.md +54 -0
- package/docs/components/PillMenu.md +91 -0
- package/docs/components/Popover.md +127 -0
- package/docs/components/Progress.md +56 -0
- package/docs/components/QrCode.md +34 -0
- package/docs/components/Radio.md +37 -0
- package/docs/components/RadioGroup.md +56 -0
- package/docs/components/Rail.md +191 -0
- package/docs/components/RelativeDateInput.md +114 -0
- package/docs/components/RichText.md +44 -0
- package/docs/components/RichTextEditor.md +112 -0
- package/docs/components/Screen.md +37 -0
- package/docs/components/ScrollArea.md +39 -0
- package/docs/components/Select.md +131 -0
- package/docs/components/SettingRow.md +98 -0
- package/docs/components/Skeleton.md +68 -0
- package/docs/components/Slider.md +92 -0
- package/docs/components/SlotGrid.md +55 -0
- package/docs/components/SocialButton.md +31 -0
- package/docs/components/Sortable.md +127 -0
- package/docs/components/SortableGroup.md +52 -0
- package/docs/components/Sparkline.md +51 -0
- package/docs/components/Split.md +76 -0
- package/docs/components/Stack.md +59 -0
- package/docs/components/StagePath.md +66 -0
- package/docs/components/StatGroup.md +61 -0
- package/docs/components/StatTile.md +58 -0
- package/docs/components/Sticky.md +69 -0
- package/docs/components/Switch.md +89 -0
- package/docs/components/Table.md +184 -0
- package/docs/components/TableOfContents.md +76 -0
- package/docs/components/Tabs.md +94 -0
- package/docs/components/Text.md +63 -0
- package/docs/components/Textarea.md +59 -0
- package/docs/components/Thread.md +52 -0
- package/docs/components/TimeField.md +70 -0
- package/docs/components/Timeline.md +57 -0
- package/docs/components/Title.md +54 -0
- package/docs/components/ToastViewport.md +61 -0
- package/docs/components/Tooltip.md +63 -0
- package/docs/components/TopBar.md +214 -0
- package/docs/components/Tour.md +85 -0
- package/docs/components/TreeView.md +113 -0
- package/docs/components/VisuallyHidden.md +43 -0
- package/docs/components/WidgetPreview.md +54 -0
- package/docs/components/useBelowBreakpoint.md +11 -0
- package/docs/components/useMonth.md +18 -0
- package/docs/setup.md +51 -0
- package/docs/theming.md +95 -0
- package/docs/tokens.md +123 -0
- package/docs/transient-state.md +56 -0
- package/package.json +86 -4
- package/src/_meta/manifest.ts +293 -0
- package/src/app/AppProvider.tsx +78 -0
- package/src/app/index.ts +3 -0
- package/src/app/themeTokens.ts +95 -0
- package/src/calendar/dateMath.ts +114 -0
- package/src/calendar/formatters.ts +75 -0
- package/src/calendar/index.ts +39 -0
- package/src/calendar/types.ts +36 -0
- package/src/calendar/useAgenda.ts +70 -0
- package/src/calendar/useDay.ts +51 -0
- package/src/calendar/useMonth.ts +82 -0
- package/src/calendar/useWeek.ts +62 -0
- package/src/calendar/weekInfo.ts +83 -0
- package/src/components/Accordion/Accordion.module.scss +304 -0
- package/src/components/Accordion/Accordion.tokens.scss +64 -0
- package/src/components/Accordion/Accordion.tsx +272 -0
- package/src/components/Accordion/AccordionContent.tsx +36 -0
- package/src/components/Accordion/AccordionItem.tsx +66 -0
- package/src/components/Accordion/AccordionTrigger.tsx +121 -0
- package/src/components/Accordion/context.ts +47 -0
- package/src/components/Accordion/index.ts +14 -0
- package/src/components/Alert/Alert.module.scss +92 -0
- package/src/components/Alert/Alert.tokens.scss +60 -0
- package/src/components/Alert/Alert.tsx +136 -0
- package/src/components/Alert/index.ts +2 -0
- package/src/components/AppLayout/AppLayout.module.scss +130 -0
- package/src/components/AppLayout/AppLayout.tokens.scss +27 -0
- package/src/components/AppLayout/AppLayout.tsx +211 -0
- package/src/components/AppLayout/index.ts +2 -0
- package/src/components/Avatar/AgentAvatar.module.scss +117 -0
- package/src/components/Avatar/AgentAvatar.tsx +122 -0
- package/src/components/Avatar/Avatar.module.scss +181 -0
- package/src/components/Avatar/Avatar.tokens.scss +107 -0
- package/src/components/Avatar/Avatar.tsx +210 -0
- package/src/components/Avatar/AvatarGroup.module.scss +128 -0
- package/src/components/Avatar/AvatarGroup.tsx +119 -0
- package/src/components/Avatar/AvatarGroupContext.tsx +20 -0
- package/src/components/Avatar/index.ts +6 -0
- package/src/components/Badge/Badge.module.scss +124 -0
- package/src/components/Badge/Badge.tokens.scss +74 -0
- package/src/components/Badge/Badge.tsx +164 -0
- package/src/components/Badge/index.ts +2 -0
- package/src/components/Banner/Banner.module.scss +73 -0
- package/src/components/Banner/Banner.tokens.scss +51 -0
- package/src/components/Banner/Banner.tsx +138 -0
- package/src/components/Banner/index.ts +2 -0
- package/src/components/BrandIcon/BrandIcon.module.scss +5 -0
- package/src/components/BrandIcon/BrandIcon.tsx +99 -0
- package/src/components/BrandIcon/index.ts +2 -0
- package/src/components/Breadcrumb/Breadcrumb.module.scss +32 -0
- package/src/components/Breadcrumb/Breadcrumb.tokens.scss +9 -0
- package/src/components/Breadcrumb/Breadcrumb.tsx +146 -0
- package/src/components/Breadcrumb/index.ts +2 -0
- package/src/components/Button/Button.module.scss +167 -0
- package/src/components/Button/Button.tokens.scss +90 -0
- package/src/components/Button/Button.tsx +205 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/ButtonGroup/ButtonGroup.module.scss +134 -0
- package/src/components/ButtonGroup/ButtonGroup.tokens.scss +42 -0
- package/src/components/ButtonGroup/ButtonGroup.tsx +278 -0
- package/src/components/ButtonGroup/ButtonGroupItem.tsx +74 -0
- package/src/components/ButtonGroup/context.ts +45 -0
- package/src/components/ButtonGroup/index.ts +2 -0
- package/src/components/Calendar/AgendaView.module.scss +231 -0
- package/src/components/Calendar/AgendaView.tsx +214 -0
- package/src/components/Calendar/AllDayBand.module.scss +18 -0
- package/src/components/Calendar/AllDayBand.tsx +75 -0
- package/src/components/Calendar/Calendar.module.scss +23 -0
- package/src/components/Calendar/Calendar.tokens.scss +262 -0
- package/src/components/Calendar/Calendar.tsx +370 -0
- package/src/components/Calendar/DayCell.module.scss +30 -0
- package/src/components/Calendar/DayCell.tsx +50 -0
- package/src/components/Calendar/DayView.module.scss +10 -0
- package/src/components/Calendar/DayView.tsx +163 -0
- package/src/components/Calendar/EventChip.module.scss +171 -0
- package/src/components/Calendar/EventChip.tsx +115 -0
- package/src/components/Calendar/HourGrid.module.scss +123 -0
- package/src/components/Calendar/HourGrid.tsx +381 -0
- package/src/components/Calendar/MonthView.module.scss +99 -0
- package/src/components/Calendar/MonthView.tsx +296 -0
- package/src/components/Calendar/TimedEvent.module.scss +205 -0
- package/src/components/Calendar/TimedEvent.tsx +247 -0
- package/src/components/Calendar/ViewSwitcher.module.scss +3 -0
- package/src/components/Calendar/ViewSwitcher.tsx +47 -0
- package/src/components/Calendar/WeekView.module.scss +10 -0
- package/src/components/Calendar/WeekView.tsx +137 -0
- package/src/components/Calendar/eventColor.ts +60 -0
- package/src/components/Calendar/index.ts +18 -0
- package/src/components/Calendar/types.ts +451 -0
- package/src/components/Calendar/useEventDrag.ts +783 -0
- package/src/components/Calendar/utils.ts +622 -0
- package/src/components/Card/Card.module.scss +264 -0
- package/src/components/Card/Card.tokens.scss +55 -0
- package/src/components/Card/Card.tsx +170 -0
- package/src/components/Card/CardBody.tsx +45 -0
- package/src/components/Card/CardHeader.tsx +113 -0
- package/src/components/Card/CardList.tsx +24 -0
- package/src/components/Card/CardListRow.tsx +24 -0
- package/src/components/Card/index.ts +7 -0
- package/src/components/CatalogPicker/CatalogPicker.module.scss +193 -0
- package/src/components/CatalogPicker/CatalogPicker.tokens.scss +26 -0
- package/src/components/CatalogPicker/CatalogPicker.tsx +339 -0
- package/src/components/CatalogPicker/index.ts +2 -0
- package/src/components/Chart/Chart.module.scss +287 -0
- package/src/components/Chart/Chart.tokens.scss +63 -0
- package/src/components/Chart/Chart.tsx +607 -0
- package/src/components/Chart/ChartLegend.tsx +99 -0
- package/src/components/Chart/ChartTable.tsx +62 -0
- package/src/components/Chart/ChartTooltip.tsx +91 -0
- package/src/components/Chart/chartModel.ts +689 -0
- package/src/components/Chart/index.ts +2 -0
- package/src/components/ChatBubble/ChatBubble.module.scss +93 -0
- package/src/components/ChatBubble/ChatBubble.tokens.scss +17 -0
- package/src/components/ChatBubble/ChatBubble.tsx +61 -0
- package/src/components/ChatBubble/ChatBubbleList.tsx +27 -0
- package/src/components/ChatBubble/index.ts +3 -0
- package/src/components/ChatLauncher/ChatLauncher.module.scss +68 -0
- package/src/components/ChatLauncher/ChatLauncher.tokens.scss +27 -0
- package/src/components/ChatLauncher/ChatLauncher.tsx +202 -0
- package/src/components/ChatLauncher/index.ts +2 -0
- package/src/components/ChatLauncher/isAtBottom.ts +12 -0
- package/src/components/Checkbox/Checkbox.module.scss +147 -0
- package/src/components/Checkbox/Checkbox.tokens.scss +44 -0
- package/src/components/Checkbox/Checkbox.tsx +188 -0
- package/src/components/Checkbox/index.ts +2 -0
- package/src/components/CircularProgress/CircularProgress.module.scss +133 -0
- package/src/components/CircularProgress/CircularProgress.tokens.scss +40 -0
- package/src/components/CircularProgress/CircularProgress.tsx +139 -0
- package/src/components/CircularProgress/index.ts +7 -0
- package/src/components/Cluster/Cluster.module.scss +145 -0
- package/src/components/Cluster/Cluster.tokens.scss +11 -0
- package/src/components/Cluster/Cluster.tsx +215 -0
- package/src/components/Cluster/index.ts +2 -0
- package/src/components/Code/Code.module.scss +28 -0
- package/src/components/Code/Code.tokens.scss +15 -0
- package/src/components/Code/Code.tsx +44 -0
- package/src/components/Code/index.ts +2 -0
- package/src/components/CodeBlock/CodeBlock.module.scss +146 -0
- package/src/components/CodeBlock/CodeBlock.tokens.scss +27 -0
- package/src/components/CodeBlock/CodeBlock.tsx +274 -0
- package/src/components/CodeBlock/highlight.ts +179 -0
- package/src/components/CodeBlock/index.ts +8 -0
- package/src/components/CodeBlock/sampleSync.ts +42 -0
- package/src/components/ColorPicker/ColorPicker.module.scss +286 -0
- package/src/components/ColorPicker/ColorPicker.tokens.scss +60 -0
- package/src/components/ColorPicker/ColorPicker.tsx +367 -0
- package/src/components/ColorPicker/ColorPickerPanel.tsx +265 -0
- package/src/components/ColorPicker/SVSquare.tsx +189 -0
- package/src/components/ColorPicker/colorMath.ts +141 -0
- package/src/components/ColorPicker/index.ts +6 -0
- package/src/components/ConfirmationPopover/ConfirmationPopover.module.scss +39 -0
- package/src/components/ConfirmationPopover/ConfirmationPopover.tokens.scss +13 -0
- package/src/components/ConfirmationPopover/ConfirmationPopover.tsx +395 -0
- package/src/components/ConfirmationPopover/index.ts +2 -0
- package/src/components/Constrain/Constrain.module.scss +99 -0
- package/src/components/Constrain/Constrain.tsx +79 -0
- package/src/components/Constrain/index.ts +2 -0
- package/src/components/CurrencySelect/CurrencySelect.module.scss +7 -0
- package/src/components/CurrencySelect/CurrencySelect.tsx +167 -0
- package/src/components/CurrencySelect/index.ts +3 -0
- package/src/components/CursorPagination/CursorPagination.module.scss +69 -0
- package/src/components/CursorPagination/CursorPagination.tokens.scss +32 -0
- package/src/components/CursorPagination/CursorPagination.tsx +121 -0
- package/src/components/CursorPagination/index.ts +2 -0
- package/src/components/DashboardCanvas/DashboardCanvas.module.scss +360 -0
- package/src/components/DashboardCanvas/DashboardCanvas.tokens.scss +48 -0
- package/src/components/DashboardCanvas/DashboardCanvas.tsx +1270 -0
- package/src/components/DashboardCanvas/DashboardCanvasItem.tsx +140 -0
- package/src/components/DashboardCanvas/DashboardCanvasSection.tsx +174 -0
- package/src/components/DashboardCanvas/engine.ts +363 -0
- package/src/components/DashboardCanvas/index.ts +9 -0
- package/src/components/DashboardWidget/DashboardWidget.module.scss +100 -0
- package/src/components/DashboardWidget/DashboardWidget.tokens.scss +16 -0
- package/src/components/DashboardWidget/DashboardWidget.tsx +188 -0
- package/src/components/DashboardWidget/index.ts +7 -0
- package/src/components/DataTable/BodyRow.tsx +197 -0
- package/src/components/DataTable/ColumnVisibilityTrigger.module.scss +7 -0
- package/src/components/DataTable/ColumnVisibilityTrigger.tsx +105 -0
- package/src/components/DataTable/DataTable.module.scss +511 -0
- package/src/components/DataTable/DataTable.tokens.scss +80 -0
- package/src/components/DataTable/DataTable.tsx +734 -0
- package/src/components/DataTable/HeaderCell.module.scss +215 -0
- package/src/components/DataTable/HeaderCell.tsx +440 -0
- package/src/components/DataTable/columnShift.ts +117 -0
- package/src/components/DataTable/index.ts +23 -0
- package/src/components/DataTable/pinStyle.ts +47 -0
- package/src/components/DataTable/reorderColumns.ts +66 -0
- package/src/components/DataTable/types.ts +289 -0
- package/src/components/DataTable/useColumnDragShift.ts +216 -0
- package/src/components/DataTable/useDataTable.ts +372 -0
- package/src/components/DataTable/useResizeHandle.ts +97 -0
- package/src/components/DatePicker/DatePicker.module.scss +180 -0
- package/src/components/DatePicker/DatePicker.tokens.scss +152 -0
- package/src/components/DatePicker/DatePicker.tsx +664 -0
- package/src/components/DatePicker/DatePickerGrid.module.scss +172 -0
- package/src/components/DatePicker/DatePickerGrid.tsx +341 -0
- package/src/components/DatePicker/InlineDatePicker.module.scss +32 -0
- package/src/components/DatePicker/InlineDatePicker.tsx +201 -0
- package/src/components/DatePicker/index.ts +4 -0
- package/src/components/DatePicker/utils.ts +364 -0
- package/src/components/DateRangePicker/DateRangePicker.module.scss +237 -0
- package/src/components/DateRangePicker/DateRangePicker.tokens.scss +78 -0
- package/src/components/DateRangePicker/DateRangePicker.tsx +720 -0
- package/src/components/DateRangePicker/InlineDateRangePicker.module.scss +94 -0
- package/src/components/DateRangePicker/InlineDateRangePicker.tsx +376 -0
- package/src/components/DateRangePicker/index.ts +5 -0
- package/src/components/DateRangePicker/utils.ts +151 -0
- package/src/components/DateStrip/DateStrip.module.scss +78 -0
- package/src/components/DateStrip/DateStrip.tokens.scss +23 -0
- package/src/components/DateStrip/DateStrip.tsx +205 -0
- package/src/components/DateStrip/index.ts +2 -0
- package/src/components/DefinitionList/DefinitionList.module.scss +102 -0
- package/src/components/DefinitionList/DefinitionList.tokens.scss +29 -0
- package/src/components/DefinitionList/DefinitionList.tsx +198 -0
- package/src/components/DefinitionList/index.ts +9 -0
- package/src/components/Divider/Divider.module.scss +144 -0
- package/src/components/Divider/Divider.tokens.scss +21 -0
- package/src/components/Divider/Divider.tsx +103 -0
- package/src/components/Divider/index.ts +2 -0
- package/src/components/Dot/Dot.module.scss +40 -0
- package/src/components/Dot/Dot.tokens.scss +4 -0
- package/src/components/Dot/Dot.tsx +45 -0
- package/src/components/Dot/index.ts +2 -0
- package/src/components/Drawer/Body.tsx +23 -0
- package/src/components/Drawer/Close.tsx +35 -0
- package/src/components/Drawer/Content.tsx +93 -0
- package/src/components/Drawer/Drawer.module.scss +232 -0
- package/src/components/Drawer/Drawer.tokens.scss +38 -0
- package/src/components/Drawer/Drawer.tsx +23 -0
- package/src/components/Drawer/DrawerRoot.tsx +190 -0
- package/src/components/Drawer/Footer.tsx +24 -0
- package/src/components/Drawer/Header.tsx +64 -0
- package/src/components/Drawer/Overlay.tsx +82 -0
- package/src/components/Drawer/context.ts +44 -0
- package/src/components/Drawer/index.ts +12 -0
- package/src/components/Drawer/useDragToClose.ts +149 -0
- package/src/components/DropdownMenu/CheckboxItem.tsx +144 -0
- package/src/components/DropdownMenu/Content.tsx +419 -0
- package/src/components/DropdownMenu/DropdownMenu.module.scss +280 -0
- package/src/components/DropdownMenu/DropdownMenu.tokens.scss +88 -0
- package/src/components/DropdownMenu/DropdownMenu.tsx +43 -0
- package/src/components/DropdownMenu/Group.tsx +76 -0
- package/src/components/DropdownMenu/Item.tsx +148 -0
- package/src/components/DropdownMenu/ItemIndicator.tsx +30 -0
- package/src/components/DropdownMenu/Radio.tsx +178 -0
- package/src/components/DropdownMenu/Root.tsx +100 -0
- package/src/components/DropdownMenu/Sub.tsx +332 -0
- package/src/components/DropdownMenu/Trigger.tsx +76 -0
- package/src/components/DropdownMenu/context.ts +65 -0
- package/src/components/DropdownMenu/index.ts +20 -0
- package/src/components/EmojiPicker/EmojiPicker.module.scss +84 -0
- package/src/components/EmojiPicker/EmojiPicker.tokens.scss +24 -0
- package/src/components/EmojiPicker/EmojiPicker.tsx +341 -0
- package/src/components/EmojiPicker/emojiData.ts +245 -0
- package/src/components/EmojiPicker/index.ts +3 -0
- package/src/components/EmptyState/EmptyState.module.scss +102 -0
- package/src/components/EmptyState/EmptyState.tokens.scss +28 -0
- package/src/components/EmptyState/EmptyState.tsx +112 -0
- package/src/components/EmptyState/index.ts +7 -0
- package/src/components/EntityChip/EntityChip.module.scss +275 -0
- package/src/components/EntityChip/EntityChip.tokens.scss +66 -0
- package/src/components/EntityChip/EntityChip.tsx +649 -0
- package/src/components/EntityChip/index.ts +10 -0
- package/src/components/ErrorState/ErrorState.module.scss +105 -0
- package/src/components/ErrorState/ErrorState.tokens.scss +32 -0
- package/src/components/ErrorState/ErrorState.tsx +125 -0
- package/src/components/ErrorState/index.ts +8 -0
- package/src/components/Field/Field.module.scss +46 -0
- package/src/components/Field/Field.tsx +185 -0
- package/src/components/Field/index.ts +2 -0
- package/src/components/FileUpload/FileUpload.module.scss +187 -0
- package/src/components/FileUpload/FileUpload.tokens.scss +81 -0
- package/src/components/FileUpload/FileUpload.tsx +569 -0
- package/src/components/FileUpload/formatBytes.ts +34 -0
- package/src/components/FileUpload/iconForFile.ts +40 -0
- package/src/components/FileUpload/index.ts +2 -0
- package/src/components/FilterChip/FilterChip.module.scss +61 -0
- package/src/components/FilterChip/FilterChip.tokens.scss +25 -0
- package/src/components/FilterChip/FilterChip.tsx +208 -0
- package/src/components/FilterChip/index.ts +5 -0
- package/src/components/FlowCanvas/FlowCanvas.module.scss +329 -0
- package/src/components/FlowCanvas/FlowCanvas.tokens.scss +45 -0
- package/src/components/FlowCanvas/FlowCanvas.tsx +1867 -0
- package/src/components/FlowCanvas/FlowControls.tsx +46 -0
- package/src/components/FlowCanvas/FlowEdge.tsx +58 -0
- package/src/components/FlowCanvas/FlowNode.tsx +76 -0
- package/src/components/FlowCanvas/edgePath.ts +85 -0
- package/src/components/FlowCanvas/index.ts +4 -0
- package/src/components/FlowCanvas/layout.ts +148 -0
- package/src/components/FlowCanvas/spatialNav.ts +76 -0
- package/src/components/FlowCanvas/types.ts +59 -0
- package/src/components/FlowCanvas/useViewport.ts +122 -0
- package/src/components/FormRow/FormRow.module.scss +2 -0
- package/src/components/FormRow/FormRow.tsx +37 -0
- package/src/components/FormRow/index.ts +2 -0
- package/src/components/FormSection/FormSection.module.scss +24 -0
- package/src/components/FormSection/FormSection.tsx +46 -0
- package/src/components/FormSection/index.ts +2 -0
- package/src/components/Grid/Grid.module.scss +162 -0
- package/src/components/Grid/Grid.tokens.scss +13 -0
- package/src/components/Grid/Grid.tsx +226 -0
- package/src/components/Grid/GridItem.tsx +77 -0
- package/src/components/Grid/index.ts +11 -0
- package/src/components/Highlight/Highlight.module.scss +43 -0
- package/src/components/Highlight/Highlight.tokens.scss +35 -0
- package/src/components/Highlight/Highlight.tsx +164 -0
- package/src/components/Highlight/HighlightOverlay.tsx +100 -0
- package/src/components/Highlight/index.ts +2 -0
- package/src/components/HighlightedText/HighlightedText.module.scss +11 -0
- package/src/components/HighlightedText/HighlightedText.tokens.scss +9 -0
- package/src/components/HighlightedText/HighlightedText.tsx +50 -0
- package/src/components/HighlightedText/highlightRanges.ts +44 -0
- package/src/components/HighlightedText/index.ts +2 -0
- package/src/components/IconPicker/IconPicker.module.scss +175 -0
- package/src/components/IconPicker/IconPicker.tokens.scss +40 -0
- package/src/components/IconPicker/IconPicker.tsx +629 -0
- package/src/components/IconPicker/index.ts +9 -0
- package/src/components/IconTile/IconTile.module.scss +57 -0
- package/src/components/IconTile/IconTile.tokens.scss +16 -0
- package/src/components/IconTile/IconTile.tsx +91 -0
- package/src/components/IconTile/index.ts +2 -0
- package/src/components/Image/Image.module.scss +266 -0
- package/src/components/Image/Image.tokens.scss +55 -0
- package/src/components/Image/Image.tsx +342 -0
- package/src/components/Image/index.ts +2 -0
- package/src/components/ImageCrop/ImageCrop.module.scss +274 -0
- package/src/components/ImageCrop/ImageCrop.tokens.scss +33 -0
- package/src/components/ImageCrop/ImageCrop.tsx +542 -0
- package/src/components/ImageCrop/cropGeometry.ts +120 -0
- package/src/components/ImageCrop/extractCropBlob.ts +140 -0
- package/src/components/ImageCrop/index.ts +11 -0
- package/src/components/ImageCrop/useCropPreview.ts +161 -0
- package/src/components/Indent/Indent.module.scss +33 -0
- package/src/components/Indent/Indent.tokens.scss +10 -0
- package/src/components/Indent/Indent.tsx +46 -0
- package/src/components/Indent/index.ts +2 -0
- package/src/components/Input/Input.module.scss +99 -0
- package/src/components/Input/Input.tokens.scss +54 -0
- package/src/components/Input/Input.tsx +105 -0
- package/src/components/Input/Suggestions.tsx +260 -0
- package/src/components/Input/index.ts +2 -0
- package/src/components/Kanban/Kanban.module.scss +39 -0
- package/src/components/Kanban/Kanban.tokens.scss +15 -0
- package/src/components/Kanban/Kanban.tsx +951 -0
- package/src/components/Kanban/index.ts +7 -0
- package/src/components/Kbd/Kbd.module.scss +47 -0
- package/src/components/Kbd/Kbd.tokens.scss +26 -0
- package/src/components/Kbd/Kbd.tsx +73 -0
- package/src/components/Kbd/index.ts +2 -0
- package/src/components/Lightbox/Lightbox.module.scss +283 -0
- package/src/components/Lightbox/Lightbox.tokens.scss +36 -0
- package/src/components/Lightbox/Lightbox.tsx +506 -0
- package/src/components/Lightbox/index.ts +2 -0
- package/src/components/Link/Link.module.scss +78 -0
- package/src/components/Link/Link.tokens.scss +28 -0
- package/src/components/Link/Link.tsx +114 -0
- package/src/components/Link/index.ts +2 -0
- package/src/components/LinkCard/LinkCard.module.scss +92 -0
- package/src/components/LinkCard/LinkCard.tokens.scss +9 -0
- package/src/components/LinkCard/LinkCard.tsx +72 -0
- package/src/components/LinkCard/index.ts +2 -0
- package/src/components/LiquidEditor/AutocompleteMenu.tsx +133 -0
- package/src/components/LiquidEditor/HighlightLayer.tsx +53 -0
- package/src/components/LiquidEditor/InsertVariableMenu.tsx +81 -0
- package/src/components/LiquidEditor/LiquidEditor.module.scss +339 -0
- package/src/components/LiquidEditor/LiquidEditor.tokens.scss +81 -0
- package/src/components/LiquidEditor/LiquidEditor.tsx +412 -0
- package/src/components/LiquidEditor/PreviewPane.tsx +29 -0
- package/src/components/LiquidEditor/caretCoordinates.ts +97 -0
- package/src/components/LiquidEditor/index.ts +7 -0
- package/src/components/LiquidEditor/liquidFilters.ts +23 -0
- package/src/components/LiquidEditor/liquidTokenizer.ts +235 -0
- package/src/components/LiquidEditor/types.ts +101 -0
- package/src/components/LiquidEditor/useLiquidAutocomplete.ts +178 -0
- package/src/components/List/List.module.scss +105 -0
- package/src/components/List/List.tokens.scss +42 -0
- package/src/components/List/List.tsx +124 -0
- package/src/components/List/index.ts +9 -0
- package/src/components/LiveRegion/LiveRegion.module.scss +3 -0
- package/src/components/LiveRegion/LiveRegion.tsx +116 -0
- package/src/components/LiveRegion/index.ts +2 -0
- package/src/components/Logo/Logo.module.scss +139 -0
- package/src/components/Logo/Logo.tokens.scss +14 -0
- package/src/components/Logo/Logo.tsx +126 -0
- package/src/components/Logo/index.ts +2 -0
- package/src/components/Masonry/Masonry.module.scss +42 -0
- package/src/components/Masonry/Masonry.tokens.scss +8 -0
- package/src/components/Masonry/Masonry.tsx +136 -0
- package/src/components/Masonry/index.ts +2 -0
- package/src/components/Masonry/masonryUtils.ts +42 -0
- package/src/components/MediaTile/MediaTile.module.scss +183 -0
- package/src/components/MediaTile/MediaTile.tokens.scss +60 -0
- package/src/components/MediaTile/MediaTile.tsx +208 -0
- package/src/components/MediaTile/index.ts +8 -0
- package/src/components/Modal/Body.tsx +27 -0
- package/src/components/Modal/Close.tsx +45 -0
- package/src/components/Modal/Content.tsx +98 -0
- package/src/components/Modal/Footer.tsx +28 -0
- package/src/components/Modal/Header.tsx +51 -0
- package/src/components/Modal/Modal.module.scss +262 -0
- package/src/components/Modal/Modal.tokens.scss +50 -0
- package/src/components/Modal/Modal.tsx +23 -0
- package/src/components/Modal/ModalRoot.tsx +299 -0
- package/src/components/Modal/Overlay.tsx +101 -0
- package/src/components/Modal/context.ts +60 -0
- package/src/components/Modal/index.ts +11 -0
- package/src/components/MoneyInput/MoneyInput.module.scss +57 -0
- package/src/components/MoneyInput/MoneyInput.tsx +433 -0
- package/src/components/MoneyInput/index.ts +2 -0
- package/src/components/OptionsPicker/OptionsPicker.module.scss +216 -0
- package/src/components/OptionsPicker/OptionsPicker.tokens.scss +68 -0
- package/src/components/OptionsPicker/OptionsPicker.tsx +936 -0
- package/src/components/OptionsPicker/index.ts +9 -0
- package/src/components/OtpInput/OtpInput.module.scss +69 -0
- package/src/components/OtpInput/OtpInput.tokens.scss +45 -0
- package/src/components/OtpInput/OtpInput.tsx +368 -0
- package/src/components/OtpInput/index.ts +2 -0
- package/src/components/Page/Page.module.scss +30 -0
- package/src/components/Page/Page.tokens.scss +11 -0
- package/src/components/Page/Page.tsx +53 -0
- package/src/components/Page/index.ts +2 -0
- package/src/components/PageHeader/PageHeader.module.scss +197 -0
- package/src/components/PageHeader/PageHeader.tokens.scss +41 -0
- package/src/components/PageHeader/PageHeader.tsx +310 -0
- package/src/components/PageHeader/index.ts +20 -0
- package/src/components/Pagination/Pagination.module.scss +117 -0
- package/src/components/Pagination/Pagination.tokens.scss +54 -0
- package/src/components/Pagination/Pagination.tsx +165 -0
- package/src/components/Pagination/index.ts +4 -0
- package/src/components/Pagination/paginationRange.ts +72 -0
- package/src/components/PasswordInput/PasswordInput.module.scss +120 -0
- package/src/components/PasswordInput/PasswordInput.tokens.scss +44 -0
- package/src/components/PasswordInput/PasswordInput.tsx +210 -0
- package/src/components/PasswordInput/index.ts +2 -0
- package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.module.scss +80 -0
- package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.tokens.scss +40 -0
- package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.tsx +96 -0
- package/src/components/PasswordStrengthMeter/index.ts +2 -0
- package/src/components/PersonDisplay/PersonDisplay.module.scss +180 -0
- package/src/components/PersonDisplay/PersonDisplay.tokens.scss +35 -0
- package/src/components/PersonDisplay/PersonDisplay.tsx +420 -0
- package/src/components/PersonDisplay/index.ts +10 -0
- package/src/components/PhoneInput/PhoneInput.module.scss +23 -0
- package/src/components/PhoneInput/PhoneInput.tsx +271 -0
- package/src/components/PhoneInput/index.ts +4 -0
- package/src/components/PhoneInput/phone.ts +128 -0
- package/src/components/PillMenu/PillMenu.module.scss +117 -0
- package/src/components/PillMenu/PillMenu.tokens.scss +22 -0
- package/src/components/PillMenu/PillMenu.tsx +324 -0
- package/src/components/PillMenu/index.ts +2 -0
- package/src/components/Popover/Anchor.tsx +37 -0
- package/src/components/Popover/Close.tsx +45 -0
- package/src/components/Popover/Content.tsx +213 -0
- package/src/components/Popover/Heading.tsx +33 -0
- package/src/components/Popover/Popover.module.scss +177 -0
- package/src/components/Popover/Popover.tokens.scss +22 -0
- package/src/components/Popover/Popover.tsx +23 -0
- package/src/components/Popover/PopoverRoot.tsx +75 -0
- package/src/components/Popover/Trigger.tsx +86 -0
- package/src/components/Popover/context.ts +22 -0
- package/src/components/Popover/index.ts +7 -0
- package/src/components/Progress/Progress.module.scss +110 -0
- package/src/components/Progress/Progress.tokens.scss +44 -0
- package/src/components/Progress/Progress.tsx +129 -0
- package/src/components/Progress/index.ts +2 -0
- package/src/components/QrCode/QrCode.module.scss +97 -0
- package/src/components/QrCode/QrCode.tokens.scss +17 -0
- package/src/components/QrCode/QrCode.tsx +233 -0
- package/src/components/QrCode/index.ts +2 -0
- package/src/components/QrCode/qr.ts +161 -0
- package/src/components/Radio/Radio.module.scss +175 -0
- package/src/components/Radio/Radio.tokens.scss +59 -0
- package/src/components/Radio/Radio.tsx +127 -0
- package/src/components/Radio/RadioGroup.module.scss +42 -0
- package/src/components/Radio/RadioGroup.tsx +120 -0
- package/src/components/Radio/RadioGroupContext.tsx +30 -0
- package/src/components/Radio/index.ts +4 -0
- package/src/components/Rail/Rail.module.scss +510 -0
- package/src/components/Rail/Rail.tokens.scss +92 -0
- package/src/components/Rail/Rail.tsx +287 -0
- package/src/components/Rail/RailCollapseToggle.tsx +57 -0
- package/src/components/Rail/RailFooter.tsx +17 -0
- package/src/components/Rail/RailGroup.tsx +728 -0
- package/src/components/Rail/RailGroupContext.ts +9 -0
- package/src/components/Rail/RailHeader.tsx +23 -0
- package/src/components/Rail/RailItem.tsx +119 -0
- package/src/components/Rail/RailSection.tsx +39 -0
- package/src/components/Rail/RailSpacer.tsx +19 -0
- package/src/components/Rail/index.ts +9 -0
- package/src/components/RelativeDateInput/RelativeDateInput.module.scss +15 -0
- package/src/components/RelativeDateInput/RelativeDateInput.tokens.scss +6 -0
- package/src/components/RelativeDateInput/RelativeDateInput.tsx +474 -0
- package/src/components/RelativeDateInput/index.ts +10 -0
- package/src/components/RelativeDateInput/relativeDate.ts +127 -0
- package/src/components/RichText/RichText.module.scss +5 -0
- package/src/components/RichText/RichText.tsx +70 -0
- package/src/components/RichText/RichTextAttachment.module.scss +82 -0
- package/src/components/RichText/RichTextAttachment.tsx +122 -0
- package/src/components/RichText/_prose.scss +79 -0
- package/src/components/RichText/attachmentIcon.tsx +24 -0
- package/src/components/RichText/engine/attachment.ts +154 -0
- package/src/components/RichText/engine/autolink.ts +64 -0
- package/src/components/RichText/engine/blockUnit.ts +174 -0
- package/src/components/RichText/engine/colorMarks.ts +85 -0
- package/src/components/RichText/engine/escape.ts +11 -0
- package/src/components/RichText/engine/fromHtml.ts +353 -0
- package/src/components/RichText/engine/fromMarkdown.ts +20 -0
- package/src/components/RichText/engine/inlines.ts +82 -0
- package/src/components/RichText/engine/listDepths.ts +32 -0
- package/src/components/RichText/engine/marks.ts +80 -0
- package/src/components/RichText/engine/mdToHtml.ts +178 -0
- package/src/components/RichText/engine/model.ts +157 -0
- package/src/components/RichText/engine/position.ts +118 -0
- package/src/components/RichText/engine/renderDoc.tsx +395 -0
- package/src/components/RichText/engine/renderLink.ts +15 -0
- package/src/components/RichText/engine/renderMention.ts +16 -0
- package/src/components/RichText/engine/safeHref.ts +22 -0
- package/src/components/RichText/engine/toHtml.ts +154 -0
- package/src/components/RichText/engine/toMarkdown.ts +97 -0
- package/src/components/RichText/engine/transforms.ts +434 -0
- package/src/components/RichText/imageMaxHeightStyle.ts +10 -0
- package/src/components/RichText/index.ts +31 -0
- package/src/components/RichTextEditor/RichTextAttachmentConfig.tsx +264 -0
- package/src/components/RichTextEditor/RichTextBlockControls.tsx +365 -0
- package/src/components/RichTextEditor/RichTextBlockMenu.tsx +162 -0
- package/src/components/RichTextEditor/RichTextColorMenu.tsx +115 -0
- package/src/components/RichTextEditor/RichTextEditor.module.scss +298 -0
- package/src/components/RichTextEditor/RichTextEditor.tsx +1910 -0
- package/src/components/RichTextEditor/RichTextImageResizer.tsx +131 -0
- package/src/components/RichTextEditor/RichTextLinkEditor.tsx +151 -0
- package/src/components/RichTextEditor/RichTextMentionMenu.tsx +99 -0
- package/src/components/RichTextEditor/RichTextToolbar.tsx +379 -0
- package/src/components/RichTextEditor/autolinkInput.ts +65 -0
- package/src/components/RichTextEditor/blockDrop.ts +9 -0
- package/src/components/RichTextEditor/blockReflow.ts +62 -0
- package/src/components/RichTextEditor/commands.ts +300 -0
- package/src/components/RichTextEditor/history.ts +93 -0
- package/src/components/RichTextEditor/icons.tsx +152 -0
- package/src/components/RichTextEditor/imageSize.ts +70 -0
- package/src/components/RichTextEditor/index.ts +5 -0
- package/src/components/RichTextEditor/input.ts +209 -0
- package/src/components/RichTextEditor/inputRules.ts +71 -0
- package/src/components/RichTextEditor/links.ts +103 -0
- package/src/components/RichTextEditor/mentionContext.ts +37 -0
- package/src/components/RichTextEditor/mentions.ts +28 -0
- package/src/components/RichTextEditor/preventSelectionLoss.ts +15 -0
- package/src/components/RichTextEditor/selection.ts +415 -0
- package/src/components/RichTextEditor/shortcuts.ts +44 -0
- package/src/components/RichTextEditor/useAnchoredFloating.ts +50 -0
- package/src/components/RichTextEditor/useAttachmentConfig.ts +134 -0
- package/src/components/RichTextEditor/useDismissOnOutsidePointerDown.ts +26 -0
- package/src/components/RichTextEditor/useLinkEditor.ts +107 -0
- package/src/components/RichTextEditor/useMention.ts +226 -0
- package/src/components/RichTextEditor/useOverlayRect.ts +73 -0
- package/src/components/RichTextEditor/useUpload.ts +246 -0
- package/src/components/Screen/Screen.module.scss +46 -0
- package/src/components/Screen/Screen.tokens.scss +20 -0
- package/src/components/Screen/Screen.tsx +97 -0
- package/src/components/Screen/index.ts +2 -0
- package/src/components/ScrollArea/ScrollArea.module.scss +39 -0
- package/src/components/ScrollArea/ScrollArea.tokens.scss +15 -0
- package/src/components/ScrollArea/ScrollArea.tsx +154 -0
- package/src/components/ScrollArea/index.ts +2 -0
- package/src/components/Select/Chip.tsx +45 -0
- package/src/components/Select/Empty.tsx +39 -0
- package/src/components/Select/Error.tsx +51 -0
- package/src/components/Select/HiddenInputs.tsx +44 -0
- package/src/components/Select/Listbox.tsx +557 -0
- package/src/components/Select/Loading.tsx +30 -0
- package/src/components/Select/Select.module.scss +512 -0
- package/src/components/Select/Select.tokens.scss +140 -0
- package/src/components/Select/Select.tsx +685 -0
- package/src/components/Select/Trigger.tsx +952 -0
- package/src/components/Select/context.ts +101 -0
- package/src/components/Select/emptyStateText.ts +19 -0
- package/src/components/Select/index.ts +9 -0
- package/src/components/Select/useSelectState.ts +157 -0
- package/src/components/Select/utils-types.ts +7 -0
- package/src/components/Select/utils.ts +122 -0
- package/src/components/SettingRow/SettingRow.module.scss +166 -0
- package/src/components/SettingRow/SettingRow.tokens.scss +37 -0
- package/src/components/SettingRow/SettingRow.tsx +242 -0
- package/src/components/SettingRow/index.ts +7 -0
- package/src/components/Skeleton/Skeleton.module.scss +55 -0
- package/src/components/Skeleton/Skeleton.tokens.scss +17 -0
- package/src/components/Skeleton/Skeleton.tsx +131 -0
- package/src/components/Skeleton/index.ts +4 -0
- package/src/components/Skeleton/useSkeletonVisibility.ts +95 -0
- package/src/components/Slider/Slider.module.scss +293 -0
- package/src/components/Slider/Slider.tokens.scss +98 -0
- package/src/components/Slider/Slider.tsx +624 -0
- package/src/components/Slider/index.ts +9 -0
- package/src/components/SlotGrid/SlotGrid.module.scss +61 -0
- package/src/components/SlotGrid/SlotGrid.tokens.scss +21 -0
- package/src/components/SlotGrid/SlotGrid.tsx +111 -0
- package/src/components/SlotGrid/index.ts +2 -0
- package/src/components/SocialButton/SocialButton.module.scss +4 -0
- package/src/components/SocialButton/SocialButton.tsx +40 -0
- package/src/components/SocialButton/index.ts +2 -0
- package/src/components/Sortable/Sortable.module.scss +177 -0
- package/src/components/Sortable/Sortable.tokens.scss +27 -0
- package/src/components/Sortable/Sortable.tsx +572 -0
- package/src/components/Sortable/containerAwareCollision.ts +125 -0
- package/src/components/Sortable/index.ts +13 -0
- package/src/components/SortableGroup/SortableGroup.module.scss +23 -0
- package/src/components/SortableGroup/SortableGroup.tsx +315 -0
- package/src/components/SortableGroup/index.ts +4 -0
- package/src/components/SortableGroup/moveSortableItem.ts +39 -0
- package/src/components/Sparkline/Sparkline.module.scss +28 -0
- package/src/components/Sparkline/Sparkline.tokens.scss +7 -0
- package/src/components/Sparkline/Sparkline.tsx +133 -0
- package/src/components/Sparkline/index.ts +2 -0
- package/src/components/Sparkline/sparklineModel.ts +119 -0
- package/src/components/Split/Split.module.scss +158 -0
- package/src/components/Split/Split.tokens.scss +10 -0
- package/src/components/Split/Split.tsx +231 -0
- package/src/components/Split/index.ts +2 -0
- package/src/components/Stack/Stack.module.scss +67 -0
- package/src/components/Stack/Stack.tokens.scss +11 -0
- package/src/components/Stack/Stack.tsx +100 -0
- package/src/components/Stack/index.ts +2 -0
- package/src/components/StagePath/StagePath.module.scss +255 -0
- package/src/components/StagePath/StagePath.tokens.scss +43 -0
- package/src/components/StagePath/StagePath.tsx +176 -0
- package/src/components/StagePath/index.ts +2 -0
- package/src/components/StatGroup/StatGroup.module.scss +6 -0
- package/src/components/StatGroup/StatGroup.tsx +70 -0
- package/src/components/StatGroup/StatGroupContext.ts +10 -0
- package/src/components/StatGroup/StatTile.module.scss +99 -0
- package/src/components/StatGroup/StatTile.tokens.scss +35 -0
- package/src/components/StatGroup/StatTile.tsx +143 -0
- package/src/components/StatGroup/index.ts +4 -0
- package/src/components/Sticky/Sticky.module.scss +98 -0
- package/src/components/Sticky/Sticky.tokens.scss +17 -0
- package/src/components/Sticky/Sticky.tsx +103 -0
- package/src/components/Sticky/index.ts +2 -0
- package/src/components/Switch/Switch.module.scss +182 -0
- package/src/components/Switch/Switch.tokens.scss +59 -0
- package/src/components/Switch/Switch.tsx +214 -0
- package/src/components/Switch/index.ts +2 -0
- package/src/components/Table/Table.module.scss +308 -0
- package/src/components/Table/Table.tokens.scss +79 -0
- package/src/components/Table/Table.tsx +381 -0
- package/src/components/Table/index.ts +15 -0
- package/src/components/TableOfContents/TableOfContents.module.scss +83 -0
- package/src/components/TableOfContents/TableOfContents.tokens.scss +26 -0
- package/src/components/TableOfContents/TableOfContents.tsx +192 -0
- package/src/components/TableOfContents/activeSection.ts +18 -0
- package/src/components/TableOfContents/index.ts +2 -0
- package/src/components/Tabs/Tabs.module.scss +359 -0
- package/src/components/Tabs/Tabs.tokens.scss +50 -0
- package/src/components/Tabs/Tabs.tsx +538 -0
- package/src/components/Tabs/index.ts +2 -0
- package/src/components/Text/Text.module.scss +115 -0
- package/src/components/Text/Text.tokens.scss +55 -0
- package/src/components/Text/Text.tsx +197 -0
- package/src/components/Text/index.ts +2 -0
- package/src/components/Textarea/Textarea.module.scss +94 -0
- package/src/components/Textarea/Textarea.tokens.scss +48 -0
- package/src/components/Textarea/Textarea.tsx +246 -0
- package/src/components/Textarea/index.ts +2 -0
- package/src/components/Thread/Thread.module.scss +161 -0
- package/src/components/Thread/Thread.tokens.scss +32 -0
- package/src/components/Thread/Thread.tsx +176 -0
- package/src/components/Thread/index.ts +2 -0
- package/src/components/TimeField/TimeField.module.scss +232 -0
- package/src/components/TimeField/TimeField.tsx +793 -0
- package/src/components/TimeField/index.ts +2 -0
- package/src/components/Timeline/Timeline.module.scss +58 -0
- package/src/components/Timeline/Timeline.tokens.scss +13 -0
- package/src/components/Timeline/Timeline.tsx +53 -0
- package/src/components/Timeline/index.ts +2 -0
- package/src/components/Title/Title.module.scss +84 -0
- package/src/components/Title/Title.tokens.scss +37 -0
- package/src/components/Title/Title.tsx +150 -0
- package/src/components/Title/index.ts +2 -0
- package/src/components/Toast/Toast.module.scss +299 -0
- package/src/components/Toast/Toast.tokens.scss +65 -0
- package/src/components/Toast/Toast.tsx +122 -0
- package/src/components/Toast/ToastViewport.tsx +166 -0
- package/src/components/Toast/api.ts +175 -0
- package/src/components/Toast/index.ts +5 -0
- package/src/components/Toast/store.ts +133 -0
- package/src/components/Toast/useToastTimer.ts +94 -0
- package/src/components/Tooltip/Tooltip.module.scss +99 -0
- package/src/components/Tooltip/Tooltip.tokens.scss +23 -0
- package/src/components/Tooltip/Tooltip.tsx +341 -0
- package/src/components/Tooltip/index.ts +2 -0
- package/src/components/TopBar/TopBar.module.scss +235 -0
- package/src/components/TopBar/TopBar.tokens.scss +79 -0
- package/src/components/TopBar/TopBar.tsx +87 -0
- package/src/components/TopBar/TopBarEnd.tsx +20 -0
- package/src/components/TopBar/TopBarIconButton.tsx +86 -0
- package/src/components/TopBar/TopBarSearch.tsx +319 -0
- package/src/components/TopBar/TopBarSearchPanel.tsx +268 -0
- package/src/components/TopBar/TopBarStart.tsx +20 -0
- package/src/components/TopBar/index.ts +11 -0
- package/src/components/Tour/Spotlight.tsx +121 -0
- package/src/components/Tour/Tour.module.scss +210 -0
- package/src/components/Tour/Tour.tokens.scss +58 -0
- package/src/components/Tour/Tour.tsx +617 -0
- package/src/components/Tour/index.ts +2 -0
- package/src/components/Tour/useTourTarget.ts +115 -0
- package/src/components/TreeView/TreeView.module.scss +268 -0
- package/src/components/TreeView/TreeView.tokens.scss +36 -0
- package/src/components/TreeView/TreeView.tsx +536 -0
- package/src/components/TreeView/index.ts +3 -0
- package/src/components/TreeView/treeModel.ts +224 -0
- package/src/components/VisuallyHidden/VisuallyHidden.module.scss +7 -0
- package/src/components/VisuallyHidden/VisuallyHidden.tsx +29 -0
- package/src/components/VisuallyHidden/index.ts +2 -0
- package/src/components/WidgetPreview/WidgetPreview.module.scss +11 -0
- package/src/components/WidgetPreview/WidgetPreview.tokens.scss +26 -0
- package/src/components/WidgetPreview/WidgetPreview.tsx +36 -0
- package/src/components/WidgetPreview/WidgetShape.module.scss +140 -0
- package/src/components/WidgetPreview/WidgetShape.tsx +159 -0
- package/src/components/WidgetPreview/index.ts +2 -0
- package/src/components/_internal/Trend.tsx +27 -0
- package/src/components/_internal/choiceTile.scss +74 -0
- package/src/components/_internal/collapse.scss +10 -0
- package/src/components/_internal/collapse.ts +58 -0
- package/src/components/_internal/currency.ts +257 -0
- package/src/components/_internal/dragAnnouncements.ts +200 -0
- package/src/components/_internal/fieldWiring.ts +225 -0
- package/src/components/_internal/gridSpan.ts +54 -0
- package/src/components/_internal/isoDay.ts +35 -0
- package/src/components/_internal/letterKey.ts +26 -0
- package/src/components/_internal/overlay/focusRestore.ts +21 -0
- package/src/components/_internal/overlay/index.ts +12 -0
- package/src/components/_internal/overlay/tourHold.ts +23 -0
- package/src/components/_internal/overlay/useFocusTrap.ts +120 -0
- package/src/components/_internal/overlay/useInOverlay.ts +81 -0
- package/src/components/_internal/overlay/useOverlayStack.ts +232 -0
- package/src/components/_internal/overlay/useScrollLock.ts +112 -0
- package/src/components/_internal/refs.ts +48 -0
- package/src/components/_internal/statusColor.ts +26 -0
- package/src/components/_internal/timeUtils.ts +23 -0
- package/src/components/_internal/useAsyncOptions.ts +145 -0
- package/src/components/_internal/useClippedTooltip.ts +50 -0
- package/src/components/_internal/useControllableState.ts +50 -0
- package/src/components.manifest.json +1141 -0
- package/src/hooks/useBelowBreakpoint.ts +58 -0
- package/src/i18n/I18nProvider.tsx +52 -0
- package/src/i18n/LocaleProvider.tsx +17 -0
- package/src/i18n/en.ts +648 -0
- package/src/i18n/format.ts +71 -0
- package/src/i18n/index.ts +13 -0
- package/src/i18n/messages.ts +1275 -0
- package/src/i18n/ru.ts +677 -0
- package/src/i18n/useLocale.ts +19 -0
- package/src/i18n/useTranslation.ts +58 -0
- package/src/index.ts +913 -0
- package/src/palette/index.ts +2 -0
- package/src/palette/palette.ts +108 -0
- package/src/styles/dark.scss +4 -0
- package/src/styles/global.scss +7 -0
- package/src/styles/mixins.scss +143 -0
- package/src/styles/reset.scss +78 -0
- package/src/styles/tokens.scss +18 -0
- package/src/styles/typography.scss +44 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
type ComponentPropsWithRef,
|
|
4
|
+
type ComponentPropsWithoutRef,
|
|
5
|
+
type CSSProperties,
|
|
6
|
+
type ElementType,
|
|
7
|
+
type ForwardedRef,
|
|
8
|
+
type ReactElement,
|
|
9
|
+
} from 'react';
|
|
10
|
+
import clsx from 'clsx';
|
|
11
|
+
import { paletteTokens, type PaletteColor } from '../../palette/palette';
|
|
12
|
+
import styles from './Button.module.scss';
|
|
13
|
+
|
|
14
|
+
/** Visual variant. See ButtonProps#variant for when to use each. */
|
|
15
|
+
export type ButtonVariant =
|
|
16
|
+
| 'primary'
|
|
17
|
+
| 'secondary'
|
|
18
|
+
| 'ghost'
|
|
19
|
+
| 'danger'
|
|
20
|
+
| 'danger-outline'
|
|
21
|
+
| 'success';
|
|
22
|
+
|
|
23
|
+
/** Control height. See ButtonProps#size for when to use each. */
|
|
24
|
+
export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';
|
|
25
|
+
|
|
26
|
+
interface ButtonOwnProps {
|
|
27
|
+
/**
|
|
28
|
+
* Visual variant.
|
|
29
|
+
* - `primary` (default) — the section's main action. Use **one** per page section.
|
|
30
|
+
* - `secondary` — supporting actions like "Cancel", "Export", "Filter".
|
|
31
|
+
* - `ghost` — tertiary actions in dense UIs (toolbar buttons, row actions).
|
|
32
|
+
* - `danger` — destructive operations only (Delete, Revoke, Remove). Pair with a confirmation if irreversible.
|
|
33
|
+
* - `danger-outline` — a destructive action that must not dominate: surface
|
|
34
|
+
* fill, danger text and border. For a Remove repeated on every row, or a
|
|
35
|
+
* destructive action beside a primary one. Use filled `danger` for the
|
|
36
|
+
* confirm step itself.
|
|
37
|
+
* - `success` — **transient confirmation only**, not an initial state. Flip to
|
|
38
|
+
* `success` for ~1.5s after an action resolves (Save → "Saved!"), then
|
|
39
|
+
* flip back. Never render a button as `success` on mount — it has no
|
|
40
|
+
* action-intent meaning, only post-action feedback. See the `@example`
|
|
41
|
+
* below for the timer pattern.
|
|
42
|
+
*/
|
|
43
|
+
variant?: ButtonVariant;
|
|
44
|
+
/**
|
|
45
|
+
* Control height (matches the shared `--size-*` scale used by Input and Avatar).
|
|
46
|
+
* - `xs` (20px) — icon-only or very dense inline actions (row controls,
|
|
47
|
+
* chip-adjacent buttons). Pass `aria-label` when icon-only. Below WCAG
|
|
48
|
+
* 2.5.5 Level AAA touch-target guidance; reserve for desktop-first surfaces.
|
|
49
|
+
* - `sm` (24px) — dense toolbars, tables, inline actions.
|
|
50
|
+
* - `md` (32px, default) — most contexts.
|
|
51
|
+
* - `lg` (40px) — marketing-style empty states or emphasized primary actions.
|
|
52
|
+
*/
|
|
53
|
+
size?: ButtonSize;
|
|
54
|
+
/**
|
|
55
|
+
* Render the button as a square icon-only target — `aspect-ratio` is forced
|
|
56
|
+
* to 1 so width tracks the size's `height` token (`xs` → 20×20, `sm` → 24×24,
|
|
57
|
+
* `md` → 32×32, `lg` → 40×40) and `padding` is tightened to a small inset
|
|
58
|
+
* (4px) so the icon has breathing room without changing the outer shape.
|
|
59
|
+
*
|
|
60
|
+
* **Always pass `aria-label`** when `iconOnly` is set, otherwise the button
|
|
61
|
+
* has no accessible name. Pass a single icon as `children`.
|
|
62
|
+
*
|
|
63
|
+
* Use for inline density (row controls, chip-adjacent actions, toolbar
|
|
64
|
+
* affordances). For an icon + short text label, leave `iconOnly` off — the
|
|
65
|
+
* button will lay out as a normal rectangle with the existing gap.
|
|
66
|
+
*/
|
|
67
|
+
iconOnly?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Controlled persistent paint for an applied filter or toolbar value.
|
|
70
|
+
* Selected paint applies only to `secondary` and `ghost` Buttons;
|
|
71
|
+
* `primary`, `danger`, and `success` retain their intent paint. This prop is
|
|
72
|
+
* visual only and does not add toggle-button semantics. Pass native
|
|
73
|
+
* `aria-pressed` explicitly only when activating the Button itself toggles
|
|
74
|
+
* the selected state; menu and disclosure triggers keep their own semantics.
|
|
75
|
+
* The consumer owns the state. Not for transient success feedback or for
|
|
76
|
+
* mutually exclusive `<ButtonGroup>` choices. Defaults to `undefined` (not
|
|
77
|
+
* selected).
|
|
78
|
+
*/
|
|
79
|
+
selected?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Paint the button with a palette color's soft pair
|
|
82
|
+
* (`--color-palette-<color>-bg` fill, `-fg` text) — the same pair a
|
|
83
|
+
* palette-colored `<PillMenu>` or `<Badge color>` uses, in both themes.
|
|
84
|
+
* For a quick action that moves a record to a status and must look like
|
|
85
|
+
* that status's pill (amber "No show" beside an amber status PillMenu).
|
|
86
|
+
* Not a decorative stand-in for `danger`/`success`: palette colors carry
|
|
87
|
+
* no meaning. When set it wins over `variant` and `selected` (like
|
|
88
|
+
* `<Badge color>` over `tone`). Hover/pressed darken via
|
|
89
|
+
* `filter: brightness()`. Defaults to `undefined` (use `variant`).
|
|
90
|
+
*/
|
|
91
|
+
color?: PaletteColor;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Polymorphic props helper. Intersects the component's own props with the
|
|
96
|
+
* underlying element's props (minus what we own), plus the `as` selector.
|
|
97
|
+
* Mirrors `<Link>`.
|
|
98
|
+
*/
|
|
99
|
+
type PolymorphicProps<C extends ElementType, P> = P & {
|
|
100
|
+
/**
|
|
101
|
+
* Render a different element — the case that matters is `as="a"` with
|
|
102
|
+
* `href`, for a link that must LOOK like a button (an external console, a
|
|
103
|
+
* download, an IdP hand-off). The element named here is what actually
|
|
104
|
+
* renders, and its own attributes are typed: `href` is REQUIRED when
|
|
105
|
+
* `as="a"` (an anchor without one is neither focusable nor a link) and
|
|
106
|
+
* rejected otherwise; `target`/`rel`/`download` come through. Never navigate from `onClick`.
|
|
107
|
+
*
|
|
108
|
+
* Reach for `<Link>` first. `<Link>` is link-SHAPED navigation — inline text
|
|
109
|
+
* in a sentence, a table cell, a breadcrumb. `<Button as="a">` is for a
|
|
110
|
+
* destination that sits in a row of buttons and must carry their weight.
|
|
111
|
+
* Either way the element is a real anchor, so assistive tech announces a
|
|
112
|
+
* link and the browser gives middle-click, "open in new tab", and the status
|
|
113
|
+
* bar preview — none of which a `<button onClick={() => navigate()}>` has.
|
|
114
|
+
*
|
|
115
|
+
* `type="button"` is emitted only for a real `<button>`; an anchor never
|
|
116
|
+
* gets it. Everything else — variant, size, `iconOnly`, `selected`, the
|
|
117
|
+
* focus ring — is unchanged.
|
|
118
|
+
*
|
|
119
|
+
* @default 'button'
|
|
120
|
+
*/
|
|
121
|
+
as?: C;
|
|
122
|
+
} & Omit<ComponentPropsWithoutRef<C>, keyof P | 'as'> &
|
|
123
|
+
// `href` is optional on every anchor in the DOM typings, so `as="a"` alone
|
|
124
|
+
// would compile to an element that is neither focusable nor a link — the
|
|
125
|
+
// silent shape #530 is about. Required here instead. The conditional is
|
|
126
|
+
// deferred until `C` is known, so `as={RouterLink}` (which names its URL
|
|
127
|
+
// prop `to`) and every non-anchor element are untouched.
|
|
128
|
+
(C extends 'a' ? { href: string } : unknown);
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Public Button prop type. Generic `C` defaults to `'button'`, so a Button
|
|
132
|
+
* with no `as` accepts exactly the `<button>` attributes it always did — and
|
|
133
|
+
* still rejects `href`. With `as="a"`, the anchor's attributes (`href`,
|
|
134
|
+
* `target`, `rel`, `download`) become available instead.
|
|
135
|
+
*/
|
|
136
|
+
export type ButtonProps<C extends ElementType = 'button'> = PolymorphicProps<C, ButtonOwnProps>;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Internal generic-preserving signature. React's `forwardRef` strips the
|
|
140
|
+
* generic from the returned component, so it is re-attached via the cast on
|
|
141
|
+
* the export below.
|
|
142
|
+
*/
|
|
143
|
+
type ButtonComponent = {
|
|
144
|
+
<C extends ElementType = 'button'>(
|
|
145
|
+
props: ButtonProps<C> & { ref?: ComponentPropsWithRef<C>['ref'] },
|
|
146
|
+
): ReactElement | null;
|
|
147
|
+
/** Kept on the type because the cast below would otherwise drop it. */
|
|
148
|
+
displayName?: string;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Action trigger. Renders a `<button type="button">` and forwards refs and HTML attributes.
|
|
153
|
+
* @see docs/components/Button.md
|
|
154
|
+
*/
|
|
155
|
+
export const Button = forwardRef(function Button<C extends ElementType = 'button'>(
|
|
156
|
+
{
|
|
157
|
+
as,
|
|
158
|
+
variant = 'primary',
|
|
159
|
+
size = 'md',
|
|
160
|
+
iconOnly = false,
|
|
161
|
+
selected,
|
|
162
|
+
color,
|
|
163
|
+
className,
|
|
164
|
+
style,
|
|
165
|
+
...props
|
|
166
|
+
}: ButtonProps<C>,
|
|
167
|
+
ref: ForwardedRef<Element>,
|
|
168
|
+
) {
|
|
169
|
+
const Component = (as || 'button') as ElementType;
|
|
170
|
+
const palette = color ? paletteTokens(color) : undefined;
|
|
171
|
+
const paintsSelected = !palette && selected && (variant === 'secondary' || variant === 'ghost');
|
|
172
|
+
|
|
173
|
+
// `type="button"` is a <button>-only guarantee — it stops the button
|
|
174
|
+
// submitting an ancestor form. An anchor's `type` is a MIME hint, so
|
|
175
|
+
// emitting the default there would be wrong; #530 rendered a <button> with a
|
|
176
|
+
// dead `href` for the mirror-image reason. A consumer-supplied `type` still
|
|
177
|
+
// wins: it rides along in {...props}, spread last.
|
|
178
|
+
const defaultType = Component === 'button' ? { type: 'button' as const } : undefined;
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<Component
|
|
182
|
+
ref={ref}
|
|
183
|
+
{...defaultType}
|
|
184
|
+
className={clsx(
|
|
185
|
+
styles.button,
|
|
186
|
+
palette ? styles.palette : styles[variant],
|
|
187
|
+
styles[size],
|
|
188
|
+
iconOnly && styles.iconOnly,
|
|
189
|
+
paintsSelected && styles.selected,
|
|
190
|
+
className,
|
|
191
|
+
)}
|
|
192
|
+
style={
|
|
193
|
+
palette
|
|
194
|
+
? ({
|
|
195
|
+
'--button-palette-bg': palette.bg,
|
|
196
|
+
'--button-palette-fg': palette.fg,
|
|
197
|
+
...style,
|
|
198
|
+
} as CSSProperties)
|
|
199
|
+
: style
|
|
200
|
+
}
|
|
201
|
+
// {...props} last so consumers can supply native semantics such as aria-pressed.
|
|
202
|
+
{...props}
|
|
203
|
+
/>
|
|
204
|
+
);
|
|
205
|
+
}) as ButtonComponent;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
@use '../../styles/mixins' as *;
|
|
2
|
+
@use './ButtonGroup.tokens';
|
|
3
|
+
|
|
4
|
+
// ─── Visual mode ────────────────────────────────────────────────────────
|
|
5
|
+
// Joined Button children: flatten inner borders, round outer corners.
|
|
6
|
+
// Targets the native `> button` element so we don't have to know Button's
|
|
7
|
+
// CSS Module hash.
|
|
8
|
+
|
|
9
|
+
.group[data-mode='visual'] {
|
|
10
|
+
display: inline-flex;
|
|
11
|
+
|
|
12
|
+
// Don't stretch to fill cross-axis when placed inside a flex/grid parent
|
|
13
|
+
// (e.g. Stack with default align="stretch"). A joined button group is an
|
|
14
|
+
// intrinsically compact UI control — like Button itself, like Tabs — and
|
|
15
|
+
// should not expand to container width. Rule 4 disallows align-self in
|
|
16
|
+
// general; this is the documented exception for inline-shaped UI controls.
|
|
17
|
+
// stylelint-disable-next-line property-disallowed-list -- inline control intrinsic shrink
|
|
18
|
+
align-self: flex-start;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.group[data-mode='visual'] > button {
|
|
22
|
+
border-radius: 0;
|
|
23
|
+
|
|
24
|
+
// -1px margin pulls each adjacent border into a single line. Rule 4 normally
|
|
25
|
+
// disallows margin on components, but this is the canonical border-collapse
|
|
26
|
+
// technique for joined buttons — transform: translateX doesn't work because
|
|
27
|
+
// it leaves the cumulative seam-to-seam gap uncollapsed past the first pair.
|
|
28
|
+
// stylelint-disable-next-line property-disallowed-list -- border-collapse for joined siblings
|
|
29
|
+
margin-left: calc(var(--border-width) * -1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.group[data-mode='visual'] > button:first-child {
|
|
33
|
+
// stylelint-disable-next-line property-disallowed-list -- counterpart to the join above
|
|
34
|
+
margin-left: 0;
|
|
35
|
+
border-top-left-radius: var(--button-group-radius);
|
|
36
|
+
border-bottom-left-radius: var(--button-group-radius);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.group[data-mode='visual'] > button:last-child {
|
|
40
|
+
border-top-right-radius: var(--button-group-radius);
|
|
41
|
+
border-bottom-right-radius: var(--button-group-radius);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Lift on hover/focus. NOT for the ring — an outline paints after every
|
|
45
|
+
// descendant background in its stacking context, so it already draws over a
|
|
46
|
+
// joined sibling unlifted, and the segmented lift added on that false premise
|
|
47
|
+
// was removed. This is for the BORDER: these children collapse their borders
|
|
48
|
+
// with `margin-left: -1px`, so without the lift the later sibling's left border
|
|
49
|
+
// paints over the hovered button's right one.
|
|
50
|
+
.group[data-mode='visual'] > button:hover,
|
|
51
|
+
.group[data-mode='visual'] > button:focus-visible {
|
|
52
|
+
position: relative;
|
|
53
|
+
z-index: 1;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ─── Segmented mode ─────────────────────────────────────────────────────
|
|
57
|
+
// Pill-inset look matching iOS / Material precedent. Owns its own styling
|
|
58
|
+
// — items are NOT Buttons, they're internal radio-role <button>s.
|
|
59
|
+
|
|
60
|
+
.group[data-mode='segmented'] {
|
|
61
|
+
background: var(--button-group-segmented-bg);
|
|
62
|
+
border-radius: var(--button-group-segmented-radius);
|
|
63
|
+
padding: var(--button-group-segmented-padding);
|
|
64
|
+
display: inline-flex;
|
|
65
|
+
gap: var(--button-group-segmented-gap);
|
|
66
|
+
|
|
67
|
+
// Shrink-to-content inside flex/grid parents (e.g. Stack with align=stretch).
|
|
68
|
+
// Documented Rule-4 exception for intrinsically compact inline controls.
|
|
69
|
+
// stylelint-disable-next-line property-disallowed-list -- inline control intrinsic shrink
|
|
70
|
+
align-self: flex-start;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.item {
|
|
74
|
+
border: none;
|
|
75
|
+
background: transparent;
|
|
76
|
+
color: var(--button-group-item-fg);
|
|
77
|
+
cursor: pointer;
|
|
78
|
+
font: inherit;
|
|
79
|
+
white-space: nowrap;
|
|
80
|
+
border-radius: calc(var(--button-group-segmented-radius) - var(--button-group-segmented-padding));
|
|
81
|
+
transition:
|
|
82
|
+
background var(--transition-fast),
|
|
83
|
+
color var(--transition-fast);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.item[data-selected] {
|
|
87
|
+
background: var(--button-group-item-bg-selected);
|
|
88
|
+
color: var(--button-group-item-fg-selected);
|
|
89
|
+
box-shadow: var(--button-group-item-shadow-selected);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.item:hover:not([data-selected], [aria-disabled]) {
|
|
93
|
+
color: var(--button-group-item-fg-hover);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.item[aria-disabled] {
|
|
97
|
+
cursor: not-allowed;
|
|
98
|
+
opacity: var(--button-group-item-opacity-disabled);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.item:focus-visible {
|
|
102
|
+
@include focus-ring;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Size variants — the TRACK matches Button's --size-* height, so a segmented
|
|
106
|
+
// control lines up with a same-size Button. Items give back the track's
|
|
107
|
+
// padding on both sides.
|
|
108
|
+
.sizeXs {
|
|
109
|
+
height: calc(var(--button-group-item-height-xs) - 2 * var(--button-group-segmented-padding));
|
|
110
|
+
padding: 0 var(--button-group-item-padding-x-xs);
|
|
111
|
+
font-size: var(--button-group-item-font-size-xs);
|
|
112
|
+
|
|
113
|
+
// 16px item: pin the line box so an inherited taller line-height (e.g.
|
|
114
|
+
// 1.5 × 11px = 16.5px from a consumer ancestor) can't overflow it.
|
|
115
|
+
line-height: var(--line-height-none);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.sizeSm {
|
|
119
|
+
height: calc(var(--button-group-item-height-sm) - 2 * var(--button-group-segmented-padding));
|
|
120
|
+
padding: 0 var(--button-group-item-padding-x-sm);
|
|
121
|
+
font-size: var(--button-group-item-font-size-sm);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.sizeMd {
|
|
125
|
+
height: calc(var(--button-group-item-height-md) - 2 * var(--button-group-segmented-padding));
|
|
126
|
+
padding: 0 var(--button-group-item-padding-x-md);
|
|
127
|
+
font-size: var(--button-group-item-font-size-md);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.sizeLg {
|
|
131
|
+
height: calc(var(--button-group-item-height-lg) - 2 * var(--button-group-segmented-padding));
|
|
132
|
+
padding: 0 var(--button-group-item-padding-x-lg);
|
|
133
|
+
font-size: var(--button-group-item-font-size-lg);
|
|
134
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// ButtonGroup.tokens.scss — component-scoped tokens for <ButtonGroup>. Visual mode joins Button children; segmented mode owns its own pill-inset styling.
|
|
2
|
+
:root {
|
|
3
|
+
// Visual mode — outer-corner radius applied to first/last children
|
|
4
|
+
--button-group-radius: var(--radius-md);
|
|
5
|
+
|
|
6
|
+
// Segmented mode — track surface + shape
|
|
7
|
+
--button-group-segmented-bg: var(--color-bg-muted);
|
|
8
|
+
--button-group-segmented-radius: var(--radius-md);
|
|
9
|
+
--button-group-segmented-padding: var(--space-05);
|
|
10
|
+
--button-group-segmented-gap: var(--space-05);
|
|
11
|
+
|
|
12
|
+
// Segmented item — base appearance
|
|
13
|
+
--button-group-item-fg: var(--color-fg-muted);
|
|
14
|
+
--button-group-item-fg-hover: var(--color-fg);
|
|
15
|
+
|
|
16
|
+
// Segmented item — selected state
|
|
17
|
+
--button-group-item-bg-selected: var(--color-bg);
|
|
18
|
+
--button-group-item-fg-selected: var(--color-fg);
|
|
19
|
+
|
|
20
|
+
// --shadow-xs has never existed; the scale is sm/md/lg, so this resolved to
|
|
21
|
+
// nothing and the selected item rendered with no shadow at all. sm is the
|
|
22
|
+
// smallest step and what "xs" was reaching for.
|
|
23
|
+
--button-group-item-shadow-selected: var(--shadow-sm);
|
|
24
|
+
|
|
25
|
+
// Segmented item — disabled
|
|
26
|
+
--button-group-item-opacity-disabled: var(--opacity-disabled);
|
|
27
|
+
|
|
28
|
+
// Segmented — sizes. Height = the outer TRACK (matches Button --size-*);
|
|
29
|
+
// each item renders at this minus 2 × --button-group-segmented-padding.
|
|
30
|
+
--button-group-item-height-xs: var(--size-xs);
|
|
31
|
+
--button-group-item-height-sm: var(--size-sm);
|
|
32
|
+
--button-group-item-height-md: var(--size-md);
|
|
33
|
+
--button-group-item-height-lg: var(--size-lg);
|
|
34
|
+
--button-group-item-padding-x-xs: var(--space-2);
|
|
35
|
+
--button-group-item-padding-x-sm: var(--space-3);
|
|
36
|
+
--button-group-item-padding-x-md: var(--space-3);
|
|
37
|
+
--button-group-item-padding-x-lg: var(--space-4);
|
|
38
|
+
--button-group-item-font-size-xs: var(--font-size-xs);
|
|
39
|
+
--button-group-item-font-size-sm: var(--font-size-sm);
|
|
40
|
+
--button-group-item-font-size-md: var(--font-size-md);
|
|
41
|
+
--button-group-item-font-size-lg: var(--font-size-md);
|
|
42
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
cloneElement,
|
|
4
|
+
isValidElement,
|
|
5
|
+
useCallback,
|
|
6
|
+
useEffect,
|
|
7
|
+
useMemo,
|
|
8
|
+
useRef,
|
|
9
|
+
useState,
|
|
10
|
+
type CSSProperties,
|
|
11
|
+
type HTMLAttributes,
|
|
12
|
+
type KeyboardEvent,
|
|
13
|
+
type ReactElement,
|
|
14
|
+
} from 'react';
|
|
15
|
+
import clsx from 'clsx';
|
|
16
|
+
import { Button, type ButtonProps } from '../Button';
|
|
17
|
+
import { ButtonGroupContext, type ButtonGroupContextValue, type ButtonGroupSize } from './context';
|
|
18
|
+
import { ButtonGroupItem } from './ButtonGroupItem';
|
|
19
|
+
import styles from './ButtonGroup.module.scss';
|
|
20
|
+
|
|
21
|
+
export type { ButtonGroupSize } from './context';
|
|
22
|
+
export type { ButtonGroupItemProps } from './ButtonGroupItem';
|
|
23
|
+
|
|
24
|
+
interface ButtonGroupBase {
|
|
25
|
+
/**
|
|
26
|
+
* Size propagated to children. Per-child `size` (Button or Item) wins
|
|
27
|
+
* when explicitly set. In visual mode this happens via cloneElement on
|
|
28
|
+
* Button children. In segmented mode, `<ButtonGroup.Item>` reads from
|
|
29
|
+
* context.
|
|
30
|
+
*/
|
|
31
|
+
size?: ButtonGroupSize;
|
|
32
|
+
/**
|
|
33
|
+
* Disabled state for the whole group. In segmented mode this is
|
|
34
|
+
* authoritative (all items become aria-disabled, clicks no-op). In
|
|
35
|
+
* visual mode this is a no-op — pass `disabled` per `<Button>` instead.
|
|
36
|
+
*/
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Segmented mode: `aria-invalid` on the radiogroup. Visual mode: consumed
|
|
40
|
+
* and ignored. Field / SettingRow inject it — it used to leak onto the
|
|
41
|
+
* group div as a stray attribute (#568). @default false
|
|
42
|
+
*/
|
|
43
|
+
invalid?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Segmented mode: `aria-required` on the radiogroup. Visual mode: consumed
|
|
46
|
+
* and ignored. Field / SettingRow inject it (#568). @default false
|
|
47
|
+
*/
|
|
48
|
+
required?: boolean;
|
|
49
|
+
className?: string;
|
|
50
|
+
style?: CSSProperties;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface ButtonGroupVisualProps
|
|
54
|
+
extends ButtonGroupBase, Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
55
|
+
/** Visual mode marker. Never set; absence flips to visual. */
|
|
56
|
+
value?: never;
|
|
57
|
+
onValueChange?: never;
|
|
58
|
+
/** Accessible name for the group landmark. Optional but recommended. */
|
|
59
|
+
'aria-label'?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface ButtonGroupSegmentedProps
|
|
63
|
+
extends ButtonGroupBase, Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
64
|
+
/** Currently-selected item value. Triggers segmented mode. */
|
|
65
|
+
value: string;
|
|
66
|
+
/**
|
|
67
|
+
* Fired when a different Item is selected.
|
|
68
|
+
*
|
|
69
|
+
* Consumers wanting literal-union narrowing can cast the setter:
|
|
70
|
+
* `onValueChange={(v) => setView(v as 'grid' | 'list')}`.
|
|
71
|
+
*/
|
|
72
|
+
onValueChange: (next: string) => void;
|
|
73
|
+
/** Required in segmented mode (radiogroup needs a label). */
|
|
74
|
+
'aria-label': string;
|
|
75
|
+
/** Alternative to aria-label: id of an external labelling element. */
|
|
76
|
+
'aria-labelledby'?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type ButtonGroupProps = ButtonGroupVisualProps | ButtonGroupSegmentedProps;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Compound. Visual mode joins Buttons; segmented mode (`value` + `onValueChange`) is a single-select radiogroup.
|
|
83
|
+
* @see docs/components/ButtonGroup.md
|
|
84
|
+
*/
|
|
85
|
+
export function ButtonGroupRoot(props: ButtonGroupProps) {
|
|
86
|
+
const isSegmented = 'value' in props && props.value !== undefined;
|
|
87
|
+
return isSegmented ? (
|
|
88
|
+
<Segmented {...(props as ButtonGroupSegmentedProps)} />
|
|
89
|
+
) : (
|
|
90
|
+
<Visual {...(props as ButtonGroupVisualProps)} />
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function Visual({
|
|
95
|
+
size = 'md',
|
|
96
|
+
disabled: _disabled,
|
|
97
|
+
// Consumed so Field-injected props never reach the div (#568).
|
|
98
|
+
invalid: _invalid,
|
|
99
|
+
required: _required,
|
|
100
|
+
children,
|
|
101
|
+
className,
|
|
102
|
+
style,
|
|
103
|
+
'aria-label': ariaLabel,
|
|
104
|
+
...rest
|
|
105
|
+
}: ButtonGroupVisualProps) {
|
|
106
|
+
// Inject size into Button children whose size isn't already set.
|
|
107
|
+
const processed = Children.map(children, (child) => {
|
|
108
|
+
if (!isValidElement(child)) return child;
|
|
109
|
+
if (child.type !== Button) return child;
|
|
110
|
+
const childProps = child.props as ButtonProps;
|
|
111
|
+
if (childProps.size !== undefined) return child;
|
|
112
|
+
return cloneElement(child as ReactElement<ButtonProps>, { size });
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<div
|
|
117
|
+
{...rest}
|
|
118
|
+
// {...rest} first so the ARIA contract (role, aria-label, data-mode)
|
|
119
|
+
// can't be silently broken by a stray consumer prop.
|
|
120
|
+
role="group"
|
|
121
|
+
aria-label={ariaLabel}
|
|
122
|
+
data-mode="visual"
|
|
123
|
+
className={clsx(styles.group, className)}
|
|
124
|
+
style={style}
|
|
125
|
+
>
|
|
126
|
+
{processed}
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function Segmented({
|
|
132
|
+
size = 'md',
|
|
133
|
+
disabled = false,
|
|
134
|
+
value,
|
|
135
|
+
onValueChange,
|
|
136
|
+
children,
|
|
137
|
+
className,
|
|
138
|
+
style,
|
|
139
|
+
'aria-label': ariaLabel,
|
|
140
|
+
'aria-labelledby': ariaLabelledBy,
|
|
141
|
+
invalid = false,
|
|
142
|
+
required = false,
|
|
143
|
+
...rest
|
|
144
|
+
}: ButtonGroupSegmentedProps) {
|
|
145
|
+
// groupRef enables DOM-order querying for keyboard nav so that consumer-
|
|
146
|
+
// reordered children are always walked in their actual visual order.
|
|
147
|
+
const groupRef = useRef<HTMLDivElement | null>(null);
|
|
148
|
+
|
|
149
|
+
// Dev warning: aria-label or aria-labelledby required in segmented mode.
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
if (process.env.NODE_ENV === 'production') return;
|
|
152
|
+
let cancelled = false;
|
|
153
|
+
queueMicrotask(() => {
|
|
154
|
+
if (cancelled) return;
|
|
155
|
+
if (!ariaLabel && !ariaLabelledBy) {
|
|
156
|
+
console.warn(
|
|
157
|
+
'<ButtonGroup> in segmented mode requires an `aria-label` or `aria-labelledby` prop for screen readers.',
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
return () => {
|
|
162
|
+
cancelled = true;
|
|
163
|
+
};
|
|
164
|
+
}, [ariaLabel, ariaLabelledBy]);
|
|
165
|
+
|
|
166
|
+
// Which item holds the tab stop when nothing is selected. Read from the DOM
|
|
167
|
+
// after each commit so consumer-reordered children resolve in visual order,
|
|
168
|
+
// exactly like handleItemKeyDown below. Runs unconditionally but only sets
|
|
169
|
+
// state when the answer actually changes, so it cannot loop.
|
|
170
|
+
const [rovingFallbackValue, setRovingFallbackValue] = useState<string | null>(null);
|
|
171
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- runs after every commit by design; the setter bails out when unchanged
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
const root = groupRef.current;
|
|
174
|
+
if (!root) return;
|
|
175
|
+
const items = [...root.querySelectorAll<HTMLButtonElement>('button[role="radio"]')];
|
|
176
|
+
const anySelected = items.some((el) => el.getAttribute('aria-checked') === 'true');
|
|
177
|
+
const firstEnabled = items.find((el) => el.getAttribute('aria-disabled') !== 'true');
|
|
178
|
+
// `?? items[0]` for the all-disabled group. Items carry `aria-disabled`,
|
|
179
|
+
// not the native `disabled`, precisely so they STAY focusable — a user can
|
|
180
|
+
// tab to them and hear why the choice is unavailable. Falling back to null
|
|
181
|
+
// here left every item at `tabIndex={-1}`, so the group vanished from the
|
|
182
|
+
// tab order entirely, which is the behaviour `aria-disabled` was chosen to
|
|
183
|
+
// avoid.
|
|
184
|
+
const next = anySelected ? null : ((firstEnabled ?? items[0])?.dataset.value ?? null);
|
|
185
|
+
setRovingFallbackValue((prev) => (prev === next ? prev : next));
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const handleItemKeyDown = useCallback(
|
|
189
|
+
(e: KeyboardEvent<HTMLButtonElement>, currentValue: string) => {
|
|
190
|
+
const root = groupRef.current;
|
|
191
|
+
if (!root) return;
|
|
192
|
+
// Query DOM order so reordered children are walked correctly.
|
|
193
|
+
const allButtons = Array.from(
|
|
194
|
+
root.querySelectorAll<HTMLButtonElement>('button[role="radio"]'),
|
|
195
|
+
);
|
|
196
|
+
const enabledButtons = allButtons.filter(
|
|
197
|
+
(btn) => btn.getAttribute('aria-disabled') !== 'true',
|
|
198
|
+
);
|
|
199
|
+
if (enabledButtons.length === 0) return;
|
|
200
|
+
|
|
201
|
+
// Find the focused button in the enabled list. If the currently-selected
|
|
202
|
+
// item is itself disabled (per-item disabled), fall back to the active
|
|
203
|
+
// element so Arrow nav still works from wherever focus is.
|
|
204
|
+
let idx = enabledButtons.findIndex((btn) => btn.dataset.value === currentValue);
|
|
205
|
+
if (idx === -1) {
|
|
206
|
+
// Selected item is disabled — use whichever enabled button is focused.
|
|
207
|
+
idx = enabledButtons.findIndex((btn) => btn === document.activeElement);
|
|
208
|
+
}
|
|
209
|
+
if (idx === -1) return;
|
|
210
|
+
|
|
211
|
+
let nextIdx: number | null = null;
|
|
212
|
+
switch (e.key) {
|
|
213
|
+
case 'ArrowRight':
|
|
214
|
+
case 'ArrowDown':
|
|
215
|
+
nextIdx = (idx + 1) % enabledButtons.length;
|
|
216
|
+
break;
|
|
217
|
+
case 'ArrowLeft':
|
|
218
|
+
case 'ArrowUp':
|
|
219
|
+
nextIdx = (idx - 1 + enabledButtons.length) % enabledButtons.length;
|
|
220
|
+
break;
|
|
221
|
+
case 'Home':
|
|
222
|
+
nextIdx = 0;
|
|
223
|
+
break;
|
|
224
|
+
case 'End':
|
|
225
|
+
nextIdx = enabledButtons.length - 1;
|
|
226
|
+
break;
|
|
227
|
+
default:
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
e.preventDefault();
|
|
232
|
+
const next = enabledButtons[nextIdx]!;
|
|
233
|
+
if (!disabled) onValueChange(next.dataset.value!);
|
|
234
|
+
next.focus();
|
|
235
|
+
},
|
|
236
|
+
[disabled, onValueChange],
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
const contextValue = useMemo<ButtonGroupContextValue>(
|
|
240
|
+
() => ({
|
|
241
|
+
value,
|
|
242
|
+
onValueChange,
|
|
243
|
+
size,
|
|
244
|
+
disabled,
|
|
245
|
+
handleItemKeyDown,
|
|
246
|
+
rovingFallbackValue,
|
|
247
|
+
}),
|
|
248
|
+
[value, onValueChange, size, disabled, handleItemKeyDown, rovingFallbackValue],
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
<ButtonGroupContext.Provider value={contextValue}>
|
|
253
|
+
<div
|
|
254
|
+
ref={groupRef}
|
|
255
|
+
{...rest}
|
|
256
|
+
// {...rest} first so the ARIA contract (role, aria-label, data-mode)
|
|
257
|
+
// can't be silently broken by a stray consumer prop.
|
|
258
|
+
role="radiogroup"
|
|
259
|
+
aria-label={ariaLabel}
|
|
260
|
+
aria-labelledby={ariaLabelledBy}
|
|
261
|
+
aria-disabled={disabled || undefined}
|
|
262
|
+
aria-invalid={invalid || undefined}
|
|
263
|
+
aria-required={required || undefined}
|
|
264
|
+
data-mode="segmented"
|
|
265
|
+
className={clsx(styles.group, className)}
|
|
266
|
+
style={style}
|
|
267
|
+
>
|
|
268
|
+
{children}
|
|
269
|
+
</div>
|
|
270
|
+
</ButtonGroupContext.Provider>
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Compound: `<ButtonGroup>` with `<ButtonGroup.Item>` attached.
|
|
276
|
+
* @see docs/components/ButtonGroup.md
|
|
277
|
+
*/
|
|
278
|
+
export const ButtonGroup = Object.assign(ButtonGroupRoot, { Item: ButtonGroupItem });
|