@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,105 @@
|
|
|
1
|
+
# `<Lightbox>` — full-screen image & document gallery overlay
|
|
2
|
+
|
|
3
|
+
`<Lightbox open onOpenChange items>` shows one large item at a time (an image, or a PDF in an `<iframe>`) with prev/next chevrons, ← → keys, a thumbnail strip, a position counter, and an optional caption. Controlled `open` like `<Modal>`; the current index is uncontrolled (`defaultIndex`) unless you pass `index` + `onIndexChange`. `loop` (default true) wraps at the ends. The consumer owns the trigger — typically a row of interactive `<Image>` thumbnails. For a single inline image use `<Image>`.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
const [open, setOpen] = useState(false);
|
|
7
|
+
const [start, setStart] = useState(0);
|
|
8
|
+
<Lightbox
|
|
9
|
+
open={open}
|
|
10
|
+
onOpenChange={setOpen}
|
|
11
|
+
defaultIndex={start}
|
|
12
|
+
items={files.map((f) => ({ src: f.url, alt: f.name, caption: f.name }))}
|
|
13
|
+
/>;
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
<!-- props:start -->
|
|
17
|
+
|
|
18
|
+
## Props
|
|
19
|
+
|
|
20
|
+
<!-- prettier-ignore -->
|
|
21
|
+
| Prop | Type | Required | Description |
|
|
22
|
+
|---|---|---|---|
|
|
23
|
+
| `open` | `boolean` | yes | Controlled open state. |
|
|
24
|
+
| `onOpenChange` | `(open: boolean) => void` | yes | Fired when the Lightbox wants to close — Esc, backdrop click, the × button. |
|
|
25
|
+
| `items` | `LightboxItem[]` | yes | The images and documents (mixed galleries are supported; see `kind` on `LightboxItem` for PDFs). A PDF without a `thumbnail` shows a document-icon placeholder in the strip; an unsafe (non-http(s)) document `src` shows a "Preview unavailable" message. An empty array renders nothing and behaves as closed (no inert page, scroll lock or focus trap) even while `open`. |
|
|
26
|
+
| `defaultIndex` | `number` | no | Initial image index (uncontrolled). Defaults to `0`. Clamped to range. |
|
|
27
|
+
| `index` | `number` | no | Controlled current index. When set, pair with `onIndexChange`. |
|
|
28
|
+
| `onIndexChange` | `((index: number) => void)` | no | Fired on navigation (chevron / arrow key / thumbnail click). |
|
|
29
|
+
| `loop` | `boolean` | no | Wrap past the first/last image. Defaults to `true`. |
|
|
30
|
+
| `actions` | `((item: LightboxItem, index: number) => ReactNode)` | no | Extra header actions for the current item (e.g. a Download `<Button>`, a `<DropdownMenu>` "more" menu). Called with the current item and its index on every render, so it follows navigation. Rendered in the top-right toolbar BEFORE the close button. Use `<Button iconOnly variant="ghost" size="sm">` (or a DropdownMenu trigger built from one) — the toolbar re-themes ghost Buttons for the dark scrim (ghost tokens, full radius, `sm` height = the toolbar control size), so text Buttons render pill-shaped — keep actions icon-only. While an action's menu or popover is open, Esc closes it first, and ←/→ stay with it (not the gallery) while focus is in it — likewise while focus is on a text field, combobox (Select), radio (ButtonGroup), slider, tab or expanded trigger; a Tooltip on an action doesn't block navigation. Returning `null`/`undefined` renders nothing. REPLACES the built-in PDF download link: when `actions` is set, the Lightbox renders no download action of its own — include your own Download for PDF items if you want one. |
|
|
31
|
+
| `className` | `string` | no | className for the dialog container. |
|
|
32
|
+
| `aria-label` | `string` | no | Accessible label for the dialog. Defaults to the i18n "Image gallery" when omitted OR empty — an empty string is not an explicit name, so it takes the default too. |
|
|
33
|
+
|
|
34
|
+
<!-- props:end -->
|
|
35
|
+
|
|
36
|
+
- Each `LightboxItem` is `{ src, alt, kind?, caption?, thumbnail? }` — `alt` is required.
|
|
37
|
+
- Single item → chevrons, counter, and strip auto-hide. Empty `items` → renders nothing.
|
|
38
|
+
- Reuses the DS overlay machinery (focus-trap, scroll-lock, Esc — yielding to open floating surfaces first like Modal/Drawer, stacking above modals).
|
|
39
|
+
|
|
40
|
+
Mixed gallery (images + a PDF):
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
<Lightbox
|
|
44
|
+
open={open}
|
|
45
|
+
onOpenChange={setOpen}
|
|
46
|
+
items={[
|
|
47
|
+
{ src: shot.url, alt: 'Screenshot' },
|
|
48
|
+
{ src: doc.url, alt: 'Contract.pdf', kind: 'pdf' },
|
|
49
|
+
]}
|
|
50
|
+
/>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Header actions — `actions(item, index)` renders consumer controls in the top-right toolbar, before the close button, for the current item (re-rendered on navigation). Use `<Button iconOnly variant="ghost" size="sm">` (and DropdownMenu triggers built from one); the toolbar re-themes ghost Buttons for the dark scrim. The toolbar re-themes any Button inside it (ghost tokens, full radius, `sm` height = the toolbar control size), so a text Button renders pill-shaped — keep actions `variant="ghost" iconOnly`. A DropdownMenu, Popover or ConfirmationPopover opened from an action works normally — while focus is in it, ←/→ stay with it (no gallery navigation), and Esc closes it first, then the Lightbox. ←/→ also stay put while focus is on a text field, a Select (combobox), a ButtonGroup radio, a Slider, a Tab or an expanded trigger. A Tooltip on an action does not block ←/→.
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
<Lightbox
|
|
57
|
+
open={open}
|
|
58
|
+
onOpenChange={setOpen}
|
|
59
|
+
items={files}
|
|
60
|
+
actions={(item) => (
|
|
61
|
+
<>
|
|
62
|
+
<Button
|
|
63
|
+
as="a"
|
|
64
|
+
href={item.src}
|
|
65
|
+
download
|
|
66
|
+
target="_blank"
|
|
67
|
+
rel="noopener noreferrer"
|
|
68
|
+
iconOnly
|
|
69
|
+
variant="ghost"
|
|
70
|
+
size="sm"
|
|
71
|
+
aria-label={t('download')}
|
|
72
|
+
>
|
|
73
|
+
<Download size={20} aria-hidden="true" />
|
|
74
|
+
</Button>
|
|
75
|
+
<DropdownMenu>
|
|
76
|
+
<DropdownMenu.Trigger>
|
|
77
|
+
<Button iconOnly variant="ghost" size="sm" aria-label={t('more')}>
|
|
78
|
+
<MoreHorizontal size={20} aria-hidden="true" />
|
|
79
|
+
</Button>
|
|
80
|
+
</DropdownMenu.Trigger>
|
|
81
|
+
<DropdownMenu.Content align="end">
|
|
82
|
+
<DropdownMenu.Item onSelect={() => rename(item)}>Rename</DropdownMenu.Item>
|
|
83
|
+
</DropdownMenu.Content>
|
|
84
|
+
</DropdownMenu>
|
|
85
|
+
</>
|
|
86
|
+
)}
|
|
87
|
+
/>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**`actions` replaces the built-in PDF download.** Without `actions`, a PDF item gets a Download link automatically. With `actions` set, the Lightbox renders no download of its own — the consumer owns the whole header, so include a Download action yourself if PDFs (or images) should be downloadable.
|
|
91
|
+
|
|
92
|
+
Tall or wide images are scaled down (`object-fit: contain`) to fit the stage — never cropped.
|
|
93
|
+
|
|
94
|
+
**When NOT to use**
|
|
95
|
+
|
|
96
|
+
- A single, always-visible image — use `<Image>` (optionally `interactive`).
|
|
97
|
+
- An arbitrary modal dialog (not an image/PDF preview) — use `<Modal>`.
|
|
98
|
+
|
|
99
|
+
**Anti-patterns**
|
|
100
|
+
|
|
101
|
+
- ❌ Building your own `Modal` + `Image` + arrows — that is what this is.
|
|
102
|
+
- ❌ Omitting `alt` on items — it is required and names the thumbnail and the stage.
|
|
103
|
+
- ❌ Passing `index` without `onIndexChange` — navigation would be a no-op.
|
|
104
|
+
- ❌ Passing `actions` and expecting the built-in PDF download to stay — `actions` replaces it; add your own Download action.
|
|
105
|
+
- ❌ Primary/secondary Buttons in `actions` — they ignore the scrim re-theme and look out of place; use `variant="ghost" iconOnly size="sm"`.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# `<Link>` — polymorphic styled anchor
|
|
2
|
+
|
|
3
|
+
Inline navigation link. Polymorphic via `as` — defaults to `<a>`, consumers pass a router's `<Link>` for SPA navigation. Three visual variants cover the inline use cases.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Link } from '@eocrm/design-system';
|
|
7
|
+
|
|
8
|
+
// External — defaults to <a>
|
|
9
|
+
<Link href="https://docs.example.com">Documentation</Link>
|
|
10
|
+
|
|
11
|
+
// SPA route — pass router's Link
|
|
12
|
+
import { Link as RouterLink } from 'react-router-dom';
|
|
13
|
+
<Link as={RouterLink} to="/contacts">Contacts</Link>
|
|
14
|
+
|
|
15
|
+
// Variants
|
|
16
|
+
<Link href="/x">View all</Link> {/* default — link colour, hover-underline */}
|
|
17
|
+
<Link href="/x" variant="muted">Subdued nav</Link> {/* breadcrumb-style */}
|
|
18
|
+
<Link href="/x" variant="subtle">Contact name</Link> {/* fg color, hover-accent */}
|
|
19
|
+
|
|
20
|
+
// underline — independent of variant
|
|
21
|
+
<Link href="/x" underline="always">documentation</Link> {/* running text / body copy — required, see below */}
|
|
22
|
+
<Link href="/x" variant="subtle" underline="none">Acme Inc</Link> {/* brand/nav — no hover underline */}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
<!-- props:start -->
|
|
26
|
+
|
|
27
|
+
## Props
|
|
28
|
+
|
|
29
|
+
<!-- prettier-ignore -->
|
|
30
|
+
| Prop | Type | Required | Description |
|
|
31
|
+
|---|---|---|---|
|
|
32
|
+
| `variant` | `'default' \| 'muted' \| 'subtle'` | no | Visual variant. See `LinkVariant` for descriptions. |
|
|
33
|
+
| `underline` | `'hover' \| 'always' \| 'none'` | no | Underline behavior. See `LinkUnderline` for descriptions. Default: `'hover'`. |
|
|
34
|
+
| `children` | `ReactNode` | no | |
|
|
35
|
+
| `as` | `ElementType` | no | |
|
|
36
|
+
| …native | | | plus native attributes of the `as` element (default `<a>`) |
|
|
37
|
+
|
|
38
|
+
<!-- props:end -->
|
|
39
|
+
|
|
40
|
+
- **Polymorphic**: `as={Component}` forwards all of Component's props with full TypeScript inference.
|
|
41
|
+
- **Library has no router dependency** — the `as` mechanism is consumer-driven.
|
|
42
|
+
- **Three variants**:
|
|
43
|
+
- `default`: link colour (`--color-link-fg`; the accent unless the accent set overrides it — `tealpine` uses a brighter teal at medium weight), hover-underline. Inline CTA ("View all →").
|
|
44
|
+
- `muted`: muted color, hover-accent. Low-emphasis nav (breadcrumb-style).
|
|
45
|
+
- `subtle`: foreground color, hover-accent + underline. Dense-surface name links. **Not deprecated** — this is `Link`'s own variant and is unrelated to `Text`/`Title`'s `tone="subtle"`, which WAS deprecated. Same word, opposite status: a grep for "subtle deprecated" will land on the tone, and `PersonDisplay.Name` uses this variant deliberately.
|
|
46
|
+
- **`underline` prop** (`'hover'` | `'always'` | `'none'`, default `'hover'`) — orthogonal to `variant`:
|
|
47
|
+
- `'hover'` (default, same as omitting it): each variant's existing look — `default`/`subtle` underline on hover only, `muted` never underlines.
|
|
48
|
+
- `'always'`: underlined at rest and on hover, on every variant.
|
|
49
|
+
- `'none'`: never underlined, not even on hover, on every variant.
|
|
50
|
+
- **Links inside running text/body copy MUST use `underline="always"`.** The default accent-on-body contrast falls short of WCAG 1.4.1's 3:1 non-text threshold, so color alone isn't a sufficient cue — a link needs an underline to be told apart from surrounding words. `underline="none"` is for brand/nav links that want a variant's subtle color without the hover underline (the opposite end of the same axis).
|
|
51
|
+
- **No `disabled` state** — render `<span>` directly for non-clickable labels.
|
|
52
|
+
|
|
53
|
+
#### When NOT to use
|
|
54
|
+
|
|
55
|
+
- ❌ Action triggers (submit, open modal) → use `<Button>`.
|
|
56
|
+
- ❌ Mutually-exclusive switchers → use `<Tabs>` or `<ButtonGroup>`.
|
|
57
|
+
- ❌ "Link styled as button" → use `<Button variant="ghost">`.
|
|
58
|
+
|
|
59
|
+
#### Anti-patterns
|
|
60
|
+
|
|
61
|
+
- ❌ `<Link href="#" onClick={...}>` — fake hrefs break right-click "open in new tab".
|
|
62
|
+
- ❌ Forgetting `rel="noopener noreferrer"` on `target="_blank"` links.
|
|
63
|
+
- ❌ Using `variant="default"` for low-emphasis nav like breadcrumbs.
|
|
64
|
+
- ❌ A Link inside running text/body copy without `underline="always"` — color alone isn't a sufficient visual cue (WCAG 1.4.1).
|
|
65
|
+
- ❌ A `default` Link inside `<Text weight="semibold">` (or `bold`) under `data-accent="tealpine"` — the link renders at the accent's medium weight, lighter than the words around it. Wrap the bold run in `<strong>` or give the Link a matching weight via `className`.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# `<LinkCard>` — clickable, full-surface Card
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
// SPA route — pass your router's Link as `as`
|
|
5
|
+
<LinkCard as={RouterLink} to="/contacts/42" padding="md">
|
|
6
|
+
<Stack gap="xs">
|
|
7
|
+
<Text weight="semibold">Acme Corp</Text>
|
|
8
|
+
<Text size="sm" tone="muted">12 open deals</Text>
|
|
9
|
+
</Stack>
|
|
10
|
+
</LinkCard>
|
|
11
|
+
|
|
12
|
+
<LinkCard href="https://status.example.com" tone="success">All systems operational</LinkCard>
|
|
13
|
+
<LinkCard as="button" type="button" onClick={openImporter}>Import contacts</LinkCard>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
<!-- props:start -->
|
|
17
|
+
|
|
18
|
+
## Props
|
|
19
|
+
|
|
20
|
+
<!-- prettier-ignore -->
|
|
21
|
+
| Prop | Type | Required | Description |
|
|
22
|
+
|---|---|---|---|
|
|
23
|
+
| `padding` | `'none' \| 'sm' \| 'md' \| 'lg'` | no | Inner padding — same scale as `Card`. Defaults to `'md'`. |
|
|
24
|
+
| `tone` | `'accent' \| 'info' \| 'success' \| 'warning' \| 'danger'` | no | Optional left-edge tone stripe — same vocabulary as `Card`. |
|
|
25
|
+
| `children` | `ReactNode` | no | |
|
|
26
|
+
| `as` | `ElementType` | no | |
|
|
27
|
+
| …native | | | plus native attributes of the `as` element (default `<a>`) |
|
|
28
|
+
|
|
29
|
+
<!-- props:end -->
|
|
30
|
+
|
|
31
|
+
- A Card whose **whole surface** navigates/acts. Polymorphic like `<Link>` — `as` defaults to `<a>`; pass `as={RouterLink} to=…` for routes or `as="button"` for actions (the library has no router dep).
|
|
32
|
+
- Carries `Card`'s `padding` (default `md`) + `tone` stripe (reuses `--card-*` tokens), plus a hover lift (border + shadow) and a `:focus-visible` ring.
|
|
33
|
+
- Use `<Card>` for non-interactive grouping, `<Link>` for inline text, `<Button>` for form actions. **Don't nest** interactive controls inside it (invalid nested interactives).
|
|
34
|
+
|
|
35
|
+
**Anti-patterns:**
|
|
36
|
+
|
|
37
|
+
- ❌ Nesting interactive controls (`<Button>` / `<Link>`) inside a LinkCard — nested interactives are invalid + confusing.
|
|
38
|
+
- ❌ `<LinkCard href="#" onClick={…}>` — fake href breaks "open in new tab". Use `as="button"` for actions.
|
|
39
|
+
- ❌ `<LinkCard href="https://…" target="_blank">` without `rel="noopener noreferrer"` — security risk.
|
|
40
|
+
|
|
41
|
+
**A11y:** renders a real `<a>` / `<button>` / router link, so it has native semantics; the children supply the accessible name — keep the primary label first. `:focus-visible` provides the keyboard ring.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# `<LiquidEditor>` — Liquid template editor
|
|
2
|
+
|
|
3
|
+
Liquid template editor: syntax highlighting, line-number gutter, variable-insert menu, caret autocomplete, client-side unknown-variable flagging, and a controlled preview pane. Controlled only (`value` + `onChange`). It never parses or renders Liquid — backend syntax errors arrive via `invalid`/`error`; the rendered preview arrives via `preview`/`previewStatus`.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
const VARS = [
|
|
7
|
+
{ code: 'first_name', label: 'First name', type: 'text', group: 'Built-in' },
|
|
8
|
+
{ code: 'last_name', label: 'Last name', type: 'text', group: 'Built-in' },
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
<LiquidEditor value={formula} onChange={setFormula} variables={VARS} />;
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
<!-- props:start -->
|
|
15
|
+
|
|
16
|
+
## Props
|
|
17
|
+
|
|
18
|
+
<!-- prettier-ignore -->
|
|
19
|
+
| Prop | Type | Required | Description |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `value` | `string` | yes | Controlled template source. |
|
|
22
|
+
| `onChange` | `(value: string) => void` | yes | Fires on every edit (typing, paste, variable insert, autocomplete accept). |
|
|
23
|
+
| `variables` | `LiquidVariable[]` | no | Available variables → insert menu, autocomplete, unknown flagging. |
|
|
24
|
+
| `flagUnknownVariables` | `boolean` | no | Underline `{{ vars }}` not present in `variables`. Default `true` (no-op when `variables` empty). |
|
|
25
|
+
| `invalid` | `boolean` | no | External error visual (red border) — set from a backend Liquid syntax error. Default `false`. |
|
|
26
|
+
| `error` | `ReactNode` | no | External error message shown in the footer. Pairs with `invalid`. |
|
|
27
|
+
| `preview` | `ReactNode` | no | Consumer-rendered preview output. When set (or `previewStatus` ≠ 'idle'), the pane shows. |
|
|
28
|
+
| `previewStatus` | `'idle' \| 'loading' \| 'error'` | no | Preview pane chrome. Default `'idle'`. |
|
|
29
|
+
| `previewPlacement` | `'bottom' \| 'right'` | no | Preview pane position. Default `'bottom'`. |
|
|
30
|
+
| `showLineNumbers` | `boolean` | no | Show the line-number gutter. Default `true`. |
|
|
31
|
+
| `showToolbar` | `boolean` | no | Show the toolbar (variable-insert menu). Default `true`. |
|
|
32
|
+
| `toolbarActions` | `ReactNode` | no | Custom action buttons rendered in the toolbar, right-aligned just before the "Insert variable" button (e.g. a Docs / Help link). Pass `<Button size="sm">` elements (or a fragment of them); a `ghost` variant pairs well next to the bordered "Insert variable" button. Only renders when `showToolbar` is true. |
|
|
33
|
+
| `filters` | `string[]` | no | Filter names offered in autocomplete after `\|`. Defaults to a common Liquid set. |
|
|
34
|
+
| `minRows` | `number` | no | Minimum visible rows. Default `4`. |
|
|
35
|
+
| `maxRows` | `number` | no | Maximum visible rows before the editor scrolls internally. Default unbounded. |
|
|
36
|
+
| `readOnly` | `boolean` | no | Read-only: caret + selection allowed, no edits. Default `false`. |
|
|
37
|
+
| `disabled` | `boolean` | no | Disabled: non-interactive + dimmed. Default `false`. |
|
|
38
|
+
| `id` | `string` | no | Optional id forwarded to the textarea (for `<Field>` / label association). |
|
|
39
|
+
| `name` | `string` | no | Optional name forwarded to the textarea. |
|
|
40
|
+
| `placeholder` | `string` | no | Placeholder shown when empty. |
|
|
41
|
+
| `aria-label` | `string` | no | Accessible label (defaults to the i18n `liquidEditor.editorLabel` when omitted OR empty — an empty string is not an explicit name). |
|
|
42
|
+
| `aria-labelledby` | `string` | no | Id of an external label element. |
|
|
43
|
+
| `aria-describedby` | `string` | no | Id(s) of external description element(s). Merged with the component's own footer description (the `error` / unknown-variable message), so a screen reader announces both. You usually don't need this — the footer is wired automatically; pass it only to add an extra external description. |
|
|
44
|
+
| `className` | `string` | no | Extra class on the root wrapper. |
|
|
45
|
+
|
|
46
|
+
<!-- props:end -->
|
|
47
|
+
|
|
48
|
+
**Toolbar:** the right-aligned "Insert variable" dropdown is a bordered `secondary` `sm` button. Pass `toolbarActions` (a `ReactNode`, e.g. `<Button variant="ghost" size="sm">…</Button>` for a Docs/Help link) to add extra buttons right-aligned just before it. Hidden when `showToolbar={false}`.
|
|
49
|
+
|
|
50
|
+
**Gutter:** `showLineNumbers={false}` hides the line-number gutter (default `true`) — right for single-line formula inputs and dense forms; combine with `showToolbar={false}` for the most minimal chrome.
|
|
51
|
+
|
|
52
|
+
**Grouped/dotted palettes (`group`, `description`, `collection`):** each `variables` entry can carry a `group` (a section label in the insert menu, first-seen order — ungrouped entries render unlabeled), a `description` (a muted second line in the insert menu and autocomplete list, and — when the caret sits inside that exact reference — the footer, as `label — description`), and `collection: true` (an autocomplete/menu "list" tag; inserting it drops a `{% for item in code %}{{ item }}{% endfor %}` snippet with the caret left after `{{ item }}`, instead of `{{ code }}`). Unknown-variable flagging matches on the dotted `code` **root** (a variable coded `event.type` still validates inside `event.type.sub` — nested-field codes don't false-flag as unknown); autocomplete prefix-matches the full dotted `code` (typing `ev` or `event.t` suggests `event.type`).
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
const VARS = [
|
|
56
|
+
{
|
|
57
|
+
code: 'event.type',
|
|
58
|
+
label: 'Event type',
|
|
59
|
+
group: 'Event',
|
|
60
|
+
description: 'The journal event type',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
code: 'record.associations',
|
|
64
|
+
label: 'Associations',
|
|
65
|
+
group: 'Record',
|
|
66
|
+
collection: true,
|
|
67
|
+
description: "The record's links — iterate with for",
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
<LiquidEditor value={tpl} onChange={setTpl} variables={VARS} />;
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
When NOT to use: plain prose → `Textarea`; static read-only code → playground `CodeBlock`. Don't expect it to validate syntax (feed `error` from the backend) or to produce its own preview (preview is consumer-rendered).
|
|
75
|
+
|
|
76
|
+
Inside a `<Field>`, the label is associated automatically (`id` / `aria-labelledby`):
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
<Field label="Formula">
|
|
80
|
+
<LiquidEditor value={formula} onChange={setFormula} variables={VARS} />
|
|
81
|
+
</Field>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- ❌ Adding `margin`/positioning hoping the editor self-places — that is the parent's job (`<Stack>` / `<Cluster>` / a wrapper `className`).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# `<List>` — bulleted / numbered prose lists (ul / ol)
|
|
2
|
+
|
|
3
|
+
Semantic list of prose items: facts, steps, header names, error extras. Renders `<ul>` / `<ol>` with `<li>`, component-drawn markers aligned to the first text line, and a hanging indent. Compound: `List`, `List.Item`.
|
|
4
|
+
|
|
5
|
+
TL;DR: `<List>` for bullets, `<List variant="number">` for ordered steps, `numberStyle="badge"` for numbered-step cards.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
<List variant="number" numberStyle="badge">
|
|
9
|
+
<List.Item>Open Settings and choose Integrations.</List.Item>
|
|
10
|
+
<List.Item>Paste the API token and save.</List.Item>
|
|
11
|
+
</List>
|
|
12
|
+
|
|
13
|
+
<List gap="xs">
|
|
14
|
+
<List.Item>
|
|
15
|
+
<code>X-RateLimit-Remaining</code> — requests left in the window.
|
|
16
|
+
</List.Item>
|
|
17
|
+
<List.Item>
|
|
18
|
+
<code>Retry-After</code> — seconds to wait after a 429.
|
|
19
|
+
</List.Item>
|
|
20
|
+
</List>
|
|
21
|
+
|
|
22
|
+
<List variant="number" numberStyle="badge" size="heading" gap="md">
|
|
23
|
+
<List.Item>
|
|
24
|
+
<Title order={3} size="xl">Create a token</Title>
|
|
25
|
+
</List.Item>
|
|
26
|
+
</List>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
<!-- props:start -->
|
|
30
|
+
|
|
31
|
+
## Props
|
|
32
|
+
|
|
33
|
+
### `ListProps`
|
|
34
|
+
|
|
35
|
+
<!-- prettier-ignore -->
|
|
36
|
+
| Prop | Type | Required | Description |
|
|
37
|
+
|---|---|---|---|
|
|
38
|
+
| `variant` | `'bullet' \| 'number'` | no | Marker style. See `ListVariant`. Default `'bullet'`. |
|
|
39
|
+
| `gap` | `'xs' \| 'sm' \| 'md'` | no | Space between items. See `ListGap`. Default `'sm'`. |
|
|
40
|
+
| `size` | `'body' \| 'heading'` | no | Marker scale; use `'heading'` when each item starts with a `Title size="xl"`. See `ListSize`. Default `'body'`. |
|
|
41
|
+
| `numberStyle` | `'plain' \| 'badge'` | no | Number look; only applies to `variant="number"`. See `ListNumberStyle`. Default `'plain'`. |
|
|
42
|
+
| `children` | `ReactNode` | no | `List.Item` elements. A nested `List` goes inside a `List.Item`. |
|
|
43
|
+
| …native | | | plus native HTML attributes |
|
|
44
|
+
|
|
45
|
+
### `ListItemProps`
|
|
46
|
+
|
|
47
|
+
<!-- prettier-ignore -->
|
|
48
|
+
| Prop | Type | Required | Description |
|
|
49
|
+
|---|---|---|---|
|
|
50
|
+
| `children` | `ReactNode` | no | Item content. Text, inline elements, or a nested `List`. |
|
|
51
|
+
| …native | | | plus native `<li>` attributes |
|
|
52
|
+
|
|
53
|
+
<!-- props:end -->
|
|
54
|
+
|
|
55
|
+
- Numbers come from CSS counters, so adding, removing or conditionally rendering items keeps them contiguous. There is no `start` prop.
|
|
56
|
+
- Markers are `aria-hidden`; the list carries an explicit `role="list"` so Safari/VoiceOver keeps list semantics.
|
|
57
|
+
- Text inherits size and colour, so it works inside `Card`, `Alert` and prose-width containers.
|
|
58
|
+
- Nest by putting a `List` inside a `List.Item`; it indents one level. A nested `List` uses its own `size`, so a body list inside a `size="heading"` step keeps body markers.
|
|
59
|
+
- On a `size="heading"` List, marker size, shape and font size come from the `--list-heading-*` tokens: overriding `--list-marker-height`/`-width`, `--list-bullet-size`, `--list-number-font-size` or `--list-badge-size`/`-radius`/`-font-size` has no effect there. Colour, weight and gap tokens (`--list-marker-fg`, `--list-badge-bg`/`-fg`, `--list-*-font-weight`, `--list-marker-gap`) apply to both sizes.
|
|
60
|
+
- `numberStyle` has no effect on bullets.
|
|
61
|
+
- With `numberStyle="badge"` the numbers are visual only; screen readers announce the list position ("1 of 3") rather than the badge text.
|
|
62
|
+
- `size="heading"` fits markers to a `Title size="xl"` first line; the badge turns into a rounded square.
|
|
63
|
+
|
|
64
|
+
When NOT to use: key–value pairs → `DefinitionList`; rows of records → `Card.List` / `Table`; interactive or selectable rows → `Card.List`; custom markers or icons (unsupported).
|
|
65
|
+
|
|
66
|
+
- ❌ Raw `<ul>` / `<ol>` or `Stack` + `Dot` composites for prose lists: use `List`.
|
|
67
|
+
- ❌ Children other than `List.Item` (a `div`, text, a raw `li`): they get no marker and are not counted. Wrapper components are fine if they render `List.Item`.
|
|
68
|
+
- ❌ Using `numberStyle="badge"` with `variant="bullet"` expecting badges: it is ignored.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# `<LiveRegion>` — announcement region for consumer-level outcomes
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
<LiveRegion>{status}</LiveRegion>
|
|
5
|
+
<LiveRegion politeness="assertive">{error}</LiveRegion>
|
|
6
|
+
<LiveRegion announceKey={saveCount}>{t('saved')}</LiveRegion>
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
<!-- props:start -->
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
<!-- prettier-ignore -->
|
|
14
|
+
| Prop | Type | Required | Description |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
| `children` | `ReactNode` | no | The message. Pass a string, a number, or an array of only strings/ numbers (e.g. `[count, ' files uploaded']`) — these compare by value, so an unchanged value does not re-announce and a changed one does. Anything else (JSX elements) compares by identity and re-announces on every parent render, even when the rendered text is unchanged. Empty, `null`, or `false` clears the region and announces nothing. |
|
|
17
|
+
| `politeness` | `'polite' \| 'assertive'` | no | How urgently the region interrupts. - `'polite'` (default) — `role="status"` + `aria-live="polite"`. Waits for the screen reader to finish its current utterance. Use for routine outcomes: saves, copy confirmations, background updates. - `'assertive'` — `role="alert"` + `aria-live="assertive"`. Interrupts immediately. Reserve for errors that need immediate attention. Change politeness in the SAME render as the message (`politeness={error ? 'assertive' : 'polite'}` next to `{error ?? status}`): the role only flips while the region is empty, so the old text is never announced at the new urgency. A politeness-only change re-announces the current text at the new urgency. |
|
|
18
|
+
| `announceKey` | `string \| number` | no | Change this (e.g. a counter) to announce the same message again. Without it, re-rendering with identical text is a no-op — screen readers only announce a live region on a text change. |
|
|
19
|
+
| …native | | | plus native `<span>` attributes |
|
|
20
|
+
|
|
21
|
+
<!-- props:end -->
|
|
22
|
+
|
|
23
|
+
- **Always mount it unconditionally** — it clears then rewrites its text ~50ms later on mount and on every change, so the empty → text transition is what triggers the announcement. A conditionally-mounted region won't announce reliably. Messages changing faster than every ~50ms keep restarting that delay — only the last one of the burst is announced.
|
|
24
|
+
- Props type omits `role` / `aria-live` / `aria-atomic` / `hidden` / `aria-hidden` — it spreads the rest of `HTMLAttributes<HTMLSpanElement>` FIRST so those can't be overridden.
|
|
25
|
+
|
|
26
|
+
**When NOT to use:** don't wrap a library component that already owns its own transient-state region (see [Transient state and screen readers](../transient-state.md)) — two regions announcing one event talk over each other. Don't announce text that's already visible and focused — the user hears it twice. Don't reach for `assertive` for routine success. Prefer a string child over JSX — element children re-announce on every parent render even when the rendered text is unchanged.
|
|
27
|
+
|
|
28
|
+
- ❌ Placing it inside a `<label>` or a `<button>` — inside a `<label>` it joins the control's accessible name via name-from-content; inside a `<button>` it is pruned as children-presentational. Render it as a sibling instead.
|
|
29
|
+
- ❌ Mounting it conditionally (`{msg && <LiveRegion>…}`) — keep it mounted and pass an empty message.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# `<LocaleProvider>` + `useLocale` — locale Context
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
<LocaleProvider locale="ru-RU">
|
|
5
|
+
<App />
|
|
6
|
+
</LocaleProvider>;
|
|
7
|
+
|
|
8
|
+
const locale = useLocale(); // 'ru-RU', or navigator.language fallback
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
<!-- props:start -->
|
|
12
|
+
|
|
13
|
+
## Props
|
|
14
|
+
|
|
15
|
+
<!-- prettier-ignore -->
|
|
16
|
+
| Prop | Type | Required | Description |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| `locale` | `string` | yes | BCP-47 locale string, e.g. 'en-US', 'ru-RU', 'de-DE'. |
|
|
19
|
+
| `children` | `ReactNode` | yes | |
|
|
20
|
+
|
|
21
|
+
<!-- props:end -->
|
|
22
|
+
|
|
23
|
+
- `LocaleProvider` exposes a BCP-47 locale string to descendants. Any locale-aware component (Calendar primitives today; future Input formatters, currency widgets) reads via `useLocale()`.
|
|
24
|
+
- No `<LocaleProvider>` mounted? `useLocale()` falls back to `navigator.language` (or `'en-US'` in SSR / Node).
|
|
25
|
+
- Stateless. To switch locale at runtime, re-render the Provider with a new `locale` prop. Nested Providers override outer ones.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# `<Logo>` — brand logo lockup
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
import logo from '../assets/eocrm-logo.svg'; // a consumer-owned asset
|
|
5
|
+
<Logo src={logo} text="eocrm" size="lg" /> // mark + wordmark
|
|
6
|
+
<Logo src={logo} label="eocrm" /> // mark only (accessible name)
|
|
7
|
+
<Logo src={logo} text="eocrm" textPlacement="bottom" />
|
|
8
|
+
<Logo src={logo} text="eocrm" subtext="Free trial" size="sm" /> // mark + name + muted subline
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
<!-- props:start -->
|
|
12
|
+
|
|
13
|
+
## Props
|
|
14
|
+
|
|
15
|
+
<!-- prettier-ignore -->
|
|
16
|
+
| Prop | Type | Required | Description |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| `src` | `string` | yes | The brand mark image URL — typically an imported SVG/PNG asset. The mark is a **consumer-owned asset**; the design system ships no logo of its own. Rendered as an `<img>` (`object-fit: contain`) with no CSS recolor — the asset carries its own color. For third-party SSO marks use `<BrandIcon>`. |
|
|
19
|
+
| `text` | `ReactNode` | no | Wordmark rendered beside (or below) the mark — consumers pass `"eocrm"`. Omit for a mark-only logo. |
|
|
20
|
+
| `textPlacement` | `'end' \| 'bottom'` | no | Where the wordmark sits relative to the mark. Defaults to `'end'` (beside); `'bottom'` stacks it under the mark, centered. |
|
|
21
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | no | Mark size — `'sm'` (24) / `'md'` (32, default) / `'lg'` (40). |
|
|
22
|
+
| `label` | `string` | no | Accessible name for the mark when there's no `text` (used as the image `alt`). Omit for a decorative mark (`alt=""`), or when `text` is present (the wordmark is the name). Never pass both `text` and `label`. |
|
|
23
|
+
| `subtext` | `ReactNode` | no | Small, muted secondary line rendered under `text` — e.g. a plan or tagline (`subtext="Free trial"`). Only shown when `text` is present. |
|
|
24
|
+
| …native | | | plus native `<div>` attributes |
|
|
25
|
+
|
|
26
|
+
<!-- props:end -->
|
|
27
|
+
|
|
28
|
+
- Arranges a **consumer-supplied** mark image (`src`, required — import an SVG/PNG) with an optional wordmark beside (default) or below (`textPlacement="bottom"`). The design system ships **no** logo of its own.
|
|
29
|
+
- **Wordmark font:** override `--logo-text-font` / `--logo-text-font-weight` to set the wordmark's font + weight (defaults: inherited sans, bold). Affects only `text`, not the mark or `subtext`; load the font yourself (the DS ships none).
|
|
30
|
+
- **Spacing:** `--logo-gap` (mark → wordmark, default `var(--space-2)`) and `--logo-text-gap` (wordmark → subtext, default `var(--space-1)`). `--logo-text-gap` only takes effect where `text-box-trim` is supported; elsewhere the lockup falls back to line-height leading for that separation, so it reads looser and taller (never clipped) — see the migration note below for how much. Where it does apply it is genuine clear space: adding a `subtext` moves the wordmark's under-edge from the baseline down to the font's descent, so a wordmark with descenders (`paygo`) keeps its tails out of the subline instead of eating the gap. Because it is measured from that descent line rather than from the ink, a descender-free wordmark shows roughly 1.8–2.3× the token as visible space (the descent is a fixed fraction of em while the token is a fixed 4px, so the ratio grows with `size`). The subtext itself keeps an `alphabetic` under-edge, so a subtext with descenders puts a little ink below the lockup's own bottom edge — ~2px at `sm`, its worst case; at `md`/`lg` the mark is tall enough to absorb it. Fine inside padded chrome, worth knowing if you clip a box sized exactly to the lockup. Like the migration figures, these depend on the subtext's face, which is `--font-family-sans` rather than your wordmark font.
|
|
31
|
+
- **Optical alignment is automatic, and `text` decides it.** Where `text-box-trim` is supported the wordmark is trimmed to its cap edge, or to its x-height edge when every glyph tops out at x-height (`eocrm`, `acme`). Anything with a capital, an ascender (`b d f h k l t`), a dotted `i`/`j`, a digit, or a non-Latin script takes the cap edge — so `<Logo text="eocrm">` and `<Logo text="lockbox">` are trimmed to different edges — their boxes differ, while the ink stays on the same optical centre against the mark. Nothing to configure; pass a non-string `text` (an element) and it takes the cap edge too.
|
|
32
|
+
- ⚠️ **_Migration:_ the lockup got shorter wherever `text-box-trim` is supported (Chrome/Safari; not Firefox).** Trimming the wordmark's half-leading is new — previous versions carried the font's full leading — most lockups with a `subtext`, and every `textPlacement="bottom"` lockup, render measurably shorter at the same `size`. Measured, per shape (before → after):
|
|
33
|
+
- `subtext="Free trial"`, beside the mark — `sm` 30.8px → 24.0px, `md` 35.2px → 32.0px
|
|
34
|
+
- `textPlacement="bottom"`, **no** subtext — `lg` 74.4px → 59.6px
|
|
35
|
+
- `textPlacement="bottom"` **with** a subtext — `sm` 62.8px → 55.3px
|
|
36
|
+
|
|
37
|
+
These come from the playground, which renders the wordmark in Outfit 600 and leaves the subtext on `--font-family-sans` — so every figure above with a subtext is a function of two faces. The DS ships no font of its own, so yours will shift all of them; treat these as the shape of the change, not constants. The side-by-side lockup **without** a subtext keeps its height at every size (the mark sets it), and at `lg` even the with-subtext lockup does — only `sm`/`md` shrink there.
|
|
38
|
+
|
|
39
|
+
**Height is not the only thing that moved.** Trimming the leading also raises the wordmark against the mark in **every** shape, including the ones whose height is unchanged. Side-by-side without a subtext, the wordmark's ink centre sat 1.3 / 2.2 / 3.0px _below_ the mark's **box** centre at `sm`/`md`/`lg` and now sits within 0.1px of it — it rises by roughly 1.5px at `sm` up to 3px at `lg`. That is the correction this is for (the wordmark used to hang low), but it means the shape you use most did change visually even though it did not change size. Firefox keeps the old position as well as the old height, so the same lockup differs across browsers by that 1.5–3px on top of the height gap — which is **up to** ~28% (`sm` with a subtext) and 0% for the side-by-side lockup without one. If you center a Logo in a fixed-height brand bar or auth splash, re-check that container; size containers off the mark, not the lockup.
|
|
40
|
+
|
|
41
|
+
⚠️ Every pixel figure above is Chromium with the playground's Outfit-600 wordmark and `--font-family-sans` subtext, and **none of it is pinned by a test** — the Logo tests assert stylesheet text, not geometry. Retuning `--font-size-*` or swapping the brand font invalidates these numbers with nothing going red. Treat them as the shape and rough scale of the change and re-measure in your own face before sizing anything to them.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# `<Masonry>` — height-balanced masonry layout
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
<Masonry minColumnWidth="220px" gap="md">
|
|
5
|
+
{photos.map((p) => (
|
|
6
|
+
<Image key={p.id} src={p.src} alt={p.alt} aspectRatio={p.ratio} />
|
|
7
|
+
))}
|
|
8
|
+
</Masonry>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
<!-- props:start -->
|
|
12
|
+
|
|
13
|
+
## Props
|
|
14
|
+
|
|
15
|
+
<!-- prettier-ignore -->
|
|
16
|
+
| Prop | Type | Required | Description |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| `gap` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'` | no | `xs`(4) / `sm`(8) / `md`(12, default) / `lg`(16) / `xl`(24) / `2xl`(32). |
|
|
19
|
+
| `children` | `ReactNode` | no | |
|
|
20
|
+
| `columns` | `number` | no | Fixed number of columns. Mutually exclusive with `minColumnWidth`. |
|
|
21
|
+
| `minColumnWidth` | `string` | no | Min column width (px) for a responsive column count. Default `'240px'`. |
|
|
22
|
+
| …native | | | plus native HTML attributes |
|
|
23
|
+
|
|
24
|
+
<!-- props:end -->
|
|
25
|
+
|
|
26
|
+
Packs variable-height children into columns (greedy shortest-column-first) →
|
|
27
|
+
left→right reading order, balanced heights. Measures on the client + rebalances
|
|
28
|
+
via `ResizeObserver`.
|
|
29
|
+
|
|
30
|
+
- `columns` **xor** `minColumnWidth` (px string, default `'240px'`) — pass one.
|
|
31
|
+
|
|
32
|
+
**When NOT to use:** equal-height tiles → `<Grid>`; one column → `<Stack>`;
|
|
33
|
+
wrapping rows → `<Cluster>`. Display content only — rebalancing remounts children.
|
|
34
|
+
|
|
35
|
+
Fixed column count:
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
<Masonry columns={3} gap="lg">
|
|
39
|
+
{notes.map((n) => (
|
|
40
|
+
<Card key={n.id}>{n.body}</Card>
|
|
41
|
+
))}
|
|
42
|
+
</Masonry>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Before measurement (and without JS) children render round-robin across the columns. Heights re-balance on container resize and when child content settles (e.g. images finish loading).
|
|
46
|
+
|
|
47
|
+
- ❌ Interactive / stateful children (videos, focus-holding forms) — rebalancing re-parents items between columns, so React remounts them.
|
|
48
|
+
- ❌ Expecting a single top-to-bottom reading column — items are distributed across columns; order is left→right by placement.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# `<MediaTile>` — media tile with caption, revealed actions and selection
|
|
2
|
+
|
|
3
|
+
`<MediaTile media title meta actions>` — a full-bleed `media` body (an `<Image>` or a file-type icon) with a `title` + `meta` caption and `actions`. Drop one per tile in a `<Masonry>` / `<Grid>` for a gallery or file grid.
|
|
4
|
+
|
|
5
|
+
- `captionPlacement="overlay"` (default) — caption in a top bar and `actions` in a bottom bar, each over a gradient scrim, **revealed on hover / keyboard focus**. Compact; the name is hidden at rest.
|
|
6
|
+
- `captionPlacement="below"` — caption in a **solid, always-visible** bar under the media (normal text colour on the surface); `actions` move to a top-right chip over the media, still revealed per `revealOn`. Use for a record's Files tab, where file names must be readable.
|
|
7
|
+
- `controls="bar"` (with `captionPlacement="below"` only; ignored in overlay placement) — the checkbox and `actions` share one **full-width solid bar** across the top of the media (divider below) instead of two chips. Reads better over busy or light images. When `selectable`, a click on the bar's free space toggles selection; nothing in the bar reaches the tile `onClick`.
|
|
8
|
+
- `selectable` adds a checkbox top-left over the media (`selected` / `onSelectedChange` / `selectLabel`); a selected tile gets `data-selected` and an accent ring. Only the checkbox toggles selection — the tile's own `onClick` (e.g. open preview) keeps working. With `revealOn="focus"` an unselected checkbox is hidden and ignores the pointer until focus-within (mouse users can't reach it), so pair `selectable` with `'hover'` or `'visible'`.
|
|
9
|
+
- Clicks and keydowns on the controls in `actions` and on the checkbox **don't bubble to the tile** (nor to React handlers on its ancestors or document/window bubble-phase listeners; native listeners on ancestors inside the React root and capture-phase listeners still see them), so a tile `onClick` / `onKeyDown` never fires from them. A click on the overlay bar's empty scrim still reaches the tile; the below-placement actions chip (padding and gaps included) does not.
|
|
10
|
+
- A tile `onClick` is a **pointer convenience** — the tile `<div>` is not focusable. Keyboard users need an equivalent control: put a Preview button in `actions`.
|
|
11
|
+
|
|
12
|
+
The reveal uses `opacity` (not `visibility`), so the controls stay tabbable — tabbing in fires `:focus-within` and reveals them. On touch devices (`(hover: none)`), `revealOn="hover"` behaves like `"visible"` in both placements, so touch users can reach the controls. A checked checkbox is always shown.
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
// File grid: readable names, multi-select, actions top-right (incl. a keyboard-reachable Preview)
|
|
16
|
+
const [selected, setSelected] = useState<Set<string>>(new Set());
|
|
17
|
+
const anySelected = selected.size > 0;
|
|
18
|
+
|
|
19
|
+
<Masonry minColumnWidth="180px" gap="sm">
|
|
20
|
+
{files.map((f) => (
|
|
21
|
+
<MediaTile
|
|
22
|
+
key={f.id}
|
|
23
|
+
captionPlacement="below"
|
|
24
|
+
media={
|
|
25
|
+
<Image
|
|
26
|
+
src={f.thumbUrl}
|
|
27
|
+
alt={f.name}
|
|
28
|
+
aspectRatio={1}
|
|
29
|
+
objectFit="cover"
|
|
30
|
+
objectPosition="top"
|
|
31
|
+
/>
|
|
32
|
+
}
|
|
33
|
+
title={f.name}
|
|
34
|
+
meta={formatBytes(f.size)}
|
|
35
|
+
selectable
|
|
36
|
+
selected={selected.has(f.id)}
|
|
37
|
+
onSelectedChange={(next) => toggle(f.id, next)}
|
|
38
|
+
revealOn={anySelected ? 'visible' : 'hover'} // selection mode: show every checkbox
|
|
39
|
+
onClick={() => openPreview(f)} // pointer shortcut; the Preview action is the keyboard path
|
|
40
|
+
actions={
|
|
41
|
+
<>
|
|
42
|
+
<Button
|
|
43
|
+
iconOnly
|
|
44
|
+
variant="ghost"
|
|
45
|
+
size="sm"
|
|
46
|
+
aria-label={`Preview ${f.name}`}
|
|
47
|
+
onClick={() => openPreview(f)}
|
|
48
|
+
>
|
|
49
|
+
<Eye size={16} />
|
|
50
|
+
</Button>
|
|
51
|
+
<Button iconOnly variant="ghost" size="sm" aria-label={`Download ${f.name}`}>
|
|
52
|
+
<Download size={16} />
|
|
53
|
+
</Button>
|
|
54
|
+
</>
|
|
55
|
+
}
|
|
56
|
+
/>
|
|
57
|
+
))}
|
|
58
|
+
</Masonry>;
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
<!-- props:start -->
|
|
62
|
+
|
|
63
|
+
## Props
|
|
64
|
+
|
|
65
|
+
<!-- prettier-ignore -->
|
|
66
|
+
| Prop | Type | Required | Description |
|
|
67
|
+
|---|---|---|---|
|
|
68
|
+
| `media` | `ReactNode` | yes | Tile body — full-bleed media (an `<Image>`, or a centered file-type icon). |
|
|
69
|
+
| `title` | `ReactNode` | no | Caption leading content (e.g. the file name). Truncates with an ellipsis. |
|
|
70
|
+
| `meta` | `ReactNode` | no | Caption trailing content (e.g. the file size). Sits at the end of the row. |
|
|
71
|
+
| `actions` | `ReactNode` | no | Tile controls (e.g. preview / download / delete icon buttons). With `captionPlacement="overlay"` they sit in a centered bottom bar over a scrim; with `"below"` they sit in a top-right cluster over the media. Either way they follow `revealOn`. Clicks and keydowns on the controls inside don't bubble to the tile (in overlay placement a click on the bar's empty scrim still does; the below-placement chip swallows all clicks), so a tile `onClick` (e.g. open preview) never fires from an action. |
|
|
72
|
+
| `captionPlacement` | `'overlay' \| 'below'` | no | Where `title` + `meta` render. Default `'overlay'`. - `'overlay'` — a top bar over a gradient scrim on the media, revealed per `revealOn`. Compact, but the name is hidden at rest for mouse users. - `'below'` — a solid bar under the media in normal text colour, ALWAYS visible (not affected by `revealOn`). Use for file grids where the name must be readable. |
|
|
73
|
+
| `controls` | `'chips' \| 'bar'` | no | How the selection checkbox and `actions` are presented. Default `'chips'`. Only applies with `captionPlacement="below"`; ignored in overlay placement. - `'chips'` — two floating surface chips: checkbox top-left, actions top-right. - `'bar'` — one full-width solid bar across the top of the media (divider below): checkbox at the start, actions at the end. Reads better over busy or light images. Follows `revealOn`; the whole bar stays shown while selected. When `selectable`, a click on the bar's free space toggles selection (a pointer shortcut; the checkbox remains the keyboard control). Clicks and keys anywhere in the bar never reach the tile `onClick` — the bar is a control region, not the media. |
|
|
74
|
+
| `revealOn` | `'hover' \| 'focus' \| 'visible'` | no | When the overlay bars, `actions` and the selection checkbox reveal. Default `'hover'`. - `'hover'` — on pointer hover OR keyboard focus-within (focus always included for a11y). On touch devices (`(hover: none)`) it behaves like `'visible'`. - `'focus'` — only on focus-within (no mouse-over reveal). - `'visible'` — always shown. A checked selection checkbox is always shown regardless. |
|
|
75
|
+
| `radius` | `'none' \| 'sm' \| 'md' \| 'lg'` | no | Corner rounding (clips the media). Default `'md'`. |
|
|
76
|
+
| `selectable` | `boolean` | no | Render a selection checkbox top-left over the media. Default `false`. Only the checkbox toggles selection — clicking the tile does not (so a tile `onClick`, e.g. open preview, keeps working; checkbox clicks and keys don't bubble to it). With `revealOn="focus"` an unselected checkbox is hidden and ignores the pointer until focus-within, so mouse users can't reach it — pair `selectable` with `'hover'` or `'visible'`. |
|
|
77
|
+
| `selected` | `boolean` | no | Controlled selected state (only used when `selectable`). Sets `data-selected` + an accent ring on the tile. Default `false`. |
|
|
78
|
+
| `onSelectedChange` | `((next: boolean) => void)` | no | Fires with the next selected state when the checkbox is toggled. |
|
|
79
|
+
| `selectLabel` | `string` | no | Accessible name of the selection checkbox, e.g. `"Select report.pdf"`. Defaults to the localized "Select {title}" when `title` is a string, else "Select". |
|
|
80
|
+
| …native | | | plus native `<div>` attributes |
|
|
81
|
+
|
|
82
|
+
<!-- props:end -->
|
|
83
|
+
|
|
84
|
+
- Bars/caption render only when they have content; icon-only `actions` need `aria-label`s.
|
|
85
|
+
- MediaTile clips + overlays only — the `media` (`<Image aspectRatio>`) owns the media's aspect; `captionPlacement="below"` adds the caption bar's height under it.
|
|
86
|
+
- `selectLabel` defaults to the localized "Select {title}" when `title` is a string, else "Select" — pass it when `title` is a node.
|
|
87
|
+
|
|
88
|
+
**When NOT to use:** a plain, non-revealing image block — `<Image>` (optionally inside a `<Card>`); a colored icon chip — `<IconTile>`.
|
|
89
|
+
|
|
90
|
+
- ❌ Putting the ONLY copy of critical info in a hover-revealed overlay bar — it is hidden at rest for mouse users. Use `captionPlacement="below"` (or `revealOn="visible"`).
|
|
91
|
+
- ❌ A click-only tile (`onClick` with no matching action) — the tile isn't focusable, so keyboard users can't open it. Add a Preview (or Open) button to `actions`.
|
|
92
|
+
- ❌ `selectable` with `revealOn="focus"` — the unselected checkbox can't be clicked with a mouse. Use `'hover'` or `'visible'`.
|
|
93
|
+
- ❌ Making the tile itself toggle selection (`onClick={() => toggle(id)}`) — it steals the click from preview/open and is not announced as a checkbox. Use `selectable` + `onSelectedChange`; the tile click stays free for opening.
|
|
94
|
+
- ❌ `controls="bar"` with `captionPlacement="overlay"` — it is ignored there (the overlay already has its own top and bottom bars). Pair it with `captionPlacement="below"`.
|
|
95
|
+
- ❌ Leaving `revealOn="hover"` while some tiles are selected — mouse users can't see which other tiles are selectable. Switch the grid to `revealOn="visible"` once anything is selected.
|