@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,163 @@
|
|
|
1
|
+
> **Breaking in 0.6.0:** `minZoom`, `maxZoom` and `showZoomControl` are deleted, with no replacement. The component is now a still image with a draggable, resizable crop box, so it is shorter (no slider row). A floating Reset button is opt-in via `showReset`. Scroll-wheel over the cropper now resizes the box (it no longer zooms the image). The i18n key `imageCrop.zoom` is removed (new keys: `imageCrop.reset`, `imageCrop.label`, `imageCrop.keyboardHint`, `imageCrop.aspectRatio`, `imageCrop.areaValue`); delete any `I18nProvider` override of `imageCrop.zoom`.
|
|
2
|
+
|
|
3
|
+
# `<ImageCrop>` — controlled image cropper
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
const [crop, setCrop] = useState<CropArea | null>(null);
|
|
7
|
+
|
|
8
|
+
<ImageCrop src={file} value={crop} onChange={setCrop} aspectRatio={1} />;
|
|
9
|
+
|
|
10
|
+
// In the Save handler:
|
|
11
|
+
const handleSave = async () => {
|
|
12
|
+
if (!crop) return;
|
|
13
|
+
const blob = await extractCropBlob(file, crop, {
|
|
14
|
+
type: 'image/jpeg',
|
|
15
|
+
quality: 0.9,
|
|
16
|
+
outputWidth: 512,
|
|
17
|
+
});
|
|
18
|
+
await uploadToS3(blob);
|
|
19
|
+
};
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
<!-- props:start -->
|
|
23
|
+
|
|
24
|
+
## Props
|
|
25
|
+
|
|
26
|
+
<!-- prettier-ignore -->
|
|
27
|
+
| Prop | Type | Required | Description |
|
|
28
|
+
|---|---|---|---|
|
|
29
|
+
| `src` | `string \| File \| Blob` | yes | Image source. String URLs (HTTP/HTTPS, data:, blob:) pass through. File/Blob are normalized to object URLs internally via `URL.createObjectURL()`, with cleanup on unmount and `src` change. |
|
|
30
|
+
| `value` | `CropArea \| null` | yes | Controlled crop area in SOURCE-IMAGE pixel coordinates. Pass `null` to use the component's default centered crop (80% of the largest centered region matching `aspectRatio`). |
|
|
31
|
+
| `onChange` | `(area: CropArea) => void` | yes | Fires on every drag/resize tick. High frequency. Also fires once on first image load when `value` is `null`, with the computed default crop; after that the consumer owns the state. |
|
|
32
|
+
| `onChangeEnd` | `((area: CropArea) => void)` | no | Fires on commit: when a drag/resize is released, ~200ms after the last wheel tick, on each key press, and on Reset/double-click. |
|
|
33
|
+
| `aspectRatio` | `number` | no | Fixed aspect ratio for the crop box (e.g. `1` for square, `16/9`). Omit for free aspect — edge handles then appear too. Toggling it at runtime does NOT re-fit `value`; pass a fresh `value` (or `null`) with the change. |
|
|
34
|
+
| `disabled` | `boolean` | no | Disable all interaction (move, resize). Default `false`. Image still renders. |
|
|
35
|
+
| `showReset` | `boolean` | no | Render the on-canvas Reset button. Default `false`; double-click reset works regardless. |
|
|
36
|
+
| `aspectRatios` | `ImageCropAspectOption[]` | no | Options for an on-canvas aspect-ratio switcher. Labels are consumer strings (your i18n). Controlled: the option whose `value === aspectRatio` shows as selected, and picking one calls `onAspectRatioChange`, then `onChange`/`onChangeEnd` with that ratio's default crop. Omit or pass `[]` for no switcher. Requires `onAspectRatioChange` and a controlled `aspectRatio`; without them the pick commits a crop in the old ratio. |
|
|
37
|
+
| `onAspectRatioChange` | `((ratio: ImageCropAspectRatio) => void)` | no | Fires when an option is picked in the switcher (`undefined` = free aspect). Update your `aspectRatio` state here. |
|
|
38
|
+
| …native | | | plus native `<div>` attributes |
|
|
39
|
+
|
|
40
|
+
<!-- props:end -->
|
|
41
|
+
|
|
42
|
+
- **Move the box**: the image is still; drag the crop box to reposition it (clamped to the image).
|
|
43
|
+
- **Resize**: the box never shrinks below 48 screen px per side. Corner handles always (ratio-locked when `aspectRatio` is set); edge handles appear in free aspect. Scroll wheel resizes around the box center, proportional to scroll distance (≈6% per mouse-wheel notch; scroll down grows, up shrinks).
|
|
44
|
+
- **Reset**: double-click (always) or the floating Reset button (opt-in via `showReset`) restores the default crop (80% of the largest fitting box).
|
|
45
|
+
- **`aspectRatio?: number`** — pass `1` for square, `16/9` for landscape, etc. Omit for free aspect (edge handles appear).
|
|
46
|
+
- **Aspect-ratio switcher**: pass `aspectRatios` + `onAspectRatioChange` for an on-canvas segmented control (stock `ButtonGroup`). You still own `aspectRatio`; picking an option reports it, then commits that ratio's default crop through `onChange`/`onChangeEnd`. Labels are your strings. With neither switcher nor `showReset`, no toolbar renders and the image uses the full viewport.
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
const [ratio, setRatio] = useState<number | undefined>(1);
|
|
50
|
+
<ImageCrop
|
|
51
|
+
src={file}
|
|
52
|
+
value={crop}
|
|
53
|
+
onChange={setCrop}
|
|
54
|
+
aspectRatio={ratio}
|
|
55
|
+
aspectRatios={[
|
|
56
|
+
{ label: '1:1', value: 1 },
|
|
57
|
+
{ label: '3:4', value: 3 / 4 },
|
|
58
|
+
{ label: '16:9', value: 16 / 9 },
|
|
59
|
+
{ label: 'Free' },
|
|
60
|
+
]}
|
|
61
|
+
onAspectRatioChange={setRatio}
|
|
62
|
+
/>;
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- **`onChange` fires per drag/resize tick (high frequency).** Debounce in the consumer OR use `onChangeEnd` (fires on drag/resize release, ~200ms after the last wheel tick, on each key press, and on Reset/double-click).
|
|
66
|
+
- **`extractCropBlob(src, area, options?)`** is a top-level utility (NOT a ref method). Call it in the Save handler to produce the cropped Blob. Supports `type` (PNG/JPEG/WebP), `quality` (0..1 for lossy), and `outputWidth` (proportional resize — useful for capping avatar size).
|
|
67
|
+
- **Keyboard** (when the crop area — `role="application"` "Crop area", whose `aria-valuetext` reads the current position and size — is focused; a screen-reader-only hint describes the keys): Arrow keys move the box by 5 source px. Shift+Arrows resize (Right/Down grow, Left/Up shrink; ratio-locked with `aspectRatio`, one axis in free mode). Home/End jump to top-left / bottom-right. Double-click resets to the default crop.
|
|
68
|
+
- **Loading state**: shows `<Skeleton variant="rectangular">` until the image's `onload` fires. Errors show "Couldn't load image" in danger tone.
|
|
69
|
+
- **`disabled`**: move, resize, wheel, keyboard, Reset and the ratio switcher all disabled. Viewport opacity dimmed.
|
|
70
|
+
|
|
71
|
+
#### `CropArea` (in source-image pixels)
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
interface CropArea {
|
|
75
|
+
x: number; // top-left X in source-image pixels
|
|
76
|
+
y: number; // top-left Y in source-image pixels
|
|
77
|
+
width: number; // crop width in source-image pixels
|
|
78
|
+
height: number; // crop height in source-image pixels
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### `ExtractCropOptions`
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
interface ExtractCropOptions {
|
|
86
|
+
type?: 'image/png' | 'image/jpeg' | 'image/webp'; // default 'image/png'
|
|
87
|
+
quality?: number; // 0..1, default 0.92 (ignored for PNG)
|
|
88
|
+
outputWidth?: number; // resize output width; height proportional
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### `useCropPreview(src, crop, options?)` — live-preview hook
|
|
93
|
+
|
|
94
|
+
Reusable hook for the canonical "avatar / cover photo picker" flow. Debounces an `extractCropBlob` encode on every crop change, guards against stale in-flight encodes, and owns the object URL lifecycle. Returns `{ previewUrl, previewBlob, previewSize, encoding }`.
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
const [file, setFile] = useState<File | null>(null);
|
|
98
|
+
const [crop, setCrop] = useState<CropArea | null>(null);
|
|
99
|
+
|
|
100
|
+
const { previewUrl, previewBlob, encoding } = useCropPreview(file, crop, {
|
|
101
|
+
type: 'image/jpeg',
|
|
102
|
+
quality: 0.9,
|
|
103
|
+
outputWidth: 256,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const handleSave = async () => {
|
|
107
|
+
if (!previewBlob) return;
|
|
108
|
+
const fd = new FormData();
|
|
109
|
+
fd.append('file', previewBlob, 'avatar.jpg');
|
|
110
|
+
await fetch('/api/upload-avatar', { method: 'POST', body: fd });
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<Stack gap="md">
|
|
115
|
+
<FileUpload onFilesAdded={([f]) => setFile(f)} ... />
|
|
116
|
+
{file && (
|
|
117
|
+
<>
|
|
118
|
+
<ImageCrop src={file} value={crop} onChange={setCrop} aspectRatio={1} />
|
|
119
|
+
{previewUrl && <img src={previewUrl} style={{ opacity: encoding ? 0.5 : 1 }} />}
|
|
120
|
+
<Button onClick={handleSave} disabled={!previewBlob || encoding}>Save</Button>
|
|
121
|
+
</>
|
|
122
|
+
)}
|
|
123
|
+
</Stack>
|
|
124
|
+
);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`previewBlob` is the same content backing `previewUrl` — reuse it in the Save handler instead of calling `extractCropBlob` again (the hook already encoded it).
|
|
128
|
+
|
|
129
|
+
`UseCropPreviewOptions` extends `ExtractCropOptions` with one extra field:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
interface UseCropPreviewOptions extends ExtractCropOptions {
|
|
133
|
+
debounceMs?: number; // default 120; set to 0 in tests, 250+ for 4K photos
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### Hard rule
|
|
138
|
+
|
|
139
|
+
- ❌ Hand-rolling a `<canvas>` + drag math per page. Use this.
|
|
140
|
+
- ❌ Calling `extractCropBlob` on every `onChange` tick. Use `useCropPreview` if you need a live preview — it debounces and race-guards correctly. For one-shot extraction (Save click only), call `extractCropBlob` once in the handler.
|
|
141
|
+
- ❌ Calling `extractCropBlob` AGAIN in the Save handler when you already have `useCropPreview` mounted. Reuse `previewBlob` — it's the same encoded result.
|
|
142
|
+
- ❌ Wrapping `<img>` in CSS clip-path for a "crop preview" — that doesn't produce a cropped Blob. Use `extractCropBlob` or `useCropPreview`.
|
|
143
|
+
- ❌ `<ImageCrop ref={ref}>` expecting `.getBlob()`. There's no imperative API. The extraction utility is a top-level export.
|
|
144
|
+
- ❌ Calling `URL.revokeObjectURL(previewUrl)` from `useCropPreview` manually. The hook owns the URL lifecycle.
|
|
145
|
+
- ❌ Cropping a circular avatar at the canvas level. Crop rectangular, then CSS-mask in the consumer.
|
|
146
|
+
- Not for server-side cropping (send `value`'s `CropArea` coordinates to your backend instead of calling `extractCropBlob`), rotation (not supported), or pinch gestures (not supported; there is no zoom).
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
// Free aspect (no aspectRatio prop)
|
|
150
|
+
<ImageCrop src={imageUrl} value={crop} onChange={setCrop} />
|
|
151
|
+
|
|
152
|
+
// Canonical "pick → crop → save" flow inside a Modal
|
|
153
|
+
<Modal isOpen onClose={cancel}>
|
|
154
|
+
<Modal.Header>Crop your photo</Modal.Header>
|
|
155
|
+
<Modal.Body>
|
|
156
|
+
<ImageCrop src={file} value={crop} onChange={setCrop} aspectRatio={1} />
|
|
157
|
+
</Modal.Body>
|
|
158
|
+
<Modal.Footer>
|
|
159
|
+
<Button variant="secondary" onClick={cancel}>Cancel</Button>
|
|
160
|
+
<Button onClick={handleSave} disabled={!crop}>Save</Button>
|
|
161
|
+
</Modal.Footer>
|
|
162
|
+
</Modal>
|
|
163
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# `<Indent>` — indent nested content by depth
|
|
2
|
+
|
|
3
|
+
`<Indent level={n} gutter="lg">` indents its own box by `level × gutter` via `padding-inline-start` (token-based, RTL-aware). The DS-native way to express nesting depth — threaded comment trees, file/outline views — without inline CSS. `level={0}` is flush; nesting compounds. It pads its own box only (wrap a `<Stack>` inside for a multi-row block). For plain sibling spacing use `<Stack gap>`, not Indent.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
{
|
|
7
|
+
comments.map((c) => (
|
|
8
|
+
<Indent key={c.id} level={c.depth}>
|
|
9
|
+
<CommentCard comment={c} />
|
|
10
|
+
</Indent>
|
|
11
|
+
));
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
<!-- props:start -->
|
|
16
|
+
|
|
17
|
+
## Props
|
|
18
|
+
|
|
19
|
+
<!-- prettier-ignore -->
|
|
20
|
+
| Prop | Type | Required | Description |
|
|
21
|
+
|---|---|---|---|
|
|
22
|
+
| `level` | `number` | no | Nesting depth — multiplies the gutter. `0` = flush (no indent, e.g. a root-level comment). Defaults to `1` (one gutter). Negative values clamp to `0`. |
|
|
23
|
+
| `gutter` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'` | no | Per-level indent size — a spacing step. Defaults to `'lg'` (16px per level). - `xs` 4px · `sm` 8px · `md` 12px · `lg` 16px · `xl` 24px · `2xl` 32px |
|
|
24
|
+
| `children` | `ReactNode` | yes | The nested content to indent. Required — an Indent with nothing inside indents nothing. |
|
|
25
|
+
| …native | | | plus native `<div>` attributes |
|
|
26
|
+
|
|
27
|
+
<!-- props:end -->
|
|
28
|
+
|
|
29
|
+
- Don't pass a fractional or huge `level`.
|
|
30
|
+
- Not for general left padding on non-nested content — it expresses hierarchy; use the parent layout primitive.
|
|
31
|
+
- Not for a bordered / padded surface (`<Card>`) or arranging children in a row (`<Cluster>`).
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# `<InlineDatePicker>` — single-date calendar in flow
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
const [date, setDate] = useState<Date | null>(null);
|
|
5
|
+
<InlineDatePicker value={date} onChange={setDate} 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 user clicks a cell. Currently always fires with a `Date`; `null` is reserved for a future clear / deselect mechanism. |
|
|
18
|
+
| `locale` | `string` | no | Override locale (otherwise reads `useLocale()`). |
|
|
19
|
+
| `min` | `Date` | no | Earliest selectable date (inclusive). |
|
|
20
|
+
| `max` | `Date` | no | Latest selectable date (inclusive). |
|
|
21
|
+
| `isDateDisabled` | `((date: Date) => boolean)` | no | Per-date disable callback. Disabled cells are non-clickable; arrow-key nav skips them. |
|
|
22
|
+
| `name` | `string` | no | Form name. When set, renders a hidden `<input type="hidden">` mirror with the ISO date. |
|
|
23
|
+
| `disabled` | `boolean` | no | Disables interaction — cells / chevrons / keyboard nav all blocked. Defaults to `false`. |
|
|
24
|
+
| `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 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`. |
|
|
25
|
+
| `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'`. |
|
|
26
|
+
| `hourCycle` | `'12' \| '24' \| 'auto'` | no | Display cycle for the embedded `<TimeField>`. - `'24'` — `"HH:mm"` text input; 24h hour list in the popover. - `'12'` — `"h:mm AM/PM"` text input; 12h hour list + AM/PM column. - `'auto'` (default) — derives from the active locale via Intl. en-US → `'12'`; ru-RU → `'24'`. Only meaningful when `granularity='minute'`. |
|
|
27
|
+
| …native | | | plus native `<div>` attributes |
|
|
28
|
+
|
|
29
|
+
<!-- props:end -->
|
|
30
|
+
|
|
31
|
+
- Same month-grid surface as `<DatePicker>` but always rendered in flow — no input, no popover, no portal. Use when the calendar should be visible at all times (sidebar pickers, schedule editors, quick-filter panels).
|
|
32
|
+
- Cursor anchors to `value ?? new Date()` on mount and re-anchors each time `value` transitions from `null` to a non-null date (e.g. loading an async initial value, or a consumer clearing and re-setting). After a transition, later non-null `value` changes do not move the cursor — `ref` is the wrapper `<div>` and exposes no cursor API; to jump to the new month, remount with a changed `key`.
|
|
33
|
+
- `forwardRef` points at the outer wrapper `<div>` (no input to forward to).
|
|
34
|
+
- ARIA: same `role="grid"` + `role="gridcell"` cells from `DatePickerGrid`. No dialog role — the picker is in flow.
|
|
35
|
+
- **Granularity.** Pass `granularity="minute"` to render a `<TimeField>` below the grid (always visible — there's no popover to gate it on); the hidden form mirror emits ISO local datetime. Defaults to `'day'`. Time is preserved across date re-picks; the field is disabled until a date is set. Same trigger-text contract is not applicable (no trigger). `timeStep` (default `15`, in minutes) controls the TimeField's minute-list row count AND rounds typed input in the time field on commit; set `timeStep={1}` to disable rounding. `hourCycle` (default `'auto'`) forwards to the embedded TimeField — `'12'` / `'24'` force a cycle, `'auto'` derives from locale.
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
// Constrained + form mirror
|
|
39
|
+
<form action="/api/dates">
|
|
40
|
+
<InlineDatePicker name="dob" min={new Date()} />
|
|
41
|
+
<button type="submit">Save</button>
|
|
42
|
+
</form>
|
|
43
|
+
|
|
44
|
+
// Disabled (read-only display)
|
|
45
|
+
<InlineDatePicker disabled defaultValue={new Date()} />
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
#### When NOT to use
|
|
49
|
+
|
|
50
|
+
- Compact form field: use `<DatePicker>` (the popover variant).
|
|
51
|
+
- Choosing a range: use `<InlineDateRangePicker>`.
|
|
52
|
+
- Seconds-precision tracking: only `granularity="minute"` is supported.
|
|
53
|
+
- Time-only fields (no date): out of scope.
|
|
54
|
+
|
|
55
|
+
#### Anti-patterns
|
|
56
|
+
|
|
57
|
+
- ❌ Rendering several `<InlineDatePicker>`s in one flex row without giving them their intrinsic width — the calendars get squashed. Wrap in `<Stack>` or give each a column.
|
|
58
|
+
- ❌ Using `value` without `onChange` — the picker is controlled when `value` is set; user clicks have no effect.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# `<InlineDateRangePicker>` — date-range calendar in flow
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
const [range, setRange] = useState<DateRange | null>(null);
|
|
5
|
+
<InlineDateRangePicker value={range} onChange={setRange} />;
|
|
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 (second click, auto-swapped). Currently always fires with a complete `DateRange`; `null` is reserved for a future clear / deselect mechanism. |
|
|
18
|
+
| `locale` | `string` | no | Override locale. |
|
|
19
|
+
| `min` | `Date` | no | Earliest selectable date (inclusive). |
|
|
20
|
+
| `max` | `Date` | no | Latest selectable date (inclusive). |
|
|
21
|
+
| `isDateDisabled` | `((date: Date) => boolean)` | no | Per-date disable predicate. |
|
|
22
|
+
| `nameStart` | `string` | no | Form name for the START half (hidden `<input>` mirror). |
|
|
23
|
+
| `nameEnd` | `string` | no | Form name for the END half. |
|
|
24
|
+
| `disabled` | `boolean` | no | Disables interaction. Defaults to `false`. |
|
|
25
|
+
| `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. 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 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. |
|
|
26
|
+
| `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'`. |
|
|
27
|
+
| `hourCycle` | `'12' \| '24' \| 'auto'` | no | Display cycle for the two embedded `<TimeField>`s. - `'24'` — `"HH:mm"` text inputs; 24h hour list in popovers. - `'12'` — `"h:mm AM/PM"` text inputs; 12h hour list + AM/PM column. - `'auto'` (default) — derives from the active locale via Intl. en-US → `'12'`; ru-RU → `'24'`. Only meaningful when `granularity='minute'`. |
|
|
28
|
+
| …native | | | plus native `<div>` attributes |
|
|
29
|
+
|
|
30
|
+
<!-- props:end -->
|
|
31
|
+
|
|
32
|
+
- Two-month calendar grid (side-by-side) embedded directly in the page. Same click-1/click-2/restart selection machine, hover preview, auto-swap on out-of-order picks, and keyboard cross-grid navigation as `<DateRangePicker>` — without the input + popover.
|
|
33
|
+
- External prev/next chevrons in the header shift both grids by ±1 month at once.
|
|
34
|
+
- Cursor anchors to `value?.start ?? new Date()` on mount and re-anchors each time `value` transitions from `null` to a non-null range (e.g. loading an async initial value, or a consumer clearing and re-setting). After a transition, later non-null `value` changes do not move the cursor — `ref` is the wrapper `<div>` and exposes no cursor API; to jump to the new month, remount with a changed `key`.
|
|
35
|
+
- Keyboard cross-grid navigation works in both directions between the two grids.
|
|
36
|
+
- `ref` forwards to the outer wrapper.
|
|
37
|
+
- Use when the consumer wants the calendar permanently visible. For a compact form field with the same selection model, use `<DateRangePicker>`. Don't render inside containers narrower than ~32rem — the two grids need side-by-side room.
|
|
38
|
+
- **Granularity.** Pass `granularity="minute"` to render dual `<TimeField>`s (start + end) below the two-month grid; the hidden form mirrors emit ISO local datetime. Defaults to `'day'`. The start/end time inputs are shown and editable below the grid 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 end-time silently clamps 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. `hourCycle` (default `'auto'`) forwards to both embedded TimeFields — `'12'` / `'24'` force a cycle, `'auto'` derives from locale.
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
<form action="/api/bookings">
|
|
42
|
+
<InlineDateRangePicker nameStart="bookingStart" nameEnd="bookingEnd" min={new Date()} />
|
|
43
|
+
<button type="submit">Save</button>
|
|
44
|
+
</form>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
#### When NOT to use
|
|
48
|
+
|
|
49
|
+
- Compact form field: use `<DateRangePicker>` (the popover variant).
|
|
50
|
+
- Single-date selection: use `<InlineDatePicker>`.
|
|
51
|
+
- Seconds-precision tracking: only `granularity="minute"` is supported.
|
|
52
|
+
- Time-only fields (no date): out of scope.
|
|
53
|
+
|
|
54
|
+
#### Anti-patterns
|
|
55
|
+
|
|
56
|
+
- ❌ Wrapping in a narrow container (< ~32rem): the two grids need side-by-side room; squashing them clips the right grid.
|
|
57
|
+
- ❌ Using `value` without `onChange`.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# `<Input>` — single-line text
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
<Input type="email" value={email} onChange={(e) => setEmail(e.target.value)} />
|
|
5
|
+
<Input invalid value={email} aria-describedby="email-error" />
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
<!-- props:start -->
|
|
9
|
+
|
|
10
|
+
## Props
|
|
11
|
+
|
|
12
|
+
<!-- prettier-ignore -->
|
|
13
|
+
| Prop | Type | Required | Description |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| `invalid` | `boolean` | no | Toggles the error visual (red border + focus ring) and sets `aria-invalid="true"`. Pair with a visible error message and `aria-describedby` pointing at the message id. |
|
|
16
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | no | Visual size. Defaults to `'md'`. - `'sm'` — 24px tall; toolbars, secondary forms. - `'md'` — 32px tall (default); most form contexts. - `'lg'` — 40px tall; hero search, mobile-friendly forms. Same scale as `<Select>`; fields have no `xs` (unlike `<Button>`). Note: this shadows the native HTML `<input size>` attribute (visible character count). If you need that legacy attribute, set width via `style` or a parent container. |
|
|
17
|
+
| `disableAutofill` | `boolean` | no | Block browser autofill AND password managers from offering to fill this input. Applies the standard set of opt-out hints: - `autoComplete="off"` - `data-1p-ignore` (1Password) - `data-lpignore="true"` (LastPass) - `data-form-type="other"` (generic "not a login field") **Smart default**: when omitted, the input blocks autofill iff `autoComplete` is also omitted (or `'off'`). Explicit autocomplete hints (`autoComplete="email"`, `"current-password"`, `"username"`, etc.) opt back IN to autofill — the assumption is that a consumer specifying autoComplete actually wants password-manager interaction. Pass `disableAutofill={true}` to force-block even with an autocomplete hint, or `false` to force-allow (except while `suggestions` is active, which always blocks). |
|
|
18
|
+
| `suggestions` | `readonly string[]` | no | Values to suggest while the value stays free text (e.g. the user's other workspace slugs). Makes the input an ARIA combobox with a suggestion list: it opens on focus, click or ↓ showing every suggestion, then filters by case-insensitive substring once the user types. ↑/↓ + Enter or a click fills the value and fires `onChange` exactly as typing would. Ignored when empty or `readOnly`. Browser autofill is forced off while active (even with an `autoComplete` hint) so its dropdown can't stack on this one. Default: none (a plain textbox). For a fixed set of allowed values use `<Select>` instead. |
|
|
19
|
+
| …native | | | plus native `<input>` attributes |
|
|
20
|
+
|
|
21
|
+
<!-- props:end -->
|
|
22
|
+
|
|
23
|
+
- All native `<input>` attributes pass through, except `size` — that's been replaced by the component-level `size` prop (the native HTML `size` attribute, visible-character count, is shadowed).
|
|
24
|
+
- **Autofill is BLOCKED by default** — `<Input />` carries `autoComplete="off"` + the 1Password / LastPass / generic data-\* opt-out hints so password managers don't misfire on search / filter / free-text fields. Set `autoComplete="email"` (or `"username"`, `"current-password"`, etc.) to opt INTO autofill for real form fields. Force the behavior either way via `disableAutofill={true | false}`.
|
|
25
|
+
- Validation logic lives in your form layer (React Hook Form + Zod recommended), not in the component.
|
|
26
|
+
- Not for multi-line (`Textarea`), a fixed list (`Select` — `suggestions` never restricts the value), date/time (`DatePicker` / `DateRangePicker`) or password reveal (`PasswordInput`).
|
|
27
|
+
- ❌ Putting validation logic inside the component. ❌ Using `placeholder` as a label — it disappears on focus; pair the Input with a real `<label>`. ❌ `type="number"` for phone numbers or zip codes — it strips leading zeros; use `inputMode="numeric"`.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
<Input size="sm" placeholder="Filter…" />
|
|
31
|
+
<Input size="lg" type="search" placeholder="Search the workspace" />
|
|
32
|
+
<Input invalid value={value} aria-describedby="email-error" />
|
|
33
|
+
<p id="email-error">Enter a valid email.</p>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Suggestions
|
|
37
|
+
|
|
38
|
+
Free text plus suggestions — e.g. a workspace slug prefilled with the last one used, suggesting the user's others:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
<Input
|
|
42
|
+
value={workspace}
|
|
43
|
+
onChange={(e) => setWorkspace(e.target.value)}
|
|
44
|
+
suggestions={['acme', 'acme-staging', 'northwind']}
|
|
45
|
+
/>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- The input becomes an ARIA combobox with a listbox named "Suggestions" (i18n `input.suggestions`). Without `suggestions` (or with `[]`, or when `readOnly`) it is a plain textbox.
|
|
49
|
+
- The list opens whenever the input gains focus — including Tab traversal, `autoFocus` and focus returned by a Modal — not only on click.
|
|
50
|
+
- While `suggestions` is active, browser autofill is forced off (as `disableAutofill`) even if you pass a real `autoComplete`, so the browser dropdown cannot stack on this one.
|
|
51
|
+
- Opens on focus, click or ↓ and shows **every** suggestion until the user edits the text, so a prefilled value doesn't hide the rest; then it filters by case-insensitive substring, in the given order. No matches → it stays closed (no "no results" row).
|
|
52
|
+
- ↓/↑ move the highlight (wraps; nothing highlighted at first). Enter on a highlight or a click fills the value and fires `onChange` exactly like typing (controlled and uncontrolled). Enter with no highlight stays native (submits the form). Esc, Tab and blur close without changing the value.
|
|
53
|
+
- The popup matches the input's width, flips when there's no room below and scrolls past `--input-suggestions-max-height`.
|
|
54
|
+
- ❌ A fixed set of allowed values → `Select` (or `Select creatable`). ❌ Async / loaded results, groups or rich rows → `Select` with `loadOptions`, or `TopBar.Search`. ❌ Re-adding a native `<datalist>` — it looks different per browser and `Input` turns browser autocomplete off.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# `<Kanban>` — multi-column board (drag-to-reorder + cross-column drag with live reflow)
|
|
2
|
+
|
|
3
|
+
Trello/Jira-style board UI. Compound: `Kanban`, `Kanban.Column`, `Kanban.Card`, `Kanban.Handle` (re-exported `Sortable.Handle`). Built on the same `@dnd-kit/sortable` plumbing as `<Sortable>` with internal items state that re-arranges cards live as the dragged card crosses column boundaries.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Kanban, type KanbanMoveEvent } from '@eocrm/design-system';
|
|
7
|
+
|
|
8
|
+
const [board, setBoard] = useState({
|
|
9
|
+
todo: [{ id: 'a', title: 'Buy milk' }],
|
|
10
|
+
doing: [{ id: 'b', title: 'Write spec' }],
|
|
11
|
+
done: [{ id: 'c', title: 'Ship Sortable' }],
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
function handleMove(event: KanbanMoveEvent) {
|
|
15
|
+
const { from, to, cardId } = event;
|
|
16
|
+
setBoard((curr) => {
|
|
17
|
+
const next = { ...curr };
|
|
18
|
+
const source = [...next[from.columnId as keyof typeof curr]];
|
|
19
|
+
const [moved] = source.splice(from.index, 1);
|
|
20
|
+
next[from.columnId as keyof typeof curr] = source;
|
|
21
|
+
const target =
|
|
22
|
+
from.columnId === to.columnId ? source : [...(next[to.columnId as keyof typeof curr] ?? [])];
|
|
23
|
+
target.splice(to.index, 0, moved);
|
|
24
|
+
next[to.columnId as keyof typeof curr] = target;
|
|
25
|
+
return next;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
<Kanban onMove={handleMove}>
|
|
30
|
+
{(['todo', 'doing', 'done'] as const).map((colId) => (
|
|
31
|
+
<Kanban.Column key={colId} id={colId}>
|
|
32
|
+
<Title order={3}>{colId}</Title>
|
|
33
|
+
{board[colId].map((c) => (
|
|
34
|
+
<Kanban.Card key={c.id} id={c.id}>
|
|
35
|
+
<Card>{c.title}</Card>
|
|
36
|
+
</Kanban.Card>
|
|
37
|
+
))}
|
|
38
|
+
</Kanban.Column>
|
|
39
|
+
))}
|
|
40
|
+
</Kanban>;
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
<!-- props:start -->
|
|
44
|
+
|
|
45
|
+
## Props
|
|
46
|
+
|
|
47
|
+
### `KanbanProps`
|
|
48
|
+
|
|
49
|
+
<!-- prettier-ignore -->
|
|
50
|
+
| Prop | Type | Required | Description |
|
|
51
|
+
|---|---|---|---|
|
|
52
|
+
| `onMove` | `((event: KanbanMoveEvent) => void)` | no | Fires once per drag (on drop) with the from/to positions and the cardId. NOT fired on drag cancel. NOT fired when from === to (no-op drop). Consumer should update their items state immutably, e.g.: (example below) |
|
|
53
|
+
| …native | | | plus native `<div>` attributes |
|
|
54
|
+
|
|
55
|
+
**`onMove`** example:
|
|
56
|
+
|
|
57
|
+
<!-- prettier-ignore -->
|
|
58
|
+
```ts
|
|
59
|
+
const [cols, setCols] = useState({ todo: ['a', 'b'], done: ['c'] });
|
|
60
|
+
const handleMove = ({ from, to, cardId }) => {
|
|
61
|
+
setCols((prev) => {
|
|
62
|
+
const next = { ...prev };
|
|
63
|
+
next[from.columnId] = [...prev[from.columnId]];
|
|
64
|
+
next[from.columnId].splice(from.index, 1);
|
|
65
|
+
next[to.columnId] = [...prev[to.columnId]];
|
|
66
|
+
next[to.columnId].splice(to.index, 0, cardId);
|
|
67
|
+
return next;
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### `KanbanCardProps`
|
|
73
|
+
|
|
74
|
+
<!-- prettier-ignore -->
|
|
75
|
+
| Prop | Type | Required | Description |
|
|
76
|
+
|---|---|---|---|
|
|
77
|
+
| `id` | `string \| number` | yes | Stable identifier for this card. Must be unique across ALL columns in the `<Kanban>`. Used by dnd-kit to track the card during drag. |
|
|
78
|
+
| `children` | `ReactNode` | yes | |
|
|
79
|
+
| …native | | | plus native `<div>` attributes |
|
|
80
|
+
|
|
81
|
+
### `KanbanColumnProps`
|
|
82
|
+
|
|
83
|
+
<!-- prettier-ignore -->
|
|
84
|
+
| Prop | Type | Required | Description |
|
|
85
|
+
|---|---|---|---|
|
|
86
|
+
| `id` | `string \| number` | yes | Stable identifier for this column. Must be unique within a `<Kanban>`. Used internally to track which cards belong to which column. |
|
|
87
|
+
| `children` | `ReactNode` | no | |
|
|
88
|
+
| …native | | | plus native `<div>` attributes |
|
|
89
|
+
|
|
90
|
+
<!-- props:end -->
|
|
91
|
+
|
|
92
|
+
Controlled-only: the consumer applies each `onMove`. Column layout (header, footer) goes before / after the `<Kanban.Card>` children.
|
|
93
|
+
|
|
94
|
+
**Drag origin** (hybrid): `<Kanban.Handle>` inside a Card restricts drag origin to the Handle. Without a Handle, the whole Card is draggable (and dnd-kit assigns it `role="button"`). With a Handle the card div gets `role="article"`.
|
|
95
|
+
|
|
96
|
+
**Cross-column drag is LIVE**: as the dragged card crosses into a new column, cards in the target column shift to make room in real time. `onMove` still fires only once on release. This is driven by internal Kanban state — consumer's state is untouched until drop, so re-renders are scoped to the Kanban subtree (avoids the measureRect cascade that would happen if mid-drag mutations went through consumer setState).
|
|
97
|
+
|
|
98
|
+
**Drop slot**: `to.index` is the slot the preview showed at release — it re-evaluates as the cursor moves inside the target column, not only when the card crosses the boundary.
|
|
99
|
+
|
|
100
|
+
**Drop slot edge cases:** dropping onto an empty column lands at index 0; dropping in a column's padding past the last card appends to that column's end (including the source column's own padding). The drop target is decided by the pointer, while the dragged card itself stays clamped to the board — a card that looks parked on the last column has still cancelled if the cursor was released past it.
|
|
101
|
+
|
|
102
|
+
**Releasing off the board cancels**: release with the cursor outside the columns — over unrelated page content, past the last column — and the card snaps back with NO `onMove`. "Outside" means outside the columns' collective bounding box, so the gutter between two columns still commits to the nearer one; only leaving the band of columns entirely cancels. Escape and a release that never left the card's own slot cancel the same way.
|
|
103
|
+
|
|
104
|
+
**Overflowing boards auto-scroll**: the board is its own horizontal scroll container, so dragging a card near the left/right edge scrolls it — that is how you reach an off-screen column. The dragged card is confined to the board's scrollable content box on both axes (it stops at the outer edge of the first/last column rather than following the cursor out of the board). That bound is what keeps auto-scroll from running away: the card renders in flow, so an unbounded one would extend the board's own `scrollWidth` and auto-scroll would chase the edge it just created. Nothing to configure. Caveat: the bound is the card's NEAREST scrolling ancestor. Capping a column (`overflow-y: auto` + `max-height` on `<Kanban.Column>`) makes the column that ancestor, and the dragged card is then confined to its own column while dragging — the drop still lands wherever the cursor is, but the card won't visibly cross into the neighbour. Scroll the board, not the columns.
|
|
105
|
+
|
|
106
|
+
**Keyboard reorder** works WITHIN a column (Tab to Card/Handle, Space pick up, Arrow keys move, Space drop). Cross-column keyboard moves are NOT supported in v1.
|
|
107
|
+
|
|
108
|
+
**When NOT to use**
|
|
109
|
+
|
|
110
|
+
- Single-column drag-to-reorder — use `<Sortable>`.
|
|
111
|
+
- Pure display boards with no drag — use `<Stack>` + `<Card>`.
|
|
112
|
+
- Column reordering is not supported; columns render in source JSX order.
|
|
113
|
+
|
|
114
|
+
**Anti-patterns**
|
|
115
|
+
|
|
116
|
+
- ❌ Expecting cross-column keyboard reorder. dnd-kit's stock coordinate-getter is per-`SortableContext`. v2 will ship a custom getter that bridges columns.
|
|
117
|
+
- ❌ Leaving `<Kanban.Column>` unnamed. Screen-reader drag announcements name the destination column from its `aria-label` or `aria-labelledby`; without either they fall back to "column 2 of 3". A named column also renders as `role="group"` so the name isn't inert.
|
|
118
|
+
- ❌ A content-heavy `<Kanban.Card>` with no `aria-label`. The card announces itself by its rendered text, so a card carrying title + assignee + due date + badges reads all of it on every drag step. One `aria-label` fixes it.
|
|
119
|
+
- ❌ Interleaving non-`Kanban.Card` children with cards inside a `<Kanban.Column>`. The Root walks each column's children to extract a contiguous card block; if non-cards appear between cards, the rendering re-arranges them awkwardly. Keep header / count badges BEFORE the cards, footer / "Add card" buttons AFTER.
|
|
120
|
+
- ❌ Wrapping `<Kanban.Card>` inside a custom component. The Root walks direct descendants of `<Kanban.Column>` to find cards; nested cards are invisible to it.
|
|
121
|
+
- ❌ Non-stable column / card ids (e.g. array indices). Both must persist across reorders.
|
|
122
|
+
- ❌ Mutating board state in place inside `onMove`. Always return a new object/array reference.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# `Kbd`
|
|
2
|
+
|
|
3
|
+
Inline keyboard-shortcut display: one `<kbd>` chip per key, joined with a faint `+` separator. Use for shortcut hints in tooltips, command palettes, search inputs, and help/shortcut sheets.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
<Kbd keys={['⌘', 'K']} />
|
|
7
|
+
<Kbd keys={['Ctrl', 'Shift', 'P']} size="md" />
|
|
8
|
+
<Kbd keys={['Esc']} />
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
<!-- props:start -->
|
|
12
|
+
|
|
13
|
+
## Props
|
|
14
|
+
|
|
15
|
+
<!-- prettier-ignore -->
|
|
16
|
+
| Prop | Type | Required | Description |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| `keys` | `string[]` | yes | Keys to display. Each entry renders one `<kbd>` chip. Multiple entries are joined with an inline `+` separator; a single-entry array renders no separator. Pass the literal label you want shown (`'⌘'`, `'Ctrl'`, `'Shift'`, `'K'`) — the component does NOT platform-translate. |
|
|
19
|
+
| `size` | `'sm' \| 'md'` | no | Visual size. `'sm'` is the inline-chrome size (18px tall — matches `TopBar.Search`'s hotkey hint). `'md'` is the standalone shortcut size (24px tall — for command-palette / shortcut-sheet UI). Default: `'sm'`. |
|
|
20
|
+
| `aria-label` | `string` | no | Accessible label for the whole shortcut, read as a single phrase by screen readers. Defaults to `keys.join(' + ')` (e.g. `'⌘ + K'`) when omitted OR empty — an empty string is not an explicit name, so it takes the default too. Override when the raw keys are unintuitive — e.g. `keys={['⌘', 'K']}` with `aria-label="Open command palette"`. |
|
|
21
|
+
| …native | | | plus native `<span>` attributes |
|
|
22
|
+
|
|
23
|
+
<!-- props:end -->
|
|
24
|
+
|
|
25
|
+
- Wrapper carries `aria-label = keys.join(' + ')` (override via prop); inner `<kbd>` and `+` separator are `aria-hidden`.
|
|
26
|
+
|
|
27
|
+
**When NOT to use:** for inline code use `<Code>`; for chip-shaped text labels use `<Badge>`. `<kbd>` implies keyboard input semantically.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
<Tooltip
|
|
31
|
+
content={
|
|
32
|
+
<>
|
|
33
|
+
Save <Kbd keys={['⌘', 'S']} />
|
|
34
|
+
</>
|
|
35
|
+
}
|
|
36
|
+
>
|
|
37
|
+
<Button>Save</Button>
|
|
38
|
+
</Tooltip>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- ❌ Nesting a `<Kbd>` inside a button as its only label. Use the button's `aria-label` and render the Kbd as a separate visual hint.
|