@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,69 @@
|
|
|
1
|
+
# `<Sticky>` — sticky-positioning primitive
|
|
2
|
+
|
|
3
|
+
Pins its box to the top of the scroll container while the page scrolls past — for a record/detail-page sidebar (owner, tags, linked records) that stays in view while the wide main column scrolls. Sets `align-self: start` so it also works as a grid/flex item. Positions its OWN box only (put a `Stack`/`Cluster` inside to arrange the pinned content).
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
// Detail page: main column scrolls, sidebar pins. align="stretch" gives the
|
|
7
|
+
// aside track full height so the Sticky has a tall containing block to pin within.
|
|
8
|
+
<Split
|
|
9
|
+
side="end"
|
|
10
|
+
asideWidth="320px"
|
|
11
|
+
align="stretch"
|
|
12
|
+
aside={
|
|
13
|
+
<Sticky top="md">
|
|
14
|
+
<Stack gap="md">{sidebarCards}</Stack>
|
|
15
|
+
</Sticky>
|
|
16
|
+
}
|
|
17
|
+
>
|
|
18
|
+
<Stack gap="lg">{fields}</Stack>
|
|
19
|
+
</Split>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
<!-- props:start -->
|
|
23
|
+
|
|
24
|
+
## Props
|
|
25
|
+
|
|
26
|
+
<!-- prettier-ignore -->
|
|
27
|
+
| Prop | Type | Required | Description |
|
|
28
|
+
|---|---|---|---|
|
|
29
|
+
| `top` | `'none' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'topbar'` | no | Offset from the top of the scroll container at which the content pins. Defaults to `'none'` (`top: 0`, flush). Use `'topbar'` inside an AppLayout with pinned TopBar; spacing steps add breathing room without chrome clearance. |
|
|
30
|
+
| `scroll` | `boolean` | no | Cap the pinned box at the viewport height and scroll its content internally, so a column TALLER than the screen stays fully reachable (the overflow scrolls within the box instead of below the fold). Sets `max-height` to `calc(100dvh - top offset - bottom gap)`, `overflow-y: auto`, and `overscroll-behavior: contain` (page scroll doesn't chain from the box). The bottom gap defaults to the selected rhythm offset; `top="topbar"` instead defaults it to the standard content gap so chrome height is not subtracted twice. Set `--sticky-bottom-gap` on this element to override either default. Default `false`. Pair with a non-`none` `top` to leave breathing room. The cap is viewport-relative (`dvh`), so this assumes the page (or a viewport-tall ancestor) is the scroll context — not a short fixed-height scroll container. |
|
|
31
|
+
| `layer` | `boolean` | no | Raise the pinned box above positioned/stacked page content (e.g. DashboardCanvas cells) so a page-level sticky bar is not painted over or click-blocked by them. Sets `z-index` just below the TopBar. Default `false`. Caveat: `z-index` on a sticky box creates a stacking context, so don't use it on a Split aside that hosts inline (non-portaled) popovers, which would be trapped inside it. |
|
|
32
|
+
| `surface` | `boolean` | no | Paint the box with the page background always; while pinned, also a bottom divider and a strip over the gap above it (the `top` offset), so content scrolling underneath doesn't show through. Pinned state is tracked with an IntersectionObserver (`data-pinned`). For page-level bars. Default `false`. |
|
|
33
|
+
| `children` | `ReactNode` | yes | The content to pin. Required — a `Sticky` with nothing inside pins nothing. |
|
|
34
|
+
| …native | | | plus native `<div>` attributes |
|
|
35
|
+
|
|
36
|
+
<!-- props:end -->
|
|
37
|
+
|
|
38
|
+
- Sticky defaults are emitted by the global token entry, so a consumer `:root` override loaded after `@eocrm/design-system/styles/tokens.scss` wins predictably. Override `--sticky-top-topbar` to match custom application chrome.
|
|
39
|
+
- Inside a `<Split>` aside, pair with `align="stretch"` (else the content-height aside track gives nowhere to pin).
|
|
40
|
+
- As a `<Split collapseBelow>` aside, it automatically becomes a plain block (no pin, no `scroll` cap/inner scroll) while the Split is stacked — no consumer shim needed. Applies only when the `Sticky` is the `aside` itself.
|
|
41
|
+
|
|
42
|
+
When NOT to use: arranging children → `<Stack>`/`<Cluster>`; a fixed overlay above content → `position: fixed` chrome (`Popover`/`Modal`/app bar); the split itself → `<Split>`. Note: `position: sticky` breaks if a clipping ancestor (`overflow: hidden/auto`) isn't the intended scroll container.
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
// A standalone sticky filter rail next to a long list:
|
|
46
|
+
<Sticky top="lg">
|
|
47
|
+
<FilterPanel />
|
|
48
|
+
</Sticky>
|
|
49
|
+
|
|
50
|
+
// Clear AppLayout's pinned TopBar with the standard content gap:
|
|
51
|
+
<Sticky top="topbar" scroll>
|
|
52
|
+
<FilterPanel />
|
|
53
|
+
</Sticky>
|
|
54
|
+
|
|
55
|
+
// A page-level edit toolbar that stays above positioned content (DashboardCanvas cells):
|
|
56
|
+
<Sticky top="topbar" layer surface>
|
|
57
|
+
<EditToolbar />
|
|
58
|
+
</Sticky>
|
|
59
|
+
|
|
60
|
+
// A tall pinned sidebar that scrolls within itself when it exceeds the screen:
|
|
61
|
+
<Sticky top="lg" scroll>
|
|
62
|
+
<Stack gap="md">{manyCards}</Stack>
|
|
63
|
+
</Sticky>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- `position: sticky` pins to the nearest scrolling ancestor, so an `overflow: hidden/auto` ancestor that isn't the intended scroll container breaks it.
|
|
67
|
+
- ❌ `margin` / `padding` on it for spacing: it carries sticky position only; spacing comes from the parent layout primitive.
|
|
68
|
+
- ℹ️ `surface` is for page-level bars: it always paints the page background; once pinned (`data-pinned`, via IntersectionObserver) it also shows the bottom divider and covers the gap above the bar when `top` is set.
|
|
69
|
+
- ❌ `layer` on a `Split` aside that hosts inline (non-portaled) popovers: `z-index` on a sticky box creates a stacking context that traps them. `layer` and `surface` are both opt-in (default `false`).
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# `<Switch>` — binary toggle
|
|
2
|
+
|
|
3
|
+
Hand-rolled track + thumb on a native `<input type="checkbox" role="switch">`. The dumb on/off toggle for settings, feature flags, and async persisted state.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Switch } from '@eocrm/design-system';
|
|
7
|
+
|
|
8
|
+
// Default — uncontrolled, accent tone.
|
|
9
|
+
<Switch>Enable notifications</Switch>
|
|
10
|
+
|
|
11
|
+
// Controlled, success tone.
|
|
12
|
+
<Switch tone="success" checked={enabled} onChange={(next) => setEnabled(next)}>
|
|
13
|
+
Daily digest
|
|
14
|
+
</Switch>
|
|
15
|
+
|
|
16
|
+
// Async (server-persisted) toggle.
|
|
17
|
+
<Switch
|
|
18
|
+
checked={enabled}
|
|
19
|
+
loading={saving}
|
|
20
|
+
onChange={async (next) => {
|
|
21
|
+
setSaving(true);
|
|
22
|
+
setEnabled(next); // optimistic
|
|
23
|
+
try { await api.save(next); }
|
|
24
|
+
catch { setEnabled(!next); } // rollback
|
|
25
|
+
finally { setSaving(false); }
|
|
26
|
+
}}
|
|
27
|
+
>
|
|
28
|
+
Two-factor auth
|
|
29
|
+
</Switch>
|
|
30
|
+
|
|
31
|
+
// Icon-only.
|
|
32
|
+
<Switch aria-label="Mute notifications" />
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
<!-- props:start -->
|
|
36
|
+
|
|
37
|
+
## Props
|
|
38
|
+
|
|
39
|
+
<!-- prettier-ignore -->
|
|
40
|
+
| Prop | Type | Required | Description |
|
|
41
|
+
|---|---|---|---|
|
|
42
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | no | Visual scale. Defaults to `'md'`. - `'sm'` — 28×16 track, 12px thumb, `--font-size-sm` label. - `'md'` — 36×20 track, 16px thumb, `--font-size-md` label (default). - `'lg'` — 44×24 track, 20px thumb, `--font-size-lg` label. Note: shadows the native HTML `<input size>` attribute (meaningless on checkboxes). |
|
|
43
|
+
| `tone` | `'accent' \| 'success' \| 'danger'` | no | Track color when checked (the unchecked track is always neutral muted). Defaults to `'accent'`. - `'accent'` — blue (default). - `'success'` — green. Use for affirmative toggles ("Enable notifications"). - `'danger'` — red. Use for destructive toggles ("Allow root access"). |
|
|
44
|
+
| `checked` | `boolean` | no | Controlled checked state. Pair with `onChange`. Omit (with optional `defaultChecked`) for uncontrolled use. |
|
|
45
|
+
| `defaultChecked` | `boolean` | no | Initial checked state for uncontrolled use. Defaults to `false`. |
|
|
46
|
+
| `onChange` | `((checked: boolean, e: ChangeEvent<HTMLInputElement, Element>) => void)` | no | Fires when the user toggles the switch. The first arg is the next boolean (convenience); the original change event is the second arg. Matches `<Checkbox>`'s signature. |
|
|
47
|
+
| `invalid` | `boolean` | no | Toggles `aria-invalid="true"` and adds a danger-tone border to the track. Use when the switch's state has caused a validation error. |
|
|
48
|
+
| `loading` | `boolean` | no | Shows a spinner inside the thumb and suppresses changes while a toggle persists to a server, keeping the native input focusable so keyboard users retain their place in the form. Announced from a polite live region the Switch owns. `aria-busy` is set too, but nothing reads it — no mainstream screen reader conveys `busy` on a non-live element. The region sits OUTSIDE the `<label>` so it does not join the input's accessible name: the name stays stable while loading, and `getByRole('switch', { name })` keeps matching. The consumer is responsible for managing the optimistic-update flow: (example below) |
|
|
49
|
+
| `children` | `ReactNode` | no | Label rendered next to the track. The whole `<label>` is the click target — clicking anywhere toggles. Omit for icon-only switches + pair with `aria-label`. |
|
|
50
|
+
| …native | | | plus native `<input>` attributes |
|
|
51
|
+
|
|
52
|
+
**`loading`** example:
|
|
53
|
+
|
|
54
|
+
<!-- prettier-ignore -->
|
|
55
|
+
```tsx
|
|
56
|
+
const [enabled, setEnabled] = useState(initial);
|
|
57
|
+
const [saving, setSaving] = useState(false);
|
|
58
|
+
|
|
59
|
+
const handleToggle = async (next: boolean) => {
|
|
60
|
+
setSaving(true);
|
|
61
|
+
setEnabled(next); // optimistic
|
|
62
|
+
try { await api.save(next); }
|
|
63
|
+
catch { setEnabled(!next); } // rollback
|
|
64
|
+
finally { setSaving(false); }
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
<Switch checked={enabled} loading={saving} onChange={handleToggle} />
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
<!-- props:end -->
|
|
71
|
+
|
|
72
|
+
- **Native `<input type="checkbox" role="switch">`**. Form submission works; AT announces as switch. `ref` and native attributes (`name`, `value`, `disabled`, `aria-label`) reach the input.
|
|
73
|
+
|
|
74
|
+
#### Hard rule
|
|
75
|
+
|
|
76
|
+
A switch whose toggle triggers an **immediate action** — persisting to a server or firing any side effect — MUST use the async optimistic-update flow: flip the state optimistically, set `loading` while the request is in flight, and roll back on failure (see the async toggle example above). Never fire-and-forget a side-effecting toggle — the user needs the in-flight (`loading`) and rollback feedback. A switch over pure local UI state (no side effect) may toggle synchronously.
|
|
77
|
+
|
|
78
|
+
#### When NOT to use
|
|
79
|
+
|
|
80
|
+
- ❌ Selecting one option from a list of mutually-exclusive choices → `<Radio>` / `<RadioGroup>`.
|
|
81
|
+
- ❌ Selecting multiple from a list → `<Checkbox>`.
|
|
82
|
+
- ❌ A mixed / indeterminate state ("some-but-not-all enabled") → use Checkbox's `indeterminate`.
|
|
83
|
+
- ❌ Triggering an action immediately on click (no state) → `<Button>`.
|
|
84
|
+
|
|
85
|
+
#### Anti-patterns
|
|
86
|
+
|
|
87
|
+
- ❌ Using `placeholder`-style hints inside the track ("OFF" / "ON" text). Use a real label.
|
|
88
|
+
- ❌ Toggle without an external optimistic-update flow when `loading` is set. Without it, the user clicks the switch, the spinner appears, and the visual state never changes — confusing.
|
|
89
|
+
- ❌ `tone="success"` for "Mark as failed". Tone communicates the meaning of "on", not just decoration.
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# `<Table>` — tabular data primitive
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
<Table>
|
|
5
|
+
<Table.Header>
|
|
6
|
+
<Table.Row>
|
|
7
|
+
<Table.HeaderCell>Name</Table.HeaderCell>
|
|
8
|
+
<Table.HeaderCell align="end">Amount</Table.HeaderCell>
|
|
9
|
+
</Table.Row>
|
|
10
|
+
</Table.Header>
|
|
11
|
+
<Table.Body>
|
|
12
|
+
{rows.map((r) => (
|
|
13
|
+
<Table.Row key={r.id}>
|
|
14
|
+
<Table.Cell>{r.name}</Table.Cell>
|
|
15
|
+
<Table.Cell align="end">{r.amount}</Table.Cell>
|
|
16
|
+
</Table.Row>
|
|
17
|
+
))}
|
|
18
|
+
</Table.Body>
|
|
19
|
+
</Table>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
<!-- props:start -->
|
|
23
|
+
|
|
24
|
+
## Props
|
|
25
|
+
|
|
26
|
+
### `TableProps`
|
|
27
|
+
|
|
28
|
+
<!-- prettier-ignore -->
|
|
29
|
+
| Prop | Type | Required | Description |
|
|
30
|
+
|---|---|---|---|
|
|
31
|
+
| `density` | `'comfortable' \| 'dense'` | no | Row height + cell padding scale. Defaults to `'comfortable'`. - `'comfortable'` — 32px row, 12px horiz padding, font-size-md. - `'dense'` — 24px row, 8px horiz padding, font-size-sm. |
|
|
32
|
+
| `striped` | `boolean` | no | Zebra-striped body rows (even rows tinted). Defaults to `false`. |
|
|
33
|
+
| `bordered` | `boolean` | no | Full-grid borders — outer border + vertical borders between every cell on top of the existing horizontal row dividers. Defaults to `false` (Atlassian-style minimal: header underline + row dividers only). |
|
|
34
|
+
| `hover` | `boolean` | no | Hover highlight on body rows. Defaults to `false` — turn on when the table represents a list of clickable / selectable items (a row a user is likely to act on). Leave off for read-only data displays where the hover affordance would suggest interactivity that isn't there. |
|
|
35
|
+
| `stickyHeader` | `boolean` | no | `position: sticky` on the header so it stays visible while body scrolls. Requires a scrollable ancestor — the default `scroll` wrapper provides one. Defaults to `false`. |
|
|
36
|
+
| `scroll` | `boolean` | no | When `true` (default), the `<table>` is wrapped in a `<div>` with `overflow-x: auto` so wide tables scroll horizontally inside their container. Set to `false` to render a bare `<table>` — the consumer manages their own scroll context. |
|
|
37
|
+
| `layout` | `'auto' \| 'fixed'` | no | Column-layout algorithm. Defaults to `'auto'`. - `'auto'` — columns size to their content (native default). - `'fixed'` — `table-layout: fixed`: widths come from a native `<colgroup><col style={{ width }} /></colgroup>` (or the first row), and unsized columns split the rest equally. Use for grids of equal-width number columns. |
|
|
38
|
+
| `children` | `ReactNode` | no | Compound-subcomponent children. |
|
|
39
|
+
| …native | | | plus native `<table>` attributes |
|
|
40
|
+
|
|
41
|
+
### `TableCaptionProps`
|
|
42
|
+
|
|
43
|
+
<!-- prettier-ignore -->
|
|
44
|
+
| Prop | Type | Required | Description |
|
|
45
|
+
|---|---|---|---|
|
|
46
|
+
| `children` | `ReactNode` | yes | |
|
|
47
|
+
| …native | | | plus native `<caption>` attributes |
|
|
48
|
+
|
|
49
|
+
### `TableCellLinkProps`
|
|
50
|
+
|
|
51
|
+
<!-- prettier-ignore -->
|
|
52
|
+
| Prop | Type | Required | Description |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| `children` | `ReactNode` | no | |
|
|
55
|
+
| `as` | `ElementType` | no | Element or component to render. Defaults to `'a'`; use for router links. |
|
|
56
|
+
| …native | | | plus native attributes of the `as` element (default `<a>`) |
|
|
57
|
+
|
|
58
|
+
### `TableCellProps`
|
|
59
|
+
|
|
60
|
+
<!-- prettier-ignore -->
|
|
61
|
+
| Prop | Type | Required | Description |
|
|
62
|
+
|---|---|---|---|
|
|
63
|
+
| `align` | `'start' \| 'center' \| 'end'` | no | Text alignment. Defaults to `'start'`. |
|
|
64
|
+
| `truncate` | `boolean` | no | Suppress wrapping and ellipsize on overflow. Requires a constrained cell width (column-level CSS or `style={{ maxWidth: … }}`). |
|
|
65
|
+
| `tone` | `'danger' \| 'accent'` | no | Tints the cell background and colours its text. Exposed as `data-tone`. Default: none. Set it on every cell of the column (header included). - `'danger'` — overdue / at-risk column. - `'accent'` — the current / highlighted column (e.g. "Today"). |
|
|
66
|
+
| `children` | `ReactNode` | no | |
|
|
67
|
+
| …native | | | plus native `<td>` attributes |
|
|
68
|
+
|
|
69
|
+
### `TableHeaderCellProps`
|
|
70
|
+
|
|
71
|
+
<!-- prettier-ignore -->
|
|
72
|
+
| Prop | Type | Required | Description |
|
|
73
|
+
|---|---|---|---|
|
|
74
|
+
| `align` | `'start' \| 'center' \| 'end'` | no | Text alignment. Defaults to `'start'`. |
|
|
75
|
+
| `scope` | `'row' \| 'rowgroup' \| 'col' \| 'colgroup'` | no | Native HTML `<th scope>` attribute. Defaults to `'col'` (the cell labels its column). Use `'row'` for the leftmost cell that labels its row when rendering row-headers inside `<Table.Body>`. `'colgroup'` / `'rowgroup'` are valid HTML but rarely needed in practice. |
|
|
76
|
+
| `sortDirection` | `'asc' \| 'desc' \| 'none'` | no | When set, the cell renders a sort indicator (up/down/unsorted chevron) and sets `aria-sort`. The consumer drives interactivity via `onClick`; this primitive only paints the indicator. Sortable headers also become keyboard-reachable (`tabIndex={0}` + Enter/Space → `onClick`). - `'asc'` → up chevron + `aria-sort="ascending"`. - `'desc'` → down chevron + `aria-sort="descending"`. - `'none'` → muted up/down chevron + `aria-sort="none"`. Omit to render a non-sortable header (no chevron, no `aria-sort`). |
|
|
77
|
+
| `tone` | `'danger' \| 'accent'` | no | Tints the header cell (top corners rounded, square under `bordered`) so a toned column reads as one band with its toned body cells. Exposed as `data-tone`. Default: none. - `'danger'` — overdue / at-risk column. - `'accent'` — the current / highlighted column (e.g. "Today"). |
|
|
78
|
+
| `children` | `ReactNode` | no | |
|
|
79
|
+
| …native | | | plus native `<th>` attributes |
|
|
80
|
+
|
|
81
|
+
### `TableRowProps`
|
|
82
|
+
|
|
83
|
+
<!-- prettier-ignore -->
|
|
84
|
+
| Prop | Type | Required | Description |
|
|
85
|
+
|---|---|---|---|
|
|
86
|
+
| `selected` | `boolean` | no | Visual selected state. Pair with the consumer's own selection logic. Adds `aria-selected="true"` and a subtle accent tint that wins over hover/striped. |
|
|
87
|
+
| `children` | `ReactNode` | yes | |
|
|
88
|
+
| …native | | | plus native `<tr>` attributes |
|
|
89
|
+
|
|
90
|
+
### `TableSectionProps`
|
|
91
|
+
|
|
92
|
+
<!-- prettier-ignore -->
|
|
93
|
+
| Prop | Type | Required | Description |
|
|
94
|
+
|---|---|---|---|
|
|
95
|
+
| `children` | `ReactNode` | yes | |
|
|
96
|
+
| …native | | | plus native `<tbody>` attributes |
|
|
97
|
+
|
|
98
|
+
<!-- props:end -->
|
|
99
|
+
|
|
100
|
+
- Compound subcomponents: `Table`, `Table.Caption`, `Table.Header`, `Table.Body`, `Table.Footer`, `Table.Row`, `Table.HeaderCell`, `Table.Cell`, `Table.CellLink`. Renders native `<table>` / `<thead>` / `<tbody>` / `<tr>` / `<th>` / `<td>` / `<tfoot>` / `<caption>` — no ARIA-on-divs.
|
|
101
|
+
- Visual modifiers on root: `density` (`'comfortable'` (default, 32px row) / `'dense'` (24px)), `hover` (default off — opt in for clickable / selectable row lists), `striped`, `bordered` (full-grid borders; default off — Atlassian-minimal style is just row dividers + header underline), `stickyHeader`, `scroll` (default `true` — wraps in `overflow-x: auto`).
|
|
102
|
+
- `<Table.Row selected>` paints a tinted bg + `aria-selected="true"`. Selection state itself is the consumer's job.
|
|
103
|
+
- `<Table.HeaderCell sortDirection>` is a visual hook: renders an up / down / unsorted chevron + sets `aria-sort`. Wire `onClick` to your own sort state. (`<DataTable>` does not use this prop: it sets `aria-sort` and draws its own chevron.)
|
|
104
|
+
- `<Table.Cell align>` / `<Table.HeaderCell align>`: `'start' | 'center' | 'end'` (CSS logical, RTL-friendly). Right-aligned headers auto-flip the sort chevron to the start side.
|
|
105
|
+
- `<Table.Cell truncate>` ellipses overflow text on one line. Requires a constrained cell width (`style={{ maxWidth }}` or `<col>`).
|
|
106
|
+
- **`colSpan` / `rowSpan`** flow through to the native `<th>` / `<td>` via spread. Use for multi-row grouped headers (`rowSpan` on a corner cell + `colSpan` on group cells over a second `<Table.Row>`), category-grouped body rows (`rowSpan` on a leftmost cell), and footer total rows (`<Table.Cell colSpan={n}>Total</Table.Cell>`). Use `<Table.HeaderCell scope="row">` (instead of `<Table.Cell>`) for the leftmost cell when it labels its row to AT.
|
|
107
|
+
- The native HTML `align` attribute on `<th>` / `<td>` is shadowed by the component-level `align` prop (logical) — `Omit<…, 'align'>` on both `*Props`.
|
|
108
|
+
- `layout="fixed"` sets `table-layout: fixed` (default `'auto'`). Column widths come from a native `<colgroup><col style={{ width }} /></colgroup>`; unsized columns split the remainder equally. Use it for grids of equal-width number columns.
|
|
109
|
+
- `tone="danger" | "accent"` on `<Table.Cell>` / `<Table.HeaderCell>` tints the cell and colours its text (exposed as `data-tone`). Set it on every cell of the column, header included: a toned header gets rounded top corners so the column reads as one band (square under `bordered`, where they would break the grid lines). There is no column-level tone prop.
|
|
110
|
+
- A toned cell's tint and colour win over the row's hover / selected tint, so the column stays one band across every row.
|
|
111
|
+
- `<Table.CellLink>` is a full-bleed link placed as the direct child of `<Table.Cell>` (not `<Table.HeaderCell>`, which wraps its children). The cell drops its padding and the link takes it over (respecting `density`), so the whole cell is the hit area. It inherits the cell's alignment and colour and renders semibold (`--table-cell-link-font-weight`) so link cells read as actionable; hover darkens the cell (no underline — the cell-wide overlay is the hover signal), keyboard focus draws an inset ring. On hover, `tone="muted"` (and deprecated `tone="subtle"`) `<Text>` inside the link takes the link's own colour, because muted text on the hover overlay falls under AA; on a toned cell that colour is the tone's hover colour. Polymorphic `as` (default `'a'`) for router links, like `<Link>`. You supply the accessible name: when the visible text is just a number, give it an `aria-label` that says what it counts (`"Deals, overdue: 3"`). A zero shown as a dash is labelled `"…: none"` because a dash has no spoken meaning — `"Deals, today: none"`.
|
|
112
|
+
- **Use `<DataTable>` instead** when you need sorting / filtering / pagination state. Table is the paint primitive; `DataTable` is the opinionated wrapper.
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
// Caption and a sortable column — you own the sort state; the primitive paints the indicator and sets aria-sort:
|
|
116
|
+
<Table>
|
|
117
|
+
<Table.Caption>Recent activity</Table.Caption>
|
|
118
|
+
<Table.Header>
|
|
119
|
+
<Table.Row>
|
|
120
|
+
<Table.HeaderCell
|
|
121
|
+
sortDirection={sortKey === 'amount' ? sortDir : 'none'}
|
|
122
|
+
onClick={() => toggleSort('amount')}
|
|
123
|
+
>
|
|
124
|
+
Amount
|
|
125
|
+
</Table.HeaderCell>
|
|
126
|
+
</Table.Row>
|
|
127
|
+
</Table.Header>
|
|
128
|
+
...
|
|
129
|
+
</Table>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
// Count grid: fixed equal-width columns, toned columns, every cell a link.
|
|
134
|
+
<Table layout="fixed">
|
|
135
|
+
<colgroup>
|
|
136
|
+
<col style={{ width: '23%' }} />
|
|
137
|
+
<col />
|
|
138
|
+
<col />
|
|
139
|
+
</colgroup>
|
|
140
|
+
<Table.Header>
|
|
141
|
+
<Table.Row>
|
|
142
|
+
<Table.HeaderCell>Type</Table.HeaderCell>
|
|
143
|
+
<Table.HeaderCell tone="danger" align="end">
|
|
144
|
+
Overdue
|
|
145
|
+
</Table.HeaderCell>
|
|
146
|
+
<Table.HeaderCell tone="accent" align="end">
|
|
147
|
+
Today
|
|
148
|
+
</Table.HeaderCell>
|
|
149
|
+
</Table.Row>
|
|
150
|
+
</Table.Header>
|
|
151
|
+
<Table.Body>
|
|
152
|
+
<Table.Row>
|
|
153
|
+
<Table.HeaderCell scope="row">Deals</Table.HeaderCell>
|
|
154
|
+
<Table.Cell tone="danger" align="end">
|
|
155
|
+
<Table.CellLink href="/deals?due=overdue" aria-label="Deals, overdue: 3">
|
|
156
|
+
3
|
|
157
|
+
</Table.CellLink>
|
|
158
|
+
</Table.Cell>
|
|
159
|
+
<Table.Cell tone="accent" align="end">
|
|
160
|
+
<Table.CellLink href="/deals?due=today" aria-label="Deals, today: none">
|
|
161
|
+
<Text as="span" size="inherit" tone="muted">
|
|
162
|
+
–
|
|
163
|
+
</Text>
|
|
164
|
+
</Table.CellLink>
|
|
165
|
+
</Table.Cell>
|
|
166
|
+
</Table.Row>
|
|
167
|
+
</Table.Body>
|
|
168
|
+
</Table>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Sizing:** the `<table>` is `min-width: 100%` (not `width: 100%`), so it fills the wrap for narrow content but grows past it when cell content or explicit `<col>` widths sum wider; the default `scroll` wrapper then scrolls horizontally.
|
|
172
|
+
|
|
173
|
+
**When NOT to use**
|
|
174
|
+
|
|
175
|
+
- Non-tabular content (cards, lists): use `<Stack>` / `<Cluster>` / `<Card>`.
|
|
176
|
+
- Editable cells: no inline editing ships; add inputs inside cells yourself.
|
|
177
|
+
|
|
178
|
+
**Anti-patterns**
|
|
179
|
+
|
|
180
|
+
- `<Table>` without `<Table.Body>` for data rows: native semantics require `<tbody>`.
|
|
181
|
+
- A `<Link>` inside a cell when the whole cell should be clickable: only the text is the hit area and the hover/focus treatment doesn't fill the cell. Use `<Table.CellLink>`.
|
|
182
|
+
- Wrapping `<Table.CellLink>` in another element inside the cell: it must be the cell's direct child, or the cell keeps its padding and the link stops being full-bleed.
|
|
183
|
+
- A `<Table.CellLink>` whose only content is a number with no `aria-label`: a screen reader hears "3, link" with no row or column context.
|
|
184
|
+
- `scope` on `<Table.Cell>`: it renders a `<td>`, where `scope="row"` is invalid. Use `<Table.HeaderCell scope="row">` for a row-header column.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# `<TableOfContents>` — "On this page" navigation
|
|
2
|
+
|
|
3
|
+
Lists a long page's h2/h3 headings as in-page links, highlights the one being read (scroll-spy), and scrolls to a heading on click clear of the pinned TopBar. It does not make itself sticky — wrap it in `<Sticky top="topbar">`.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { useState } from 'react';
|
|
7
|
+
import { Split, Sticky, TableOfContents } from '@eocrm/design-system';
|
|
8
|
+
|
|
9
|
+
const toc = [
|
|
10
|
+
{ id: 'overview', label: 'Overview', level: 2 },
|
|
11
|
+
{ id: 'install', label: 'Install', level: 3 },
|
|
12
|
+
{ id: 'usage', label: 'Usage', level: 2 },
|
|
13
|
+
] as const;
|
|
14
|
+
|
|
15
|
+
function GuidePage() {
|
|
16
|
+
const [narrow, setNarrow] = useState(false);
|
|
17
|
+
return (
|
|
18
|
+
// Exactly one TOC at a time: a pinned rail while wide; once Split stacks, the
|
|
19
|
+
// aside is dropped (null renders no cell) and a collapsed TOC leads the main pane.
|
|
20
|
+
// align="stretch" is required for the pin: Split defaults to align="start", so the aside
|
|
21
|
+
// cell would be only as tall as the TOC and Sticky would have nothing to pin within.
|
|
22
|
+
<Split
|
|
23
|
+
side="end"
|
|
24
|
+
asideWidth="240px"
|
|
25
|
+
align="stretch"
|
|
26
|
+
collapseBelow="md"
|
|
27
|
+
onCollapsedChange={setNarrow}
|
|
28
|
+
aside={
|
|
29
|
+
narrow ? null : (
|
|
30
|
+
<Sticky top="topbar">
|
|
31
|
+
<TableOfContents items={toc} />
|
|
32
|
+
</Sticky>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
>
|
|
36
|
+
{narrow && <TableOfContents items={toc} collapsed />}
|
|
37
|
+
<article>
|
|
38
|
+
<h2 id="overview">Overview</h2>
|
|
39
|
+
<h3 id="install">Install</h3>
|
|
40
|
+
<h2 id="usage">Usage</h2>
|
|
41
|
+
</article>
|
|
42
|
+
</Split>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
<!-- props:start -->
|
|
48
|
+
|
|
49
|
+
## Props
|
|
50
|
+
|
|
51
|
+
<!-- prettier-ignore -->
|
|
52
|
+
| Prop | Type | Required | Description |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| `items` | `readonly TableOfContentsItem[]` | yes | Entries in document order. An empty list renders nothing. |
|
|
55
|
+
| `collapsed` | `boolean` | no | Render a `<details>` disclosure (summary "On this page · <active>") instead of the heading + list. Use where there is no room for a side rail, e.g. on narrow viewports above the content. Default `false`. |
|
|
56
|
+
| …native | | | plus native HTML attributes |
|
|
57
|
+
|
|
58
|
+
<!-- props:end -->
|
|
59
|
+
|
|
60
|
+
- `items` are explicit `{ id, label, level: 2 | 3 }`; every `id` must match a heading's `id` on the page. Level 3 is indented under the preceding level 2.
|
|
61
|
+
- Exactly one `<nav>` named "On this page", in both modes. Override with `aria-label` when two TOCs share a page.
|
|
62
|
+
- The active link gets `aria-current="location"`; there are no live announcements. The server render has no active item.
|
|
63
|
+
- Only the **window** scrolls: scroll-spy and click-scroll ignore inner scroll containers.
|
|
64
|
+
- Click scrolls smoothly (instantly under `prefers-reduced-motion`) to the heading's top minus `--sticky-top-topbar`, updates the URL hash (`pushState`, or `replaceState` when the hash is unchanged) and focuses the heading. A heading that isn't focusable gets `tabindex="-1"` added, and keeps it.
|
|
65
|
+
- Modifier clicks (cmd/ctrl/shift/alt, non-primary button) and ids with no matching element fall through to native link behaviour.
|
|
66
|
+
- Scrolled to the bottom of the page, the last item is active (short final sections can't otherwise reach the top). A page too short to scroll counts as scrolled to the bottom, so its last item is active.
|
|
67
|
+
- The hash update uses `history.pushState` / `replaceState`, which fire no `hashchange`: router or `hashchange` listeners don't see the jump.
|
|
68
|
+
- `collapsed` renders a `<details>` disclosure (summary "On this page · active heading"); choosing an entry closes it.
|
|
69
|
+
- Empty `items` renders nothing.
|
|
70
|
+
- For `#hash` links opened directly (not via a click) to clear the bar, add `html { scroll-padding-top: var(--sticky-top-topbar); }` to the app's global CSS.
|
|
71
|
+
|
|
72
|
+
When NOT to use: app or page-level navigation → `Rail` / `Tabs`; short pages with a few headings need no TOC; headings inside an inner scroll container (only the window is tracked).
|
|
73
|
+
|
|
74
|
+
- ❌ Omitting the `<Sticky top="topbar">` wrapper and expecting the rail to pin: the component is not sticky.
|
|
75
|
+
- ❌ `items` ids that don't match heading ids: the entry renders but never becomes active, and clicking falls back to native jump (no TopBar offset).
|
|
76
|
+
- ❌ Rendering the rail TOC and the collapsed TOC together: that yields two "On this page" navs. Render one at a time (`narrow ? null : rail`, `narrow && collapsed`).
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# `<Tabs>` — tab strip (horizontal or vertical)
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
const [tab, setTab] = useState('overview');
|
|
5
|
+
|
|
6
|
+
<Tabs
|
|
7
|
+
items={[
|
|
8
|
+
{ id: 'overview', label: 'Overview', icon: <Eye size={14} /> },
|
|
9
|
+
{ id: 'activity', label: 'Activity', icon: <Activity size={14} />, count: 12 },
|
|
10
|
+
]}
|
|
11
|
+
activeId={tab}
|
|
12
|
+
onChange={setTab}
|
|
13
|
+
/>;
|
|
14
|
+
{
|
|
15
|
+
tab === 'overview' && <OverviewPanel />;
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
<!-- props:start -->
|
|
20
|
+
|
|
21
|
+
## Props
|
|
22
|
+
|
|
23
|
+
<!-- prettier-ignore -->
|
|
24
|
+
| Prop | Type | Required | Description |
|
|
25
|
+
|---|---|---|---|
|
|
26
|
+
| `items` | `TabItem[]` | yes | The tabs to render. Each item must have a unique `id`. |
|
|
27
|
+
| `activeId` | `string` | yes | 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). |
|
|
28
|
+
| `onChange` | `(id: string) => void` | yes | Called with the tab id when the user activates a different tab. Won't fire when re-clicking the already-active tab. |
|
|
29
|
+
| `panelIdPrefix` | `string` | no | Optional id prefix for controlled tabpanels. When set, the ACTIVE tab gets `aria-controls="${panelIdPrefix}-${itemId}-panel"` — the consumer must render the matching panel with that id. When omitted, NO tab carries `aria-controls` at all — the internal id (sanitized React `useId`) named below is the tab's own id, not a panel's, and pointing at it would be the dangling IDREF that was removed. Only the active tab carries it, because consumers render only the active panel; stamping every tab would point N-1 of them at elements that do not exist. Inactive tabs keep their own `id` for the panel's `aria-labelledby` to reference. |
|
|
30
|
+
| `activationMode` | `'auto' \| 'manual'` | no | `'auto'` (default): arrow keys move focus AND fire onChange — the visible panel changes with each keystroke. Best for cheap, eager-rendered panels. `'manual'`: arrow keys only move focus; Enter/Space (the native button activation keys) then commits via onChange. Use this when panels are expensive (lazy-load, network) so the user can scan tab labels without triggering loads. |
|
|
31
|
+
| `orientation` | `'horizontal' \| 'vertical' \| 'auto'` | no | `'horizontal'` (default) — a horizontal strip with a sliding underline. `'vertical'` — a stacked master–detail rail: full-width rows, a left accent bar + tinted background on the active row, and ArrowUp/ArrowDown navigation. `'auto'` — measures available Tabs/tab-strip width: vertical below `autoOrientationBreakpoint` and horizontal at or above it. It starts vertical during SSR and whenever `ResizeObserver` is unavailable. Use it with a collapsing `Split`: the fixed-width aside remains a vertical rail, then the full-width stacked tablist becomes horizontal. `aria-orientation`, keyboard navigation, and presentation always follow the effective orientation. |
|
|
32
|
+
| `autoOrientationBreakpoint` | `number` | no | Available tab-strip width in px where `orientation="auto"` switches from vertical to horizontal. Defaults to `320`. Set this per Tabs instance to align automatic orientation with the surrounding layout's threshold. |
|
|
33
|
+
| `action` | `TabsAction` | no | A trailing action rendered after the tab items, inside the same strip (e.g. `{ label: 'New deal', icon: <Plus/>, onClick: addDeal }`). Styled tab-like but visibly muted, never becomes the selected tab, and is skipped by arrow-key roving — reachable via the Tab key instead. For controls that apply to the whole bar but aren't shaped like a tab (a filter toggle), use `endContent`. For a control on a single tab, use `TabItem.actions`. |
|
|
34
|
+
| `endContent` | `ReactNode` | no | Controls for the whole tab bar (e.g. an "add tab" button, a filter toggle), rendered at the end of the strip OUTSIDE the tablist so it never scrolls with the tabs and is not part of tab keyboard navigation. For a control attached to a single tab, use `TabItem.actions` instead. |
|
|
35
|
+
| …native | | | plus native `<div>` attributes |
|
|
36
|
+
|
|
37
|
+
<!-- props:end -->
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
// Responsive master–detail rail:
|
|
41
|
+
<Split
|
|
42
|
+
asideWidth="220px"
|
|
43
|
+
collapseBelow="sm"
|
|
44
|
+
aside={
|
|
45
|
+
<Tabs
|
|
46
|
+
orientation="auto"
|
|
47
|
+
items={[
|
|
48
|
+
{ id: 'general', label: 'General' },
|
|
49
|
+
{ id: 'security', label: 'Security', trailing: <Badge tone="warning">Unsaved</Badge> },
|
|
50
|
+
{ id: 'billing', label: 'Billing', count: 3 },
|
|
51
|
+
]}
|
|
52
|
+
activeId={section}
|
|
53
|
+
onChange={setSection}
|
|
54
|
+
/>
|
|
55
|
+
}
|
|
56
|
+
>
|
|
57
|
+
<SectionPanel id={section} />
|
|
58
|
+
</Split>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- `items: { id, label, icon?, count?, leading?, trailing?, actions? }[]` — `id` must be unique. `icon` is a decorative leading glyph; `count` renders as a chip after the label. `leading`/`trailing` are free-form ReactNode adornments (status dot, unsaved-changes `Badge`); they are NOT `aria-hidden`, so give meaningful ones accessible text. In vertical orientation `trailing` pins to the row's right edge.
|
|
62
|
+
- `actions` on a `TabItem` renders **interactive** control(s) (a `Switch`, a close button, a `⋯` menu) OUTSIDE that tab's `role="tab"` button — use it for anything focusable/clickable (a `Badge` or a static status dot stays in `leading`/`trailing`, which render _inside_ the button). `endContent` (a `TabsProps` slot) renders controls for the whole bar (an "add tab" button, a filter toggle) at the end of the strip, outside the tablist, so they never scroll with the tabs and aren't part of arrow-key tab navigation. Keyboard: arrows rove tabs only; `Tab` reaches a tab's `actions`, then `endContent`. Each per-tab `actions` adds a Tab stop, so they're cleanest on the active tab or a handful of tabs.
|
|
63
|
+
- `attrs` on a `TabItem` (``Record<`data-${string}`, string>``) spreads onto that tab's `role="tab"` button, before the component's own attributes (a key can't override the `id`/`role`/`aria-*`/handlers Tabs owns). Use it to target one tab from a `Tour` or to add a test/analytics id: `{ id: 'sec', label: 'Security', attrs: { 'data-tour': 'security-tab' } }`, then `<Tour steps={[{ target: 'security-tab', title: '...' }]} />`.
|
|
64
|
+
- The active-tab underline slides between tabs when `activeId` changes. Respects `prefers-reduced-motion: reduce`.
|
|
65
|
+
- `action?: { label, icon?, onClick, disabled? }` renders a `+ New entity`-style button-like pseudo-tab after the tab items, inside the same strip — tab-shaped but visibly muted, NOT `role="tab"`, never selected, skipped by arrow-key roving (reachable via `Tab` instead), and the sliding indicator never targets it. It only fires `onClick`; if the click should change `activeId`, do that yourself in the handler (e.g. append + select a new tab). Known, accepted a11y tradeoff: like the `TabItem.actions` button, this leaves one non-`"tab"` child in the `role="tablist"` container (an `aria-required-children` deviation) — a real `<button>` still announces correctly to assistive tech regardless of its parent's role.
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
// Lazy-loaded panels — manual mode, so arrows scan without loading:
|
|
69
|
+
<Tabs items={items} activeId={tab} onChange={setTab} activationMode="manual" />
|
|
70
|
+
|
|
71
|
+
// Trailing action — a button-like pseudo-tab that never becomes selected:
|
|
72
|
+
<Tabs
|
|
73
|
+
items={items}
|
|
74
|
+
activeId={tab}
|
|
75
|
+
onChange={setTab}
|
|
76
|
+
action={{ label: '+ New entity', icon: <Plus size={14} />, onClick: createEntity }}
|
|
77
|
+
/>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Implements the WAI-ARIA Tabs pattern: roving `tabIndex`, arrow keys (Left/Right horizontal, Up/Down vertical) plus Home/End, `aria-controls`, `aria-orientation`, per-tab/per-panel ids. Controlled: pass `activeId` and `onChange`.
|
|
81
|
+
|
|
82
|
+
**When NOT to use**
|
|
83
|
+
|
|
84
|
+
- Navigation between pages: use the sidebar or breadcrumbs. Tabs switch views within a page.
|
|
85
|
+
- 5+ tabs: usually the entity is doing too much; split the page or rethink the IA.
|
|
86
|
+
- When the user may want two views at once: use side-by-side panels.
|
|
87
|
+
|
|
88
|
+
**Anti-patterns**
|
|
89
|
+
|
|
90
|
+
- Lazy-loading tab content but losing form state on switch: preserve state or warn before data is lost.
|
|
91
|
+
- The page's primary action inside a tab: it belongs in the page header.
|
|
92
|
+
- `orientation="vertical"` as a page sidebar / primary navigation: it is for intra-page section switching, not route changes.
|
|
93
|
+
- `orientation="auto"` combined with app-owned viewport measurement: auto measures the available strip width, so let it react to the `Split`'s layout instead of duplicating breakpoint state.
|
|
94
|
+
- `action` to switch views: it never sets `activeId`; if the click should select a tab, add a `TabItem`.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# `<Text>` — body / inline text
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
<Text>Default body — block <p>, md, regular.</Text>
|
|
5
|
+
<Text as="span" size="sm" tone="muted">12m ago</Text>
|
|
6
|
+
<Text as="label" htmlFor="email" weight="medium">Email</Text>
|
|
7
|
+
<Text lineClamp={2}>A long description that wraps and ellipses after two lines.</Text>
|
|
8
|
+
<Text size="sm" tone="danger">Email is required.</Text>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
<!-- props:start -->
|
|
12
|
+
|
|
13
|
+
## Props
|
|
14
|
+
|
|
15
|
+
<!-- prettier-ignore -->
|
|
16
|
+
| Prop | Type | Required | Description |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| `htmlFor` | `string` | no | Associates a `<label>` with its form control. Only meaningful when `as="label"` — passes through as the native `for` attribute. |
|
|
19
|
+
| `as` | `'p' \| 'span' \| 'div' \| 'label'` | no | Rendered element. Defaults to `'p'` (block, default body text). Use `'span'` for inline runs, `'div'` for block containers that can't be a `<p>` (e.g. when the body needs nested block-level elements that React would warn about inside `<p>`), `'label'` for form labels (pair with `htmlFor`). |
|
|
20
|
+
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'inherit'` | no | Visual size. Defaults to `'md'` (body text). - `xs` — 11px, dense metadata / captions - `sm` — 12px, small body / labels - `md` — 14px, body text (default) - `lg` — 16px, large body / lead text - `xl` — 20px, very large body (rare) - `inherit` — no fixed size; font-size AND line-height inherit from the parent. For inline runs inside a heading (`as="span"` inside a `<Title>` / `<PageHeader.Title>`) that must keep the heading's size — e.g. a muted task-key prefix. Tone / weight still apply — font-weight stays Text's own (default `regular`), it does NOT inherit; pass `weight` to match the heading if needed. |
|
|
21
|
+
| `tone` | `'default' \| 'muted' \| 'subtle' \| 'accent' \| 'danger' \| 'success' \| 'warning'` | no | Color tone. Defaults to `'default'`. - `default` — `--color-fg` - `muted` — `--color-fg-muted` (for secondary copy) - `subtle` — **@deprecated: resolves to `muted`. Use `muted`.** In LIGHT theme the two neutrals were indistinguishable: OKLab ΔE 0.0261 when the deprecation was filed, 0.0365 after `--color-fg-muted` was retuned, against the 0.065 floor this library's perceptual gates use. In DARK they were 0.0707 apart — a real step — so **this deprecation changes dark-theme appearance**: `subtle` text in dark gets lighter, moving from `--color-fg-subtle` to `--color-fg-muted`. That is the accepted trade (a tier that exists in one theme only is not a tier), but it is a visual change, not the removal of a duplicate. `--text-fg-subtle` now aliases `--text-fg-muted`, so nothing breaks at the type or build level; if you need the old dark value back, override `--text-fg-subtle`. - `accent` — `--color-accent` - `danger` / `success` / `warning` — state-coded text |
|
|
22
|
+
| `weight` | `'regular' \| 'medium' \| 'semibold' \| 'bold'` | no | Font weight. Defaults to `'regular'`. |
|
|
23
|
+
| `align` | `'left' \| 'center' \| 'right'` | no | Text alignment. Defaults to `'left'`. |
|
|
24
|
+
| `truncate` | `boolean` | no | Truncate to a single line with ellipsis. Defaults to `false`. Use inside narrow containers (table cells, card list rows). Mutually exclusive with `lineClamp` — if both are set, `lineClamp` wins. |
|
|
25
|
+
| `lineClamp` | `number` | no | Clamp to N lines with ellipsis (uses `-webkit-line-clamp`). Defaults to `undefined`. Overrides `truncate` when set. Example: `lineClamp={2}` for a 2-line description that ellipses on the third. If you also pass `style.WebkitLineClamp`, the `lineClamp` prop takes precedence — the component merges the dynamic line-clamp value into `style` AFTER spreading your `style`, so the prop wins. |
|
|
26
|
+
| `children` | `ReactNode` | yes | Text content. |
|
|
27
|
+
| …native | | | plus native HTML attributes |
|
|
28
|
+
|
|
29
|
+
<!-- props:end -->
|
|
30
|
+
|
|
31
|
+
- `as: 'p' | 'span' | 'div' | 'label'` (default `'p'`). Constrained string union — no polymorphic generic.
|
|
32
|
+
- `size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'inherit'` (default `'md'`).
|
|
33
|
+
- **Use `<Text>` for every non-heading run.** No more `<span style={{ fontSize: 'var(--font-size-sm)', color: 'var(--color-fg-muted)' }}>`.
|
|
34
|
+
- **`size="inherit"`** — for a muted/toned inline run INSIDE a heading (e.g. `<Text as="span" size="inherit" tone="muted">ENG-5</Text>` at the start of a `<Title order={1}>` task name) that must keep the heading's size instead of shrinking to `md`. Font-size AND line-height both inherit from the parent.
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
// Muted inline run inside a heading — keeps the heading's font size:
|
|
38
|
+
<Title order={1}>
|
|
39
|
+
<Text as="span" size="inherit" tone="muted">ENG-5</Text> Fix login
|
|
40
|
+
</Title>
|
|
41
|
+
|
|
42
|
+
// Body copy under a heading, spaced with Stack — the canonical CRM-page shape:
|
|
43
|
+
<Stack gap="xs">
|
|
44
|
+
<Title order={2}>Pipeline</Title>
|
|
45
|
+
<Text tone="muted">Active deals for Q3.</Text>
|
|
46
|
+
</Stack>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
If you need a size or tone the primitive doesn't expose, that is a token-vocabulary conversation, not a reason to skip the component.
|
|
50
|
+
|
|
51
|
+
**When NOT to use**
|
|
52
|
+
|
|
53
|
+
- Heading text: use `<Title order={N}>`.
|
|
54
|
+
- Inline code: use `<Code>`.
|
|
55
|
+
- Clickable text / action triggers: use `<Button>` or `<Link>`.
|
|
56
|
+
- Pure layout containers: use `<Stack>` / `<Cluster>` / `<Grid>`.
|
|
57
|
+
|
|
58
|
+
**Anti-patterns**
|
|
59
|
+
|
|
60
|
+
- `<Text style={{ color: '#someHex' }}>`: pick a tone from the whitelist; the whitelist is the contract.
|
|
61
|
+
- `<Text as="h2">`: Text doesn't accept heading tags; use `<Title order={2}>`.
|
|
62
|
+
- Wrapping a `<Title>` in `<Text>` for tone/weight tweaks: pass tone/weight to the `<Title>`. `size="inherit"` is for runs INSIDE a heading, not for wrapping it.
|
|
63
|
+
- Nesting `<Text>` in another `<Text>` with the default `as="p"`: the inner `<p>` inside the outer `<p>` is invalid HTML and triggers React's DOM nesting warning. Use `<Text as="span" tone="...">` for an inline override inside a paragraph.
|