@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,538 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useEffect,
|
|
4
|
+
useId,
|
|
5
|
+
useLayoutEffect,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
type HTMLAttributes,
|
|
9
|
+
type KeyboardEvent,
|
|
10
|
+
type ReactNode,
|
|
11
|
+
} from 'react';
|
|
12
|
+
import clsx from 'clsx';
|
|
13
|
+
import styles from './Tabs.module.scss';
|
|
14
|
+
|
|
15
|
+
/** One tab in the tablist. */
|
|
16
|
+
export interface TabItem {
|
|
17
|
+
/** Stable identifier — used for `activeId`/`onChange` and id generation. Must be unique within the items array. */
|
|
18
|
+
id: string;
|
|
19
|
+
/** Visible label for the tab. */
|
|
20
|
+
label: string;
|
|
21
|
+
/** Optional count chip shown next to the label (e.g. "Activity · 12"). */
|
|
22
|
+
count?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Optional leading icon rendered before the label. Typically a `lucide-react`
|
|
25
|
+
* icon. Sized via CSS to match the label's line height. Rendered with
|
|
26
|
+
* `aria-hidden="true"` (decorative — the label carries the accessible name).
|
|
27
|
+
*/
|
|
28
|
+
icon?: ReactNode;
|
|
29
|
+
/**
|
|
30
|
+
* Optional leading adornment rendered before the icon/label (e.g. a status
|
|
31
|
+
* dot). Rendered as-is (NOT `aria-hidden`): if purely decorative mark your
|
|
32
|
+
* node `aria-hidden`; if meaningful, give it accessible text so it joins the
|
|
33
|
+
* tab's accessible name. Distinct from `icon`, which is always decorative.
|
|
34
|
+
*/
|
|
35
|
+
leading?: ReactNode;
|
|
36
|
+
/**
|
|
37
|
+
* Optional trailing adornment rendered at the end of the tab (e.g. an
|
|
38
|
+
* unsaved-changes badge or status `Badge`). In `vertical` orientation it is
|
|
39
|
+
* pinned to the row's far-right edge; in `horizontal` it follows the label/
|
|
40
|
+
* count. Rendered as-is (NOT `aria-hidden`) — same a11y note as `leading`.
|
|
41
|
+
*/
|
|
42
|
+
trailing?: ReactNode;
|
|
43
|
+
/**
|
|
44
|
+
* Interactive control(s) for this tab (a `Switch`, a close button, a `⋯`
|
|
45
|
+
* menu), rendered OUTSIDE the tab's `role="tab"` button so the markup is
|
|
46
|
+
* valid and the control is focusable and keyboard-operable. For STATIC
|
|
47
|
+
* adornments (a `Badge`, a status dot, a numeric count) use
|
|
48
|
+
* `leading`/`trailing`/`count` — those render inside the button. Not
|
|
49
|
+
* `aria-hidden`; give controls an accessible label. Adds a Tab stop.
|
|
50
|
+
*/
|
|
51
|
+
actions?: ReactNode;
|
|
52
|
+
/**
|
|
53
|
+
* Extra `data-*` attributes spread onto this tab's `role="tab"` button
|
|
54
|
+
* (e.g. `{ 'data-tour': 'security-tab' }` to target it from a `Tour`, or a
|
|
55
|
+
* test/analytics id). Spread first, so a key here can't override the
|
|
56
|
+
* `id` / `role` / `aria-*` / handlers Tabs owns on the button.
|
|
57
|
+
*/
|
|
58
|
+
attrs?: Record<`data-${string}`, string>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A trailing action rendered after the tab items in the same strip (e.g. a
|
|
63
|
+
* `+ New deal` pseudo-tab). Rendered as a real `<button type="button">`, NOT
|
|
64
|
+
* `role="tab"` — it has no tabpanel to control, is excluded from the
|
|
65
|
+
* arrow-key roving order, and the animated selection indicator never targets
|
|
66
|
+
* it. Reachable via the Tab key like any ordinary button, right after the
|
|
67
|
+
* currently-focusable tab.
|
|
68
|
+
*/
|
|
69
|
+
export interface TabsAction {
|
|
70
|
+
/** Visible label. Also the button's accessible name — no separate aria-label needed. */
|
|
71
|
+
label: string;
|
|
72
|
+
/** Optional decorative icon rendered before the label. Rendered `aria-hidden` — the label carries the accessible name. */
|
|
73
|
+
icon?: ReactNode;
|
|
74
|
+
/** Called when the button is clicked. Never changes `activeId` or fires `onChange` — wire up your own state (e.g. append a new tab) in the handler. */
|
|
75
|
+
onClick: () => void;
|
|
76
|
+
/** Disables the button (dimmed, non-interactive). Default `false`. */
|
|
77
|
+
disabled?: boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Determines what happens when Arrow keys move focus between tabs.
|
|
82
|
+
* - `auto` (default) — focus and onChange both fire on Arrow. Best for cheap, eager-rendered panels.
|
|
83
|
+
* - `manual` — Arrow only moves focus; Enter/Space activates via native button click. Best for lazy-loaded panels.
|
|
84
|
+
*/
|
|
85
|
+
export type TabsActivationMode = 'auto' | 'manual';
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Tablist layout and `aria-orientation` value. Use `'horizontal'` (the
|
|
89
|
+
* default) for a conventional tab strip or `'vertical'` for a fixed
|
|
90
|
+
* master–detail rail. `'auto'` starts vertical and switches from vertical to
|
|
91
|
+
* horizontal when the available tab-strip width reaches a configurable
|
|
92
|
+
* breakpoint (320px by default); it is for a `Split` rail that becomes a
|
|
93
|
+
* full-width strip when the panes stack.
|
|
94
|
+
*/
|
|
95
|
+
export type TabsOrientation = 'horizontal' | 'vertical' | 'auto';
|
|
96
|
+
|
|
97
|
+
type EffectiveTabsOrientation = Exclude<TabsOrientation, 'auto'>;
|
|
98
|
+
|
|
99
|
+
export interface TabsProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
100
|
+
/** The tabs to render. Each item must have a unique `id`. */
|
|
101
|
+
items: TabItem[];
|
|
102
|
+
/** The id of the currently-active tab. If it doesn't match any item, the strip still stays keyboard-reachable (first tab gets tabindex=0). */
|
|
103
|
+
activeId: string;
|
|
104
|
+
/** Called with the tab id when the user activates a different tab. Won't fire when re-clicking the already-active tab. */
|
|
105
|
+
onChange: (id: string) => void;
|
|
106
|
+
/**
|
|
107
|
+
* Optional id prefix for controlled tabpanels. When set, the ACTIVE tab gets
|
|
108
|
+
* `aria-controls="${panelIdPrefix}-${itemId}-panel"` — the consumer must
|
|
109
|
+
* render the matching panel with that id. When omitted, NO tab carries
|
|
110
|
+
* `aria-controls` at all — the internal id (sanitized React `useId`) named
|
|
111
|
+
* below is the tab's own id, not a panel's, and pointing at it would be the
|
|
112
|
+
* dangling IDREF that was removed.
|
|
113
|
+
*
|
|
114
|
+
* Only the active tab carries it, because consumers render only the active
|
|
115
|
+
* panel; stamping every tab would point N-1 of them at elements that do not
|
|
116
|
+
* exist. Inactive tabs keep their own `id` for the panel's
|
|
117
|
+
* `aria-labelledby` to reference.
|
|
118
|
+
*/
|
|
119
|
+
panelIdPrefix?: string;
|
|
120
|
+
/**
|
|
121
|
+
* `'auto'` (default): arrow keys move focus AND fire onChange — the visible
|
|
122
|
+
* panel changes with each keystroke. Best for cheap, eager-rendered panels.
|
|
123
|
+
*
|
|
124
|
+
* `'manual'`: arrow keys only move focus; Enter/Space (the native button
|
|
125
|
+
* activation keys) then commits via onChange. Use this when panels are
|
|
126
|
+
* expensive (lazy-load, network) so the user can scan tab labels without
|
|
127
|
+
* triggering loads.
|
|
128
|
+
*/
|
|
129
|
+
activationMode?: TabsActivationMode;
|
|
130
|
+
/**
|
|
131
|
+
* `'horizontal'` (default) — a horizontal strip with a sliding underline.
|
|
132
|
+
* `'vertical'` — a stacked master–detail rail: full-width rows, a left accent
|
|
133
|
+
* bar + tinted background on the active row, and ArrowUp/ArrowDown navigation.
|
|
134
|
+
* `'auto'` — measures available Tabs/tab-strip width: vertical below
|
|
135
|
+
* `autoOrientationBreakpoint` and horizontal at or above it. It starts
|
|
136
|
+
* vertical during SSR and whenever `ResizeObserver` is unavailable. Use it
|
|
137
|
+
* with a collapsing `Split`: the fixed-width aside remains a vertical rail,
|
|
138
|
+
* then the full-width stacked tablist becomes horizontal. `aria-orientation`,
|
|
139
|
+
* keyboard navigation, and presentation always follow the effective orientation.
|
|
140
|
+
*/
|
|
141
|
+
orientation?: TabsOrientation;
|
|
142
|
+
/**
|
|
143
|
+
* Available tab-strip width in px where `orientation="auto"` switches from
|
|
144
|
+
* vertical to horizontal. Defaults to `320`. Set this per Tabs instance to
|
|
145
|
+
* align automatic orientation with the surrounding layout's threshold.
|
|
146
|
+
* @default 320
|
|
147
|
+
*/
|
|
148
|
+
autoOrientationBreakpoint?: number;
|
|
149
|
+
/**
|
|
150
|
+
* A trailing action rendered after the tab items, inside the same strip
|
|
151
|
+
* (e.g. `{ label: 'New deal', icon: <Plus/>, onClick: addDeal }`). Styled
|
|
152
|
+
* tab-like but visibly muted, never becomes the selected tab, and is
|
|
153
|
+
* skipped by arrow-key roving — reachable via the Tab key instead. For
|
|
154
|
+
* controls that apply to the whole bar but aren't shaped like a tab (a
|
|
155
|
+
* filter toggle), use `endContent`. For a control on a single tab, use
|
|
156
|
+
* `TabItem.actions`.
|
|
157
|
+
*/
|
|
158
|
+
action?: TabsAction;
|
|
159
|
+
/**
|
|
160
|
+
* Controls for the whole tab bar (e.g. an "add tab" button, a filter
|
|
161
|
+
* toggle), rendered at the end of the strip OUTSIDE the tablist so it never
|
|
162
|
+
* scrolls with the tabs and is not part of tab keyboard navigation. For a
|
|
163
|
+
* control attached to a single tab, use `TabItem.actions` instead.
|
|
164
|
+
*/
|
|
165
|
+
endContent?: ReactNode;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// React 19's useId() can include characters that are valid HTML id values but
|
|
169
|
+
// break CSS selectors (`:r0:` → `#:r0:` is not a valid selector). Sanitize to
|
|
170
|
+
// `[a-zA-Z0-9_-]` so the generated panel ids stay CSS-queryable.
|
|
171
|
+
function sanitizeId(raw: string): string {
|
|
172
|
+
return raw.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Some consumer environments (RSC, edge runtimes) don't define `process`.
|
|
176
|
+
// Read NODE_ENV defensively so the library never throws at module init.
|
|
177
|
+
const IS_DEV = typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production';
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Responsive controlled tab strip (horizontal, vertical or auto) with count chips and leading/trailing adornments, following the WAI-ARIA Tabs pattern.
|
|
181
|
+
* @see docs/components/Tabs.md
|
|
182
|
+
*/
|
|
183
|
+
export const Tabs = forwardRef<HTMLDivElement, TabsProps>(function Tabs(
|
|
184
|
+
{
|
|
185
|
+
items,
|
|
186
|
+
activeId,
|
|
187
|
+
onChange,
|
|
188
|
+
panelIdPrefix,
|
|
189
|
+
activationMode = 'auto',
|
|
190
|
+
orientation = 'horizontal',
|
|
191
|
+
autoOrientationBreakpoint = 320,
|
|
192
|
+
action,
|
|
193
|
+
endContent,
|
|
194
|
+
className,
|
|
195
|
+
...props
|
|
196
|
+
},
|
|
197
|
+
ref,
|
|
198
|
+
) {
|
|
199
|
+
const reactId = useId();
|
|
200
|
+
const prefix = panelIdPrefix ?? sanitizeId(reactId);
|
|
201
|
+
const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({});
|
|
202
|
+
const scrollWrapRef = useRef<HTMLDivElement>(null);
|
|
203
|
+
const rootRef = useRef<HTMLDivElement>(null);
|
|
204
|
+
const endContentRef = useRef<HTMLDivElement>(null);
|
|
205
|
+
const indicatorRef = useRef<HTMLSpanElement>(null);
|
|
206
|
+
const firstMeasureRef = useRef(true);
|
|
207
|
+
const hasEndContent = endContent != null;
|
|
208
|
+
const [automaticOrientation, setAutomaticOrientation] =
|
|
209
|
+
useState<EffectiveTabsOrientation>('vertical');
|
|
210
|
+
const effectiveOrientation: EffectiveTabsOrientation =
|
|
211
|
+
orientation === 'auto' ? automaticOrientation : orientation;
|
|
212
|
+
|
|
213
|
+
useLayoutEffect(() => {
|
|
214
|
+
if (orientation !== 'auto') return;
|
|
215
|
+
// Measure the box that receives the available layout width, rather than
|
|
216
|
+
// the tablist's intrinsic inline-flex width. With end content, the strip
|
|
217
|
+
// shares a stable root row with controls at its end, so its horizontal
|
|
218
|
+
// budget is root width minus the end region's border-box width (including
|
|
219
|
+
// the gap padding). The end region keeps that footprint in both
|
|
220
|
+
// orientations, so the same measurement cannot bounce the mode at the
|
|
221
|
+
// boundary.
|
|
222
|
+
const root = hasEndContent ? rootRef.current : scrollWrapRef.current;
|
|
223
|
+
const end = hasEndContent ? endContentRef.current : null;
|
|
224
|
+
if (!root || (hasEndContent && !end) || typeof ResizeObserver === 'undefined') return;
|
|
225
|
+
|
|
226
|
+
let rootWidth = root.getBoundingClientRect().width;
|
|
227
|
+
let endContentWidth = end?.getBoundingClientRect().width ?? 0;
|
|
228
|
+
const update = () => {
|
|
229
|
+
const availableWidth = Math.max(0, rootWidth - endContentWidth);
|
|
230
|
+
setAutomaticOrientation(
|
|
231
|
+
availableWidth >= autoOrientationBreakpoint ? 'horizontal' : 'vertical',
|
|
232
|
+
);
|
|
233
|
+
};
|
|
234
|
+
const observer = new ResizeObserver((entries) => {
|
|
235
|
+
for (const entry of entries) {
|
|
236
|
+
// contentRect excludes padding, but the end-content gap consumes real
|
|
237
|
+
// horizontal strip space. Read the border box from the observed target.
|
|
238
|
+
const width = entry.target.getBoundingClientRect().width;
|
|
239
|
+
if (entry.target === root) rootWidth = width;
|
|
240
|
+
if (entry.target === end) endContentWidth = width;
|
|
241
|
+
}
|
|
242
|
+
update();
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
update();
|
|
246
|
+
observer.observe(root);
|
|
247
|
+
if (end) observer.observe(end);
|
|
248
|
+
return () => observer.disconnect();
|
|
249
|
+
}, [orientation, hasEndContent, autoOrientationBreakpoint]);
|
|
250
|
+
|
|
251
|
+
// Scroll only on real overflow. A strip sized to its own content (a
|
|
252
|
+
// shrink-to-fit flex item) has a fractional width, and at non-integer DPRs
|
|
253
|
+
// scrollWidth rounds 1px past clientWidth, so the UA shows a scrollbar for
|
|
254
|
+
// nothing (#710). Within 1px counts as fitting: `data-fits` turns the
|
|
255
|
+
// scrollbar off. Without ResizeObserver the strip simply stays scrollable.
|
|
256
|
+
useLayoutEffect(() => {
|
|
257
|
+
const wrap = scrollWrapRef.current;
|
|
258
|
+
const list = wrap?.firstElementChild;
|
|
259
|
+
if (!wrap || !list || typeof ResizeObserver === 'undefined') return;
|
|
260
|
+
const update = () => {
|
|
261
|
+
wrap.toggleAttribute('data-fits', list.getBoundingClientRect().width - wrap.clientWidth <= 1);
|
|
262
|
+
};
|
|
263
|
+
const observer = new ResizeObserver(update);
|
|
264
|
+
update();
|
|
265
|
+
observer.observe(list);
|
|
266
|
+
observer.observe(wrap);
|
|
267
|
+
return () => observer.disconnect();
|
|
268
|
+
// endContent re-parents the strip, which remounts the wrapper.
|
|
269
|
+
}, [hasEndContent]);
|
|
270
|
+
|
|
271
|
+
// Dev-only: warn on duplicate ids. The ref map would silently collapse them
|
|
272
|
+
// and roving tabindex would behave unpredictably. Run as an effect (not in
|
|
273
|
+
// render) so it fires once per items change and doesn't double-warn in
|
|
274
|
+
// StrictMode dev.
|
|
275
|
+
useEffect(() => {
|
|
276
|
+
if (!IS_DEV) return;
|
|
277
|
+
const ids = items.map((i) => i.id);
|
|
278
|
+
if (new Set(ids).size !== ids.length) {
|
|
279
|
+
console.warn('[Tabs] items contains duplicate ids:', ids);
|
|
280
|
+
}
|
|
281
|
+
}, [items]);
|
|
282
|
+
|
|
283
|
+
// Position the shared indicator. Reads layout metrics from the active tab's
|
|
284
|
+
// button and writes them as inline styles on the indicator. In horizontal
|
|
285
|
+
// mode it's an underline driven by translateX + width; in vertical mode it's
|
|
286
|
+
// a left accent bar driven by translateY + height. The cross-axis dimension
|
|
287
|
+
// is cleared each pass so a runtime orientation flip can't leave a stale
|
|
288
|
+
// width/height behind. useLayoutEffect (not useEffect) so the bar's new
|
|
289
|
+
// position is committed before paint — avoids a one-frame flash at the old
|
|
290
|
+
// location.
|
|
291
|
+
useLayoutEffect(() => {
|
|
292
|
+
const indicator = indicatorRef.current;
|
|
293
|
+
if (!indicator) return;
|
|
294
|
+
const node = tabRefs.current[activeId];
|
|
295
|
+
if (!node) {
|
|
296
|
+
// activeId doesn't match any item, or items is empty — hide the bar
|
|
297
|
+
// rather than leave it stranded mid-slide. Important: we return BEFORE
|
|
298
|
+
// touching firstMeasureRef, so a later "missing → valid" transition
|
|
299
|
+
// still gets the no-animation first-paint treatment.
|
|
300
|
+
indicator.style.opacity = '0';
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
indicator.style.opacity = '1';
|
|
304
|
+
|
|
305
|
+
// When the active tab is wrapped in a per-tab `actions` cell
|
|
306
|
+
// (role="presentation"), measure the CELL so the underline spans the whole
|
|
307
|
+
// tab — label AND its controls — instead of just the button. Bare tabs
|
|
308
|
+
// (no actions) measure the button, unchanged.
|
|
309
|
+
const cell = node.parentElement;
|
|
310
|
+
const measureNode = cell && cell.getAttribute('role') === 'presentation' ? cell : node;
|
|
311
|
+
|
|
312
|
+
const vertical = effectiveOrientation === 'vertical';
|
|
313
|
+
const write = () => {
|
|
314
|
+
if (vertical) {
|
|
315
|
+
indicator.style.transform = `translateY(${measureNode.offsetTop}px)`;
|
|
316
|
+
indicator.style.height = `${measureNode.offsetHeight}px`;
|
|
317
|
+
indicator.style.width = ''; // CSS owns the bar thickness in vertical
|
|
318
|
+
} else {
|
|
319
|
+
indicator.style.transform = `translateX(${measureNode.offsetLeft}px)`;
|
|
320
|
+
indicator.style.width = `${measureNode.offsetWidth}px`;
|
|
321
|
+
indicator.style.height = ''; // CSS owns the bar thickness in horizontal
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
if (firstMeasureRef.current) {
|
|
326
|
+
// First paint: disable the transition for one frame so the indicator
|
|
327
|
+
// doesn't slide in from (0, 0) on mount.
|
|
328
|
+
indicator.style.transition = 'none';
|
|
329
|
+
write();
|
|
330
|
+
// Force a reflow before clearing the inline transition override so the
|
|
331
|
+
// first measurement lands without animation.
|
|
332
|
+
void indicator.offsetWidth;
|
|
333
|
+
indicator.style.transition = '';
|
|
334
|
+
firstMeasureRef.current = false;
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
write();
|
|
339
|
+
}, [activeId, items, effectiveOrientation]);
|
|
340
|
+
|
|
341
|
+
// Focused tab can drift from activeId in manual activation mode. In auto
|
|
342
|
+
// mode they stay in sync because focusTab also calls onChange.
|
|
343
|
+
const [focusedId, setFocusedId] = useState<string>(activeId);
|
|
344
|
+
useEffect(() => {
|
|
345
|
+
setFocusedId(activeId);
|
|
346
|
+
}, [activeId]);
|
|
347
|
+
|
|
348
|
+
// The effective focused id ALWAYS resolves to an item (or null when items is
|
|
349
|
+
// empty). When `focusedId` doesn't match any item — e.g. activeId is invalid
|
|
350
|
+
// or the active item was just deleted — we fall back to items[0] so the
|
|
351
|
+
// tablist stays keyboard-reachable.
|
|
352
|
+
const effectiveFocusedId = items.find((i) => i.id === focusedId)?.id ?? items[0]?.id ?? null;
|
|
353
|
+
|
|
354
|
+
const focusTab = (id: string) => {
|
|
355
|
+
setFocusedId(id);
|
|
356
|
+
tabRefs.current[id]?.focus();
|
|
357
|
+
if (activationMode === 'auto') {
|
|
358
|
+
onChange(id);
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
|
|
363
|
+
// Only rove when the key originates on a tab (or the tablist itself). This
|
|
364
|
+
// stops Arrow/Home/End inside a per-tab `actions` control from hijacking
|
|
365
|
+
// tab navigation. Real roving focus always lands on a role="tab".
|
|
366
|
+
if (
|
|
367
|
+
event.target !== event.currentTarget &&
|
|
368
|
+
(event.target as HTMLElement).getAttribute('role') !== 'tab'
|
|
369
|
+
) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (items.length === 0 || effectiveFocusedId === null) return;
|
|
373
|
+
const currentIndex = items.findIndex((i) => i.id === effectiveFocusedId);
|
|
374
|
+
// Vertical strips navigate with Up/Down; horizontal with Left/Right. The
|
|
375
|
+
// matching `case nextKey:` below reads the active axis's keys.
|
|
376
|
+
const vertical = effectiveOrientation === 'vertical';
|
|
377
|
+
const nextKey = vertical ? 'ArrowDown' : 'ArrowRight';
|
|
378
|
+
const prevKey = vertical ? 'ArrowUp' : 'ArrowLeft';
|
|
379
|
+
let nextIndex = -1;
|
|
380
|
+
switch (event.key) {
|
|
381
|
+
case nextKey:
|
|
382
|
+
nextIndex = (currentIndex + 1) % items.length;
|
|
383
|
+
break;
|
|
384
|
+
case prevKey:
|
|
385
|
+
nextIndex = (currentIndex - 1 + items.length) % items.length;
|
|
386
|
+
break;
|
|
387
|
+
case 'Home':
|
|
388
|
+
nextIndex = 0;
|
|
389
|
+
break;
|
|
390
|
+
case 'End':
|
|
391
|
+
nextIndex = items.length - 1;
|
|
392
|
+
break;
|
|
393
|
+
default:
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
event.preventDefault();
|
|
397
|
+
focusTab(items[nextIndex].id);
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
const strip = (
|
|
401
|
+
// The scroll wrapper owns overflow-x so the tablist itself stays an
|
|
402
|
+
// overflow-visible box — that keeps the indicator span (positioned just
|
|
403
|
+
// below the tablist's baseline) from being clipped by the auto-promoted
|
|
404
|
+
// overflow-y.
|
|
405
|
+
<div
|
|
406
|
+
ref={scrollWrapRef}
|
|
407
|
+
className={clsx(
|
|
408
|
+
styles.scrollWrap,
|
|
409
|
+
effectiveOrientation === 'vertical' && styles.scrollWrapVertical,
|
|
410
|
+
)}
|
|
411
|
+
>
|
|
412
|
+
<div
|
|
413
|
+
// Consumer-controlled props come first so component-owned attrs below
|
|
414
|
+
// (role, aria-orientation, onKeyDown, className) always win.
|
|
415
|
+
{...props}
|
|
416
|
+
ref={ref}
|
|
417
|
+
role="tablist"
|
|
418
|
+
aria-orientation={effectiveOrientation}
|
|
419
|
+
onKeyDown={onKeyDown}
|
|
420
|
+
className={clsx(
|
|
421
|
+
styles.tabs,
|
|
422
|
+
effectiveOrientation === 'vertical' && styles.vertical,
|
|
423
|
+
className,
|
|
424
|
+
)}
|
|
425
|
+
>
|
|
426
|
+
{items.map((item) => {
|
|
427
|
+
const active = item.id === activeId;
|
|
428
|
+
const focused = item.id === effectiveFocusedId;
|
|
429
|
+
const tabId = `${prefix}-${item.id}-tab`;
|
|
430
|
+
// Only meaningful with a consumer-supplied prefix — without one no
|
|
431
|
+
// panel carries the id, so building it would just re-create #501's
|
|
432
|
+
// dangling IDREF.
|
|
433
|
+
const panelId = panelIdPrefix ? `${prefix}-${item.id}-panel` : undefined;
|
|
434
|
+
const tab = (
|
|
435
|
+
<button
|
|
436
|
+
key={item.id}
|
|
437
|
+
// attrs first so they can't override the component-owned id/role/aria/handlers below
|
|
438
|
+
{...item.attrs}
|
|
439
|
+
ref={(el) => {
|
|
440
|
+
tabRefs.current[item.id] = el;
|
|
441
|
+
// React 19 ref-callback cleanup — runs when the element unmounts
|
|
442
|
+
// or this callback identity changes (i.e. when items change).
|
|
443
|
+
return () => {
|
|
444
|
+
delete tabRefs.current[item.id];
|
|
445
|
+
};
|
|
446
|
+
}}
|
|
447
|
+
id={tabId}
|
|
448
|
+
type="button"
|
|
449
|
+
role="tab"
|
|
450
|
+
aria-selected={active}
|
|
451
|
+
// ONLY on the active tab. Consumers render just the active
|
|
452
|
+
// panel — that is what this API's shape implies and what the
|
|
453
|
+
// docs describe — so stamping every tab shipped N-1 dangling
|
|
454
|
+
// IDREFs that no consumer could fix without eagerly mounting
|
|
455
|
+
// every panel and firing every panel's queries on first paint
|
|
456
|
+
// (#501). Inactive tabs keep their `id`, which is what the
|
|
457
|
+
// panel's `aria-labelledby` points back to, so the relationship
|
|
458
|
+
// is still expressed in both directions for the pair that
|
|
459
|
+
// actually exists.
|
|
460
|
+
// Also requires panelIdPrefix. Without it the prefix is a
|
|
461
|
+
// generated useId that no consumer can know, Tabs renders no
|
|
462
|
+
// panel itself, and nothing else can — so the id is not merely
|
|
463
|
+
// absent, it CANNOT exist. Stamping it there left the default
|
|
464
|
+
// configuration with exactly the dangling IDREF this fixes.
|
|
465
|
+
aria-controls={active && panelIdPrefix ? panelId : undefined}
|
|
466
|
+
tabIndex={focused ? 0 : -1}
|
|
467
|
+
className={clsx(styles.tab, active && styles.active)}
|
|
468
|
+
// Skip the onChange call when clicking the already-active tab —
|
|
469
|
+
// avoids unnecessary parent re-renders.
|
|
470
|
+
onClick={() => {
|
|
471
|
+
if (item.id !== activeId) onChange(item.id);
|
|
472
|
+
}}
|
|
473
|
+
>
|
|
474
|
+
<span className={styles.main}>
|
|
475
|
+
{item.leading != null && <span className={styles.leading}>{item.leading}</span>}
|
|
476
|
+
{item.icon != null && (
|
|
477
|
+
<span className={styles.icon} aria-hidden="true">
|
|
478
|
+
{item.icon}
|
|
479
|
+
</span>
|
|
480
|
+
)}
|
|
481
|
+
<span className={styles.label}>{item.label}</span>
|
|
482
|
+
{item.count !== undefined && <span className={styles.count}>{item.count}</span>}
|
|
483
|
+
</span>
|
|
484
|
+
{item.trailing != null && <span className={styles.trailing}>{item.trailing}</span>}
|
|
485
|
+
</button>
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
if (item.actions == null) return tab;
|
|
489
|
+
return (
|
|
490
|
+
<span key={item.id} role="presentation" className={styles.cell}>
|
|
491
|
+
{tab}
|
|
492
|
+
<span className={styles.tabActions}>{item.actions}</span>
|
|
493
|
+
</span>
|
|
494
|
+
);
|
|
495
|
+
})}
|
|
496
|
+
{action != null && (
|
|
497
|
+
// Plain button — deliberately NOT role="tab": no tabpanel to
|
|
498
|
+
// control, excluded from the arrow-key roving above (which only
|
|
499
|
+
// ever reads `items`/`tabRefs`), and never measured by the
|
|
500
|
+
// indicator effect (which only looks up `tabRefs[activeId]`).
|
|
501
|
+
// Known, accepted `aria-required-children` deviation: this leaves
|
|
502
|
+
// one non-"tab" child in a `role="tablist"` container, same as the
|
|
503
|
+
// `TabItem.actions` button above already does. A real `<button>`
|
|
504
|
+
// still announces correctly to AT regardless of its parent's role.
|
|
505
|
+
<button
|
|
506
|
+
type="button"
|
|
507
|
+
className={styles.action}
|
|
508
|
+
onClick={action.onClick}
|
|
509
|
+
disabled={action.disabled}
|
|
510
|
+
>
|
|
511
|
+
{action.icon != null && (
|
|
512
|
+
<span className={styles.icon} aria-hidden="true">
|
|
513
|
+
{action.icon}
|
|
514
|
+
</span>
|
|
515
|
+
)}
|
|
516
|
+
<span className={styles.label}>{action.label}</span>
|
|
517
|
+
</button>
|
|
518
|
+
)}
|
|
519
|
+
<span ref={indicatorRef} className={styles.indicator} aria-hidden="true" />
|
|
520
|
+
</div>
|
|
521
|
+
</div>
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
if (!hasEndContent) return strip;
|
|
525
|
+
|
|
526
|
+
return (
|
|
527
|
+
<div
|
|
528
|
+
ref={rootRef}
|
|
529
|
+
className={clsx(styles.root, effectiveOrientation === 'vertical' && styles.rootVertical)}
|
|
530
|
+
>
|
|
531
|
+
{strip}
|
|
532
|
+
{/* data-tabs-end is an internal test hook (module classes are hashed), not public API. */}
|
|
533
|
+
<div ref={endContentRef} data-tabs-end="" className={styles.endContent}>
|
|
534
|
+
{endContent}
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
537
|
+
);
|
|
538
|
+
});
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
@use './Text.tokens';
|
|
2
|
+
|
|
3
|
+
.text {
|
|
4
|
+
// stylelint-disable-next-line property-disallowed-list -- native <p> margin reset (component-internal, not at the boundary)
|
|
5
|
+
margin: 0;
|
|
6
|
+
font-family: var(--font-family-sans);
|
|
7
|
+
font-weight: var(--text-font-weight);
|
|
8
|
+
line-height: var(--text-line-height);
|
|
9
|
+
color: var(--text-fg);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.sizeXs {
|
|
13
|
+
font-size: var(--text-font-size-xs);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.sizeSm {
|
|
17
|
+
font-size: var(--text-font-size-sm);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.sizeMd {
|
|
21
|
+
font-size: var(--text-font-size-md);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.sizeLg {
|
|
25
|
+
font-size: var(--text-font-size-lg);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.sizeXl {
|
|
29
|
+
font-size: var(--text-font-size-xl);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// `inherit` — no fixed size: font-size AND line-height come from the parent
|
|
33
|
+
// (inline runs inside headings). Line-height must inherit too or Text's
|
|
34
|
+
// base 1.5 would inflate a tight heading's line box.
|
|
35
|
+
.sizeInherit {
|
|
36
|
+
font-size: inherit;
|
|
37
|
+
line-height: inherit;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.weightRegular {
|
|
41
|
+
font-weight: var(--text-font-weight-regular);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.weightMedium {
|
|
45
|
+
font-weight: var(--text-font-weight-medium);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.weightSemibold {
|
|
49
|
+
font-weight: var(--text-font-weight-semibold);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.weightBold {
|
|
53
|
+
font-weight: var(--text-font-weight-bold);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.toneDefault {
|
|
57
|
+
color: var(--text-fg-default);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.toneMuted {
|
|
61
|
+
color: var(--text-fg-muted);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.toneSubtle {
|
|
65
|
+
color: var(--text-fg-subtle);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.toneAccent {
|
|
69
|
+
color: var(--text-fg-accent);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.toneDanger {
|
|
73
|
+
color: var(--text-fg-danger);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.toneSuccess {
|
|
77
|
+
color: var(--text-fg-success);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.toneWarning {
|
|
81
|
+
color: var(--text-fg-warning);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.alignLeft {
|
|
85
|
+
// stylelint-disable-next-line scale-unlimited/declaration-strict-value -- text-align keywords don't have tokens
|
|
86
|
+
text-align: left;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.alignCenter {
|
|
90
|
+
// stylelint-disable-next-line scale-unlimited/declaration-strict-value -- text-align keywords don't have tokens
|
|
91
|
+
text-align: center;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.alignRight {
|
|
95
|
+
// stylelint-disable-next-line scale-unlimited/declaration-strict-value -- text-align keywords don't have tokens
|
|
96
|
+
text-align: right;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.truncate {
|
|
100
|
+
overflow: hidden;
|
|
101
|
+
text-overflow: ellipsis;
|
|
102
|
+
white-space: nowrap;
|
|
103
|
+
|
|
104
|
+
// Allow shrinkage below intrinsic size inside flex/grid parents — without
|
|
105
|
+
// this, the truncate has no effect when the heading is a flex/grid child.
|
|
106
|
+
min-width: 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.lineClamp {
|
|
110
|
+
display: -webkit-box;
|
|
111
|
+
-webkit-box-orient: vertical;
|
|
112
|
+
overflow: hidden;
|
|
113
|
+
|
|
114
|
+
// -webkit-line-clamp value is set inline via style (dynamic), not a class.
|
|
115
|
+
}
|