@eocrm/design-system 0.0.0-stage → 0.6.17
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/README.md +262 -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 +82 -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,131 @@
|
|
|
1
|
+
# `<DashboardWidget>` — card for a DashboardCanvas cell
|
|
2
|
+
|
|
3
|
+
A widget card that fills its `DashboardCanvas` cell, in five presentations: `standard`, `list`, `kpi`, `chart` and `stats`. Owns the header (title, actions), the body chrome and a variant-matched loading skeleton. The app keeps data, error state, permissions and the overflow menu.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import {
|
|
7
|
+
Card,
|
|
8
|
+
Chart,
|
|
9
|
+
DashboardCanvas,
|
|
10
|
+
DashboardWidget,
|
|
11
|
+
EmptyState,
|
|
12
|
+
ErrorState,
|
|
13
|
+
} from '@eocrm/design-system';
|
|
14
|
+
|
|
15
|
+
<DashboardCanvas
|
|
16
|
+
items={layout}
|
|
17
|
+
onItemsChange={setLayout}
|
|
18
|
+
renderItem={(id) => (
|
|
19
|
+
<DashboardWidget
|
|
20
|
+
variant="kpi"
|
|
21
|
+
title="Open deals"
|
|
22
|
+
actions={menu}
|
|
23
|
+
value="128"
|
|
24
|
+
trend={{ label: '+12% vs last month', direction: 'up' }}
|
|
25
|
+
/>
|
|
26
|
+
)}
|
|
27
|
+
/>;
|
|
28
|
+
|
|
29
|
+
// kpi with a trend graphic: a Sparkline child renders under value/trend
|
|
30
|
+
<DashboardWidget variant="kpi" title="Open deals" value="128">
|
|
31
|
+
<Sparkline label="Open deals per day" values={dailyCounts} />
|
|
32
|
+
</DashboardWidget>;
|
|
33
|
+
|
|
34
|
+
// kpi, where "up" is bad
|
|
35
|
+
<DashboardWidget
|
|
36
|
+
variant="kpi"
|
|
37
|
+
title="Churned accounts"
|
|
38
|
+
value="14"
|
|
39
|
+
trend={{ label: '+3 vs last month', direction: 'up', sentiment: 'negative' }}
|
|
40
|
+
/>;
|
|
41
|
+
|
|
42
|
+
// list: Card.List bleeds edge to edge
|
|
43
|
+
<DashboardWidget variant="list" title="Tasks due" actions={menu} loading={isLoading}>
|
|
44
|
+
<Card.List>{/* rows */}</Card.List>
|
|
45
|
+
</DashboardWidget>;
|
|
46
|
+
|
|
47
|
+
// chart: the plot fills the cell; a note under it goes in Chart's `footnote`
|
|
48
|
+
<DashboardWidget variant="chart" title="Revenue">
|
|
49
|
+
<Chart
|
|
50
|
+
type="line"
|
|
51
|
+
label="Revenue per month"
|
|
52
|
+
categories={months}
|
|
53
|
+
series={revenue}
|
|
54
|
+
formatValue={formatCurrency}
|
|
55
|
+
footnote="3 deals in other currencies not included"
|
|
56
|
+
/>
|
|
57
|
+
</DashboardWidget>;
|
|
58
|
+
|
|
59
|
+
// stats: a StatGroup KPI strip; compact padding leaves slack in a 3-row cell
|
|
60
|
+
<DashboardWidget variant="stats" title="Key metrics">
|
|
61
|
+
<StatGroup aria-label="Key metrics">{/* StatTiles */}</StatGroup>
|
|
62
|
+
</DashboardWidget>;
|
|
63
|
+
|
|
64
|
+
// quiet view-mode header: actions appear on hover / focus
|
|
65
|
+
<DashboardWidget title="Pipeline" actions={menu} actionsReveal="hover">
|
|
66
|
+
{/* body */}
|
|
67
|
+
</DashboardWidget>;
|
|
68
|
+
|
|
69
|
+
// standard (default), with error and empty states as children
|
|
70
|
+
<DashboardWidget title="Recent activity" loading={isLoading}>
|
|
71
|
+
{error ? (
|
|
72
|
+
<ErrorState title="Could not load" headingLevel={4} />
|
|
73
|
+
) : items.length === 0 ? (
|
|
74
|
+
<EmptyState title="Nothing yet" />
|
|
75
|
+
) : (
|
|
76
|
+
<Feed items={items} />
|
|
77
|
+
)}
|
|
78
|
+
</DashboardWidget>;
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
<!-- props:start -->
|
|
82
|
+
|
|
83
|
+
## Props
|
|
84
|
+
|
|
85
|
+
<!-- prettier-ignore -->
|
|
86
|
+
| Prop | Type | Required | Description |
|
|
87
|
+
|---|---|---|---|
|
|
88
|
+
| `variant` | `'standard' \| 'list' \| 'kpi' \| 'chart' \| 'stats'` | no | Presentation variant. Default `'standard'`. - `'standard'` — header (title + actions) over a padded scrolling body. Today's widget card. - `'list'` — same fixed header as `standard`; flush scrolling body so `Card.List` bleeds edge to edge. - `'kpi'` — compact muted title, a large `value`, optional `trend`; optional `children` below. No scrolling. - `'chart'` — compact header; flush non-scrolling body that fills the cell (give the plot `height: 100%`). - `'stats'` — compact header and padding over a scrolling body, for a `StatGroup` KPI strip; unlike `standard` it leaves vertical slack in a 3-row cell. |
|
|
89
|
+
| `title` | `ReactNode` | yes | Widget title, rendered as the heading at `headerLevel`. Required. |
|
|
90
|
+
| `meta` | `ReactNode` | no | Secondary, non-interactive header text such as freshness ("Updated 3 minutes ago") or status. Sits before `actions` and yields first in a narrow cell: it truncates (then hides visually, still read by screen readers) before the title shrinks, while `actions` never shrinks. Also describes the body region (`aria-describedby`) for `standard` / `list` / `stats`. Repeat it in the refresh button's tooltip if it matters when truncated. |
|
|
91
|
+
| `actions` | `ReactNode` | no | Header actions, e.g. the edit-mode overflow `DropdownMenu`. Never wraps. |
|
|
92
|
+
| `actionsReveal` | `'always' \| 'hover'` | no | When `actions` are visible. Default `'always'`. - `'always'` — always shown. - `'hover'` — dimmed to invisible until the card is hovered or holds focus (they stay in the tab order, and Tab into the card reveals them); an open menu launched from an action keeps them shown. On touch / `(hover: none)` they stay visible. They keep their layout width. |
|
|
93
|
+
| `headerLevel` | `'h2' \| 'h3' \| 'h4' \| 'h5' \| 'h6'` | no | Heading level of the title. Default `'h3'`. |
|
|
94
|
+
| `value` | `ReactNode` | no | KPI value (`variant="kpi"` only), e.g. `"128"` or a formatted currency node. |
|
|
95
|
+
| `trend` | `DashboardWidgetTrend` | no | KPI trend (`variant="kpi"` only). |
|
|
96
|
+
| `loading` | `boolean` | no | Show a variant-matched loading skeleton instead of the body (and, for kpi, instead of `value`/`trend`); title and actions stay. Adds visually hidden "Loading…" body text and `aria-busy`. Deliberately NO live region: a dashboard loads many widgets at once, so per-widget announcements would flood screen readers — announce "dashboard loaded" once at page level if needed. Default `false`. |
|
|
97
|
+
| `children` | `ReactNode` | no | Widget body. Pass `ErrorState` / `EmptyState` here for error and empty states. |
|
|
98
|
+
| …native | | | plus native `<div>` attributes |
|
|
99
|
+
|
|
100
|
+
<!-- props:end -->
|
|
101
|
+
|
|
102
|
+
- **Fills its cell.** It is a `<Card fill padding="none">`; `DashboardCanvas` sizes the cell, the widget fills it. The root is a `div` with a heading (no landmark; 20 regions on one dashboard is noise). Heading level is `headerLevel` (default `h3`).
|
|
103
|
+
- **Variants.** `standard`: header + padded scrolling body. `list`: same fixed header as `standard`, flush scrolling body so `Card.List` bleeds edge to edge. `kpi`: compact muted title, large `value`, optional `trend`, optional `children` below; does not scroll. `chart`: compact header, flush body that does not scroll and fills the remaining height, so give the plot `height: 100%`. `stats`: compact header and padding over a scrolling body, for a [`StatGroup`](StatGroup.md) KPI strip; scrolls only on real overflow.
|
|
104
|
+
- **Only `standard`, `list` and `stats` scroll.** `kpi` and `chart` bodies are non-scrolling (`Card.Body` without `scroll`).
|
|
105
|
+
- **`value` / `trend` are kpi only** and ignored on other variants.
|
|
106
|
+
- **Trend.** Direction icon plus a visually hidden "Increase / Decrease / No change" before `label`. Colour is by `sentiment`, which defaults from direction (up positive, down negative, flat neutral). Set `sentiment` explicitly when the direction is not the judgement (churn, overdue tasks up = `negative`).
|
|
107
|
+
- **`loading`** swaps the body (for kpi, the value and trend) for a skeleton matching the variant (standard: lines, list: rows, kpi: value + trend, chart: bars, stats: kpi shape). Title and actions stay. For `stats`, prefer `StatGroup loading` (per-tile skeletons) over widget `loading`, which shows a single kpi blob; don't set both. The skeleton is `aria-hidden`; the body instead contains visually hidden "Loading..." text and the root gets `aria-busy` as a hint.
|
|
108
|
+
- **No live region, on purpose.** A dashboard loads 10 to 20 widgets at once; a live region per widget would flood a screen reader. If you want an announcement, make one at page level ("Dashboard loaded") once all widgets settle. That is the app's job.
|
|
109
|
+
- **Error and empty states** are the app's `ErrorState` / `EmptyState`, passed as `children` (for kpi, as `value` or `children`).
|
|
110
|
+
- **`actions`** (e.g. an edit-mode `DropdownMenu`) sit at the header's end and never wrap.
|
|
111
|
+
- **`actionsReveal="hover"`** (default `'always'`) is for quiet view-mode headers: the actions are transparent until the card is hovered or holds focus (`:focus-within`, so Tab into the card reveals them), and stay shown while a menu launched from them is open. They are hidden with opacity only: they keep their layout width (the title and meta do not jump) and stay in the tab order. On touch / `(hover: none)` they are always visible.
|
|
112
|
+
- **`meta`** is secondary, non-interactive header text (freshness such as "Updated 3 minutes ago", or status). It sits just before `actions`, muted and on one line, and yields first in a narrow cell: it truncates with an ellipsis, then hides visually (screen readers still read it) once only a sliver is left, before the title gives up any width, while `actions` keeps its width. For `standard` / `list` / `stats` it also describes the body region (`aria-describedby`). If the text matters when truncated, repeat it in the refresh button's tooltip.
|
|
113
|
+
|
|
114
|
+
#### When NOT to use
|
|
115
|
+
|
|
116
|
+
- ❌ A generic content card outside a dashboard → `<Card>`.
|
|
117
|
+
- ❌ A standalone stat with no grid cell → `<Card>` with your own layout.
|
|
118
|
+
- ❌ A placeholder in a widget catalog → `<WidgetPreview>`.
|
|
119
|
+
|
|
120
|
+
#### Anti-patterns
|
|
121
|
+
|
|
122
|
+
- ❌ `actionsReveal="hover"` when the only way to reach an essential action is that header. Touch users see it, but mouse users get no visible cue; keep primary actions visible.
|
|
123
|
+
- ❌ Wrapping `DashboardWidget` in another `Card`. It already is one.
|
|
124
|
+
- ❌ Freshness or status text in `actions`. `actions` never shrinks, so the title gets crushed in a narrow cell; use `meta`.
|
|
125
|
+
- ❌ Buttons or links in `meta`. They can be truncated out of reach; controls go in `actions`.
|
|
126
|
+
- ❌ `standard` for a `StatGroup` KPI strip in a 3-row widget: the roomy padding leaves no slack and the strip scrolls. Use `stats`.
|
|
127
|
+
- ❌ Passing `value` / `trend` to `standard`, `list`, `chart` or `stats`. They are ignored; put content in `children`.
|
|
128
|
+
- ❌ Rendering your own `Skeleton` in `children` instead of `loading`. You lose the variant-matched shape, the hidden "Loading..." text and `aria-busy`.
|
|
129
|
+
- ❌ Adding a live region (`role="status"`, `aria-live`) to each widget while loading.
|
|
130
|
+
- ❌ Relying on direction-derived colour when up is bad. Set `sentiment`.
|
|
131
|
+
- ❌ A scrolling or fixed-height wrapper inside a `kpi` / `chart` body. The cell is the size; size the plot at `height: 100%`.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# `<DataTable>` — server-driven data table with column features
|
|
2
|
+
|
|
3
|
+
- The table owns its polite live region; do not wrap it in another — two regions would fire for one event.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
const instance = useDataTable<Deal>({
|
|
7
|
+
data,
|
|
8
|
+
columns,
|
|
9
|
+
getRowId: (r) => r.id,
|
|
10
|
+
enableRowSelection: true,
|
|
11
|
+
sort,
|
|
12
|
+
onSortChange: setSort,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
<Cluster>
|
|
16
|
+
<ColumnVisibilityTrigger instance={instance} />
|
|
17
|
+
</Cluster>
|
|
18
|
+
<DataTable instance={instance} aria-label="Deals" />
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
<!-- props:start -->
|
|
22
|
+
|
|
23
|
+
## Props
|
|
24
|
+
|
|
25
|
+
<!-- prettier-ignore -->
|
|
26
|
+
| Prop | Type | Required | Description |
|
|
27
|
+
|---|---|---|---|
|
|
28
|
+
| `instance` | `DataTableInstance<T>` | yes | |
|
|
29
|
+
| `density` | `'comfortable' \| 'dense'` | no | |
|
|
30
|
+
| `striped` | `boolean` | no | |
|
|
31
|
+
| `hover` | `boolean` | no | Hover highlight on body rows. Defaults TRUE (DataTable rows are usually interactive). |
|
|
32
|
+
| `bordered` | `boolean` | no | |
|
|
33
|
+
| `loading` | `boolean` | no | Marks the table busy. Empty tables show skeleton rows; populated tables keep their rows mounted during a refetch so focus and local row state are preserved. Defaults to `false`. Announced from a polite live region the table owns, gated on the SKELETON rather than on this prop: a load shorter than `skeletonDelay` shows nothing and so says nothing, and a refetch over rows already on screen is silent because nothing visibly changes. The resolution is announced too — "Rows loaded" or "No rows loaded". `aria-busy` is also set, but reaches no screen reader on its own. |
|
|
34
|
+
| `loadingRowCount` | `number` | no | Number of skeleton rows when `loading`. Defaults 10. |
|
|
35
|
+
| `skeletonDelay` | `number` | no | Milliseconds to wait before showing skeleton rows for an empty initial load. Defaults to `0`; fast loads that finish inside the delay never show a skeleton. |
|
|
36
|
+
| `skeletonMinDuration` | `number` | no | Minimum milliseconds skeleton rows remain visible after appearing. Defaults to `0`. Arriving rows and the empty state remain hidden until the visual tail finishes. `aria-busy` still follows actual `loading`, not the skeleton's visual tail. |
|
|
37
|
+
| `emptyState` | `ReactNode` | no | Element shown when `data` is empty and not loading. Defaults to a stock <EmptyState>. |
|
|
38
|
+
| `collapseBelow` | `'sm' \| 'md' \| 'lg'` | no | Stacks responsive data cells below this container-query breakpoint: `sm` (480px), `md` (640px), or `lg` (768px). Selection, expansion, sorting, row actions, and column visibility remain usable. Column sizing, pinning, and ordering state is retained, but resize/reorder controls and sticky pin presentation are unavailable while stacked and return after widening. This adds a wrapper with `container-type: inline-size`, so the breakpoint measures the table's available container width, not the viewport. Avoid an intrinsic-width parent such as `width: max-content`: inline-size containment can make the wrapper contribute zero intrinsic width there. |
|
|
39
|
+
| `aria-label` | `string` | no | Required for a11y when no caption is provided. |
|
|
40
|
+
| `caption` | `ReactNode` | no | |
|
|
41
|
+
| `dragWholeColumn` | `boolean` | no | Drag the whole column while reordering, not just its header cell. Default `true` — the dragged column's body cells travel with its header, and every column the drag displaces shifts its body cells too, so the header row and the body never disagree mid-drag. Costs one CSS-variable write per shifted column per frame; the cells move on the compositor, so the table body is not re-rendered during pointer movement. It does cost two full body reconciliations per drag — one at drag start, one at drag end — because the drag-active flag is component state and body rows are not memoized; that is the number to weigh for a very large table. Set `false` for the cheaper preview: only the dragged header cell follows the pointer and the body stays put until drop. Worth it for very large tables on low-end hardware, or to restore the previous behavior. Pinned columns never move under either setting — they are excluded from reordering entirely. The two settings also differ on **what a release means when no unpinned slot is under the column** — over a pinned column, or off the table entirely. Default: the drop commits the slot the preview is showing. The opt-out: the drop is discarded, because dnd-kit's own preview retracts (the header snaps back home) in that situation, and a commit would contradict it. See `docs/components/DataTable.md`, the column-drag bullet. |
|
|
42
|
+
| `className` | `string` | no | |
|
|
43
|
+
|
|
44
|
+
<!-- props:end -->
|
|
45
|
+
|
|
46
|
+
- Config-driven via `columns: ColumnDef<T>[]`. Each column has a stable `id` used as the key for all per-column state.
|
|
47
|
+
- **Column header names.** The `<th>` is named by the label span's content — the header text — so the resize handle is never folded into it. The one override: a header that renders no TEXT OF ITS OWN — a ReactNode, a render function, or `''` — is named by `visibilityLabel` when you set one. So `header: <strong>Revenue</strong>` announces "Revenue", and adding `visibilityLabel="Revenue (USD)"` makes it announce "Revenue (USD)". That is a name-vs-label mismatch, and a WCAG 2.5.3 one only when `sortable` makes the label a button — 2.5.3 is scoped to user interface components, and it is violated only when the label does not CONTAIN the visible text, so "Revenue (USD)" over "Revenue" passes. Accepted because the alternative — a runtime measurement deciding which source names the header — produced UNNAMED column headers ten separate times before it was deleted. A string header that renders text is always named by that text; `visibilityLabel` does not override it. `header: ''` is not such a string: it renders nothing, so the label wins, which is what the trailing row-actions column wants. `column.id` is used for nothing a user hears — not the header, not the drag grip, not the resize handle. What such a header announces, measured off Chromium's AX tree: an `aria-labelledby` resolving to no text is marked INVALID, not treated as a name, so naming falls through to the cell's contents — the drag grip, or under `collapseBelow` the resize handle's live pixel width. `header: ''` is special-cased to a generic "Unlabelled column" so the width cannot win; a ReactNode rendering nothing is indistinguishable from one that names itself, so it is not. Either way it is not a name you chose, so set `visibilityLabel` on every text-less header. That is a change from before the fix, where such a header WAS named — from content, which swept in the resize handle, so it announced the handle's label, `column.id` when the column had nothing better. That name was the bug, not a feature worth preserving. (The "Resize … column" wrapper came with that fix; before it the handle's label was the bare identifier.) There is no dev warning for it: nothing static can tell a node that names itself (`<strong>Revenue</strong>`) from one that does not (an icon), so a warning fired on the commonest valid shape and was removed. Give any non-text header a `visibilityLabel`.
|
|
48
|
+
- **Responsive rows:** `collapseBelow="sm" | "md" | "lg"` re-templates rows as labelled cards based on the DataTable container. Labels use `visibilityLabel`, then a string `header`; give non-text headers a `visibilityLabel` when a visible card label is required. Plain non-sortable string headers leave the compact strip, while React-node and render-function headers remain because they may contain controls. Sorting, selection, expansion, row actions, and `ColumnVisibilityTrigger` remain available. Column sizing, pinning, and ordering state is retained while stacked, but resize/reorder controls and sticky pin presentation are unavailable until the table widens again. Give the table concrete available width because inline-size containment has no intrinsic-width contribution.
|
|
49
|
+
- All state pieces (column order/sizing/visibility/pinning, row selection/expansion, sort) follow the Radix controlled/uncontrolled pattern: `value` + `onValueChange`, OR `defaultValue` only, OR neither.
|
|
50
|
+
- Server-driven sort/search/pagination. DataTable does NOT transform data — `data` must be the server's pre-sorted, pre-paginated slice. `onSortChange` is your trigger to refetch.
|
|
51
|
+
- `enableRowSelection: true` adds a leading checkbox column with select-all (indeterminate when partial). `toggleAllOnPage` ignores `pinnedRows`.
|
|
52
|
+
- Drag-to-reorder is keyboard-accessible (Tab to grip → Space to pick up → ←/→ to move → Space/Enter to drop → Esc to cancel). The grip is hover-revealed on desktop.
|
|
53
|
+
- Resize via the right-edge handle. Without `collapseBelow`, the legacy keyboard path stays on a focused sortable header label: `←`/`→` for −/+8px; Shift+`←`/`→` for ±32px. With `collapseBelow`, the wide presentation exposes a dedicated focusable resize separator with the same keys; the separator and resize interaction are unavailable while stacked and return after widening.
|
|
54
|
+
- `ColumnVisibilityTrigger` is the only built-in companion. For column pinning UI (Phase 2 ships state, no built-in UI), wire your own using `instance.pinColumn(id, side)`.
|
|
55
|
+
- **Phase 2 ships pinning rendering.** `columnPinning` now applies sticky CSS with cumulative offsets and an inside-edge shadow; `pinnedRows` renders in a separate `<tbody>` above the main body. The selection auto-column is auto-left-pinned at offset 0. Pinned columns are LOCKED in place — no drag grip, can't be reordered. Their sort still works. Declare initial pinning either on the hook (`defaultColumnPinning: { left: ['name'], right: ['actions'] }`) or directly on each column (`pin: 'left' | 'right'`); the hook prop wins when both are set. **Phase 3 ships expandable rows.** Pass `renderExpandedRow: (row) => ReactNode` to add a per-row chevron auto-column at the left edge. Clicking the chevron toggles a detail row beneath the main row, spanning all columns. ARIA-wired with `aria-expanded` + `aria-controls`. The chevron auto-column is sticky-left like the selection cell; when both are enabled, selection is first and expand is second. DataTable is now feature-complete per the original spec.
|
|
56
|
+
- **Cell content is single-line + ellipsized by default.** DataTable's internal table uses `table-layout: fixed` so column widths from `ColumnDef.size` (or runtime `columnSizing`) are authoritative, and every cell gets `overflow: hidden; text-overflow: ellipsis; white-space: nowrap`. Wide content truncates with `…` at the column boundary; the column does NOT expand to fit. If you need multi-line cells, render `<Table>` directly — DataTable is opinionated here so pinning offsets stay pixel-correct.
|
|
57
|
+
- **A column drag commits wherever the preview parked it** — however far the pointer roams, including over a pinned column or clear off the table. There is no "outside" to release into: the column is clamped to the unpinned band, so the preview is always showing a real slot and the drop honors it. This deliberately differs from `Kanban`, where releasing outside the columns cancels — there the pointer can genuinely aim somewhere else. **Escape is the only cancel.** The `dragWholeColumn={false}` opt-out is the exception: its preview is dnd-kit's own and RETRACTS (the header snaps home) when no unpinned slot is under the column, so a release there is discarded — matching what that preview shows.
|
|
58
|
+
|
|
59
|
+
**When NOT to use:**
|
|
60
|
+
|
|
61
|
+
- A static read-only table without column features — use `<Table>` directly.
|
|
62
|
+
- Huge datasets (10k+ rows on screen at once): rows are not virtualized, so it gets slow.
|
|
63
|
+
- Excel-like cell editing or cell selection — out of scope; compose it yourself.
|
|
64
|
+
|
|
65
|
+
**Anti-patterns:**
|
|
66
|
+
|
|
67
|
+
- ❌ Mutating `columns` array identity on every render. `useDataTable` captures `defaultColumnOrder` from `columns` once at mount — later identity changes don't trigger a re-derive of the default order. Use a stable reference (`useMemo` or module-level).
|
|
68
|
+
- ❌ Client-sorting `data` AND passing `sort` controlled. Pick one — server is the canonical source. Spinning both means rows reorder twice and ghost-rows appear during fetches. `data` is the server's pre-paginated, pre-sorted slice.
|
|
69
|
+
- ❌ Rolling your own column visibility UI when `ColumnVisibilityTrigger` does the job. The built-in handles the "last column" guard for you.
|
|
70
|
+
- ❌ Using `<Table>` directly when you want any of: ordering, sizing, visibility, selection, sort indicator wiring. Compose `<DataTable>` instead — the primitive `<Table>` is for static read-only views.
|
|
71
|
+
- ❌ Putting interactive controls in `renderExpandedRow` that need to participate in row selection or row click. The detail row is its own `<tr>`, not part of the main row — `onRowClick` doesn't fire from inside it (by design), and `rowSelection` only tracks main-row checkboxes.
|
|
72
|
+
- ⚠ Pinned rows (passed via `pinnedRows`) ALSO render a chevron when `renderExpandedRow` is set — they're expandable just like main-body rows. Decide whether your starred/anchored rows should reveal detail; if not, omit `renderExpandedRow` or filter `expandedRows` state in the consumer to ignore pinned-row ids.
|
|
73
|
+
|
|
74
|
+
#### `<ColumnVisibilityTrigger>`
|
|
75
|
+
|
|
76
|
+
Companion for `<DataTable>`: a ghost Button trigger plus a DropdownMenu of CheckboxItems, one per column where `enableHide !== false`. When only one hidable column is visible its item renders disabled, so the table can never reach a zero-column state. Pass the same `instance` to both `<DataTable>` and `<ColumnVisibilityTrigger>` so visibility state stays in sync.
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
// Custom label + right-aligned menu
|
|
80
|
+
<ColumnVisibilityTrigger instance={instance} label="Manage columns" align="end" />
|
|
81
|
+
|
|
82
|
+
// Icon-only trigger
|
|
83
|
+
<ColumnVisibilityTrigger instance={instance} label={null} />
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- When NOT to use: you want a different visibility UI (a settings drawer, a multi-select combobox, a Popover with column grouping) — build it against `instance.columns`, `instance.columnVisibility` and `instance.toggleColumnVisibility`; or every column has `enableHide: false` (the menu would be empty — don't render it).
|
|
87
|
+
- ❌ Passing a different `instance` to the trigger than to `<DataTable>`: visibility changes in one won't reflect in the other.
|
|
88
|
+
- ❌ Rendering it when every column has `enableHide: false` — check `instance.columns` first and suppress the trigger.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# `<DatePicker>` — single-date input + popover
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
const [value, setValue] = useState<Date | null>(null);
|
|
5
|
+
<DatePicker value={value} onChange={setValue} min={new Date()} />;
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
<!-- props:start -->
|
|
9
|
+
|
|
10
|
+
## Props
|
|
11
|
+
|
|
12
|
+
<!-- prettier-ignore -->
|
|
13
|
+
| Prop | Type | Required | Description |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| `value` | `Date \| null` | no | Selected date. `null` = no value. Pair with `onChange` for controlled use. |
|
|
16
|
+
| `defaultValue` | `Date \| null` | no | Initial selected date for uncontrolled use. |
|
|
17
|
+
| `onChange` | `((date: Date \| null) => void)` | no | Fires when the value changes. |
|
|
18
|
+
| `locale` | `string` | no | Override locale (otherwise reads `useLocale()`). |
|
|
19
|
+
| `min` | `Date` | no | Earliest selectable date (inclusive, day-granular). Gates both the grid and typed input. |
|
|
20
|
+
| `max` | `Date` | no | Latest selectable date (inclusive). |
|
|
21
|
+
| `isDateDisabled` | `((date: Date) => boolean)` | no | Per-date disable callback; applied per grid cell and to parsed typed input. |
|
|
22
|
+
| `clearable` | `boolean` | no | Show the ✕ clear button when a value is set. Defaults to `true`. |
|
|
23
|
+
| `invalid` | `boolean` | no | Toggle red border + focus ring + `aria-invalid="true"`. Pair with a visible error and `aria-describedby`. |
|
|
24
|
+
| `name` | `string` | no | Form name. When set, renders a hidden mirror `<input>` with the ISO date so native `<form>` submission works. |
|
|
25
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | no | Field height + type scale. Same scale as `<Input>`. Defaults to `'md'`. Affects only the trigger row; the popover month grid is fixed-size. - `'sm'` — 24px tall. - `'md'` — 32px tall (default). - `'lg'` — 40px tall. |
|
|
26
|
+
| `granularity` | `'day' \| 'minute'` | no | Picker precision. - `'day'` (default) — date only; behavior unchanged from prior releases. - `'minute'` — adds a manual-entry time input below the calendar grid. The trigger text shows `HH:mm` after the date. The hidden form mirror (when `name` is set) emits ISO local datetime (`2026-05-28T14:30`). Time is preserved across date re-picks. Picking from a `null` value defaults the time to `00:00`. In `'minute'` mode picking a day keeps the popover open and moves focus to the time input; Enter there (or Escape / outside click) closes it. |
|
|
27
|
+
| `timeStep` | `number` | no | Minutes step for the `<TimeField>` popover and for rounding typed time input on commit. Defaults to `15`. Set `1` to disable rounding. Only meaningful when `granularity='minute'`. |
|
|
28
|
+
| `hourCycle` | `'12' \| '24' \| 'auto'` | no | Display cycle for the embedded `<TimeField>` + the trigger's time tail. - `'24'` — `"HH:mm"` in the trigger; 24h hour list in the time popover. - `'12'` — `"h:mm AM/PM"` in the trigger; 12h hour list + AM/PM column. - `'auto'` (default) — derives from the active locale via Intl. en-US → `'12'`; ru-RU / de-DE / fr-FR → `'24'`. Only meaningful when `granularity='minute'`. Typed input is lenient regardless of cycle — both `"14:30"` and `"2:30 PM"` parse on blur. |
|
|
29
|
+
| …native | | | plus native `<input>` attributes |
|
|
30
|
+
|
|
31
|
+
<!-- props:end -->
|
|
32
|
+
|
|
33
|
+
- Single-date selection (date-only by default; opt into date+time with `granularity="minute"`). Range → `<DateRangePicker>`. Year-picker — out of scope for v1.
|
|
34
|
+
- Looks like an `<Input>`. Click the input or press ArrowDown to open the popover. The 📅 button toggles and the ✕ button clears; clicking either never moves focus while it's in the field or the open popover, so half-typed trigger text survives the toggle and is discarded by clear. Reaching them by keyboard (Tab) leaves the input first, which commits the typed text. Toggling closed from inside the popover commits a time typed into the time input and returns focus to the input; clear from there wins over the typed time (one `onChange(null)`).
|
|
35
|
+
- Typed input parses on Enter, or when focus leaves the field — ArrowDown into the open calendar, an outside click, or Tabbing away (Tab from the trigger goes ✕ → 📅 → the page; the portaled calendar is reached with ArrowDown) — using the active locale: en-US `M/D/YYYY`, ru-RU `D.M.YYYY`, ja-JP `Y/M/D`. ISO `YYYY-MM-DD` is always accepted as a paste fallback. Unparseable / out-of-range / disabled input reverts to the last committed value.
|
|
36
|
+
- Locale-aware via `useLocale()`; override with `locale` prop. UI strings (previousMonth / nextMonth / openCalendar / clear) translate via `datePicker.*` keys — override with `<I18nProvider overrides={{ datePicker: { ... } }}>`.
|
|
37
|
+
- ARIA: typed input has `aria-haspopup="dialog"` + `aria-expanded`. Popover wrapper is `role="dialog"` (labelled by `aria-label={t('datePicker.openCalendar')}`); the grid inside is `role="grid"` with `role="gridcell"` buttons that carry `aria-selected` / `aria-disabled` as appropriate.
|
|
38
|
+
- Keyboard inside the grid: ←→↑↓ move focus by 1 day, Home/End to start/end of week, PageUp/PageDown step a month, Enter/Space selects, Escape closes and returns focus to the input. Tab / Shift+Tab out of the popover closes it and returns focus to the input (both granularities).
|
|
39
|
+
- **Granularity.** Pass `granularity="minute"` to add a `<TimeField>` below the calendar grid; the trigger text becomes `MM/DD/YYYY HH:mm` (24h locales) or `MM/DD/YYYY h:mm AM/PM` (12h locales) and the hidden form mirror emits ISO local datetime (`2026-05-28T14:30`). Defaults to `'day'` (backward compat — date-only). Picking a different date re-uses the existing time-of-day, so the grid feels like it "just changes the date"; picking from `null` defaults to `00:00`. Picking a day does NOT close the popover in minute mode: focus moves to the embedded time input so the time is reachable; Enter in the time input (with its clock closed) or Escape closes it and returns focus to the trigger input; an outside click closes it and leaves focus where the user clicked; Tabbing out of the popover closes it and returns focus to the trigger input, so the next Tab continues in page order. Every close path keeps a date typed into the trigger and a time typed into the time input. The `<TimeField>` accepts free text (parsed on blur / Enter via `parseTime` — both 24h and AM/PM shapes) AND a chevron-toggled popover with hour + minute (+ AM/PM in 12h mode) lists, plus a "Now" footer button. `timeStep` (default `15`, in minutes) controls the minute-list row count AND rounds typed input in the time field on commit; set `timeStep={1}` to disable rounding. The trigger text-input parses exactly as typed — `timeStep` does not round trigger input. `hourCycle` (default `'auto'`) forwards to the embedded TimeField and controls the trigger text — `'12'` / `'24'` force a cycle, `'auto'` derives from locale (en-US → 12h, ru-RU → 24h).
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
// Uncontrolled, today as the default
|
|
43
|
+
<DatePicker defaultValue={new Date()} onChange={(d) => console.log(d)} />
|
|
44
|
+
|
|
45
|
+
// Constrained
|
|
46
|
+
<DatePicker
|
|
47
|
+
value={value}
|
|
48
|
+
onChange={setValue}
|
|
49
|
+
min={new Date()}
|
|
50
|
+
isDateDisabled={(d) => d.getDay() === 0 || d.getDay() === 6}
|
|
51
|
+
/>
|
|
52
|
+
|
|
53
|
+
// Form integration via the hidden mirror
|
|
54
|
+
<form action="/dates"><DatePicker name="dob" /></form>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The popover is portaled into `document.body`, so it escapes overflow-hidden ancestors.
|
|
58
|
+
|
|
59
|
+
#### When NOT to use
|
|
60
|
+
|
|
61
|
+
- Datetime with seconds precision: only `granularity="minute"` is supported; compose with a separate input.
|
|
62
|
+
- Time-only fields (no date): out of scope.
|
|
63
|
+
- Free-form date strings without a clear locale: use a plain `<Input>`.
|
|
64
|
+
|
|
65
|
+
#### Anti-patterns
|
|
66
|
+
|
|
67
|
+
- ❌ Wrapping the picker in `<label htmlFor={id}>` while also passing `aria-label` — pick one. The wrapper label is preferred.
|
|
68
|
+
- ❌ Using `value` without `onChange` and expecting state to update on user input — the picker is fully controlled when `value` is passed.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# `<DateRangePicker>` — date-range input + two-month popover
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
const [range, setRange] = useState<DateRange | null>(null);
|
|
5
|
+
<DateRangePicker value={range} onChange={setRange} min={new Date()} />;
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
<!-- props:start -->
|
|
9
|
+
|
|
10
|
+
## Props
|
|
11
|
+
|
|
12
|
+
<!-- prettier-ignore -->
|
|
13
|
+
| Prop | Type | Required | Description |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| `value` | `DateRange \| null` | no | Selected range. `null` = no range. Pair with `onChange` for controlled use. |
|
|
16
|
+
| `defaultValue` | `DateRange \| null` | no | Initial range for uncontrolled use. |
|
|
17
|
+
| `onChange` | `((range: DateRange \| null) => void)` | no | Fires when a complete range commits (after second click in grid, or successful typed parse on blur). |
|
|
18
|
+
| `locale` | `string` | no | Override locale (otherwise reads `useLocale()`). |
|
|
19
|
+
| `min` | `Date` | no | Earliest selectable date (inclusive). Both halves and typed input are gated. |
|
|
20
|
+
| `max` | `Date` | no | Latest selectable date (inclusive). |
|
|
21
|
+
| `isDateDisabled` | `((date: Date) => boolean)` | no | Per-date disable predicate; gates both the popover grid and typed-input parsing. |
|
|
22
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | no | Field height + type scale. Same scale as `<DatePicker>`. Defaults to `'md'`. Affects only the trigger row; the two-month popover grid is fixed-size. - `'sm'` — 24px tall. - `'md'` — 32px tall (default). - `'lg'` — 40px tall. |
|
|
23
|
+
| `clearable` | `boolean` | no | Show the ✕ clear button when a range is set. Defaults to `true`. |
|
|
24
|
+
| `invalid` | `boolean` | no | Toggle red border + focus ring + `aria-invalid="true"`. Pair with a visible error and `aria-describedby`. |
|
|
25
|
+
| `nameStart` | `string` | no | Form name for the START half (hidden `<input>` with an ISO date, so native `<form>` submission works). Post both keys or just one. |
|
|
26
|
+
| `nameEnd` | `string` | no | Form name for the END half. |
|
|
27
|
+
| `granularity` | `'day' \| 'minute'` | no | Picker precision. - `'day'` (default) — date only; behavior unchanged from prior releases. - `'minute'` — adds two manual-entry time inputs (start + end) below the two-month grid. The trigger text shows `HH:mm` after each date. Hidden form mirrors (when `nameStart` / `nameEnd` are set) emit ISO local datetime (`2026-05-28T14:30`). At `'minute'` the start/end time inputs are shown and editable in the popover even before a range is picked (defaulting to `00:00` / `23:59`). Times entered in the empty state are applied when the range is committed (instead of the bare defaults), and existing times are preserved across date re-picks. Same-day ranges with end-time < start-time are silently clamped so end-time ≥ start-time. |
|
|
28
|
+
| `timeStep` | `number` | no | Minutes step for the start + end `<TimeField>` popovers and for rounding typed time input on commit. Defaults to `15`. Set `1` to disable rounding. Only meaningful when `granularity='minute'`. |
|
|
29
|
+
| `hourCycle` | `'12' \| '24' \| 'auto'` | no | Display cycle for the two embedded `<TimeField>`s + the trigger's time tails. - `'24'` — `"HH:mm"` in trigger + 24h hour lists in popovers. - `'12'` — `"h:mm AM/PM"` in trigger + 12h hour lists + AM/PM column. - `'auto'` (default) — derives from the active locale via Intl. en-US → `'12'`; ru-RU → `'24'`. Only meaningful when `granularity='minute'`. Typed input is lenient regardless of cycle — both `"14:30"` and `"2:30 PM"` parse on blur. |
|
|
30
|
+
| …native | | | plus native `<input>` attributes |
|
|
31
|
+
|
|
32
|
+
<!-- props:end -->
|
|
33
|
+
|
|
34
|
+
- Date-range selection (date-only by default; opt into date+time on each side with `granularity="minute"`). Single-date → `<DatePicker>`. Multi-date / preset ranges (Today, Last 7 days) — out of scope for v1.
|
|
35
|
+
- Looks like an `<Input>`. Click the input or press ArrowDown to open; the popover shows two months side-by-side. The 📅 button toggles, the ✕ button clears the whole range.
|
|
36
|
+
- Selection flow: first click sets the start; hover (or keyboard-focus) another cell to preview the range; second click commits and closes. If the second pick is earlier than the start, the range is auto-swapped to `[earlier, later]`. A third click in a reopened popover restarts selection.
|
|
37
|
+
- Typed input parses on blur / Enter using the active locale. Accepts `—` (em dash), `–` (en dash), `-` (hyphen with spaces), or `to` (case-insensitive word) as the separator. ISO `YYYY-MM-DD` works for each half too. Out-of-order typed input is auto-swapped. Anything unparseable / out-of-range / disabled reverts to the last committed value.
|
|
38
|
+
- ARIA: typed input has `aria-haspopup="dialog"` + `aria-expanded`. Popover wrapper is `role="dialog"` (labelled by `aria-label={t('datePicker.openCalendar')}`); each grid inside is `role="grid"` with `gridcell` buttons. The range-start and range-end cells (and the live hover end during selection) carry `aria-selected="true"`.
|
|
39
|
+
- Keyboard inside a grid: ←→↑↓ move focus by 1 day, Home/End to start/end of week, PageUp/PageDown step a month, Enter/Space drives the same first-click → second-click flow, Escape closes and returns focus to the input. With selection-start set, the focused cell acts as the hover end so the preview range follows arrow keys.
|
|
40
|
+
- Reuses `<DatePickerGrid>` via `selectionMode='range'` + `rangeStart`/`rangeEnd`/`hoverDate`/`onHoverDate` + `chevrons={false}`. The two grids share the same cursor; the picker renders its own prev/next chevrons outside them.
|
|
41
|
+
- **Granularity.** Pass `granularity="minute"` to add dual `<TimeField>`s (start + end) below the two-month grid; the trigger text becomes `MM/DD/YYYY HH:mm — MM/DD/YYYY HH:mm` (24h locales) or `MM/DD/YYYY h:mm AM/PM — MM/DD/YYYY h:mm AM/PM` (12h locales) and the hidden form mirrors emit ISO local datetime. Defaults to `'day'` (backward compat). The start/end time inputs are shown and editable in the popover even before a range is picked — defaulting to `00:00` start / `23:59` end. Times set in this empty state are applied when the range is committed (no need to seed a placeholder range), and existing times are preserved across subsequent date picks. Same-day ranges silently clamp end-time to ≥ start-time on every commit; different-day ranges are not clamped. `timeStep` (default `15`, in minutes) applies to BOTH TimeFields, controlling each minute-list row count AND rounding typed input in the time fields on commit; set `timeStep={1}` to disable rounding. The trigger text-input parses exactly as typed — `timeStep` does not round trigger input. `hourCycle` (default `'auto'`) forwards to both embedded TimeFields and controls the trigger text — `'12'` / `'24'` force a cycle, `'auto'` derives from locale.
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
// Uncontrolled
|
|
45
|
+
<DateRangePicker defaultValue={{ start: new Date(), end: new Date() }} />
|
|
46
|
+
|
|
47
|
+
// Controlled, constrained to a 90-day window
|
|
48
|
+
<DateRangePicker
|
|
49
|
+
value={range}
|
|
50
|
+
onChange={setRange}
|
|
51
|
+
min={new Date()}
|
|
52
|
+
max={new Date(Date.now() + 90 * 86_400_000)}
|
|
53
|
+
/>
|
|
54
|
+
|
|
55
|
+
// Form mirror, two separate fields
|
|
56
|
+
<form action="/api/bookings">
|
|
57
|
+
<DateRangePicker nameStart="bookingStart" nameEnd="bookingEnd" />
|
|
58
|
+
</form>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### When NOT to use
|
|
62
|
+
|
|
63
|
+
- Single date: use `<DatePicker>`.
|
|
64
|
+
- Seconds-precision tracking: only `granularity="minute"` is supported.
|
|
65
|
+
- Time-only fields (no date): out of scope.
|
|
66
|
+
- Multi-date selection (3+ non-contiguous dates): out of scope.
|
|
67
|
+
|
|
68
|
+
#### Anti-patterns
|
|
69
|
+
|
|
70
|
+
- ❌ Passing `value` without `onChange` — the picker is fully controlled when `value` is set; user input has no effect.
|
|
71
|
+
- ❌ Using `defaultValue` AND `value` together — pick one.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# `<DateStrip>` — week of selectable day tiles
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
const [day, setDay] = useState<string | null>(null);
|
|
5
|
+
<DateStrip
|
|
6
|
+
days={week} // [{ date: '2026-10-05', free: 3 }, … 7 days]
|
|
7
|
+
value={day}
|
|
8
|
+
onChange={setDay}
|
|
9
|
+
onPrevious={prevWeek}
|
|
10
|
+
onNext={nextWeek}
|
|
11
|
+
canPrevious={!isCurrentWeek}
|
|
12
|
+
/>;
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
<!-- props:start -->
|
|
16
|
+
|
|
17
|
+
## Props
|
|
18
|
+
|
|
19
|
+
<!-- prettier-ignore -->
|
|
20
|
+
| Prop | Type | Required | Description |
|
|
21
|
+
|---|---|---|---|
|
|
22
|
+
| `days` | `DateStripDay[]` | yes | The days to show, in order — usually one week (7); one grid column per day. The month heading is derived from the first and last. |
|
|
23
|
+
| `value` | `string \| null` | yes | Selected day (`'YYYY-MM-DD'`), or `null`. A value not in `days` checks nothing. |
|
|
24
|
+
| `onChange` | `(date: string) => void` | yes | Called with the chosen day's `'YYYY-MM-DD'`. Controlled — update `value` yourself. |
|
|
25
|
+
| `onPrevious` | `() => void` | yes | Previous-week button handler. Replace `days` with the earlier week. |
|
|
26
|
+
| `onNext` | `() => void` | yes | Next-week button handler. Replace `days` with the later week. |
|
|
27
|
+
| `canPrevious` | `boolean` | no | `false` disables the previous-week button (e.g. the current week). Default `true`. |
|
|
28
|
+
| `canNext` | `boolean` | no | `false` disables the next-week button (end of the booking window). Default `true`. |
|
|
29
|
+
| `titleOrder` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | no | Heading level of the month label. Default `2`. |
|
|
30
|
+
| `name` | `string` | no | Radio group `name` (also submitted with a form). Default: a generated id. |
|
|
31
|
+
| `invalid` | `boolean` | no | Marks the group `aria-invalid` (the radios themselves do not support it). Field / SettingRow inject it. Default: `false`. |
|
|
32
|
+
| `required` | `boolean` | no | Native `required` on the radios (the group then fails form validation until one is chosen). Field / SettingRow inject it; it used to land on the root as a stray attribute. |
|
|
33
|
+
| …native | | | plus native `<fieldset>` attributes |
|
|
34
|
+
|
|
35
|
+
<!-- props:end -->
|
|
36
|
+
|
|
37
|
+
- `date` is an ISO `'YYYY-MM-DD'` calendar day (the business's day, not a `Date`); the strip formats weekday / number / month through the locale in UTC, so the browser timezone never shifts it. The month heading is derived ("October 2026", "September – October 2026").
|
|
38
|
+
- `free: 0` → "No times", tile natively disabled (skipped by Tab and arrows). Keep full days in the array.
|
|
39
|
+
- Native radios, one `name`: one Tab stop, arrows move AND select (so `onChange` fires per arrow press — debounce slot fetching if needed). Tiles are `role="radio"` named "Wednesday, October 7, 9 free"; query them that way in tests.
|
|
40
|
+
- Controlled only.
|
|
41
|
+
- In `<Field>` / `<SettingRow>`: the row label is merged in front of the month (group name "Day October 2026"), the error describes the group, `invalid` → `aria-invalid` on the group, `required` → native `required` on the radios. One column per day (`days.length`), so a 5-day week has 5 columns.
|
|
42
|
+
- Previous/next use `aria-disabled` (not `disabled`) when `canPrevious`/`canNext` is false, so focus stays on the button that reached the boundary.
|
|
43
|
+
- Changing week announces the new range politely; same-week re-renders stay silent.
|
|
44
|
+
- ❌ No `aria-label` on the strip — the month heading names the group. ❌ No `Date`/`toISOString()` for `date`.
|
|
45
|
+
- ❌ In an intrinsic-width context (`Split`'s default `auto` aside track, a `Cluster` item, `width: max-content`) it renders at width 0 — `container-type: inline-size` zeroes its intrinsic-width contribution; give the parent a concrete width (e.g. `asideWidth` on a Split). It is also the containing block for absolutely-positioned descendants (layout containment).
|
|
46
|
+
- When NOT to use: any-date picking → `<InlineDatePicker>`; events → `<Calendar>`; times → `<SlotGrid>`.
|
|
47
|
+
- ❌ Building `date` from `toISOString()` of a local-midnight `Date` — it shifts a day west of UTC. Produce the business-timezone calendar day.
|
|
48
|
+
- When NOT to use: scheduling or showing events → `<Calendar>`; free-form time entry → `<TimeField>`.
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
// Booking time step: DateStrip picks the day, SlotGrid the time.
|
|
52
|
+
<Stack gap="lg">
|
|
53
|
+
<DateStrip days={week} value={day} onChange={setDay} onPrevious={prev} onNext={next} />
|
|
54
|
+
<SlotGrid groups={slotsFor(day)} value={slot} onChange={setSlot} />
|
|
55
|
+
</Stack>
|
|
56
|
+
```
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# `<DefinitionList>` — semantic key/value pairs (dl / dt / dd)
|
|
2
|
+
|
|
3
|
+
For displaying entity properties — contact details, settings rows, metadata sidebars. Renders proper `<dl>`/`<dt>`/`<dd>` so screen readers announce term/description pairs natively. Compound: `DefinitionList`, `DefinitionList.Item`, `DefinitionList.Term`, `DefinitionList.Description`.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
<DefinitionList dividers>
|
|
7
|
+
<DefinitionList.Item>
|
|
8
|
+
<DefinitionList.Term>Email</DefinitionList.Term>
|
|
9
|
+
<DefinitionList.Description icon={<Mail size={14} />}>
|
|
10
|
+
ada@example.com
|
|
11
|
+
</DefinitionList.Description>
|
|
12
|
+
</DefinitionList.Item>
|
|
13
|
+
<DefinitionList.Item>
|
|
14
|
+
<DefinitionList.Term>Phone</DefinitionList.Term>
|
|
15
|
+
<DefinitionList.Description icon={<Phone size={14} />}>
|
|
16
|
+
+1 (415) 555-0142
|
|
17
|
+
</DefinitionList.Description>
|
|
18
|
+
</DefinitionList.Item>
|
|
19
|
+
</DefinitionList>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
<!-- props:start -->
|
|
23
|
+
|
|
24
|
+
## Props
|
|
25
|
+
|
|
26
|
+
### `DefinitionListProps`
|
|
27
|
+
|
|
28
|
+
<!-- prettier-ignore -->
|
|
29
|
+
| Prop | Type | Required | Description |
|
|
30
|
+
|---|---|---|---|
|
|
31
|
+
| `layout` | `'horizontal' \| 'stacked'` | no | Layout direction. See `DefinitionListLayout`. Default `'horizontal'`. |
|
|
32
|
+
| `termWidth` | `string` | no | CSS length applied to the term column in horizontal layout (e.g. `'180px'`, `'20%'`, `'max-content'`). Default `'max-content'` — column sizes to the longest term across all rows. Set explicitly when you need consistent alignment across multiple DefinitionLists on the same screen. |
|
|
33
|
+
| `spacing` | `'sm' \| 'md' \| 'lg'` | no | Vertical padding per item. See `DefinitionListSpacing`. Default `'sm'`. |
|
|
34
|
+
| `dividers` | `boolean` | no | Render a 1px border between items. Default `false` (clean, dense look). Set when migrating from a `Card.List` and you want to preserve the table-row separator visual. |
|
|
35
|
+
| …native | | | plus native `<dl>` attributes |
|
|
36
|
+
|
|
37
|
+
### `DefinitionListDescriptionProps`
|
|
38
|
+
|
|
39
|
+
<!-- prettier-ignore -->
|
|
40
|
+
| Prop | Type | Required | Description |
|
|
41
|
+
|---|---|---|---|
|
|
42
|
+
| `icon` | `ReactNode` | no | Leading decorative icon, rendered inside the `<dd>` before children. Wrapped in an `aria-hidden` span — the `<dt>` carries the semantic label so the icon is purely visual. |
|
|
43
|
+
| `children` | `ReactNode` | yes | The value content. Any ReactNode — text, Badges, Links, etc. |
|
|
44
|
+
| …native | | | plus native HTML attributes |
|
|
45
|
+
|
|
46
|
+
### `DefinitionListItemProps`
|
|
47
|
+
|
|
48
|
+
<!-- prettier-ignore -->
|
|
49
|
+
| Prop | Type | Required | Description |
|
|
50
|
+
|---|---|---|---|
|
|
51
|
+
| `children` | `ReactNode` | yes | A `DefinitionList.Term` and a `DefinitionList.Description`. |
|
|
52
|
+
| …native | | | plus native `<div>` attributes |
|
|
53
|
+
|
|
54
|
+
### `DefinitionListTermProps`
|
|
55
|
+
|
|
56
|
+
<!-- prettier-ignore -->
|
|
57
|
+
| Prop | Type | Required | Description |
|
|
58
|
+
|---|---|---|---|
|
|
59
|
+
| `children` | `ReactNode` | yes | The label text — kept short, terms are headings for their values. |
|
|
60
|
+
| …native | | | plus native HTML attributes |
|
|
61
|
+
|
|
62
|
+
<!-- props:end -->
|
|
63
|
+
|
|
64
|
+
Use this instead of `Card.List` + `Card.ListRow` whenever the data is genuinely key/value (every row has a label and a value). Use `Card.List` when rows aren't keyed (activity feeds, list of cards).
|
|
65
|
+
|
|
66
|
+
**Anti-patterns**
|
|
67
|
+
|
|
68
|
+
- ❌ Wrapping a `<DefinitionList.Description>` directly in `<DefinitionList>` without an enclosing `<DefinitionList.Item>` — the dev warning fires and grid layout breaks.
|
|
69
|
+
- ❌ Putting interactive content in `<DefinitionList.Term>`. Use `<DefinitionList.Description>` for values, including ones containing `<Link>` or `<Button>`.
|
|
70
|
+
- ❌ Stacking multiple `<DefinitionList.Description>` children under one Item to render "multiple values for one key." Works HTML-wise but doesn't have styling support — render multiple Items with the same Term text if you need that pattern.
|
|
71
|
+
|
|
72
|
+
Not for tabular data with multiple columns per row — use `Table` / `DataTable`.
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
// Stacked (settings-style)
|
|
76
|
+
<DefinitionList layout="stacked">
|
|
77
|
+
<DefinitionList.Item>
|
|
78
|
+
<DefinitionList.Term>Workspace name</DefinitionList.Term>
|
|
79
|
+
<DefinitionList.Description>Acme Corp</DefinitionList.Description>
|
|
80
|
+
</DefinitionList.Item>
|
|
81
|
+
</DefinitionList>
|
|
82
|
+
```
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# `<Divider>` — separator primitive
|
|
2
|
+
|
|
3
|
+
Thin rule between content sections. Horizontal (default) or vertical. Optional centered label slot. Three size tiers + solid/dashed variants.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Divider } from '@eocrm/design-system';
|
|
7
|
+
|
|
8
|
+
// Default horizontal
|
|
9
|
+
<Divider />
|
|
10
|
+
|
|
11
|
+
// Vertical inside a Cluster (toolbar separator)
|
|
12
|
+
<Cluster gap="sm">
|
|
13
|
+
<Button>Edit</Button>
|
|
14
|
+
<Divider orientation="vertical" />
|
|
15
|
+
<Button>Duplicate</Button>
|
|
16
|
+
</Cluster>
|
|
17
|
+
|
|
18
|
+
// Labeled (auth-form pattern)
|
|
19
|
+
<Divider>OR</Divider>
|
|
20
|
+
|
|
21
|
+
// Variants + sizes
|
|
22
|
+
<Divider variant="dashed" />
|
|
23
|
+
<Divider size="lg" />
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
<!-- props:start -->
|
|
27
|
+
|
|
28
|
+
## Props
|
|
29
|
+
|
|
30
|
+
<!-- prettier-ignore -->
|
|
31
|
+
| Prop | Type | Required | Description |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| `orientation` | `'horizontal' \| 'vertical'` | no | Layout direction. Defaults to `'horizontal'`. |
|
|
34
|
+
| `variant` | `'solid' \| 'dashed'` | no | Line style. Defaults to `'solid'`. |
|
|
35
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | no | Line thickness tier. Defaults to `'sm'`. |
|
|
36
|
+
| `children` | `ReactNode` | no | Optional centered label rendered between two line segments. Common pattern: `<Divider>OR</Divider>` for auth-form section breaks. When `children` is set, the root becomes `<div role="separator">` instead of `<hr>` (HTML `<hr>` cannot have children). Works with `orientation="vertical"` but renders awkwardly (text wraps across two short line segments). Avoid vertical + label combos. |
|
|
37
|
+
| …native | | | plus native HTML attributes |
|
|
38
|
+
|
|
39
|
+
<!-- props:end -->
|
|
40
|
+
|
|
41
|
+
- **Without `children`** it renders a native `<hr>` (the right semantic for a thematic break).
|
|
42
|
+
- **Default**: solid, size `'sm'` (1px), horizontal.
|
|
43
|
+
- **Labeled** dividers use `<div role="separator">` instead of `<hr>` because HTML `<hr>` can't have children.
|
|
44
|
+
- **Vertical** dividers stretch to the parent's height — works inside Cluster/Stack/Flex but needs a parent with known height. Falls back to `--space-3` minimum height as a sanity floor.
|
|
45
|
+
- **No spacing prop** — parent owns layout per Rule 4. Use Stack `gap` around the Divider.
|
|
46
|
+
|
|
47
|
+
#### When NOT to use
|
|
48
|
+
|
|
49
|
+
- ❌ Decorative under a heading → just style the heading's `border-bottom`.
|
|
50
|
+
- ❌ Between unrelated stacked sections → use Stack with `gap` instead.
|
|
51
|
+
- ❌ A tone-driven separator (warning/danger) → use `<Alert>` for persistent tone-tied messages.
|
|
52
|
+
|
|
53
|
+
#### Anti-patterns
|
|
54
|
+
|
|
55
|
+
- ❌ `<Divider>OR</Divider>` with `orientation="vertical"` — text wraps awkwardly across two short line segments.
|
|
56
|
+
- ❌ `<Divider size="lg" />` for casual section breaks. Reserve `lg` (3px) for strong visual hierarchy.
|
|
57
|
+
- ❌ Adding `margin` via inline `style`. The parent should own spacing.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# `<Dot>` — bare palette/tone colored circle
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
// Palette color, paired with a label:
|
|
5
|
+
<Cluster gap="xs"><Dot color="violet" /> Design</Cluster>
|
|
6
|
+
|
|
7
|
+
// Semantic tone:
|
|
8
|
+
<Dot tone="success" />
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
<!-- props:start -->
|
|
12
|
+
|
|
13
|
+
## Props
|
|
14
|
+
|
|
15
|
+
<!-- prettier-ignore -->
|
|
16
|
+
| Prop | Type | Required | Description |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| `color` | `PaletteColor` | no | One of the 30 `PaletteColor`s — renders the bare circle in that color's saturated `--color-palette-<name>-fg` token (the same color OptionsPicker groups and palette Badges use). Takes precedence over `tone`. |
|
|
19
|
+
| `tone` | `'neutral' \| 'info' \| 'success' \| 'warning' \| 'danger' \| 'purple'` | no | A semantic `BadgeTone` (`neutral` default / `info` / `success` / `warning` / `danger` / `purple`) — used when `color` is omitted. Neither set → `neutral`. |
|
|
20
|
+
| …native | | | plus native `<span>` attributes |
|
|
21
|
+
|
|
22
|
+
<!-- props:end -->
|
|
23
|
+
|
|
24
|
+
- A bare, background-less 6px circle (`--size-badge-dot`) for color-coding affordances — a leading dot on a filter / `FilterChip`, a status indicator, a legend swatch. Unlike `<Badge dot>` it paints NO badge surface; it is just the dot.
|
|
25
|
+
- **Decorative**: `aria-hidden` by default (overridable). The dot alone conveys nothing to assistive tech — always pair it with a visible label / accessible text.
|
|
26
|
+
- **When NOT to use**: a status pill WITH text → use `<Badge>` (it owns a surface + label). The sole signal of meaning → color isn't an accessible signal on its own; accompany with text.
|