@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,264 @@
|
|
|
1
|
+
// RichTextAttachmentConfig.tsx — floating config popover for a ready attachment.
|
|
2
|
+
// Internal + presentational: the editor owns the model and passes the block's
|
|
3
|
+
// current values + callbacks. Mirrors RichTextLinkEditor's portal + Floating-UI
|
|
4
|
+
// virtual-anchor + Esc/pointerdown-outside pattern. Image attachments get alt/
|
|
5
|
+
// align/replace/open/download — plus width ONLY when the image renders as a
|
|
6
|
+
// preview (a safe, fetchable src — an embed); an uploaded object-URL image is a
|
|
7
|
+
// chip, so it gets no width. Non-image chips get replace/open/download.
|
|
8
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
9
|
+
import { overlayStack, useFloatingSurface } from '../_internal/overlay';
|
|
10
|
+
import { createPortal } from 'react-dom';
|
|
11
|
+
import { Button } from '../Button';
|
|
12
|
+
import { Input } from '../Input';
|
|
13
|
+
import { Slider } from '../Slider';
|
|
14
|
+
import { Stack } from '../Stack';
|
|
15
|
+
import { Cluster } from '../Cluster';
|
|
16
|
+
import { useTranslation } from '../../i18n';
|
|
17
|
+
import type { Block } from '../RichText/engine/model';
|
|
18
|
+
import { safeHref } from '../RichText/engine/safeHref';
|
|
19
|
+
import { attachmentIsImage } from '../RichText/engine/attachment';
|
|
20
|
+
import type { Rect } from './selection';
|
|
21
|
+
import { useAnchoredFloating } from './useAnchoredFloating';
|
|
22
|
+
import { useDismissOnOutsidePointerDown } from './useDismissOnOutsidePointerDown';
|
|
23
|
+
import styles from './RichTextEditor.module.scss';
|
|
24
|
+
|
|
25
|
+
export interface RichTextAttachmentConfigProps {
|
|
26
|
+
/** The attachment block being configured (current values). */
|
|
27
|
+
block: Block;
|
|
28
|
+
/** Figure rect (viewport coords) to anchor the popover to. */
|
|
29
|
+
anchorRect: Rect;
|
|
30
|
+
/**
|
|
31
|
+
* Live anchor rect — re-queried by Floating UI on scroll/resize so the popover
|
|
32
|
+
* tracks the figure (the static `anchorRect` is only the initial position; it
|
|
33
|
+
* goes stale on a pure scroll). Falls back to `anchorRect` when it returns null.
|
|
34
|
+
*/
|
|
35
|
+
getAnchorRect?: () => Rect | null;
|
|
36
|
+
/** Editor content width (px) — the upper bound for the width slider. */
|
|
37
|
+
maxWidth: number;
|
|
38
|
+
/** Native picker filter for Replace. */
|
|
39
|
+
accept?: string;
|
|
40
|
+
onAltChange: (alt: string) => void;
|
|
41
|
+
onAlignChange: (align: 'left' | 'center' | 'right') => void;
|
|
42
|
+
onWidthChange: (width: number) => void;
|
|
43
|
+
onWidthReset: () => void;
|
|
44
|
+
onReplace: (file: File) => void;
|
|
45
|
+
onClose: () => void;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const MIN_W = 80;
|
|
49
|
+
const ALIGNS = ['left', 'center', 'right'] as const;
|
|
50
|
+
const ALIGN_GLYPH: Record<(typeof ALIGNS)[number], string> = {
|
|
51
|
+
left: '⇤',
|
|
52
|
+
center: '↔',
|
|
53
|
+
right: '⇥',
|
|
54
|
+
};
|
|
55
|
+
const ALIGN_LABEL_KEY = {
|
|
56
|
+
left: 'richTextEditor.attachmentAlignLeft',
|
|
57
|
+
center: 'richTextEditor.attachmentAlignCenter',
|
|
58
|
+
right: 'richTextEditor.attachmentAlignRight',
|
|
59
|
+
} as const;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Internal floating config popover for a ready attachment. Rendered by
|
|
63
|
+
* `<RichTextEditor>` when the attachment config is open; not exported from the
|
|
64
|
+
* package. Image attachments get alt / align / replace / open / download — and a
|
|
65
|
+
* width slider ONLY when the image renders as a preview (a safe, fetchable src —
|
|
66
|
+
* an embedded image); an uploaded object-URL image renders as a chip and gets no
|
|
67
|
+
* width control. Non-image chips get replace / open / download. Remount it (via
|
|
68
|
+
* `key`) per open so the alt + width fields re-seed from the block.
|
|
69
|
+
*/
|
|
70
|
+
export function RichTextAttachmentConfig({
|
|
71
|
+
block,
|
|
72
|
+
anchorRect,
|
|
73
|
+
getAnchorRect,
|
|
74
|
+
maxWidth,
|
|
75
|
+
accept,
|
|
76
|
+
onAltChange,
|
|
77
|
+
onAlignChange,
|
|
78
|
+
onWidthChange,
|
|
79
|
+
onWidthReset,
|
|
80
|
+
onReplace,
|
|
81
|
+
onClose,
|
|
82
|
+
}: RichTextAttachmentConfigProps) {
|
|
83
|
+
// #274: mounted only while open — register as a floating surface so
|
|
84
|
+
// Modal/Drawer/Lightbox yield Escape to us (our own Escape handling closes
|
|
85
|
+
// us; without registration one press would close the host too).
|
|
86
|
+
useFloatingSurface(true);
|
|
87
|
+
const t = useTranslation();
|
|
88
|
+
const isImage = attachmentIsImage(block);
|
|
89
|
+
const popRef = useRef<HTMLDivElement | null>(null);
|
|
90
|
+
const fileRef = useRef<HTMLInputElement | null>(null);
|
|
91
|
+
const seededAlt = block.alt ?? block.name ?? '';
|
|
92
|
+
const [alt, setAlt] = useState(seededAlt);
|
|
93
|
+
const sliderMax = Math.max(MIN_W + 1, Math.round(maxWidth));
|
|
94
|
+
const [width, setWidth] = useState<number>(
|
|
95
|
+
Math.max(MIN_W, Math.min(block.width ?? sliderMax, sliderMax)),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
// Commit alt only when it differs from what was shown on open, so a focus→blur
|
|
99
|
+
// with no edit doesn't write the seeded `block.name` fallback into `alt`.
|
|
100
|
+
const commitAlt = useCallback(() => {
|
|
101
|
+
if (alt !== seededAlt) onAltChange(alt);
|
|
102
|
+
}, [alt, seededAlt, onAltChange]);
|
|
103
|
+
|
|
104
|
+
const { refs, floatingStyles } = useAnchoredFloating(anchorRect, getAnchorRect, { offset: 6 });
|
|
105
|
+
const setRefs = useCallback(
|
|
106
|
+
(node: HTMLDivElement | null) => {
|
|
107
|
+
popRef.current = node;
|
|
108
|
+
refs.setFloating(node);
|
|
109
|
+
},
|
|
110
|
+
[refs],
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// Dismiss on a pointerdown outside the popover.
|
|
114
|
+
const onCloseRef = useRef(onClose);
|
|
115
|
+
onCloseRef.current = onClose;
|
|
116
|
+
useDismissOnOutsidePointerDown(popRef, onClose);
|
|
117
|
+
|
|
118
|
+
// #274: Escape from anywhere — see RichTextLinkEditor for the rationale
|
|
119
|
+
// (focus trap can hold focus outside this body-portaled popover).
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
const onKeyDown = (e: globalThis.KeyboardEvent) => {
|
|
122
|
+
if (e.key !== 'Escape') return;
|
|
123
|
+
e.preventDefault();
|
|
124
|
+
overlayStack.consumeEscape(e);
|
|
125
|
+
onCloseRef.current();
|
|
126
|
+
};
|
|
127
|
+
document.addEventListener('keydown', onKeyDown, true);
|
|
128
|
+
return () => document.removeEventListener('keydown', onKeyDown, true);
|
|
129
|
+
}, []);
|
|
130
|
+
|
|
131
|
+
// Move focus into the popover on open so the Escape handler (on the container)
|
|
132
|
+
// works without the trigger keeping focus — mirrors RichTextLinkEditor focusing
|
|
133
|
+
// its input. Prefer the first focusable control (alt input, else first button).
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
const root = popRef.current;
|
|
136
|
+
if (!root) return;
|
|
137
|
+
const focusable = root.querySelector<HTMLElement>('input, button, [tabindex]');
|
|
138
|
+
focusable?.focus();
|
|
139
|
+
}, []);
|
|
140
|
+
|
|
141
|
+
const href = safeHref(block.src ?? '');
|
|
142
|
+
const curAlign = block.align ?? 'left';
|
|
143
|
+
// Slider is single-thumb here, so its value is a number; guard a tuple defensively.
|
|
144
|
+
const sliderNum = (v: number | [number, number]): number => (Array.isArray(v) ? v[0] : v);
|
|
145
|
+
|
|
146
|
+
return createPortal(
|
|
147
|
+
<div
|
|
148
|
+
ref={setRefs}
|
|
149
|
+
className={styles.configPopover}
|
|
150
|
+
style={floatingStyles}
|
|
151
|
+
role="group"
|
|
152
|
+
data-rte-overlay=""
|
|
153
|
+
aria-label={t('richTextEditor.attachmentConfigure')}
|
|
154
|
+
onKeyDown={(e) => {
|
|
155
|
+
if (e.key === 'Escape') {
|
|
156
|
+
e.preventDefault();
|
|
157
|
+
e.stopPropagation();
|
|
158
|
+
onClose();
|
|
159
|
+
}
|
|
160
|
+
}}
|
|
161
|
+
>
|
|
162
|
+
<Stack gap="sm">
|
|
163
|
+
{isImage && (
|
|
164
|
+
<>
|
|
165
|
+
<label className={styles.configRow}>
|
|
166
|
+
<span className={styles.configLabel}>{t('richTextEditor.attachmentAlt')}</span>
|
|
167
|
+
<Input
|
|
168
|
+
size="sm"
|
|
169
|
+
value={alt}
|
|
170
|
+
aria-label={t('richTextEditor.attachmentAlt')}
|
|
171
|
+
onChange={(e) => setAlt(e.target.value)}
|
|
172
|
+
onBlur={commitAlt}
|
|
173
|
+
onKeyDown={(e) => {
|
|
174
|
+
if (e.key === 'Enter') {
|
|
175
|
+
e.preventDefault();
|
|
176
|
+
commitAlt();
|
|
177
|
+
}
|
|
178
|
+
}}
|
|
179
|
+
/>
|
|
180
|
+
</label>
|
|
181
|
+
<Cluster gap="xs">
|
|
182
|
+
<span className={styles.configLabel}>{t('richTextEditor.attachmentAlign')}</span>
|
|
183
|
+
{ALIGNS.map((a) => (
|
|
184
|
+
<Button
|
|
185
|
+
key={a}
|
|
186
|
+
size="sm"
|
|
187
|
+
iconOnly
|
|
188
|
+
variant={curAlign === a ? 'secondary' : 'ghost'}
|
|
189
|
+
aria-pressed={curAlign === a}
|
|
190
|
+
aria-label={t(ALIGN_LABEL_KEY[a])}
|
|
191
|
+
onClick={() => onAlignChange(a)}
|
|
192
|
+
>
|
|
193
|
+
{ALIGN_GLYPH[a]}
|
|
194
|
+
</Button>
|
|
195
|
+
))}
|
|
196
|
+
</Cluster>
|
|
197
|
+
{/* Width is offered only for an image that actually renders as a
|
|
198
|
+
preview — i.e. one with a safe, fetchable src (`href`). An uploaded
|
|
199
|
+
image carries an object-URL src that `safeHref` blocks, so it renders
|
|
200
|
+
as a download chip (RichTextAttachment uses the same isImage && href
|
|
201
|
+
test); resizing such a chip does nothing, so the slider is hidden.
|
|
202
|
+
Gating on the src (not on `block.width`) keeps it available after a
|
|
203
|
+
Reset and for embeds that arrived without an explicit width attr. */}
|
|
204
|
+
{href && (
|
|
205
|
+
<Cluster gap="xs">
|
|
206
|
+
<span className={styles.configLabel}>{t('richTextEditor.attachmentWidth')}</span>
|
|
207
|
+
<Slider
|
|
208
|
+
value={width}
|
|
209
|
+
min={MIN_W}
|
|
210
|
+
max={sliderMax}
|
|
211
|
+
step={1}
|
|
212
|
+
aria-label={t('richTextEditor.attachmentWidth')}
|
|
213
|
+
onChange={(v) => {
|
|
214
|
+
const w = sliderNum(v);
|
|
215
|
+
setWidth(w); // drive the thumb
|
|
216
|
+
onWidthChange(w); // live: resize the image on every move
|
|
217
|
+
}}
|
|
218
|
+
onChangeEnd={(v) => onWidthChange(sliderNum(v))} // seal the final value
|
|
219
|
+
/>
|
|
220
|
+
<Button
|
|
221
|
+
size="sm"
|
|
222
|
+
variant="ghost"
|
|
223
|
+
onClick={() => {
|
|
224
|
+
onWidthReset();
|
|
225
|
+
setWidth(sliderMax); // re-seed the thumb to "natural/full"
|
|
226
|
+
}}
|
|
227
|
+
>
|
|
228
|
+
{t('richTextEditor.attachmentWidthReset')}
|
|
229
|
+
</Button>
|
|
230
|
+
</Cluster>
|
|
231
|
+
)}
|
|
232
|
+
</>
|
|
233
|
+
)}
|
|
234
|
+
<Cluster gap="xs">
|
|
235
|
+
<input
|
|
236
|
+
ref={fileRef}
|
|
237
|
+
type="file"
|
|
238
|
+
accept={accept}
|
|
239
|
+
style={{ display: 'none' }}
|
|
240
|
+
onChange={(e) => {
|
|
241
|
+
const f = e.target.files?.[0];
|
|
242
|
+
if (f) onReplace(f);
|
|
243
|
+
e.target.value = '';
|
|
244
|
+
}}
|
|
245
|
+
/>
|
|
246
|
+
<Button size="sm" variant="ghost" onClick={() => fileRef.current?.click()}>
|
|
247
|
+
{t('richTextEditor.attachmentReplace')}
|
|
248
|
+
</Button>
|
|
249
|
+
{href && (
|
|
250
|
+
<a className={styles.configLink} href={href} target="_blank" rel="noopener noreferrer">
|
|
251
|
+
{t('richTextEditor.attachmentOpen')}
|
|
252
|
+
</a>
|
|
253
|
+
)}
|
|
254
|
+
{href && (
|
|
255
|
+
<a className={styles.configLink} href={href} download rel="noopener noreferrer">
|
|
256
|
+
{t('richTextEditor.attachmentDownload')}
|
|
257
|
+
</a>
|
|
258
|
+
)}
|
|
259
|
+
</Cluster>
|
|
260
|
+
</Stack>
|
|
261
|
+
</div>,
|
|
262
|
+
document.body,
|
|
263
|
+
);
|
|
264
|
+
}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
// RichTextBlockControls.tsx — the per-block gutter overlay. Absolutely positioned
|
|
2
|
+
// inside the editor shell (position: relative), aligned to the active block's box.
|
|
3
|
+
// Lives OUTSIDE the contentEditable so it is never editable content.
|
|
4
|
+
import { memo, useCallback, useEffect, useMemo, useRef, type RefObject } from 'react';
|
|
5
|
+
import {
|
|
6
|
+
DndContext,
|
|
7
|
+
PointerSensor,
|
|
8
|
+
useDraggable,
|
|
9
|
+
useSensor,
|
|
10
|
+
useSensors,
|
|
11
|
+
type DragEndEvent,
|
|
12
|
+
type DragMoveEvent,
|
|
13
|
+
type DragStartEvent,
|
|
14
|
+
} from '@dnd-kit/core';
|
|
15
|
+
import { Button } from '../Button';
|
|
16
|
+
import { useTranslation } from '../../i18n';
|
|
17
|
+
import { RichTextBlockMenu, type BlockAction } from './RichTextBlockMenu';
|
|
18
|
+
import type { BlockChoice } from './RichTextToolbar';
|
|
19
|
+
import type { BlockType } from '../RichText/engine/model';
|
|
20
|
+
import { PlusIcon } from './icons';
|
|
21
|
+
import { preventSelectionLoss } from './preventSelectionLoss';
|
|
22
|
+
import { computeReflow, type BlockRect, type UnitRange } from './blockReflow';
|
|
23
|
+
import { gapIndexFromY } from './blockDrop';
|
|
24
|
+
import { useShellRelativeRect, useDraggingReporter } from './useOverlayRect';
|
|
25
|
+
import { tidy } from '../_internal/dragAnnouncements';
|
|
26
|
+
import styles from './RichTextEditor.module.scss';
|
|
27
|
+
|
|
28
|
+
export interface RichTextBlockControlsProps {
|
|
29
|
+
/** The editor shell element ref — used to locate block boxes + anchor overlays. */
|
|
30
|
+
rootRef: RefObject<HTMLElement | null>;
|
|
31
|
+
/** Block currently hovered or holding the caret; null hides the gutter. */
|
|
32
|
+
activeBlockId: string | null;
|
|
33
|
+
/**
|
|
34
|
+
* A signature of the current block order (e.g. the ids joined). The gutter's
|
|
35
|
+
* vertical position is measured from the active block's DOM box; the active
|
|
36
|
+
* block keeps its id across a reorder, so without an order-derived dependency
|
|
37
|
+
* the measurement would go stale and the controls would linger at the block's
|
|
38
|
+
* OLD row after a drop / insert / delete. Pass an order-derived string so the
|
|
39
|
+
* gutter re-measures whenever the block layout shifts.
|
|
40
|
+
*/
|
|
41
|
+
blockOrderKey?: string;
|
|
42
|
+
/** Type of the active block (gates the menu's "Turn into" — hidden for voids). */
|
|
43
|
+
activeBlockType?: BlockType;
|
|
44
|
+
/** Controlled open state of the block menu. */
|
|
45
|
+
menuOpen: boolean;
|
|
46
|
+
onMenuOpenChange: (open: boolean) => void;
|
|
47
|
+
onInsertBelow: (blockId: string) => void;
|
|
48
|
+
onAction: (blockId: string, action: BlockAction) => void;
|
|
49
|
+
onTurnInto: (blockId: string, choice: BlockChoice) => void;
|
|
50
|
+
/**
|
|
51
|
+
* Open the block's configuration affordance (e.g. attachment settings). When
|
|
52
|
+
* set, a "Configure" item is added to the ⠿ block menu and fires with the
|
|
53
|
+
* active block id. Omit for blocks that have nothing to configure.
|
|
54
|
+
*/
|
|
55
|
+
onConfigure?: (blockId: string) => void;
|
|
56
|
+
/**
|
|
57
|
+
* Set a whole-block color from the ⠿ menu's Color submenu. When set, a Color
|
|
58
|
+
* submenu is added to the menu and fires with the active block id, the color
|
|
59
|
+
* type (`textColor`/`bgColor`), and the palette key (`null` clears). Omit to
|
|
60
|
+
* hide the submenu.
|
|
61
|
+
*/
|
|
62
|
+
onColor?: (blockId: string, type: 'textColor' | 'bgColor', key: string | null) => void;
|
|
63
|
+
/**
|
|
64
|
+
* Reorder the active block to land at `targetIndex` — a "gap" (0..N) in the
|
|
65
|
+
* CURRENT block array. Fired when a block drag is dropped. Wired by the editor
|
|
66
|
+
* to the subtree-aware `moveBlockUnitToIndex` engine transform.
|
|
67
|
+
*/
|
|
68
|
+
onReorder: (blockId: string, targetIndex: number) => void;
|
|
69
|
+
/**
|
|
70
|
+
* Reports block-drag lifecycle so the editor can suppress hover-driven active-block
|
|
71
|
+
* changes while a drag is in progress (mirrors how `menuOpen` is mirrored into a
|
|
72
|
+
* ref). Called `true` on drag start, `false` on drag end/cancel.
|
|
73
|
+
*/
|
|
74
|
+
onDraggingChange?: (dragging: boolean) => void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Stable draggable id — there is only ever one active gutter handle at a time.
|
|
78
|
+
const GUTTER_DRAGGABLE_ID = 'rte-block-gutter';
|
|
79
|
+
|
|
80
|
+
/** Strip all transient drag styles a reflow applied. */
|
|
81
|
+
function clearReflow(
|
|
82
|
+
snap: { els: HTMLElement[]; unit: UnitRange } | null,
|
|
83
|
+
shell: HTMLElement | null,
|
|
84
|
+
): void {
|
|
85
|
+
if (snap) {
|
|
86
|
+
for (const el of snap.els) el.style.transform = '';
|
|
87
|
+
for (let i = snap.unit.u0; i <= snap.unit.u1; i += 1) {
|
|
88
|
+
snap.els[i]?.classList.remove(styles.blockLifted);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
shell?.classList.remove(styles.reflowing);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The gutter strip, wired as the dnd-kit drag handle (the WHOLE strip — + / ⠿
|
|
96
|
+
* and the space around them). A sub-4px press still reaches the buttons (insert /
|
|
97
|
+
* open menu); a press-drag past the 4px activation lifts the row.
|
|
98
|
+
* Spreads only `listeners` — never dnd-kit's `attributes` — so the gutter stays out
|
|
99
|
+
* of the tab order (keyboard reorder is the editor's ⌘/Ctrl+⇧↑/↓ shortcuts).
|
|
100
|
+
*/
|
|
101
|
+
function DraggableGutter({
|
|
102
|
+
top,
|
|
103
|
+
height,
|
|
104
|
+
innerRef,
|
|
105
|
+
children,
|
|
106
|
+
}: {
|
|
107
|
+
top: number;
|
|
108
|
+
height: number | null;
|
|
109
|
+
/** Captures the gutter DOM node so the drag can translate it with the lifted row. */
|
|
110
|
+
innerRef: RefObject<HTMLDivElement | null>;
|
|
111
|
+
children: React.ReactNode;
|
|
112
|
+
}) {
|
|
113
|
+
const { setNodeRef, listeners } = useDraggable({ id: GUTTER_DRAGGABLE_ID });
|
|
114
|
+
const setRefs = useCallback(
|
|
115
|
+
(node: HTMLDivElement | null) => {
|
|
116
|
+
setNodeRef(node);
|
|
117
|
+
innerRef.current = node;
|
|
118
|
+
},
|
|
119
|
+
[setNodeRef, innerRef],
|
|
120
|
+
);
|
|
121
|
+
return (
|
|
122
|
+
<div
|
|
123
|
+
ref={setRefs}
|
|
124
|
+
className={styles.gutter}
|
|
125
|
+
style={{ top, height: height ?? undefined }}
|
|
126
|
+
contentEditable={false}
|
|
127
|
+
{...listeners}
|
|
128
|
+
>
|
|
129
|
+
{children}
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Internal: the gutter overlay for the active block. Measures the block element's
|
|
136
|
+
* vertical offset within the shell and renders the `+` insert button + the block
|
|
137
|
+
* menu there. Renders nothing when there is no active block. The whole gutter is
|
|
138
|
+
* the drag handle: dragging it reorders the active block via an in-place reflow,
|
|
139
|
+
* while a plain click on +/⠿ still triggers that button. Block configuration
|
|
140
|
+
* (e.g. attachment settings) lives in the ⠿ menu's "Configure" item, not a
|
|
141
|
+
* separate gutter button.
|
|
142
|
+
*/
|
|
143
|
+
export const RichTextBlockControls = memo(function RichTextBlockControls({
|
|
144
|
+
rootRef,
|
|
145
|
+
activeBlockId,
|
|
146
|
+
blockOrderKey,
|
|
147
|
+
activeBlockType,
|
|
148
|
+
menuOpen,
|
|
149
|
+
onMenuOpenChange,
|
|
150
|
+
onInsertBelow,
|
|
151
|
+
onAction,
|
|
152
|
+
onTurnInto,
|
|
153
|
+
onConfigure,
|
|
154
|
+
onColor,
|
|
155
|
+
onReorder,
|
|
156
|
+
onDraggingChange,
|
|
157
|
+
}: RichTextBlockControlsProps) {
|
|
158
|
+
const t = useTranslation();
|
|
159
|
+
// Drag snapshot, captured once at drag start (measuring transformed DOM would feed
|
|
160
|
+
// back on itself). null when not dragging.
|
|
161
|
+
const dragRef = useRef<{
|
|
162
|
+
rects: BlockRect[];
|
|
163
|
+
els: HTMLElement[];
|
|
164
|
+
unit: UnitRange;
|
|
165
|
+
parentIdx: number[];
|
|
166
|
+
} | null>(null);
|
|
167
|
+
// Block id captured at drag start — reorder by this, not the live activeBlockId.
|
|
168
|
+
const draggedIdRef = useRef<string | null>(null);
|
|
169
|
+
// The gutter DOM node, so the drag can translate it in lockstep with the lifted row.
|
|
170
|
+
const gutterElRef = useRef<HTMLDivElement | null>(null);
|
|
171
|
+
// The dragged block's own text, captured at drag start so the announcement can
|
|
172
|
+
// name it after the reflow has been cleared.
|
|
173
|
+
const dragLabelRef = useRef('');
|
|
174
|
+
|
|
175
|
+
// Reports block-drag lifecycle + fires (false) on a mid-drag unmount so nothing
|
|
176
|
+
// leaks (dnd-kit fires neither end nor cancel when the controls unmount).
|
|
177
|
+
const reportDragging = useDraggingReporter(onDraggingChange);
|
|
178
|
+
|
|
179
|
+
// If the controls unmount mid-drag (blockControls turned off, or the editor
|
|
180
|
+
// unmounts), clear any applied reflow transforms. The dragging-state report is
|
|
181
|
+
// handled by useDraggingReporter; this effect owns the DOM-style cleanup. Order:
|
|
182
|
+
// this effect is registered AFTER the reporter, so its cleanup runs FIRST —
|
|
183
|
+
// clearReflow then onDraggingChange(false), matching the original order.
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
return () => {
|
|
186
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- clears the reflow on the root as it is at unmount
|
|
187
|
+
clearReflow(dragRef.current, rootRef.current);
|
|
188
|
+
dragRef.current = null;
|
|
189
|
+
};
|
|
190
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- unmount-only cleanup
|
|
191
|
+
}, []);
|
|
192
|
+
|
|
193
|
+
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 4 } }));
|
|
194
|
+
|
|
195
|
+
// Measure the active block's box relative to the shell. getEl folds in
|
|
196
|
+
// activeBlockId (null → no target); blockOrderKey + menuOpen drive re-measure via
|
|
197
|
+
// `key` — a reorder/insert/delete keeps the active block's id but moves its row, so
|
|
198
|
+
// an order-derived key re-measures rather than leaving the gutter stranded.
|
|
199
|
+
const blockEl = useCallback(
|
|
200
|
+
() =>
|
|
201
|
+
activeBlockId
|
|
202
|
+
? (rootRef.current?.querySelector<HTMLElement>(
|
|
203
|
+
`[data-block-id="${CSS.escape(activeBlockId)}"]`,
|
|
204
|
+
) ?? null)
|
|
205
|
+
: null,
|
|
206
|
+
[rootRef, activeBlockId],
|
|
207
|
+
);
|
|
208
|
+
const rect = useShellRelativeRect(rootRef, blockEl, `${blockOrderKey ?? ''}|${menuOpen}`);
|
|
209
|
+
const top = rect?.top ?? null;
|
|
210
|
+
const height = rect?.height ?? null;
|
|
211
|
+
|
|
212
|
+
const handleDragStart = (_event: DragStartEvent) => {
|
|
213
|
+
const root = rootRef.current;
|
|
214
|
+
if (!activeBlockId || !root) return;
|
|
215
|
+
|
|
216
|
+
const shellTop = root.getBoundingClientRect().top;
|
|
217
|
+
const nodes = Array.from(root.querySelectorAll<HTMLElement>('[data-block-id]'));
|
|
218
|
+
const rects: BlockRect[] = nodes.map((el) => {
|
|
219
|
+
const b = el.getBoundingClientRect();
|
|
220
|
+
return { top: b.top - shellTop, height: b.height };
|
|
221
|
+
});
|
|
222
|
+
// The dragged unit = the active block element PLUS its nested descendant blocks
|
|
223
|
+
// (renderDoc nests deeper list items inside the parent <li>) — a contiguous run.
|
|
224
|
+
const activeEl = nodes.find((el) => el.getAttribute('data-block-id') === activeBlockId);
|
|
225
|
+
const unitIds = new Set<string>([activeBlockId]);
|
|
226
|
+
activeEl?.querySelectorAll<HTMLElement>('[data-block-id]').forEach((d) => {
|
|
227
|
+
const id = d.getAttribute('data-block-id');
|
|
228
|
+
if (id) unitIds.add(id);
|
|
229
|
+
});
|
|
230
|
+
const idxs: number[] = [];
|
|
231
|
+
nodes.forEach((el, i) => {
|
|
232
|
+
const id = el.getAttribute('data-block-id');
|
|
233
|
+
if (id && unitIds.has(id)) idxs.push(i);
|
|
234
|
+
});
|
|
235
|
+
if (idxs.length === 0) return;
|
|
236
|
+
const unit: UnitRange = { u0: idxs[0], u1: idxs[idxs.length - 1] };
|
|
237
|
+
|
|
238
|
+
// For each box, the index of its nearest [data-block-id] ANCESTOR (or -1). CSS
|
|
239
|
+
// transforms inherit, so a nested box's own translate is offset against its
|
|
240
|
+
// ancestor's in handleDragMove to land at exactly the desired shift.
|
|
241
|
+
const indexOf = new Map<HTMLElement, number>(nodes.map((el, i) => [el, i]));
|
|
242
|
+
const parentIdx = nodes.map((el) => {
|
|
243
|
+
const anc = el.parentElement?.closest<HTMLElement>('[data-block-id]') ?? null;
|
|
244
|
+
return anc && indexOf.has(anc) ? (indexOf.get(anc) as number) : -1;
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
draggedIdRef.current = activeBlockId;
|
|
248
|
+
dragLabelRef.current = tidy(nodes[unit.u0].textContent ?? '');
|
|
249
|
+
onMenuOpenChange(false); // a drag should never leave the block menu open
|
|
250
|
+
reportDragging(true);
|
|
251
|
+
dragRef.current = { rects, els: nodes, unit, parentIdx };
|
|
252
|
+
root.classList.add(styles.reflowing);
|
|
253
|
+
nodes[unit.u0].classList.add(styles.blockLifted);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const handleDragMove = (event: DragMoveEvent) => {
|
|
257
|
+
const snap = dragRef.current;
|
|
258
|
+
const root = rootRef.current;
|
|
259
|
+
if (!snap || !root) return;
|
|
260
|
+
const activator = event.activatorEvent as PointerEvent;
|
|
261
|
+
const initialY = typeof activator?.clientY === 'number' ? activator.clientY : null;
|
|
262
|
+
if (initialY == null) return;
|
|
263
|
+
const pointerY = initialY + event.delta.y - root.getBoundingClientRect().top;
|
|
264
|
+
const reflow = computeReflow(snap.rects, snap.unit, event.delta.y, pointerY);
|
|
265
|
+
// Transforms inherit: set each box's OWN transform to the desired shift minus its
|
|
266
|
+
// ancestor's desired shift, so inheritance composes to exactly shifts[i].
|
|
267
|
+
for (let i = 0; i < snap.els.length; i += 1) {
|
|
268
|
+
const pid = snap.parentIdx[i];
|
|
269
|
+
const own = reflow.shifts[i] - (pid >= 0 ? reflow.shifts[pid] : 0);
|
|
270
|
+
snap.els[i].style.transform = own ? `translateY(${own}px)` : '';
|
|
271
|
+
}
|
|
272
|
+
// Carry the gutter (+ / ⠿) along with the lifted row by the same clamped
|
|
273
|
+
// travel, so the controls feel attached to the row being dragged. The gutter is
|
|
274
|
+
// not nested, so it shifts by the unit's net movement (liftDy) directly.
|
|
275
|
+
if (gutterElRef.current) {
|
|
276
|
+
gutterElRef.current.style.transform = reflow.liftDy ? `translateY(${reflow.liftDy}px)` : '';
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const endDrag = () => {
|
|
281
|
+
clearReflow(dragRef.current, rootRef.current);
|
|
282
|
+
if (gutterElRef.current) gutterElRef.current.style.transform = '';
|
|
283
|
+
dragRef.current = null;
|
|
284
|
+
draggedIdRef.current = null;
|
|
285
|
+
reportDragging(false);
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const handleDragEnd = (event: DragEndEvent) => {
|
|
289
|
+
const snap = dragRef.current;
|
|
290
|
+
const root = rootRef.current;
|
|
291
|
+
const id = draggedIdRef.current;
|
|
292
|
+
let gap: number | null = null;
|
|
293
|
+
if (snap && root) {
|
|
294
|
+
const activator = event.activatorEvent as PointerEvent;
|
|
295
|
+
const initialY = typeof activator?.clientY === 'number' ? activator.clientY : null;
|
|
296
|
+
if (initialY != null) {
|
|
297
|
+
const pointerY = initialY + event.delta.y - root.getBoundingClientRect().top;
|
|
298
|
+
gap = gapIndexFromY(snap.rects, pointerY);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
endDrag(); // clear transforms BEFORE the reorder re-render so no inline styles linger
|
|
302
|
+
if (id != null && gap != null) onReorder(id, gap);
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
const handleDragCancel = () => {
|
|
306
|
+
endDrag();
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
// Localized announcements (Hard rule 9, #390). This context deliberately does
|
|
310
|
+
// NOT go through `useDragAccessibility`: it registers no droppables (the drop
|
|
311
|
+
// slot is computed from the pointer against the document flow), so `over` is
|
|
312
|
+
// always null and the shared over-driven messages would all be wrong here.
|
|
313
|
+
// Same `drag.*` copy, three of the five callbacks.
|
|
314
|
+
const accessibility = useMemo(() => {
|
|
315
|
+
const item = () => dragLabelRef.current || t('drag.unnamed');
|
|
316
|
+
return {
|
|
317
|
+
announcements: {
|
|
318
|
+
onDragStart: () => t('drag.pickedUp', { item: item() }),
|
|
319
|
+
// Silent: with no droppables, dnd-kit's per-move announcement would be
|
|
320
|
+
// a permanent, false "not over a drop target".
|
|
321
|
+
onDragOver: () => undefined,
|
|
322
|
+
onDragEnd: () => t('drag.moved', { item: item() }),
|
|
323
|
+
onDragCancel: () => t('drag.cancelled', { item: item() }),
|
|
324
|
+
},
|
|
325
|
+
screenReaderInstructions: { draggable: t('drag.instructions') },
|
|
326
|
+
};
|
|
327
|
+
}, [t]);
|
|
328
|
+
|
|
329
|
+
if (!activeBlockId || top == null) return null;
|
|
330
|
+
|
|
331
|
+
return (
|
|
332
|
+
<DndContext
|
|
333
|
+
accessibility={accessibility}
|
|
334
|
+
sensors={sensors}
|
|
335
|
+
onDragStart={handleDragStart}
|
|
336
|
+
onDragMove={handleDragMove}
|
|
337
|
+
onDragEnd={handleDragEnd}
|
|
338
|
+
onDragCancel={handleDragCancel}
|
|
339
|
+
>
|
|
340
|
+
<DraggableGutter top={top} height={height} innerRef={gutterElRef}>
|
|
341
|
+
<Button
|
|
342
|
+
size="sm"
|
|
343
|
+
variant="ghost"
|
|
344
|
+
iconOnly
|
|
345
|
+
tabIndex={-1}
|
|
346
|
+
aria-label={t('richTextEditor.blockInsert')}
|
|
347
|
+
className={styles.gutterButton}
|
|
348
|
+
onMouseDown={preventSelectionLoss}
|
|
349
|
+
onClick={() => onInsertBelow(activeBlockId)}
|
|
350
|
+
>
|
|
351
|
+
<PlusIcon />
|
|
352
|
+
</Button>
|
|
353
|
+
<RichTextBlockMenu
|
|
354
|
+
open={menuOpen}
|
|
355
|
+
onOpenChange={onMenuOpenChange}
|
|
356
|
+
onAction={(a) => onAction(activeBlockId, a)}
|
|
357
|
+
onTurnInto={(c) => onTurnInto(activeBlockId, c)}
|
|
358
|
+
blockType={activeBlockType}
|
|
359
|
+
onConfigure={onConfigure ? () => onConfigure(activeBlockId) : undefined}
|
|
360
|
+
onColor={onColor ? (type, key) => onColor(activeBlockId, type, key) : undefined}
|
|
361
|
+
/>
|
|
362
|
+
</DraggableGutter>
|
|
363
|
+
</DndContext>
|
|
364
|
+
);
|
|
365
|
+
});
|