@eocrm/design-system 0.0.0-stage → 0.6.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI-PRIMER.md +341 -0
- package/LICENSE +202 -0
- package/README.md +266 -2
- package/docs/components/Accordion.md +114 -0
- package/docs/components/AgentAvatar.md +58 -0
- package/docs/components/Alert.md +81 -0
- package/docs/components/AppLayout.md +70 -0
- package/docs/components/Avatar.md +49 -0
- package/docs/components/AvatarGroup.md +47 -0
- package/docs/components/Badge.md +60 -0
- package/docs/components/Banner.md +89 -0
- package/docs/components/BrandIcon.md +32 -0
- package/docs/components/Breadcrumb.md +72 -0
- package/docs/components/Button.md +107 -0
- package/docs/components/ButtonGroup.md +78 -0
- package/docs/components/Calendar.md +158 -0
- package/docs/components/Card.md +165 -0
- package/docs/components/CatalogPicker.md +83 -0
- package/docs/components/Chart.md +114 -0
- package/docs/components/ChatBubble.md +55 -0
- package/docs/components/ChatLauncher.md +97 -0
- package/docs/components/Checkbox.md +55 -0
- package/docs/components/CircularProgress.md +53 -0
- package/docs/components/Cluster.md +96 -0
- package/docs/components/Code.md +35 -0
- package/docs/components/CodeBlock.md +67 -0
- package/docs/components/ColorPicker.md +115 -0
- package/docs/components/ConfirmationPopover.md +70 -0
- package/docs/components/Constrain.md +39 -0
- package/docs/components/CurrencySelect.md +57 -0
- package/docs/components/CursorPagination.md +43 -0
- package/docs/components/DashboardCanvas.md +79 -0
- package/docs/components/DashboardWidget.md +131 -0
- package/docs/components/DataTable.md +88 -0
- package/docs/components/DatePicker.md +68 -0
- package/docs/components/DateRangePicker.md +71 -0
- package/docs/components/DateStrip.md +56 -0
- package/docs/components/DefinitionList.md +82 -0
- package/docs/components/Divider.md +57 -0
- package/docs/components/Dot.md +26 -0
- package/docs/components/Drawer.md +94 -0
- package/docs/components/DropdownMenu.md +299 -0
- package/docs/components/EmojiPicker.md +84 -0
- package/docs/components/EmptyState.md +55 -0
- package/docs/components/EntityChip.md +102 -0
- package/docs/components/ErrorState.md +72 -0
- package/docs/components/Field.md +91 -0
- package/docs/components/FileUpload.md +109 -0
- package/docs/components/FilterChip.md +88 -0
- package/docs/components/FlowCanvas.md +108 -0
- package/docs/components/FormRow.md +31 -0
- package/docs/components/FormSection.md +37 -0
- package/docs/components/Grid.md +103 -0
- package/docs/components/Highlight.md +75 -0
- package/docs/components/HighlightedText.md +50 -0
- package/docs/components/IconPicker.md +134 -0
- package/docs/components/IconTile.md +30 -0
- package/docs/components/Image.md +84 -0
- package/docs/components/ImageCrop.md +163 -0
- package/docs/components/Indent.md +31 -0
- package/docs/components/InlineDatePicker.md +58 -0
- package/docs/components/InlineDateRangePicker.md +57 -0
- package/docs/components/Input.md +54 -0
- package/docs/components/Kanban.md +122 -0
- package/docs/components/Kbd.md +41 -0
- package/docs/components/Lightbox.md +105 -0
- package/docs/components/Link.md +65 -0
- package/docs/components/LinkCard.md +41 -0
- package/docs/components/LiquidEditor.md +84 -0
- package/docs/components/List.md +68 -0
- package/docs/components/LiveRegion.md +29 -0
- package/docs/components/LocaleProvider.md +25 -0
- package/docs/components/Logo.md +41 -0
- package/docs/components/Masonry.md +48 -0
- package/docs/components/MediaTile.md +95 -0
- package/docs/components/Modal.md +107 -0
- package/docs/components/MoneyInput.md +62 -0
- package/docs/components/OptionsPicker.md +123 -0
- package/docs/components/OtpInput.md +65 -0
- package/docs/components/Page.md +35 -0
- package/docs/components/PageHeader.md +133 -0
- package/docs/components/Pagination.md +44 -0
- package/docs/components/Palette.md +32 -0
- package/docs/components/PasswordInput.md +45 -0
- package/docs/components/PasswordStrengthMeter.md +27 -0
- package/docs/components/PersonDisplay.md +153 -0
- package/docs/components/PhoneInput.md +54 -0
- package/docs/components/PillMenu.md +91 -0
- package/docs/components/Popover.md +127 -0
- package/docs/components/Progress.md +56 -0
- package/docs/components/QrCode.md +34 -0
- package/docs/components/Radio.md +37 -0
- package/docs/components/RadioGroup.md +56 -0
- package/docs/components/Rail.md +191 -0
- package/docs/components/RelativeDateInput.md +114 -0
- package/docs/components/RichText.md +44 -0
- package/docs/components/RichTextEditor.md +112 -0
- package/docs/components/Screen.md +37 -0
- package/docs/components/ScrollArea.md +39 -0
- package/docs/components/Select.md +131 -0
- package/docs/components/SettingRow.md +98 -0
- package/docs/components/Skeleton.md +68 -0
- package/docs/components/Slider.md +92 -0
- package/docs/components/SlotGrid.md +55 -0
- package/docs/components/SocialButton.md +31 -0
- package/docs/components/Sortable.md +127 -0
- package/docs/components/SortableGroup.md +52 -0
- package/docs/components/Sparkline.md +51 -0
- package/docs/components/Split.md +76 -0
- package/docs/components/Stack.md +59 -0
- package/docs/components/StagePath.md +66 -0
- package/docs/components/StatGroup.md +61 -0
- package/docs/components/StatTile.md +58 -0
- package/docs/components/Sticky.md +69 -0
- package/docs/components/Switch.md +89 -0
- package/docs/components/Table.md +184 -0
- package/docs/components/TableOfContents.md +76 -0
- package/docs/components/Tabs.md +94 -0
- package/docs/components/Text.md +63 -0
- package/docs/components/Textarea.md +59 -0
- package/docs/components/Thread.md +52 -0
- package/docs/components/TimeField.md +70 -0
- package/docs/components/Timeline.md +57 -0
- package/docs/components/Title.md +54 -0
- package/docs/components/ToastViewport.md +61 -0
- package/docs/components/Tooltip.md +63 -0
- package/docs/components/TopBar.md +214 -0
- package/docs/components/Tour.md +85 -0
- package/docs/components/TreeView.md +113 -0
- package/docs/components/VisuallyHidden.md +43 -0
- package/docs/components/WidgetPreview.md +54 -0
- package/docs/components/useBelowBreakpoint.md +11 -0
- package/docs/components/useMonth.md +18 -0
- package/docs/setup.md +51 -0
- package/docs/theming.md +95 -0
- package/docs/tokens.md +123 -0
- package/docs/transient-state.md +56 -0
- package/package.json +86 -4
- package/src/_meta/manifest.ts +293 -0
- package/src/app/AppProvider.tsx +78 -0
- package/src/app/index.ts +3 -0
- package/src/app/themeTokens.ts +95 -0
- package/src/calendar/dateMath.ts +114 -0
- package/src/calendar/formatters.ts +75 -0
- package/src/calendar/index.ts +39 -0
- package/src/calendar/types.ts +36 -0
- package/src/calendar/useAgenda.ts +70 -0
- package/src/calendar/useDay.ts +51 -0
- package/src/calendar/useMonth.ts +82 -0
- package/src/calendar/useWeek.ts +62 -0
- package/src/calendar/weekInfo.ts +83 -0
- package/src/components/Accordion/Accordion.module.scss +304 -0
- package/src/components/Accordion/Accordion.tokens.scss +64 -0
- package/src/components/Accordion/Accordion.tsx +272 -0
- package/src/components/Accordion/AccordionContent.tsx +36 -0
- package/src/components/Accordion/AccordionItem.tsx +66 -0
- package/src/components/Accordion/AccordionTrigger.tsx +121 -0
- package/src/components/Accordion/context.ts +47 -0
- package/src/components/Accordion/index.ts +14 -0
- package/src/components/Alert/Alert.module.scss +92 -0
- package/src/components/Alert/Alert.tokens.scss +60 -0
- package/src/components/Alert/Alert.tsx +136 -0
- package/src/components/Alert/index.ts +2 -0
- package/src/components/AppLayout/AppLayout.module.scss +130 -0
- package/src/components/AppLayout/AppLayout.tokens.scss +27 -0
- package/src/components/AppLayout/AppLayout.tsx +211 -0
- package/src/components/AppLayout/index.ts +2 -0
- package/src/components/Avatar/AgentAvatar.module.scss +117 -0
- package/src/components/Avatar/AgentAvatar.tsx +122 -0
- package/src/components/Avatar/Avatar.module.scss +181 -0
- package/src/components/Avatar/Avatar.tokens.scss +107 -0
- package/src/components/Avatar/Avatar.tsx +210 -0
- package/src/components/Avatar/AvatarGroup.module.scss +128 -0
- package/src/components/Avatar/AvatarGroup.tsx +119 -0
- package/src/components/Avatar/AvatarGroupContext.tsx +20 -0
- package/src/components/Avatar/index.ts +6 -0
- package/src/components/Badge/Badge.module.scss +124 -0
- package/src/components/Badge/Badge.tokens.scss +74 -0
- package/src/components/Badge/Badge.tsx +164 -0
- package/src/components/Badge/index.ts +2 -0
- package/src/components/Banner/Banner.module.scss +73 -0
- package/src/components/Banner/Banner.tokens.scss +51 -0
- package/src/components/Banner/Banner.tsx +138 -0
- package/src/components/Banner/index.ts +2 -0
- package/src/components/BrandIcon/BrandIcon.module.scss +5 -0
- package/src/components/BrandIcon/BrandIcon.tsx +99 -0
- package/src/components/BrandIcon/index.ts +2 -0
- package/src/components/Breadcrumb/Breadcrumb.module.scss +32 -0
- package/src/components/Breadcrumb/Breadcrumb.tokens.scss +9 -0
- package/src/components/Breadcrumb/Breadcrumb.tsx +146 -0
- package/src/components/Breadcrumb/index.ts +2 -0
- package/src/components/Button/Button.module.scss +167 -0
- package/src/components/Button/Button.tokens.scss +90 -0
- package/src/components/Button/Button.tsx +205 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/ButtonGroup/ButtonGroup.module.scss +134 -0
- package/src/components/ButtonGroup/ButtonGroup.tokens.scss +42 -0
- package/src/components/ButtonGroup/ButtonGroup.tsx +278 -0
- package/src/components/ButtonGroup/ButtonGroupItem.tsx +74 -0
- package/src/components/ButtonGroup/context.ts +45 -0
- package/src/components/ButtonGroup/index.ts +2 -0
- package/src/components/Calendar/AgendaView.module.scss +231 -0
- package/src/components/Calendar/AgendaView.tsx +214 -0
- package/src/components/Calendar/AllDayBand.module.scss +18 -0
- package/src/components/Calendar/AllDayBand.tsx +75 -0
- package/src/components/Calendar/Calendar.module.scss +23 -0
- package/src/components/Calendar/Calendar.tokens.scss +262 -0
- package/src/components/Calendar/Calendar.tsx +370 -0
- package/src/components/Calendar/DayCell.module.scss +30 -0
- package/src/components/Calendar/DayCell.tsx +50 -0
- package/src/components/Calendar/DayView.module.scss +10 -0
- package/src/components/Calendar/DayView.tsx +163 -0
- package/src/components/Calendar/EventChip.module.scss +171 -0
- package/src/components/Calendar/EventChip.tsx +115 -0
- package/src/components/Calendar/HourGrid.module.scss +123 -0
- package/src/components/Calendar/HourGrid.tsx +381 -0
- package/src/components/Calendar/MonthView.module.scss +99 -0
- package/src/components/Calendar/MonthView.tsx +296 -0
- package/src/components/Calendar/TimedEvent.module.scss +205 -0
- package/src/components/Calendar/TimedEvent.tsx +247 -0
- package/src/components/Calendar/ViewSwitcher.module.scss +3 -0
- package/src/components/Calendar/ViewSwitcher.tsx +47 -0
- package/src/components/Calendar/WeekView.module.scss +10 -0
- package/src/components/Calendar/WeekView.tsx +137 -0
- package/src/components/Calendar/eventColor.ts +60 -0
- package/src/components/Calendar/index.ts +18 -0
- package/src/components/Calendar/types.ts +451 -0
- package/src/components/Calendar/useEventDrag.ts +783 -0
- package/src/components/Calendar/utils.ts +622 -0
- package/src/components/Card/Card.module.scss +264 -0
- package/src/components/Card/Card.tokens.scss +55 -0
- package/src/components/Card/Card.tsx +170 -0
- package/src/components/Card/CardBody.tsx +45 -0
- package/src/components/Card/CardHeader.tsx +113 -0
- package/src/components/Card/CardList.tsx +24 -0
- package/src/components/Card/CardListRow.tsx +24 -0
- package/src/components/Card/index.ts +7 -0
- package/src/components/CatalogPicker/CatalogPicker.module.scss +193 -0
- package/src/components/CatalogPicker/CatalogPicker.tokens.scss +26 -0
- package/src/components/CatalogPicker/CatalogPicker.tsx +339 -0
- package/src/components/CatalogPicker/index.ts +2 -0
- package/src/components/Chart/Chart.module.scss +287 -0
- package/src/components/Chart/Chart.tokens.scss +63 -0
- package/src/components/Chart/Chart.tsx +607 -0
- package/src/components/Chart/ChartLegend.tsx +99 -0
- package/src/components/Chart/ChartTable.tsx +62 -0
- package/src/components/Chart/ChartTooltip.tsx +91 -0
- package/src/components/Chart/chartModel.ts +689 -0
- package/src/components/Chart/index.ts +2 -0
- package/src/components/ChatBubble/ChatBubble.module.scss +93 -0
- package/src/components/ChatBubble/ChatBubble.tokens.scss +17 -0
- package/src/components/ChatBubble/ChatBubble.tsx +61 -0
- package/src/components/ChatBubble/ChatBubbleList.tsx +27 -0
- package/src/components/ChatBubble/index.ts +3 -0
- package/src/components/ChatLauncher/ChatLauncher.module.scss +68 -0
- package/src/components/ChatLauncher/ChatLauncher.tokens.scss +27 -0
- package/src/components/ChatLauncher/ChatLauncher.tsx +202 -0
- package/src/components/ChatLauncher/index.ts +2 -0
- package/src/components/ChatLauncher/isAtBottom.ts +12 -0
- package/src/components/Checkbox/Checkbox.module.scss +147 -0
- package/src/components/Checkbox/Checkbox.tokens.scss +44 -0
- package/src/components/Checkbox/Checkbox.tsx +188 -0
- package/src/components/Checkbox/index.ts +2 -0
- package/src/components/CircularProgress/CircularProgress.module.scss +133 -0
- package/src/components/CircularProgress/CircularProgress.tokens.scss +40 -0
- package/src/components/CircularProgress/CircularProgress.tsx +139 -0
- package/src/components/CircularProgress/index.ts +7 -0
- package/src/components/Cluster/Cluster.module.scss +145 -0
- package/src/components/Cluster/Cluster.tokens.scss +11 -0
- package/src/components/Cluster/Cluster.tsx +215 -0
- package/src/components/Cluster/index.ts +2 -0
- package/src/components/Code/Code.module.scss +28 -0
- package/src/components/Code/Code.tokens.scss +15 -0
- package/src/components/Code/Code.tsx +44 -0
- package/src/components/Code/index.ts +2 -0
- package/src/components/CodeBlock/CodeBlock.module.scss +146 -0
- package/src/components/CodeBlock/CodeBlock.tokens.scss +27 -0
- package/src/components/CodeBlock/CodeBlock.tsx +274 -0
- package/src/components/CodeBlock/highlight.ts +179 -0
- package/src/components/CodeBlock/index.ts +8 -0
- package/src/components/CodeBlock/sampleSync.ts +42 -0
- package/src/components/ColorPicker/ColorPicker.module.scss +286 -0
- package/src/components/ColorPicker/ColorPicker.tokens.scss +60 -0
- package/src/components/ColorPicker/ColorPicker.tsx +367 -0
- package/src/components/ColorPicker/ColorPickerPanel.tsx +265 -0
- package/src/components/ColorPicker/SVSquare.tsx +189 -0
- package/src/components/ColorPicker/colorMath.ts +141 -0
- package/src/components/ColorPicker/index.ts +6 -0
- package/src/components/ConfirmationPopover/ConfirmationPopover.module.scss +39 -0
- package/src/components/ConfirmationPopover/ConfirmationPopover.tokens.scss +13 -0
- package/src/components/ConfirmationPopover/ConfirmationPopover.tsx +395 -0
- package/src/components/ConfirmationPopover/index.ts +2 -0
- package/src/components/Constrain/Constrain.module.scss +99 -0
- package/src/components/Constrain/Constrain.tsx +79 -0
- package/src/components/Constrain/index.ts +2 -0
- package/src/components/CurrencySelect/CurrencySelect.module.scss +7 -0
- package/src/components/CurrencySelect/CurrencySelect.tsx +167 -0
- package/src/components/CurrencySelect/index.ts +3 -0
- package/src/components/CursorPagination/CursorPagination.module.scss +69 -0
- package/src/components/CursorPagination/CursorPagination.tokens.scss +32 -0
- package/src/components/CursorPagination/CursorPagination.tsx +121 -0
- package/src/components/CursorPagination/index.ts +2 -0
- package/src/components/DashboardCanvas/DashboardCanvas.module.scss +360 -0
- package/src/components/DashboardCanvas/DashboardCanvas.tokens.scss +48 -0
- package/src/components/DashboardCanvas/DashboardCanvas.tsx +1270 -0
- package/src/components/DashboardCanvas/DashboardCanvasItem.tsx +140 -0
- package/src/components/DashboardCanvas/DashboardCanvasSection.tsx +174 -0
- package/src/components/DashboardCanvas/engine.ts +363 -0
- package/src/components/DashboardCanvas/index.ts +9 -0
- package/src/components/DashboardWidget/DashboardWidget.module.scss +100 -0
- package/src/components/DashboardWidget/DashboardWidget.tokens.scss +16 -0
- package/src/components/DashboardWidget/DashboardWidget.tsx +188 -0
- package/src/components/DashboardWidget/index.ts +7 -0
- package/src/components/DataTable/BodyRow.tsx +197 -0
- package/src/components/DataTable/ColumnVisibilityTrigger.module.scss +7 -0
- package/src/components/DataTable/ColumnVisibilityTrigger.tsx +105 -0
- package/src/components/DataTable/DataTable.module.scss +511 -0
- package/src/components/DataTable/DataTable.tokens.scss +80 -0
- package/src/components/DataTable/DataTable.tsx +734 -0
- package/src/components/DataTable/HeaderCell.module.scss +215 -0
- package/src/components/DataTable/HeaderCell.tsx +440 -0
- package/src/components/DataTable/columnShift.ts +117 -0
- package/src/components/DataTable/index.ts +23 -0
- package/src/components/DataTable/pinStyle.ts +47 -0
- package/src/components/DataTable/reorderColumns.ts +66 -0
- package/src/components/DataTable/types.ts +289 -0
- package/src/components/DataTable/useColumnDragShift.ts +216 -0
- package/src/components/DataTable/useDataTable.ts +372 -0
- package/src/components/DataTable/useResizeHandle.ts +97 -0
- package/src/components/DatePicker/DatePicker.module.scss +180 -0
- package/src/components/DatePicker/DatePicker.tokens.scss +152 -0
- package/src/components/DatePicker/DatePicker.tsx +664 -0
- package/src/components/DatePicker/DatePickerGrid.module.scss +172 -0
- package/src/components/DatePicker/DatePickerGrid.tsx +341 -0
- package/src/components/DatePicker/InlineDatePicker.module.scss +32 -0
- package/src/components/DatePicker/InlineDatePicker.tsx +201 -0
- package/src/components/DatePicker/index.ts +4 -0
- package/src/components/DatePicker/utils.ts +364 -0
- package/src/components/DateRangePicker/DateRangePicker.module.scss +237 -0
- package/src/components/DateRangePicker/DateRangePicker.tokens.scss +78 -0
- package/src/components/DateRangePicker/DateRangePicker.tsx +720 -0
- package/src/components/DateRangePicker/InlineDateRangePicker.module.scss +94 -0
- package/src/components/DateRangePicker/InlineDateRangePicker.tsx +376 -0
- package/src/components/DateRangePicker/index.ts +5 -0
- package/src/components/DateRangePicker/utils.ts +151 -0
- package/src/components/DateStrip/DateStrip.module.scss +78 -0
- package/src/components/DateStrip/DateStrip.tokens.scss +23 -0
- package/src/components/DateStrip/DateStrip.tsx +205 -0
- package/src/components/DateStrip/index.ts +2 -0
- package/src/components/DefinitionList/DefinitionList.module.scss +102 -0
- package/src/components/DefinitionList/DefinitionList.tokens.scss +29 -0
- package/src/components/DefinitionList/DefinitionList.tsx +198 -0
- package/src/components/DefinitionList/index.ts +9 -0
- package/src/components/Divider/Divider.module.scss +144 -0
- package/src/components/Divider/Divider.tokens.scss +21 -0
- package/src/components/Divider/Divider.tsx +103 -0
- package/src/components/Divider/index.ts +2 -0
- package/src/components/Dot/Dot.module.scss +40 -0
- package/src/components/Dot/Dot.tokens.scss +4 -0
- package/src/components/Dot/Dot.tsx +45 -0
- package/src/components/Dot/index.ts +2 -0
- package/src/components/Drawer/Body.tsx +23 -0
- package/src/components/Drawer/Close.tsx +35 -0
- package/src/components/Drawer/Content.tsx +93 -0
- package/src/components/Drawer/Drawer.module.scss +232 -0
- package/src/components/Drawer/Drawer.tokens.scss +38 -0
- package/src/components/Drawer/Drawer.tsx +23 -0
- package/src/components/Drawer/DrawerRoot.tsx +190 -0
- package/src/components/Drawer/Footer.tsx +24 -0
- package/src/components/Drawer/Header.tsx +64 -0
- package/src/components/Drawer/Overlay.tsx +82 -0
- package/src/components/Drawer/context.ts +44 -0
- package/src/components/Drawer/index.ts +12 -0
- package/src/components/Drawer/useDragToClose.ts +149 -0
- package/src/components/DropdownMenu/CheckboxItem.tsx +144 -0
- package/src/components/DropdownMenu/Content.tsx +419 -0
- package/src/components/DropdownMenu/DropdownMenu.module.scss +280 -0
- package/src/components/DropdownMenu/DropdownMenu.tokens.scss +88 -0
- package/src/components/DropdownMenu/DropdownMenu.tsx +43 -0
- package/src/components/DropdownMenu/Group.tsx +76 -0
- package/src/components/DropdownMenu/Item.tsx +148 -0
- package/src/components/DropdownMenu/ItemIndicator.tsx +30 -0
- package/src/components/DropdownMenu/Radio.tsx +178 -0
- package/src/components/DropdownMenu/Root.tsx +100 -0
- package/src/components/DropdownMenu/Sub.tsx +332 -0
- package/src/components/DropdownMenu/Trigger.tsx +76 -0
- package/src/components/DropdownMenu/context.ts +65 -0
- package/src/components/DropdownMenu/index.ts +20 -0
- package/src/components/EmojiPicker/EmojiPicker.module.scss +84 -0
- package/src/components/EmojiPicker/EmojiPicker.tokens.scss +24 -0
- package/src/components/EmojiPicker/EmojiPicker.tsx +341 -0
- package/src/components/EmojiPicker/emojiData.ts +245 -0
- package/src/components/EmojiPicker/index.ts +3 -0
- package/src/components/EmptyState/EmptyState.module.scss +102 -0
- package/src/components/EmptyState/EmptyState.tokens.scss +28 -0
- package/src/components/EmptyState/EmptyState.tsx +112 -0
- package/src/components/EmptyState/index.ts +7 -0
- package/src/components/EntityChip/EntityChip.module.scss +275 -0
- package/src/components/EntityChip/EntityChip.tokens.scss +66 -0
- package/src/components/EntityChip/EntityChip.tsx +649 -0
- package/src/components/EntityChip/index.ts +10 -0
- package/src/components/ErrorState/ErrorState.module.scss +105 -0
- package/src/components/ErrorState/ErrorState.tokens.scss +32 -0
- package/src/components/ErrorState/ErrorState.tsx +125 -0
- package/src/components/ErrorState/index.ts +8 -0
- package/src/components/Field/Field.module.scss +46 -0
- package/src/components/Field/Field.tsx +185 -0
- package/src/components/Field/index.ts +2 -0
- package/src/components/FileUpload/FileUpload.module.scss +187 -0
- package/src/components/FileUpload/FileUpload.tokens.scss +81 -0
- package/src/components/FileUpload/FileUpload.tsx +569 -0
- package/src/components/FileUpload/formatBytes.ts +34 -0
- package/src/components/FileUpload/iconForFile.ts +40 -0
- package/src/components/FileUpload/index.ts +2 -0
- package/src/components/FilterChip/FilterChip.module.scss +61 -0
- package/src/components/FilterChip/FilterChip.tokens.scss +25 -0
- package/src/components/FilterChip/FilterChip.tsx +208 -0
- package/src/components/FilterChip/index.ts +5 -0
- package/src/components/FlowCanvas/FlowCanvas.module.scss +329 -0
- package/src/components/FlowCanvas/FlowCanvas.tokens.scss +45 -0
- package/src/components/FlowCanvas/FlowCanvas.tsx +1867 -0
- package/src/components/FlowCanvas/FlowControls.tsx +46 -0
- package/src/components/FlowCanvas/FlowEdge.tsx +58 -0
- package/src/components/FlowCanvas/FlowNode.tsx +76 -0
- package/src/components/FlowCanvas/edgePath.ts +85 -0
- package/src/components/FlowCanvas/index.ts +4 -0
- package/src/components/FlowCanvas/layout.ts +148 -0
- package/src/components/FlowCanvas/spatialNav.ts +76 -0
- package/src/components/FlowCanvas/types.ts +59 -0
- package/src/components/FlowCanvas/useViewport.ts +122 -0
- package/src/components/FormRow/FormRow.module.scss +2 -0
- package/src/components/FormRow/FormRow.tsx +37 -0
- package/src/components/FormRow/index.ts +2 -0
- package/src/components/FormSection/FormSection.module.scss +24 -0
- package/src/components/FormSection/FormSection.tsx +46 -0
- package/src/components/FormSection/index.ts +2 -0
- package/src/components/Grid/Grid.module.scss +162 -0
- package/src/components/Grid/Grid.tokens.scss +13 -0
- package/src/components/Grid/Grid.tsx +226 -0
- package/src/components/Grid/GridItem.tsx +77 -0
- package/src/components/Grid/index.ts +11 -0
- package/src/components/Highlight/Highlight.module.scss +43 -0
- package/src/components/Highlight/Highlight.tokens.scss +35 -0
- package/src/components/Highlight/Highlight.tsx +164 -0
- package/src/components/Highlight/HighlightOverlay.tsx +100 -0
- package/src/components/Highlight/index.ts +2 -0
- package/src/components/HighlightedText/HighlightedText.module.scss +11 -0
- package/src/components/HighlightedText/HighlightedText.tokens.scss +9 -0
- package/src/components/HighlightedText/HighlightedText.tsx +50 -0
- package/src/components/HighlightedText/highlightRanges.ts +44 -0
- package/src/components/HighlightedText/index.ts +2 -0
- package/src/components/IconPicker/IconPicker.module.scss +175 -0
- package/src/components/IconPicker/IconPicker.tokens.scss +40 -0
- package/src/components/IconPicker/IconPicker.tsx +629 -0
- package/src/components/IconPicker/index.ts +9 -0
- package/src/components/IconTile/IconTile.module.scss +57 -0
- package/src/components/IconTile/IconTile.tokens.scss +16 -0
- package/src/components/IconTile/IconTile.tsx +91 -0
- package/src/components/IconTile/index.ts +2 -0
- package/src/components/Image/Image.module.scss +266 -0
- package/src/components/Image/Image.tokens.scss +55 -0
- package/src/components/Image/Image.tsx +342 -0
- package/src/components/Image/index.ts +2 -0
- package/src/components/ImageCrop/ImageCrop.module.scss +274 -0
- package/src/components/ImageCrop/ImageCrop.tokens.scss +33 -0
- package/src/components/ImageCrop/ImageCrop.tsx +542 -0
- package/src/components/ImageCrop/cropGeometry.ts +120 -0
- package/src/components/ImageCrop/extractCropBlob.ts +140 -0
- package/src/components/ImageCrop/index.ts +11 -0
- package/src/components/ImageCrop/useCropPreview.ts +161 -0
- package/src/components/Indent/Indent.module.scss +33 -0
- package/src/components/Indent/Indent.tokens.scss +10 -0
- package/src/components/Indent/Indent.tsx +46 -0
- package/src/components/Indent/index.ts +2 -0
- package/src/components/Input/Input.module.scss +99 -0
- package/src/components/Input/Input.tokens.scss +54 -0
- package/src/components/Input/Input.tsx +105 -0
- package/src/components/Input/Suggestions.tsx +260 -0
- package/src/components/Input/index.ts +2 -0
- package/src/components/Kanban/Kanban.module.scss +39 -0
- package/src/components/Kanban/Kanban.tokens.scss +15 -0
- package/src/components/Kanban/Kanban.tsx +951 -0
- package/src/components/Kanban/index.ts +7 -0
- package/src/components/Kbd/Kbd.module.scss +47 -0
- package/src/components/Kbd/Kbd.tokens.scss +26 -0
- package/src/components/Kbd/Kbd.tsx +73 -0
- package/src/components/Kbd/index.ts +2 -0
- package/src/components/Lightbox/Lightbox.module.scss +283 -0
- package/src/components/Lightbox/Lightbox.tokens.scss +36 -0
- package/src/components/Lightbox/Lightbox.tsx +506 -0
- package/src/components/Lightbox/index.ts +2 -0
- package/src/components/Link/Link.module.scss +78 -0
- package/src/components/Link/Link.tokens.scss +28 -0
- package/src/components/Link/Link.tsx +114 -0
- package/src/components/Link/index.ts +2 -0
- package/src/components/LinkCard/LinkCard.module.scss +92 -0
- package/src/components/LinkCard/LinkCard.tokens.scss +9 -0
- package/src/components/LinkCard/LinkCard.tsx +72 -0
- package/src/components/LinkCard/index.ts +2 -0
- package/src/components/LiquidEditor/AutocompleteMenu.tsx +133 -0
- package/src/components/LiquidEditor/HighlightLayer.tsx +53 -0
- package/src/components/LiquidEditor/InsertVariableMenu.tsx +81 -0
- package/src/components/LiquidEditor/LiquidEditor.module.scss +339 -0
- package/src/components/LiquidEditor/LiquidEditor.tokens.scss +81 -0
- package/src/components/LiquidEditor/LiquidEditor.tsx +412 -0
- package/src/components/LiquidEditor/PreviewPane.tsx +29 -0
- package/src/components/LiquidEditor/caretCoordinates.ts +97 -0
- package/src/components/LiquidEditor/index.ts +7 -0
- package/src/components/LiquidEditor/liquidFilters.ts +23 -0
- package/src/components/LiquidEditor/liquidTokenizer.ts +235 -0
- package/src/components/LiquidEditor/types.ts +101 -0
- package/src/components/LiquidEditor/useLiquidAutocomplete.ts +178 -0
- package/src/components/List/List.module.scss +105 -0
- package/src/components/List/List.tokens.scss +42 -0
- package/src/components/List/List.tsx +124 -0
- package/src/components/List/index.ts +9 -0
- package/src/components/LiveRegion/LiveRegion.module.scss +3 -0
- package/src/components/LiveRegion/LiveRegion.tsx +116 -0
- package/src/components/LiveRegion/index.ts +2 -0
- package/src/components/Logo/Logo.module.scss +139 -0
- package/src/components/Logo/Logo.tokens.scss +14 -0
- package/src/components/Logo/Logo.tsx +126 -0
- package/src/components/Logo/index.ts +2 -0
- package/src/components/Masonry/Masonry.module.scss +42 -0
- package/src/components/Masonry/Masonry.tokens.scss +8 -0
- package/src/components/Masonry/Masonry.tsx +136 -0
- package/src/components/Masonry/index.ts +2 -0
- package/src/components/Masonry/masonryUtils.ts +42 -0
- package/src/components/MediaTile/MediaTile.module.scss +183 -0
- package/src/components/MediaTile/MediaTile.tokens.scss +60 -0
- package/src/components/MediaTile/MediaTile.tsx +208 -0
- package/src/components/MediaTile/index.ts +8 -0
- package/src/components/Modal/Body.tsx +27 -0
- package/src/components/Modal/Close.tsx +45 -0
- package/src/components/Modal/Content.tsx +98 -0
- package/src/components/Modal/Footer.tsx +28 -0
- package/src/components/Modal/Header.tsx +51 -0
- package/src/components/Modal/Modal.module.scss +262 -0
- package/src/components/Modal/Modal.tokens.scss +50 -0
- package/src/components/Modal/Modal.tsx +23 -0
- package/src/components/Modal/ModalRoot.tsx +299 -0
- package/src/components/Modal/Overlay.tsx +101 -0
- package/src/components/Modal/context.ts +60 -0
- package/src/components/Modal/index.ts +11 -0
- package/src/components/MoneyInput/MoneyInput.module.scss +57 -0
- package/src/components/MoneyInput/MoneyInput.tsx +433 -0
- package/src/components/MoneyInput/index.ts +2 -0
- package/src/components/OptionsPicker/OptionsPicker.module.scss +216 -0
- package/src/components/OptionsPicker/OptionsPicker.tokens.scss +68 -0
- package/src/components/OptionsPicker/OptionsPicker.tsx +936 -0
- package/src/components/OptionsPicker/index.ts +9 -0
- package/src/components/OtpInput/OtpInput.module.scss +69 -0
- package/src/components/OtpInput/OtpInput.tokens.scss +45 -0
- package/src/components/OtpInput/OtpInput.tsx +368 -0
- package/src/components/OtpInput/index.ts +2 -0
- package/src/components/Page/Page.module.scss +30 -0
- package/src/components/Page/Page.tokens.scss +11 -0
- package/src/components/Page/Page.tsx +53 -0
- package/src/components/Page/index.ts +2 -0
- package/src/components/PageHeader/PageHeader.module.scss +197 -0
- package/src/components/PageHeader/PageHeader.tokens.scss +41 -0
- package/src/components/PageHeader/PageHeader.tsx +310 -0
- package/src/components/PageHeader/index.ts +20 -0
- package/src/components/Pagination/Pagination.module.scss +117 -0
- package/src/components/Pagination/Pagination.tokens.scss +54 -0
- package/src/components/Pagination/Pagination.tsx +165 -0
- package/src/components/Pagination/index.ts +4 -0
- package/src/components/Pagination/paginationRange.ts +72 -0
- package/src/components/PasswordInput/PasswordInput.module.scss +120 -0
- package/src/components/PasswordInput/PasswordInput.tokens.scss +44 -0
- package/src/components/PasswordInput/PasswordInput.tsx +210 -0
- package/src/components/PasswordInput/index.ts +2 -0
- package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.module.scss +80 -0
- package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.tokens.scss +40 -0
- package/src/components/PasswordStrengthMeter/PasswordStrengthMeter.tsx +96 -0
- package/src/components/PasswordStrengthMeter/index.ts +2 -0
- package/src/components/PersonDisplay/PersonDisplay.module.scss +180 -0
- package/src/components/PersonDisplay/PersonDisplay.tokens.scss +35 -0
- package/src/components/PersonDisplay/PersonDisplay.tsx +420 -0
- package/src/components/PersonDisplay/index.ts +10 -0
- package/src/components/PhoneInput/PhoneInput.module.scss +23 -0
- package/src/components/PhoneInput/PhoneInput.tsx +271 -0
- package/src/components/PhoneInput/index.ts +4 -0
- package/src/components/PhoneInput/phone.ts +128 -0
- package/src/components/PillMenu/PillMenu.module.scss +117 -0
- package/src/components/PillMenu/PillMenu.tokens.scss +22 -0
- package/src/components/PillMenu/PillMenu.tsx +324 -0
- package/src/components/PillMenu/index.ts +2 -0
- package/src/components/Popover/Anchor.tsx +37 -0
- package/src/components/Popover/Close.tsx +45 -0
- package/src/components/Popover/Content.tsx +213 -0
- package/src/components/Popover/Heading.tsx +33 -0
- package/src/components/Popover/Popover.module.scss +177 -0
- package/src/components/Popover/Popover.tokens.scss +22 -0
- package/src/components/Popover/Popover.tsx +23 -0
- package/src/components/Popover/PopoverRoot.tsx +75 -0
- package/src/components/Popover/Trigger.tsx +86 -0
- package/src/components/Popover/context.ts +22 -0
- package/src/components/Popover/index.ts +7 -0
- package/src/components/Progress/Progress.module.scss +110 -0
- package/src/components/Progress/Progress.tokens.scss +44 -0
- package/src/components/Progress/Progress.tsx +129 -0
- package/src/components/Progress/index.ts +2 -0
- package/src/components/QrCode/QrCode.module.scss +97 -0
- package/src/components/QrCode/QrCode.tokens.scss +17 -0
- package/src/components/QrCode/QrCode.tsx +233 -0
- package/src/components/QrCode/index.ts +2 -0
- package/src/components/QrCode/qr.ts +161 -0
- package/src/components/Radio/Radio.module.scss +175 -0
- package/src/components/Radio/Radio.tokens.scss +59 -0
- package/src/components/Radio/Radio.tsx +127 -0
- package/src/components/Radio/RadioGroup.module.scss +42 -0
- package/src/components/Radio/RadioGroup.tsx +120 -0
- package/src/components/Radio/RadioGroupContext.tsx +30 -0
- package/src/components/Radio/index.ts +4 -0
- package/src/components/Rail/Rail.module.scss +510 -0
- package/src/components/Rail/Rail.tokens.scss +92 -0
- package/src/components/Rail/Rail.tsx +287 -0
- package/src/components/Rail/RailCollapseToggle.tsx +57 -0
- package/src/components/Rail/RailFooter.tsx +17 -0
- package/src/components/Rail/RailGroup.tsx +728 -0
- package/src/components/Rail/RailGroupContext.ts +9 -0
- package/src/components/Rail/RailHeader.tsx +23 -0
- package/src/components/Rail/RailItem.tsx +119 -0
- package/src/components/Rail/RailSection.tsx +39 -0
- package/src/components/Rail/RailSpacer.tsx +19 -0
- package/src/components/Rail/index.ts +9 -0
- package/src/components/RelativeDateInput/RelativeDateInput.module.scss +15 -0
- package/src/components/RelativeDateInput/RelativeDateInput.tokens.scss +6 -0
- package/src/components/RelativeDateInput/RelativeDateInput.tsx +474 -0
- package/src/components/RelativeDateInput/index.ts +10 -0
- package/src/components/RelativeDateInput/relativeDate.ts +127 -0
- package/src/components/RichText/RichText.module.scss +5 -0
- package/src/components/RichText/RichText.tsx +70 -0
- package/src/components/RichText/RichTextAttachment.module.scss +82 -0
- package/src/components/RichText/RichTextAttachment.tsx +122 -0
- package/src/components/RichText/_prose.scss +79 -0
- package/src/components/RichText/attachmentIcon.tsx +24 -0
- package/src/components/RichText/engine/attachment.ts +154 -0
- package/src/components/RichText/engine/autolink.ts +64 -0
- package/src/components/RichText/engine/blockUnit.ts +174 -0
- package/src/components/RichText/engine/colorMarks.ts +85 -0
- package/src/components/RichText/engine/escape.ts +11 -0
- package/src/components/RichText/engine/fromHtml.ts +353 -0
- package/src/components/RichText/engine/fromMarkdown.ts +20 -0
- package/src/components/RichText/engine/inlines.ts +82 -0
- package/src/components/RichText/engine/listDepths.ts +32 -0
- package/src/components/RichText/engine/marks.ts +80 -0
- package/src/components/RichText/engine/mdToHtml.ts +178 -0
- package/src/components/RichText/engine/model.ts +157 -0
- package/src/components/RichText/engine/position.ts +118 -0
- package/src/components/RichText/engine/renderDoc.tsx +395 -0
- package/src/components/RichText/engine/renderLink.ts +15 -0
- package/src/components/RichText/engine/renderMention.ts +16 -0
- package/src/components/RichText/engine/safeHref.ts +22 -0
- package/src/components/RichText/engine/toHtml.ts +154 -0
- package/src/components/RichText/engine/toMarkdown.ts +97 -0
- package/src/components/RichText/engine/transforms.ts +434 -0
- package/src/components/RichText/imageMaxHeightStyle.ts +10 -0
- package/src/components/RichText/index.ts +31 -0
- package/src/components/RichTextEditor/RichTextAttachmentConfig.tsx +264 -0
- package/src/components/RichTextEditor/RichTextBlockControls.tsx +365 -0
- package/src/components/RichTextEditor/RichTextBlockMenu.tsx +162 -0
- package/src/components/RichTextEditor/RichTextColorMenu.tsx +115 -0
- package/src/components/RichTextEditor/RichTextEditor.module.scss +298 -0
- package/src/components/RichTextEditor/RichTextEditor.tsx +1910 -0
- package/src/components/RichTextEditor/RichTextImageResizer.tsx +131 -0
- package/src/components/RichTextEditor/RichTextLinkEditor.tsx +151 -0
- package/src/components/RichTextEditor/RichTextMentionMenu.tsx +99 -0
- package/src/components/RichTextEditor/RichTextToolbar.tsx +379 -0
- package/src/components/RichTextEditor/autolinkInput.ts +65 -0
- package/src/components/RichTextEditor/blockDrop.ts +9 -0
- package/src/components/RichTextEditor/blockReflow.ts +62 -0
- package/src/components/RichTextEditor/commands.ts +300 -0
- package/src/components/RichTextEditor/history.ts +93 -0
- package/src/components/RichTextEditor/icons.tsx +152 -0
- package/src/components/RichTextEditor/imageSize.ts +70 -0
- package/src/components/RichTextEditor/index.ts +5 -0
- package/src/components/RichTextEditor/input.ts +209 -0
- package/src/components/RichTextEditor/inputRules.ts +71 -0
- package/src/components/RichTextEditor/links.ts +103 -0
- package/src/components/RichTextEditor/mentionContext.ts +37 -0
- package/src/components/RichTextEditor/mentions.ts +28 -0
- package/src/components/RichTextEditor/preventSelectionLoss.ts +15 -0
- package/src/components/RichTextEditor/selection.ts +415 -0
- package/src/components/RichTextEditor/shortcuts.ts +44 -0
- package/src/components/RichTextEditor/useAnchoredFloating.ts +50 -0
- package/src/components/RichTextEditor/useAttachmentConfig.ts +134 -0
- package/src/components/RichTextEditor/useDismissOnOutsidePointerDown.ts +26 -0
- package/src/components/RichTextEditor/useLinkEditor.ts +107 -0
- package/src/components/RichTextEditor/useMention.ts +226 -0
- package/src/components/RichTextEditor/useOverlayRect.ts +73 -0
- package/src/components/RichTextEditor/useUpload.ts +246 -0
- package/src/components/Screen/Screen.module.scss +46 -0
- package/src/components/Screen/Screen.tokens.scss +20 -0
- package/src/components/Screen/Screen.tsx +97 -0
- package/src/components/Screen/index.ts +2 -0
- package/src/components/ScrollArea/ScrollArea.module.scss +39 -0
- package/src/components/ScrollArea/ScrollArea.tokens.scss +15 -0
- package/src/components/ScrollArea/ScrollArea.tsx +154 -0
- package/src/components/ScrollArea/index.ts +2 -0
- package/src/components/Select/Chip.tsx +45 -0
- package/src/components/Select/Empty.tsx +39 -0
- package/src/components/Select/Error.tsx +51 -0
- package/src/components/Select/HiddenInputs.tsx +44 -0
- package/src/components/Select/Listbox.tsx +557 -0
- package/src/components/Select/Loading.tsx +30 -0
- package/src/components/Select/Select.module.scss +512 -0
- package/src/components/Select/Select.tokens.scss +140 -0
- package/src/components/Select/Select.tsx +685 -0
- package/src/components/Select/Trigger.tsx +952 -0
- package/src/components/Select/context.ts +101 -0
- package/src/components/Select/emptyStateText.ts +19 -0
- package/src/components/Select/index.ts +9 -0
- package/src/components/Select/useSelectState.ts +157 -0
- package/src/components/Select/utils-types.ts +7 -0
- package/src/components/Select/utils.ts +122 -0
- package/src/components/SettingRow/SettingRow.module.scss +166 -0
- package/src/components/SettingRow/SettingRow.tokens.scss +37 -0
- package/src/components/SettingRow/SettingRow.tsx +242 -0
- package/src/components/SettingRow/index.ts +7 -0
- package/src/components/Skeleton/Skeleton.module.scss +55 -0
- package/src/components/Skeleton/Skeleton.tokens.scss +17 -0
- package/src/components/Skeleton/Skeleton.tsx +131 -0
- package/src/components/Skeleton/index.ts +4 -0
- package/src/components/Skeleton/useSkeletonVisibility.ts +95 -0
- package/src/components/Slider/Slider.module.scss +293 -0
- package/src/components/Slider/Slider.tokens.scss +98 -0
- package/src/components/Slider/Slider.tsx +624 -0
- package/src/components/Slider/index.ts +9 -0
- package/src/components/SlotGrid/SlotGrid.module.scss +61 -0
- package/src/components/SlotGrid/SlotGrid.tokens.scss +21 -0
- package/src/components/SlotGrid/SlotGrid.tsx +111 -0
- package/src/components/SlotGrid/index.ts +2 -0
- package/src/components/SocialButton/SocialButton.module.scss +4 -0
- package/src/components/SocialButton/SocialButton.tsx +40 -0
- package/src/components/SocialButton/index.ts +2 -0
- package/src/components/Sortable/Sortable.module.scss +177 -0
- package/src/components/Sortable/Sortable.tokens.scss +27 -0
- package/src/components/Sortable/Sortable.tsx +572 -0
- package/src/components/Sortable/containerAwareCollision.ts +125 -0
- package/src/components/Sortable/index.ts +13 -0
- package/src/components/SortableGroup/SortableGroup.module.scss +23 -0
- package/src/components/SortableGroup/SortableGroup.tsx +315 -0
- package/src/components/SortableGroup/index.ts +4 -0
- package/src/components/SortableGroup/moveSortableItem.ts +39 -0
- package/src/components/Sparkline/Sparkline.module.scss +28 -0
- package/src/components/Sparkline/Sparkline.tokens.scss +7 -0
- package/src/components/Sparkline/Sparkline.tsx +133 -0
- package/src/components/Sparkline/index.ts +2 -0
- package/src/components/Sparkline/sparklineModel.ts +119 -0
- package/src/components/Split/Split.module.scss +158 -0
- package/src/components/Split/Split.tokens.scss +10 -0
- package/src/components/Split/Split.tsx +231 -0
- package/src/components/Split/index.ts +2 -0
- package/src/components/Stack/Stack.module.scss +67 -0
- package/src/components/Stack/Stack.tokens.scss +11 -0
- package/src/components/Stack/Stack.tsx +100 -0
- package/src/components/Stack/index.ts +2 -0
- package/src/components/StagePath/StagePath.module.scss +255 -0
- package/src/components/StagePath/StagePath.tokens.scss +43 -0
- package/src/components/StagePath/StagePath.tsx +176 -0
- package/src/components/StagePath/index.ts +2 -0
- package/src/components/StatGroup/StatGroup.module.scss +6 -0
- package/src/components/StatGroup/StatGroup.tsx +70 -0
- package/src/components/StatGroup/StatGroupContext.ts +10 -0
- package/src/components/StatGroup/StatTile.module.scss +99 -0
- package/src/components/StatGroup/StatTile.tokens.scss +35 -0
- package/src/components/StatGroup/StatTile.tsx +143 -0
- package/src/components/StatGroup/index.ts +4 -0
- package/src/components/Sticky/Sticky.module.scss +98 -0
- package/src/components/Sticky/Sticky.tokens.scss +17 -0
- package/src/components/Sticky/Sticky.tsx +103 -0
- package/src/components/Sticky/index.ts +2 -0
- package/src/components/Switch/Switch.module.scss +182 -0
- package/src/components/Switch/Switch.tokens.scss +59 -0
- package/src/components/Switch/Switch.tsx +214 -0
- package/src/components/Switch/index.ts +2 -0
- package/src/components/Table/Table.module.scss +308 -0
- package/src/components/Table/Table.tokens.scss +79 -0
- package/src/components/Table/Table.tsx +381 -0
- package/src/components/Table/index.ts +15 -0
- package/src/components/TableOfContents/TableOfContents.module.scss +83 -0
- package/src/components/TableOfContents/TableOfContents.tokens.scss +26 -0
- package/src/components/TableOfContents/TableOfContents.tsx +192 -0
- package/src/components/TableOfContents/activeSection.ts +18 -0
- package/src/components/TableOfContents/index.ts +2 -0
- package/src/components/Tabs/Tabs.module.scss +359 -0
- package/src/components/Tabs/Tabs.tokens.scss +50 -0
- package/src/components/Tabs/Tabs.tsx +538 -0
- package/src/components/Tabs/index.ts +2 -0
- package/src/components/Text/Text.module.scss +115 -0
- package/src/components/Text/Text.tokens.scss +55 -0
- package/src/components/Text/Text.tsx +197 -0
- package/src/components/Text/index.ts +2 -0
- package/src/components/Textarea/Textarea.module.scss +94 -0
- package/src/components/Textarea/Textarea.tokens.scss +48 -0
- package/src/components/Textarea/Textarea.tsx +246 -0
- package/src/components/Textarea/index.ts +2 -0
- package/src/components/Thread/Thread.module.scss +161 -0
- package/src/components/Thread/Thread.tokens.scss +32 -0
- package/src/components/Thread/Thread.tsx +176 -0
- package/src/components/Thread/index.ts +2 -0
- package/src/components/TimeField/TimeField.module.scss +232 -0
- package/src/components/TimeField/TimeField.tsx +793 -0
- package/src/components/TimeField/index.ts +2 -0
- package/src/components/Timeline/Timeline.module.scss +58 -0
- package/src/components/Timeline/Timeline.tokens.scss +13 -0
- package/src/components/Timeline/Timeline.tsx +53 -0
- package/src/components/Timeline/index.ts +2 -0
- package/src/components/Title/Title.module.scss +84 -0
- package/src/components/Title/Title.tokens.scss +37 -0
- package/src/components/Title/Title.tsx +150 -0
- package/src/components/Title/index.ts +2 -0
- package/src/components/Toast/Toast.module.scss +299 -0
- package/src/components/Toast/Toast.tokens.scss +65 -0
- package/src/components/Toast/Toast.tsx +122 -0
- package/src/components/Toast/ToastViewport.tsx +166 -0
- package/src/components/Toast/api.ts +175 -0
- package/src/components/Toast/index.ts +5 -0
- package/src/components/Toast/store.ts +133 -0
- package/src/components/Toast/useToastTimer.ts +94 -0
- package/src/components/Tooltip/Tooltip.module.scss +99 -0
- package/src/components/Tooltip/Tooltip.tokens.scss +23 -0
- package/src/components/Tooltip/Tooltip.tsx +341 -0
- package/src/components/Tooltip/index.ts +2 -0
- package/src/components/TopBar/TopBar.module.scss +235 -0
- package/src/components/TopBar/TopBar.tokens.scss +79 -0
- package/src/components/TopBar/TopBar.tsx +87 -0
- package/src/components/TopBar/TopBarEnd.tsx +20 -0
- package/src/components/TopBar/TopBarIconButton.tsx +86 -0
- package/src/components/TopBar/TopBarSearch.tsx +319 -0
- package/src/components/TopBar/TopBarSearchPanel.tsx +268 -0
- package/src/components/TopBar/TopBarStart.tsx +20 -0
- package/src/components/TopBar/index.ts +11 -0
- package/src/components/Tour/Spotlight.tsx +121 -0
- package/src/components/Tour/Tour.module.scss +210 -0
- package/src/components/Tour/Tour.tokens.scss +58 -0
- package/src/components/Tour/Tour.tsx +617 -0
- package/src/components/Tour/index.ts +2 -0
- package/src/components/Tour/useTourTarget.ts +115 -0
- package/src/components/TreeView/TreeView.module.scss +268 -0
- package/src/components/TreeView/TreeView.tokens.scss +36 -0
- package/src/components/TreeView/TreeView.tsx +536 -0
- package/src/components/TreeView/index.ts +3 -0
- package/src/components/TreeView/treeModel.ts +224 -0
- package/src/components/VisuallyHidden/VisuallyHidden.module.scss +7 -0
- package/src/components/VisuallyHidden/VisuallyHidden.tsx +29 -0
- package/src/components/VisuallyHidden/index.ts +2 -0
- package/src/components/WidgetPreview/WidgetPreview.module.scss +11 -0
- package/src/components/WidgetPreview/WidgetPreview.tokens.scss +26 -0
- package/src/components/WidgetPreview/WidgetPreview.tsx +36 -0
- package/src/components/WidgetPreview/WidgetShape.module.scss +140 -0
- package/src/components/WidgetPreview/WidgetShape.tsx +159 -0
- package/src/components/WidgetPreview/index.ts +2 -0
- package/src/components/_internal/Trend.tsx +27 -0
- package/src/components/_internal/choiceTile.scss +74 -0
- package/src/components/_internal/collapse.scss +10 -0
- package/src/components/_internal/collapse.ts +58 -0
- package/src/components/_internal/currency.ts +257 -0
- package/src/components/_internal/dragAnnouncements.ts +200 -0
- package/src/components/_internal/fieldWiring.ts +225 -0
- package/src/components/_internal/gridSpan.ts +54 -0
- package/src/components/_internal/isoDay.ts +35 -0
- package/src/components/_internal/letterKey.ts +26 -0
- package/src/components/_internal/overlay/focusRestore.ts +21 -0
- package/src/components/_internal/overlay/index.ts +12 -0
- package/src/components/_internal/overlay/tourHold.ts +23 -0
- package/src/components/_internal/overlay/useFocusTrap.ts +120 -0
- package/src/components/_internal/overlay/useInOverlay.ts +81 -0
- package/src/components/_internal/overlay/useOverlayStack.ts +232 -0
- package/src/components/_internal/overlay/useScrollLock.ts +112 -0
- package/src/components/_internal/refs.ts +48 -0
- package/src/components/_internal/statusColor.ts +26 -0
- package/src/components/_internal/timeUtils.ts +23 -0
- package/src/components/_internal/useAsyncOptions.ts +145 -0
- package/src/components/_internal/useClippedTooltip.ts +50 -0
- package/src/components/_internal/useControllableState.ts +50 -0
- package/src/components.manifest.json +1141 -0
- package/src/hooks/useBelowBreakpoint.ts +58 -0
- package/src/i18n/I18nProvider.tsx +52 -0
- package/src/i18n/LocaleProvider.tsx +17 -0
- package/src/i18n/en.ts +648 -0
- package/src/i18n/format.ts +71 -0
- package/src/i18n/index.ts +13 -0
- package/src/i18n/messages.ts +1275 -0
- package/src/i18n/ru.ts +677 -0
- package/src/i18n/useLocale.ts +19 -0
- package/src/i18n/useTranslation.ts +58 -0
- package/src/index.ts +913 -0
- package/src/palette/index.ts +2 -0
- package/src/palette/palette.ts +108 -0
- package/src/styles/dark.scss +4 -0
- package/src/styles/global.scss +7 -0
- package/src/styles/mixins.scss +143 -0
- package/src/styles/reset.scss +78 -0
- package/src/styles/tokens.scss +18 -0
- package/src/styles/typography.scss +44 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
// renderDoc.tsx — pure model → React. Read-only; used by <RichText>. The model
|
|
2
|
+
// is flat; this reconstructs list nesting from `depth` at render time.
|
|
3
|
+
import { Fragment, type ReactElement, type ReactNode } from 'react';
|
|
4
|
+
import type { RichDoc, Block, Inline, Mark, MarkType } from './model';
|
|
5
|
+
import { runsText, runsLength } from './inlines';
|
|
6
|
+
import { safeHref } from './safeHref';
|
|
7
|
+
import { textColorVar, bgColorVar } from './colorMarks';
|
|
8
|
+
import { isListItem, effectiveDepths } from './listDepths';
|
|
9
|
+
import { MARK_ORDER, marksSignature } from './marks';
|
|
10
|
+
import type { RenderLink } from './renderLink';
|
|
11
|
+
import type { RenderMention } from './renderMention';
|
|
12
|
+
import { RichTextAttachment } from '../RichTextAttachment';
|
|
13
|
+
|
|
14
|
+
export interface RenderDocOptions {
|
|
15
|
+
/** Editable surface: add `data-block-id` anchors + render empty blocks with a `<br>`. */
|
|
16
|
+
editable?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Replace how a link renders (e.g. a task/member chip). In the read-only viewer
|
|
19
|
+
* the returned node substitutes the `<a>` directly; on an editable surface a
|
|
20
|
+
* substituted node is wrapped in an atomic, non-editable `[data-rich-link]`
|
|
21
|
+
* widget so the caret steps over it as a single unit. Return the supplied
|
|
22
|
+
* default node to keep the standard `<a>`.
|
|
23
|
+
*/
|
|
24
|
+
renderLink?: RenderLink;
|
|
25
|
+
/**
|
|
26
|
+
* Replace how a `mention` mark renders (e.g. an interactive member chip /
|
|
27
|
+
* popover trigger). In the read-only viewer the returned node substitutes the
|
|
28
|
+
* default mention span directly; on an editable surface a substituted node is
|
|
29
|
+
* wrapped in an atomic, non-editable `[data-rich-mention]` widget so the caret
|
|
30
|
+
* steps over it as a single unit. Return the supplied default node to keep the
|
|
31
|
+
* standard non-interactive mention span. Composes with `renderLink`.
|
|
32
|
+
*/
|
|
33
|
+
renderMention?: RenderMention;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Resolved options threaded through the render call chain (never module state).
|
|
37
|
+
interface ResolvedOptions {
|
|
38
|
+
editable: boolean;
|
|
39
|
+
renderLink?: RenderLink;
|
|
40
|
+
renderMention?: RenderMention;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Per-block element cache for CONTEXT-INDEPENDENT blocks only (paragraph, heading,
|
|
44
|
+
// blockquote, code_block, attachment). The model is immutable: a block keeps its
|
|
45
|
+
// reference across edits unless it changed, so an element built purely from
|
|
46
|
+
// (block + options) can be cached by block reference — reusing the same element
|
|
47
|
+
// lets React bail out of reconciling unchanged blocks (referential equality).
|
|
48
|
+
//
|
|
49
|
+
// Keyed in a WeakMap on the immutable Block object, so entries are GC'd with their
|
|
50
|
+
// block — no leak, no manual invalidation. The render options are part of the
|
|
51
|
+
// stored entry: a change to `editable`/`renderLink`/`renderMention` correctly
|
|
52
|
+
// misses the cache and rebuilds.
|
|
53
|
+
//
|
|
54
|
+
// LIST items (bullet_item/ordered_item) are NEVER cached here: their nested
|
|
55
|
+
// <ul>/<ol>/<li> shape depends on NEIGHBORS (grouping + relative depth), so a
|
|
56
|
+
// sibling change can alter a list item's output while its own reference is
|
|
57
|
+
// unchanged. They render fresh every time via collectList/renderListTree.
|
|
58
|
+
type BlockCacheEntry = {
|
|
59
|
+
editable: boolean;
|
|
60
|
+
renderLink?: RenderLink;
|
|
61
|
+
renderMention?: RenderMention;
|
|
62
|
+
el: ReactElement;
|
|
63
|
+
};
|
|
64
|
+
const blockCache = new WeakMap<Block, BlockCacheEntry>();
|
|
65
|
+
|
|
66
|
+
function cachedBlockEl(
|
|
67
|
+
block: Block,
|
|
68
|
+
editable: boolean,
|
|
69
|
+
renderLink: RenderLink | undefined,
|
|
70
|
+
renderMention: RenderMention | undefined,
|
|
71
|
+
build: () => ReactElement,
|
|
72
|
+
): ReactElement {
|
|
73
|
+
const hit = blockCache.get(block);
|
|
74
|
+
if (
|
|
75
|
+
hit &&
|
|
76
|
+
hit.editable === editable &&
|
|
77
|
+
hit.renderLink === renderLink &&
|
|
78
|
+
hit.renderMention === renderMention
|
|
79
|
+
) {
|
|
80
|
+
return hit.el;
|
|
81
|
+
}
|
|
82
|
+
const el = build();
|
|
83
|
+
blockCache.set(block, { editable, renderLink, renderMention, el });
|
|
84
|
+
return el;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function wrapMark(type: MarkType, mark: Mark, child: ReactNode): ReactNode {
|
|
88
|
+
switch (type) {
|
|
89
|
+
case 'bold':
|
|
90
|
+
return <strong>{child}</strong>;
|
|
91
|
+
case 'italic':
|
|
92
|
+
return <em>{child}</em>;
|
|
93
|
+
case 'underline':
|
|
94
|
+
return <u>{child}</u>;
|
|
95
|
+
case 'strike':
|
|
96
|
+
return <s>{child}</s>;
|
|
97
|
+
case 'code':
|
|
98
|
+
return <code>{child}</code>;
|
|
99
|
+
case 'textColor': {
|
|
100
|
+
// Resolve the palette key to a token-backed var. An unknown key yields no
|
|
101
|
+
// wrapper (never emit an empty `style`).
|
|
102
|
+
const value = mark.type === 'textColor' ? textColorVar(mark.color) : undefined;
|
|
103
|
+
return value ? <span style={{ color: value }}>{child}</span> : child;
|
|
104
|
+
}
|
|
105
|
+
case 'bgColor': {
|
|
106
|
+
const value = mark.type === 'bgColor' ? bgColorVar(mark.color) : undefined;
|
|
107
|
+
return value ? <span style={{ backgroundColor: value }}>{child}</span> : child;
|
|
108
|
+
}
|
|
109
|
+
case 'link': {
|
|
110
|
+
// The `renderLink` substitution is handled in `renderInlines` (which coalesces
|
|
111
|
+
// contiguous same-href runs into one logical link); here we only emit the
|
|
112
|
+
// default <a> for the unsubstituted path.
|
|
113
|
+
const href = mark.type === 'link' ? safeHref(mark.href) : undefined;
|
|
114
|
+
return (
|
|
115
|
+
<a href={href} rel="noopener noreferrer">
|
|
116
|
+
{child}
|
|
117
|
+
</a>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
case 'mention':
|
|
121
|
+
return (
|
|
122
|
+
<span
|
|
123
|
+
data-mention
|
|
124
|
+
data-mention-id={mark.type === 'mention' ? mark.id : undefined}
|
|
125
|
+
data-mention-label={mark.type === 'mention' ? mark.label : undefined}
|
|
126
|
+
>
|
|
127
|
+
{child}
|
|
128
|
+
</span>
|
|
129
|
+
);
|
|
130
|
+
default:
|
|
131
|
+
return child;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function renderRun(run: Inline, key: string): ReactNode {
|
|
136
|
+
const present = MARK_ORDER.filter((t) => run.marks.some((m) => m.type === t));
|
|
137
|
+
let node: ReactNode = run.text;
|
|
138
|
+
// Wrap innermost-first so present[0] (link) ends up outermost.
|
|
139
|
+
for (let i = present.length - 1; i >= 0; i -= 1) {
|
|
140
|
+
const type = present[i];
|
|
141
|
+
const mark = run.marks.find((m) => m.type === type)!;
|
|
142
|
+
node = wrapMark(type, mark, node);
|
|
143
|
+
}
|
|
144
|
+
return <Fragment key={key}>{node}</Fragment>;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function renderInlines(inlines: Inline[], opts: ResolvedOptions): ReactNode {
|
|
148
|
+
const out: ReactNode[] = [];
|
|
149
|
+
let i = 0;
|
|
150
|
+
while (i < inlines.length) {
|
|
151
|
+
const run = inlines[i];
|
|
152
|
+
const mm = run.marks.find((m) => m.type === 'mention');
|
|
153
|
+
const mention = mm && mm.type === 'mention' ? { id: mm.id, label: mm.label } : null;
|
|
154
|
+
if (opts.renderMention && mention) {
|
|
155
|
+
// Coalesce contiguous runs that share this exact mention (same id AND label)
|
|
156
|
+
// into ONE logical mention, so a mention split across runs (e.g. internal
|
|
157
|
+
// formatting, HTML import) resolves to a single chip — not one per run.
|
|
158
|
+
let j = i;
|
|
159
|
+
let text = '';
|
|
160
|
+
while (j < inlines.length) {
|
|
161
|
+
const m = inlines[j].marks.find((mk) => mk.type === 'mention');
|
|
162
|
+
if (!m || m.type !== 'mention' || m.id !== mention.id || m.label !== mention.label) break;
|
|
163
|
+
text += inlines[j].text;
|
|
164
|
+
j += 1;
|
|
165
|
+
}
|
|
166
|
+
const fallback = (
|
|
167
|
+
<span data-mention data-mention-id={mention.id} data-mention-label={mention.label}>
|
|
168
|
+
{text}
|
|
169
|
+
</span>
|
|
170
|
+
);
|
|
171
|
+
const custom = opts.renderMention(mention, fallback);
|
|
172
|
+
if (custom !== fallback) {
|
|
173
|
+
// Substituted: one node for the whole span. In the editor it's an atomic,
|
|
174
|
+
// non-editable widget tagged with the span's MODEL length (`data-len`).
|
|
175
|
+
const mkey = `m${i}:${mention.id}:${mention.label}`;
|
|
176
|
+
out.push(
|
|
177
|
+
opts.editable ? (
|
|
178
|
+
<span key={mkey} data-rich-mention data-len={text.length} contentEditable={false}>
|
|
179
|
+
{custom}
|
|
180
|
+
</span>
|
|
181
|
+
) : (
|
|
182
|
+
<Fragment key={mkey}>{custom}</Fragment>
|
|
183
|
+
),
|
|
184
|
+
);
|
|
185
|
+
i = j;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
// Consumer declined → fall through to the link/default handling below.
|
|
189
|
+
}
|
|
190
|
+
const lm = run.marks.find((m) => m.type === 'link');
|
|
191
|
+
const linkHref = lm && lm.type === 'link' ? lm.href : null;
|
|
192
|
+
const safe = opts.renderLink && linkHref != null ? safeHref(linkHref) : undefined;
|
|
193
|
+
if (safe) {
|
|
194
|
+
// Coalesce contiguous runs that share this exact link href into ONE logical
|
|
195
|
+
// link, so a link split across runs (e.g. internal formatting, HTML import)
|
|
196
|
+
// resolves to a single chip — not one chip per run.
|
|
197
|
+
let j = i;
|
|
198
|
+
let text = '';
|
|
199
|
+
while (j < inlines.length) {
|
|
200
|
+
const m = inlines[j].marks.find((mm) => mm.type === 'link');
|
|
201
|
+
if (!m || m.type !== 'link' || m.href !== linkHref) break;
|
|
202
|
+
text += inlines[j].text;
|
|
203
|
+
j += 1;
|
|
204
|
+
}
|
|
205
|
+
const fallback = (
|
|
206
|
+
<a href={safe} rel="noopener noreferrer">
|
|
207
|
+
{text}
|
|
208
|
+
</a>
|
|
209
|
+
);
|
|
210
|
+
const custom = opts.renderLink!({ href: safe, text }, fallback);
|
|
211
|
+
if (custom !== fallback) {
|
|
212
|
+
// Substituted: one node for the whole span. In the editor it's an atomic,
|
|
213
|
+
// non-editable widget tagged with the span's MODEL length (`data-len`).
|
|
214
|
+
const lkey = `l${i}:${linkHref}`;
|
|
215
|
+
out.push(
|
|
216
|
+
opts.editable ? (
|
|
217
|
+
<span key={lkey} data-rich-link data-len={text.length} contentEditable={false}>
|
|
218
|
+
{custom}
|
|
219
|
+
</span>
|
|
220
|
+
) : (
|
|
221
|
+
<Fragment key={lkey}>{custom}</Fragment>
|
|
222
|
+
),
|
|
223
|
+
);
|
|
224
|
+
i = j;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
// Consumer declined → fall through to normal per-run rendering (default <a>).
|
|
228
|
+
}
|
|
229
|
+
// Key folds in the run's mark signature (not just its index): when a run's
|
|
230
|
+
// formatting changes, React replaces its subtree cleanly instead of re-wrapping
|
|
231
|
+
// a live contentEditable text node in place (which orphaned text / reset colors).
|
|
232
|
+
out.push(renderRun(run, `${i}:${marksSignature(run.marks)}`));
|
|
233
|
+
i += 1;
|
|
234
|
+
}
|
|
235
|
+
return out;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function blockContent(block: Block, opts: ResolvedOptions): ReactNode {
|
|
239
|
+
if (opts.editable && runsLength(block.inlines) === 0) return <br />;
|
|
240
|
+
return renderInlines(block.inlines, opts);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Build the element for a single NON-LIST block. Pure in (block, opts): no
|
|
244
|
+
// position/index/depth/neighbor input (the effective depths computed in renderDoc
|
|
245
|
+
// are consumed only by the list path). Every branch returns a single top-level
|
|
246
|
+
// element carrying `key={block.id}` — so caching + reusing the reference preserves
|
|
247
|
+
// the key and lets React skip reconciling the block.
|
|
248
|
+
function buildBlock(block: Block, opts: ResolvedOptions): ReactElement {
|
|
249
|
+
const anchor = opts.editable ? { 'data-block-id': block.id } : undefined;
|
|
250
|
+
switch (block.type) {
|
|
251
|
+
case 'heading': {
|
|
252
|
+
const Tag = `h${block.level ?? 1}` as 'h1' | 'h2' | 'h3';
|
|
253
|
+
return (
|
|
254
|
+
<Tag key={block.id} {...anchor}>
|
|
255
|
+
{blockContent(block, opts)}
|
|
256
|
+
</Tag>
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
case 'blockquote':
|
|
260
|
+
return (
|
|
261
|
+
<blockquote key={block.id} {...anchor}>
|
|
262
|
+
{blockContent(block, opts)}
|
|
263
|
+
</blockquote>
|
|
264
|
+
);
|
|
265
|
+
case 'code_block':
|
|
266
|
+
return (
|
|
267
|
+
<pre key={block.id} {...anchor}>
|
|
268
|
+
<code>
|
|
269
|
+
{opts.editable && runsLength(block.inlines) === 0 ? <br /> : runsText(block.inlines)}
|
|
270
|
+
</code>
|
|
271
|
+
</pre>
|
|
272
|
+
);
|
|
273
|
+
case 'attachment':
|
|
274
|
+
return (
|
|
275
|
+
<figure
|
|
276
|
+
key={block.id}
|
|
277
|
+
{...anchor}
|
|
278
|
+
contentEditable={false}
|
|
279
|
+
data-attachment=""
|
|
280
|
+
data-align={block.align || undefined}
|
|
281
|
+
>
|
|
282
|
+
<RichTextAttachment block={block} editable={opts.editable} />
|
|
283
|
+
</figure>
|
|
284
|
+
);
|
|
285
|
+
case 'paragraph':
|
|
286
|
+
default:
|
|
287
|
+
return (
|
|
288
|
+
<p key={block.id} {...anchor}>
|
|
289
|
+
{blockContent(block, opts)}
|
|
290
|
+
</p>
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Cache wrapper for a non-list block: returns the cached element when the block
|
|
296
|
+
// reference AND the relevant options are unchanged, otherwise builds + stores it.
|
|
297
|
+
function renderBlock(block: Block, opts: ResolvedOptions): ReactElement {
|
|
298
|
+
return cachedBlockEl(block, opts.editable, opts.renderLink, opts.renderMention, () =>
|
|
299
|
+
buildBlock(block, opts),
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
interface ListItemNode {
|
|
304
|
+
key: string;
|
|
305
|
+
blockId: string;
|
|
306
|
+
content: ReactNode;
|
|
307
|
+
child: ReactNode | null;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Collect a list starting at `start`, at its base (effective) depth; items one
|
|
311
|
+
// level deeper recurse into a child list attached to the preceding item. Because
|
|
312
|
+
// `eff` is gap-free, a deeper run is always exactly base+1, so every item lands
|
|
313
|
+
// in exactly one list — no item is overwritten. Returns the items + next index.
|
|
314
|
+
function collectList(
|
|
315
|
+
blocks: Block[],
|
|
316
|
+
start: number,
|
|
317
|
+
eff: number[],
|
|
318
|
+
opts: ResolvedOptions,
|
|
319
|
+
): { tag: 'ul' | 'ol'; items: ListItemNode[]; next: number } {
|
|
320
|
+
const baseDepth = eff[start];
|
|
321
|
+
const tag = blocks[start].type === 'ordered_item' ? 'ol' : 'ul';
|
|
322
|
+
const items: ListItemNode[] = [];
|
|
323
|
+
let i = start;
|
|
324
|
+
while (i < blocks.length && isListItem(blocks[i])) {
|
|
325
|
+
const d = eff[i];
|
|
326
|
+
if (d < baseDepth) break;
|
|
327
|
+
if (d > baseDepth) {
|
|
328
|
+
const sub = collectList(blocks, i, eff, opts);
|
|
329
|
+
if (items.length > 0)
|
|
330
|
+
items[items.length - 1].child = renderListTree(sub.tag, sub.items, opts);
|
|
331
|
+
i = sub.next;
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
items.push({
|
|
335
|
+
key: blocks[i].id,
|
|
336
|
+
blockId: blocks[i].id,
|
|
337
|
+
content: blockContent(blocks[i], opts),
|
|
338
|
+
child: null,
|
|
339
|
+
});
|
|
340
|
+
i += 1;
|
|
341
|
+
}
|
|
342
|
+
return { tag, items, next: i };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function renderListTree(tag: 'ul' | 'ol', items: ListItemNode[], opts: ResolvedOptions): ReactNode {
|
|
346
|
+
const ListTag = tag;
|
|
347
|
+
return (
|
|
348
|
+
<ListTag>
|
|
349
|
+
{items.map((it) => (
|
|
350
|
+
<li key={it.key} {...(opts.editable ? { 'data-block-id': it.blockId } : {})}>
|
|
351
|
+
{it.content}
|
|
352
|
+
{it.child}
|
|
353
|
+
</li>
|
|
354
|
+
))}
|
|
355
|
+
</ListTag>
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Render a `RichDoc` to React nodes.
|
|
361
|
+
*
|
|
362
|
+
* Blocks map to semantic elements (`<p>`, `<h1|h2|h3>`, `<blockquote>`,
|
|
363
|
+
* `<pre><code>`). Consecutive list-item blocks are grouped back into `<ul>`/`<ol>`
|
|
364
|
+
* trees, with nesting reconstructed from each item's `depth` (the flat model is
|
|
365
|
+
* lossy-free: depths are normalized gap-free first, so malformed depth jumps
|
|
366
|
+
* never drop items). Inline runs render as nested mark tags in a deterministic
|
|
367
|
+
* order (`link` outermost … `code` innermost). Block `id` is the React key. An
|
|
368
|
+
* empty document renders nothing. `code_block` content is treated as plain text.
|
|
369
|
+
*
|
|
370
|
+
* Pass `{ editable: true }` to add `data-block-id` anchors on every block element
|
|
371
|
+
* and render empty blocks with a `<br>` (required for contentEditable caret placement).
|
|
372
|
+
* Read-only output (default) is byte-identical to the pre-options behaviour.
|
|
373
|
+
*/
|
|
374
|
+
export function renderDoc(doc: RichDoc, options: RenderDocOptions = {}): ReactNode {
|
|
375
|
+
const opts: ResolvedOptions = {
|
|
376
|
+
editable: options.editable ?? false,
|
|
377
|
+
renderLink: options.renderLink,
|
|
378
|
+
renderMention: options.renderMention,
|
|
379
|
+
};
|
|
380
|
+
const eff = effectiveDepths(doc.blocks);
|
|
381
|
+
const out: ReactNode[] = [];
|
|
382
|
+
let i = 0;
|
|
383
|
+
while (i < doc.blocks.length) {
|
|
384
|
+
if (isListItem(doc.blocks[i])) {
|
|
385
|
+
const startId = doc.blocks[i].id;
|
|
386
|
+
const { tag, items, next } = collectList(doc.blocks, i, eff, opts);
|
|
387
|
+
out.push(<Fragment key={`list-${startId}`}>{renderListTree(tag, items, opts)}</Fragment>);
|
|
388
|
+
i = next;
|
|
389
|
+
} else {
|
|
390
|
+
out.push(renderBlock(doc.blocks[i], opts));
|
|
391
|
+
i += 1;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return out;
|
|
395
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/** A link encountered while rendering, passed to `renderLink`. */
|
|
4
|
+
export interface RichTextLink {
|
|
5
|
+
/** The sanitized URL. */
|
|
6
|
+
href: string;
|
|
7
|
+
/** The link's visible text in the document. */
|
|
8
|
+
text: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Replace how a link renders. Return your own node (e.g. a task/member chip) to
|
|
13
|
+
* substitute the link, or `defaultNode` for the standard `<a>`.
|
|
14
|
+
*/
|
|
15
|
+
export type RenderLink = (link: RichTextLink, defaultNode: ReactNode) => ReactNode;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/** A mention encountered while rendering, passed to `renderMention`. */
|
|
4
|
+
export interface RichTextMention {
|
|
5
|
+
/** The mention's stable id (from the `mention` mark). */
|
|
6
|
+
id: string;
|
|
7
|
+
/** The mention's display label (without the trigger). */
|
|
8
|
+
label: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Replace how a `mention` mark renders. Return your own node (e.g. an interactive
|
|
13
|
+
* member chip / popover trigger) to substitute the mention, or `defaultNode` for
|
|
14
|
+
* the standard non-interactive mention span. Mirrors {@link RenderLink}.
|
|
15
|
+
*/
|
|
16
|
+
export type RenderMention = (mention: RichTextMention, defaultNode: ReactNode) => ReactNode;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// safeHref.ts — the canonical, render-independent URL allowlist shared by the
|
|
2
|
+
// renderer (renderDoc) and the HTML importer (fromHtml). It is the SOLE scheme
|
|
3
|
+
// gate for hrefs that enter the model from untrusted input, so it must normalize
|
|
4
|
+
// URLs the way browsers do before resolving a scheme. Allows relative URLs + a
|
|
5
|
+
// small scheme allowlist; blocks javascript:/data:/protocol-relative.
|
|
6
|
+
export function safeHref(href: string): string | undefined {
|
|
7
|
+
// Browsers strip ASCII tab/LF/CR from anywhere in a URL, and drop leading C0
|
|
8
|
+
// controls + spaces, before resolving the scheme — so `java\tscript:` and
|
|
9
|
+
// `\x01javascript:` would both navigate as javascript:. Normalize the same way
|
|
10
|
+
// so the scheme allowlist below can't be smuggled past with embedded or leading
|
|
11
|
+
// control characters.
|
|
12
|
+
const trimmed = href.replace(/[\t\n\r]/g, '').replace(/^[\x00-\x20]+|[\x00-\x20]+$/g, '');
|
|
13
|
+
if (trimmed === '') return undefined;
|
|
14
|
+
// Block protocol-relative URLs (`//host`) — they navigate cross-origin and
|
|
15
|
+
// would otherwise slip through the "relative" branch below.
|
|
16
|
+
if (trimmed.startsWith('//')) return undefined;
|
|
17
|
+
// Has an explicit scheme? Only http(s)/mailto/tel are allowed.
|
|
18
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) {
|
|
19
|
+
return /^(https?:|mailto:|tel:)/i.test(trimmed) ? trimmed : undefined;
|
|
20
|
+
}
|
|
21
|
+
return trimmed; // relative (/, ./, #, ?, plain path) — safe
|
|
22
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// toHtml.ts — serialize a RichDoc to a compact HTML string. The inverse of
|
|
2
|
+
// fromHtml; mirrors renderDoc's structure (block elements, mark nesting order,
|
|
3
|
+
// list-depth grouping) but emits a string. Text/attributes are escaped and hrefs
|
|
4
|
+
// run through safeHref, so output is injection-safe. Lossless for the model
|
|
5
|
+
// (underline → <u>), so fromHtml(toHtml(doc)) reproduces the document.
|
|
6
|
+
import type { RichDoc, Block, Inline, Mark, MarkType } from './model';
|
|
7
|
+
import { runsText } from './inlines';
|
|
8
|
+
import { escapeHtml, escapeAttr } from './escape';
|
|
9
|
+
import { safeHref } from './safeHref';
|
|
10
|
+
import { textColorVar, bgColorVar } from './colorMarks';
|
|
11
|
+
import { isListItem, effectiveDepths } from './listDepths';
|
|
12
|
+
import { attachmentIsImage } from './attachment';
|
|
13
|
+
import { MARK_ORDER } from './marks';
|
|
14
|
+
|
|
15
|
+
/** Wrap an already-escaped HTML string in one mark's tag. */
|
|
16
|
+
function wrapMark(type: MarkType, mark: Mark, inner: string): string {
|
|
17
|
+
switch (type) {
|
|
18
|
+
case 'bold':
|
|
19
|
+
return `<strong>${inner}</strong>`;
|
|
20
|
+
case 'italic':
|
|
21
|
+
return `<em>${inner}</em>`;
|
|
22
|
+
case 'underline':
|
|
23
|
+
return `<u>${inner}</u>`;
|
|
24
|
+
case 'strike':
|
|
25
|
+
return `<s>${inner}</s>`;
|
|
26
|
+
case 'code':
|
|
27
|
+
return `<code>${inner}</code>`;
|
|
28
|
+
case 'textColor': {
|
|
29
|
+
// Resolve the palette key to a token-backed var; an unknown key drops the
|
|
30
|
+
// wrapper (never emit an empty/bogus style). The value is from a fixed
|
|
31
|
+
// allowlist, so it needs no attribute escaping.
|
|
32
|
+
const value = mark.type === 'textColor' ? textColorVar(mark.color) : undefined;
|
|
33
|
+
return value ? `<span style="color:${value}">${inner}</span>` : inner;
|
|
34
|
+
}
|
|
35
|
+
case 'bgColor': {
|
|
36
|
+
const value = mark.type === 'bgColor' ? bgColorVar(mark.color) : undefined;
|
|
37
|
+
return value ? `<span style="background-color:${value}">${inner}</span>` : inner;
|
|
38
|
+
}
|
|
39
|
+
case 'link': {
|
|
40
|
+
const safe = mark.type === 'link' ? safeHref(mark.href) : undefined;
|
|
41
|
+
if (safe === undefined) return inner; // unsafe href → drop the anchor, keep text
|
|
42
|
+
return `<a href="${escapeAttr(safe)}" rel="noopener noreferrer">${inner}</a>`;
|
|
43
|
+
}
|
|
44
|
+
case 'mention': {
|
|
45
|
+
if (mark.type !== 'mention') return inner;
|
|
46
|
+
return `<span data-mention-id="${escapeAttr(mark.id)}" data-mention-label="${escapeAttr(mark.label)}">${inner}</span>`;
|
|
47
|
+
}
|
|
48
|
+
default:
|
|
49
|
+
return inner;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Serialize one inline run: escaped text wrapped innermost-first. */
|
|
54
|
+
function inlineRun(run: Inline): string {
|
|
55
|
+
const present = MARK_ORDER.filter((t) => run.marks.some((m) => m.type === t));
|
|
56
|
+
let html = escapeHtml(run.text);
|
|
57
|
+
for (let i = present.length - 1; i >= 0; i -= 1) {
|
|
58
|
+
const type = present[i];
|
|
59
|
+
const mark = run.marks.find((m) => m.type === type)!;
|
|
60
|
+
html = wrapMark(type, mark, html);
|
|
61
|
+
}
|
|
62
|
+
return html;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const inlines = (block: Block): string => block.inlines.map(inlineRun).join('');
|
|
66
|
+
|
|
67
|
+
/** Serialize a contiguous run of list items starting at `start` (its base depth). */
|
|
68
|
+
function listHtml(blocks: Block[], start: number, eff: number[]): [string, number] {
|
|
69
|
+
const base = eff[start];
|
|
70
|
+
const tag = blocks[start].type === 'ordered_item' ? 'ol' : 'ul';
|
|
71
|
+
const items: string[] = [];
|
|
72
|
+
let i = start;
|
|
73
|
+
while (i < blocks.length && isListItem(blocks[i])) {
|
|
74
|
+
const d = eff[i];
|
|
75
|
+
if (d < base) break;
|
|
76
|
+
if (d > base) {
|
|
77
|
+
const [child, next] = listHtml(blocks, i, eff);
|
|
78
|
+
if (items.length > 0) {
|
|
79
|
+
items[items.length - 1] = items[items.length - 1].replace(/<\/li>$/, `${child}</li>`);
|
|
80
|
+
}
|
|
81
|
+
i = next;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
items.push(`<li>${inlines(blocks[i])}</li>`);
|
|
85
|
+
i += 1;
|
|
86
|
+
}
|
|
87
|
+
return [`<${tag}>${items.join('')}</${tag}>`, i];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function blockHtml(block: Block): string {
|
|
91
|
+
switch (block.type) {
|
|
92
|
+
case 'heading': {
|
|
93
|
+
// Clamp to the model's h1–h3 range so a hand-built doc with an out-of-range
|
|
94
|
+
// level never emits a malformed <undefined>/<h0> tag.
|
|
95
|
+
const tag = `h${Math.min(3, Math.max(1, block.level ?? 1))}`;
|
|
96
|
+
return `<${tag}>${inlines(block)}</${tag}>`;
|
|
97
|
+
}
|
|
98
|
+
case 'blockquote':
|
|
99
|
+
return `<blockquote>${inlines(block)}</blockquote>`;
|
|
100
|
+
case 'code_block':
|
|
101
|
+
return `<pre><code>${escapeHtml(runsText(block.inlines))}</code></pre>`;
|
|
102
|
+
case 'attachment': {
|
|
103
|
+
// Only finalized (ready/absent-status) attachments serialize; in-flight or
|
|
104
|
+
// failed uploads emit nothing.
|
|
105
|
+
if (block.status && block.status !== 'ready') return '';
|
|
106
|
+
const safe = safeHref(block.src ?? '');
|
|
107
|
+
if (safe === undefined) return '';
|
|
108
|
+
if (attachmentIsImage(block)) {
|
|
109
|
+
const alt = escapeAttr(block.alt ?? block.name ?? '');
|
|
110
|
+
const widthAttr = typeof block.width === 'number' ? ` width="${block.width}"` : '';
|
|
111
|
+
const heightAttr = typeof block.height === 'number' ? ` height="${block.height}"` : '';
|
|
112
|
+
const figStyle =
|
|
113
|
+
block.align === 'center' || block.align === 'right'
|
|
114
|
+
? ` style="text-align:${block.align}"`
|
|
115
|
+
: '';
|
|
116
|
+
return `<figure${figStyle}><img src="${escapeAttr(safe)}" alt="${alt}"${widthAttr}${heightAttr}></figure>`;
|
|
117
|
+
}
|
|
118
|
+
return `<a href="${escapeAttr(safe)}" download>${escapeHtml(block.name ?? safe)}</a>`;
|
|
119
|
+
}
|
|
120
|
+
case 'paragraph':
|
|
121
|
+
default:
|
|
122
|
+
return `<p>${inlines(block)}</p>`;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Serialize a `RichDoc` to a compact HTML string (the inverse of `fromHtml`).
|
|
128
|
+
* Text and attributes are escaped and hrefs run through `safeHref`, so the output
|
|
129
|
+
* is injection-safe. Lossless for the model — `fromHtml(toHtml(doc))` reproduces
|
|
130
|
+
* the document structurally.
|
|
131
|
+
*
|
|
132
|
+
* @remarks An unsafe href (rejected by `safeHref`) drops the `<a>` wrapper and
|
|
133
|
+
* emits the bare text — unlike `renderDoc`, which keeps a hrefless `<a>`. Both are
|
|
134
|
+
* safe and `fromHtml(toHtml(doc))` stays consistent (neither yields a link mark).
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* const html = toHtml(doc); // '<h2>Title</h2><p>Hello <strong>world</strong></p>'
|
|
138
|
+
*/
|
|
139
|
+
export function toHtml(doc: RichDoc): string {
|
|
140
|
+
const eff = effectiveDepths(doc.blocks);
|
|
141
|
+
let out = '';
|
|
142
|
+
let i = 0;
|
|
143
|
+
while (i < doc.blocks.length) {
|
|
144
|
+
if (isListItem(doc.blocks[i])) {
|
|
145
|
+
const [html, next] = listHtml(doc.blocks, i, eff);
|
|
146
|
+
out += html;
|
|
147
|
+
i = next;
|
|
148
|
+
} else {
|
|
149
|
+
out += blockHtml(doc.blocks[i]);
|
|
150
|
+
i += 1;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|