@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,506 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useCallback,
|
|
3
|
+
useEffect,
|
|
4
|
+
useId,
|
|
5
|
+
useLayoutEffect,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
type CSSProperties,
|
|
9
|
+
type MouseEvent as ReactMouseEvent,
|
|
10
|
+
type ReactNode,
|
|
11
|
+
} from 'react';
|
|
12
|
+
import { createPortal } from 'react-dom';
|
|
13
|
+
import clsx from 'clsx';
|
|
14
|
+
import { ChevronLeft, ChevronRight, Download, FileText, X } from 'lucide-react';
|
|
15
|
+
import { Image } from '../Image';
|
|
16
|
+
import { Skeleton } from '../Skeleton';
|
|
17
|
+
import { useFocusTrap } from '../_internal/overlay/useFocusTrap';
|
|
18
|
+
import { useScrollLock } from '../_internal/overlay/useScrollLock';
|
|
19
|
+
import { overlayStack, restoreFocusTo, useOverlayStack } from '../_internal/overlay';
|
|
20
|
+
import { useTranslation } from '../../i18n/useTranslation';
|
|
21
|
+
import styles from './Lightbox.module.scss';
|
|
22
|
+
|
|
23
|
+
/** One item (image or document) in a `<Lightbox>`. */
|
|
24
|
+
export interface LightboxItem {
|
|
25
|
+
/** Full-size source URL (an image, or a PDF/document when `kind: 'pdf'`). */
|
|
26
|
+
src: string;
|
|
27
|
+
/** Alt text / document name (required — the accessible stage + thumbnail name). */
|
|
28
|
+
alt: string;
|
|
29
|
+
/** Item kind. Defaults to `'image'`, or `'pdf'` when `src` ends in `.pdf`. A
|
|
30
|
+
* `pdf` item renders in an `<iframe>` (the browser's PDF viewer) with a download
|
|
31
|
+
* action instead of an `<img>`. Security: the PDF iframe is NOT sandboxed (Chrome
|
|
32
|
+
* blocks its PDF viewer in any sandboxed frame), so a `pdf` `src` MUST be a trusted
|
|
33
|
+
* URL — the scheme is restricted to http(s)/relative, but a URL that returns HTML
|
|
34
|
+
* instead of a PDF would run with its own origin's privileges. */
|
|
35
|
+
kind?: 'image' | 'pdf';
|
|
36
|
+
/** Optional caption shown below the stage. */
|
|
37
|
+
caption?: ReactNode;
|
|
38
|
+
/** Optional thumbnail URL for the strip. Images default to `src`; a `pdf` item
|
|
39
|
+
* without a thumbnail shows a document-icon placeholder. */
|
|
40
|
+
thumbnail?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const isPdfSrc = (src: string) => /\.pdf($|[?#])/i.test(src);
|
|
44
|
+
const itemKind = (it: LightboxItem): 'image' | 'pdf' =>
|
|
45
|
+
it.kind ?? (isPdfSrc(it.src) ? 'pdf' : 'image');
|
|
46
|
+
|
|
47
|
+
/** Allow only http(s) + relative URLs as an iframe/document src (block
|
|
48
|
+
* javascript:/data: etc). Returns the original src when safe, else undefined. */
|
|
49
|
+
function safeDocSrc(src: string): string | undefined {
|
|
50
|
+
try {
|
|
51
|
+
const u = new URL(src, 'https://_'); // dummy base resolves relative URLs
|
|
52
|
+
return u.protocol === 'http:' || u.protocol === 'https:' ? src : undefined;
|
|
53
|
+
} catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface LightboxProps {
|
|
59
|
+
/** Controlled open state. */
|
|
60
|
+
open: boolean;
|
|
61
|
+
/** Fired when the Lightbox wants to close — Esc, backdrop click, the × button. */
|
|
62
|
+
onOpenChange: (open: boolean) => void;
|
|
63
|
+
/**
|
|
64
|
+
* The images and documents (mixed galleries are supported; see `kind` on
|
|
65
|
+
* `LightboxItem` for PDFs). A PDF without a `thumbnail` shows a document-icon
|
|
66
|
+
* placeholder in the strip; an unsafe (non-http(s)) document `src` shows a
|
|
67
|
+
* "Preview unavailable" message. An empty array renders nothing and behaves as
|
|
68
|
+
* closed (no inert page, scroll lock or focus trap) even while `open`.
|
|
69
|
+
*/
|
|
70
|
+
items: LightboxItem[];
|
|
71
|
+
/** Initial image index (uncontrolled). Defaults to `0`. Clamped to range. */
|
|
72
|
+
defaultIndex?: number;
|
|
73
|
+
/** Controlled current index. When set, pair with `onIndexChange`. */
|
|
74
|
+
index?: number;
|
|
75
|
+
/** Fired on navigation (chevron / arrow key / thumbnail click). */
|
|
76
|
+
onIndexChange?: (index: number) => void;
|
|
77
|
+
/** Wrap past the first/last image. Defaults to `true`. */
|
|
78
|
+
loop?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Extra header actions for the current item (e.g. a Download `<Button>`, a
|
|
81
|
+
* `<DropdownMenu>` "more" menu). Called with the current item and its index on
|
|
82
|
+
* every render, so it follows navigation. Rendered in the top-right toolbar
|
|
83
|
+
* BEFORE the close button. Use `<Button iconOnly variant="ghost" size="sm">`
|
|
84
|
+
* (or a DropdownMenu trigger built from one) — the toolbar re-themes ghost
|
|
85
|
+
* Buttons for the dark scrim (ghost tokens, full radius, `sm` height = the
|
|
86
|
+
* toolbar control size), so text Buttons render pill-shaped — keep actions
|
|
87
|
+
* icon-only. While an action's menu or popover is open, Esc closes it first, and
|
|
88
|
+
* ←/→ stay with it (not the gallery) while focus is in it — likewise while focus
|
|
89
|
+
* is on a text field, combobox (Select), radio (ButtonGroup), slider, tab or
|
|
90
|
+
* expanded trigger; a Tooltip on an action doesn't block navigation. Returning `null`/`undefined` renders nothing.
|
|
91
|
+
* REPLACES the built-in PDF download link: when `actions` is set, the
|
|
92
|
+
* Lightbox renders no download action of its own — include your own
|
|
93
|
+
* Download for PDF items if you want one.
|
|
94
|
+
*/
|
|
95
|
+
actions?: (item: LightboxItem, index: number) => ReactNode;
|
|
96
|
+
/** className for the dialog container. */
|
|
97
|
+
className?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Accessible label for the dialog. Defaults to the i18n "Image gallery" when
|
|
100
|
+
* omitted OR empty — an empty string is not an explicit name, so it takes
|
|
101
|
+
* the default too.
|
|
102
|
+
*/
|
|
103
|
+
'aria-label'?: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// In-dialog elements that own ←/→ while focused: text entry, a Select-style
|
|
107
|
+
// combobox (focus stays on it while its listbox is open), arrow-driven widgets
|
|
108
|
+
// (ButtonGroup radios, Slider, Tabs) and any expanded trigger.
|
|
109
|
+
const ARROW_OWNING_CONTROL = [
|
|
110
|
+
'input:not([type="checkbox"], [type="button"], [type="submit"], [type="reset"], [type="file"], [type="image"])',
|
|
111
|
+
'textarea',
|
|
112
|
+
'select',
|
|
113
|
+
'[contenteditable]:not([contenteditable="false"])',
|
|
114
|
+
'[role="combobox"]',
|
|
115
|
+
'[role="radio"]',
|
|
116
|
+
'[role="slider"]',
|
|
117
|
+
'[role="tab"]',
|
|
118
|
+
'[aria-expanded="true"]',
|
|
119
|
+
].join(', ');
|
|
120
|
+
|
|
121
|
+
const clampIndex = (i: number, n: number) => Math.min(Math.max(i, 0), Math.max(n - 1, 0));
|
|
122
|
+
const wrapIndex = (i: number, n: number) => ((i % n) + n) % n;
|
|
123
|
+
|
|
124
|
+
// Body children matching these are NOT made inert when the Lightbox is on top —
|
|
125
|
+
// other overlay portals stay interactive (stacked overlays), mirroring Modal.
|
|
126
|
+
const PORTAL_EXEMPT =
|
|
127
|
+
'[data-lightbox-portal-root], [data-modal-portal-root], [data-drawer-portal-root]';
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Full-screen image and PDF gallery overlay with prev/next, thumbnail strip and optional captions; controlled `open`.
|
|
131
|
+
* @see docs/components/Lightbox.md
|
|
132
|
+
*/
|
|
133
|
+
export function Lightbox({
|
|
134
|
+
open: openProp,
|
|
135
|
+
onOpenChange,
|
|
136
|
+
items,
|
|
137
|
+
defaultIndex = 0,
|
|
138
|
+
index,
|
|
139
|
+
onIndexChange,
|
|
140
|
+
loop = true,
|
|
141
|
+
actions,
|
|
142
|
+
className,
|
|
143
|
+
'aria-label': ariaLabel,
|
|
144
|
+
}: LightboxProps) {
|
|
145
|
+
const t = useTranslation();
|
|
146
|
+
const id = useId();
|
|
147
|
+
const n = items.length;
|
|
148
|
+
// An open Lightbox with nothing to show behaves as closed: no overlay-stack
|
|
149
|
+
// entry, inert background, scroll lock or focus trap (#612).
|
|
150
|
+
const open = openProp && n > 0;
|
|
151
|
+
const isControlled = index !== undefined;
|
|
152
|
+
|
|
153
|
+
const [internalIndex, setInternalIndex] = useState(() => clampIndex(defaultIndex, n));
|
|
154
|
+
const current = clampIndex(isControlled ? (index as number) : internalIndex, n);
|
|
155
|
+
|
|
156
|
+
const { depth, isTop } = useOverlayStack(id, open, 'replace');
|
|
157
|
+
|
|
158
|
+
// Focus restoration (WCAG 2.4.3, like Modal/Drawer). Split into two effects:
|
|
159
|
+
// - CAPTURE is a layout effect so it snapshots the trigger BEFORE focus moves
|
|
160
|
+
// into the dialog (the focus-into-dialog effect below is also layout).
|
|
161
|
+
// - RESTORE is a PASSIVE effect so it runs AFTER the inert-background cleanup
|
|
162
|
+
// (also passive) has removed `inert` from the trigger's subtree — otherwise
|
|
163
|
+
// `.focus()` would silently fail on a still-inert element (→ falls to <body>).
|
|
164
|
+
const previouslyFocusedRef = useRef<HTMLElement | null>(null);
|
|
165
|
+
const prevOpenRef = useRef<boolean>(open);
|
|
166
|
+
useLayoutEffect(() => {
|
|
167
|
+
if (open) previouslyFocusedRef.current = (document.activeElement as HTMLElement | null) ?? null;
|
|
168
|
+
}, [open]);
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
if (!open && prevOpenRef.current) {
|
|
171
|
+
const target = previouslyFocusedRef.current;
|
|
172
|
+
if (target && document.contains(target)) restoreFocusTo(target);
|
|
173
|
+
previouslyFocusedRef.current = null;
|
|
174
|
+
}
|
|
175
|
+
prevOpenRef.current = open;
|
|
176
|
+
}, [open]);
|
|
177
|
+
|
|
178
|
+
useScrollLock(open);
|
|
179
|
+
const dialogRef = useRef<HTMLDivElement | null>(null);
|
|
180
|
+
useFocusTrap(dialogRef, open && isTop);
|
|
181
|
+
|
|
182
|
+
// Reseed the uncontrolled index whenever the Lightbox (re)opens.
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
if (open && !isControlled) setInternalIndex(clampIndex(defaultIndex, n));
|
|
185
|
+
// Only on open transition — defaultIndex/n changes mid-open shouldn't yank the user.
|
|
186
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
187
|
+
}, [open]);
|
|
188
|
+
|
|
189
|
+
const goTo = useCallback(
|
|
190
|
+
(nextIndex: number) => {
|
|
191
|
+
if (n === 0) return;
|
|
192
|
+
const target = loop ? wrapIndex(nextIndex, n) : clampIndex(nextIndex, n);
|
|
193
|
+
if (target === current) return; // no-op move (e.g. an arrow key at a non-looping end)
|
|
194
|
+
if (!isControlled) setInternalIndex(target);
|
|
195
|
+
onIndexChange?.(target);
|
|
196
|
+
},
|
|
197
|
+
[n, loop, isControlled, onIndexChange, current],
|
|
198
|
+
);
|
|
199
|
+
const goNext = useCallback(() => goTo(current + 1), [goTo, current]);
|
|
200
|
+
const goPrev = useCallback(() => goTo(current - 1), [goTo, current]);
|
|
201
|
+
const close = useCallback(() => onOpenChange(false), [onOpenChange]);
|
|
202
|
+
|
|
203
|
+
// Per-image stage load/error state, reset when the source changes.
|
|
204
|
+
const currentItem: LightboxItem | undefined = items[current];
|
|
205
|
+
const currentSrc = currentItem?.src;
|
|
206
|
+
// Reset during render, not in an effect: a mount-time effect ran after a
|
|
207
|
+
// cached image's `load` and left the skeleton up for good (#574).
|
|
208
|
+
const [stageState, setStageState] = useState<'loading' | 'loaded' | 'error'>('loading');
|
|
209
|
+
const [prevSrc, setPrevSrc] = useState(currentSrc);
|
|
210
|
+
if (currentSrc !== prevSrc) {
|
|
211
|
+
setPrevSrc(currentSrc);
|
|
212
|
+
setStageState('loading');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Inert the rest of the page while we're the top overlay (mirrors Modal.Overlay).
|
|
216
|
+
useEffect(() => {
|
|
217
|
+
if (!open || !isTop) return;
|
|
218
|
+
const kids = Array.from(document.body.children) as HTMLElement[];
|
|
219
|
+
const restore: Array<{ el: HTMLElement; had: boolean }> = [];
|
|
220
|
+
for (const el of kids) {
|
|
221
|
+
if (el.matches(PORTAL_EXEMPT)) continue;
|
|
222
|
+
const had = el.hasAttribute('inert');
|
|
223
|
+
if (!had) el.setAttribute('inert', '');
|
|
224
|
+
restore.push({ el, had });
|
|
225
|
+
}
|
|
226
|
+
return () => {
|
|
227
|
+
for (const { el, had } of restore) if (!had) el.removeAttribute('inert');
|
|
228
|
+
};
|
|
229
|
+
}, [open, isTop]);
|
|
230
|
+
|
|
231
|
+
// Keyboard: Esc closes, ← → navigate (capture-phase + gated to top, like Modal.Content).
|
|
232
|
+
useEffect(() => {
|
|
233
|
+
if (!open || !isTop) return;
|
|
234
|
+
function onKeyDown(e: KeyboardEvent) {
|
|
235
|
+
// #274: yield Escape to an open floating surface — see Modal/Content.tsx.
|
|
236
|
+
if (
|
|
237
|
+
e.key === 'Escape' &&
|
|
238
|
+
(overlayStack.hasOpenFloating() || overlayStack.wasEscapeConsumed(e))
|
|
239
|
+
)
|
|
240
|
+
return;
|
|
241
|
+
// Arrows navigate only while focus is in the gallery itself. Focus outside the
|
|
242
|
+
// dialog means a portaled surface from an action has it (DropdownMenu,
|
|
243
|
+
// Popover/ConfirmationPopover, …) — navigating would retarget its still-open
|
|
244
|
+
// "Delete" at a different file. Not hasOpenFloating(): a Tooltip on a focused
|
|
245
|
+
// action is floating too, and must not kill navigation. Focus dropped to
|
|
246
|
+
// <body> (a focused action unmounted) still counts as the gallery.
|
|
247
|
+
if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
|
|
248
|
+
const active = document.activeElement as HTMLElement | null;
|
|
249
|
+
const inGallery =
|
|
250
|
+
!active || active === document.body || !!dialogRef.current?.contains(active);
|
|
251
|
+
if (!inGallery || active?.matches(ARROW_OWNING_CONTROL)) return;
|
|
252
|
+
}
|
|
253
|
+
if (e.key === 'Escape') {
|
|
254
|
+
e.stopPropagation();
|
|
255
|
+
close();
|
|
256
|
+
} else if (e.key === 'ArrowRight' && n > 1) {
|
|
257
|
+
e.preventDefault();
|
|
258
|
+
goNext();
|
|
259
|
+
} else if (e.key === 'ArrowLeft' && n > 1) {
|
|
260
|
+
e.preventDefault();
|
|
261
|
+
goPrev();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
document.addEventListener('keydown', onKeyDown, true);
|
|
265
|
+
return () => document.removeEventListener('keydown', onKeyDown, true);
|
|
266
|
+
}, [open, isTop, n, close, goNext, goPrev]);
|
|
267
|
+
|
|
268
|
+
// Move focus into the overlay on open. Gated to the OPEN transition only
|
|
269
|
+
// (like Modal/Drawer, #551): isTop also flips false -> true when a nested
|
|
270
|
+
// overlay (e.g. a Modal opened above the Lightbox) closes, and re-running
|
|
271
|
+
// unconditionally here would steal focus back from wherever that overlay
|
|
272
|
+
// restored it.
|
|
273
|
+
const initialFocusPendingRef = useRef(true);
|
|
274
|
+
useLayoutEffect(() => {
|
|
275
|
+
if (!open) {
|
|
276
|
+
initialFocusPendingRef.current = true;
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (!isTop || !initialFocusPendingRef.current) return;
|
|
280
|
+
initialFocusPendingRef.current = false;
|
|
281
|
+
dialogRef.current?.focus();
|
|
282
|
+
}, [open, isTop]);
|
|
283
|
+
|
|
284
|
+
// Keep the active thumbnail in view (guarded — jsdom has no scrollIntoView).
|
|
285
|
+
const thumbRefs = useRef<Array<HTMLDivElement | null>>([]);
|
|
286
|
+
useEffect(() => {
|
|
287
|
+
if (!open) return;
|
|
288
|
+
thumbRefs.current[current]?.scrollIntoView?.({ block: 'nearest', inline: 'center' });
|
|
289
|
+
}, [open, current]);
|
|
290
|
+
|
|
291
|
+
if (!open || n === 0 || !currentItem) return null;
|
|
292
|
+
|
|
293
|
+
const currentKind = itemKind(currentItem);
|
|
294
|
+
// Sanitized document URL (http(s)/relative only) for the current PDF item, or
|
|
295
|
+
// undefined when the item isn't a PDF or its src is unsafe. Computed once and
|
|
296
|
+
// reused by the download link, the stage iframe, and the unavailable fallback.
|
|
297
|
+
const docSrc = currentKind === 'pdf' ? safeDocSrc(currentItem.src) : undefined;
|
|
298
|
+
const multi = n > 1;
|
|
299
|
+
const atStart = current === 0;
|
|
300
|
+
const atEnd = current === n - 1;
|
|
301
|
+
|
|
302
|
+
const closeIfBackdrop = (e: ReactMouseEvent<HTMLDivElement>) => {
|
|
303
|
+
if (e.target === e.currentTarget) close();
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const style = { ['--lightbox-depth' as string]: String(depth ?? 0) } as CSSProperties;
|
|
307
|
+
|
|
308
|
+
return createPortal(
|
|
309
|
+
<div
|
|
310
|
+
data-lightbox-portal-root=""
|
|
311
|
+
ref={dialogRef}
|
|
312
|
+
role="dialog"
|
|
313
|
+
aria-modal="true"
|
|
314
|
+
aria-label={ariaLabel || t('lightbox.label')}
|
|
315
|
+
tabIndex={-1}
|
|
316
|
+
className={clsx(styles.root, className)}
|
|
317
|
+
style={style}
|
|
318
|
+
onClick={closeIfBackdrop}
|
|
319
|
+
>
|
|
320
|
+
{/* Top-right chrome: [consumer actions | built-in PDF download][close]. */}
|
|
321
|
+
<div className={styles.toolbar}>
|
|
322
|
+
{actions ? (
|
|
323
|
+
actions(currentItem, current)
|
|
324
|
+
) : docSrc ? (
|
|
325
|
+
<a
|
|
326
|
+
className={styles.download}
|
|
327
|
+
href={docSrc}
|
|
328
|
+
download
|
|
329
|
+
// Open/save in a new tab: a cross-origin `download` is ignored by the
|
|
330
|
+
// browser, so without target the click would navigate the whole app
|
|
331
|
+
// away from the gallery. noopener/noreferrer guard the opened context.
|
|
332
|
+
target="_blank"
|
|
333
|
+
rel="noopener noreferrer"
|
|
334
|
+
aria-label={t('lightbox.download')}
|
|
335
|
+
>
|
|
336
|
+
<Download size={20} aria-hidden="true" />
|
|
337
|
+
</a>
|
|
338
|
+
) : null}
|
|
339
|
+
|
|
340
|
+
<button
|
|
341
|
+
type="button"
|
|
342
|
+
className={styles.close}
|
|
343
|
+
aria-label={t('lightbox.close')}
|
|
344
|
+
onClick={close}
|
|
345
|
+
>
|
|
346
|
+
<X size={20} aria-hidden="true" />
|
|
347
|
+
</button>
|
|
348
|
+
</div>
|
|
349
|
+
|
|
350
|
+
<div className={styles.stage} onClick={closeIfBackdrop}>
|
|
351
|
+
{multi && (
|
|
352
|
+
<button
|
|
353
|
+
type="button"
|
|
354
|
+
className={clsx(styles.chev, styles.chevPrev)}
|
|
355
|
+
aria-label={t('lightbox.previous')}
|
|
356
|
+
onClick={goPrev}
|
|
357
|
+
disabled={!loop && atStart}
|
|
358
|
+
>
|
|
359
|
+
<ChevronLeft size={28} aria-hidden="true" />
|
|
360
|
+
</button>
|
|
361
|
+
)}
|
|
362
|
+
|
|
363
|
+
<div className={styles.imageWrap}>
|
|
364
|
+
{currentKind === 'pdf' ? (
|
|
365
|
+
docSrc ? (
|
|
366
|
+
<iframe
|
|
367
|
+
key={docSrc}
|
|
368
|
+
src={docSrc}
|
|
369
|
+
title={currentItem.alt}
|
|
370
|
+
className={styles.doc}
|
|
371
|
+
referrerPolicy="no-referrer"
|
|
372
|
+
// No `sandbox`: a PDF is rendered by the browser's own PDF engine
|
|
373
|
+
// (PDFium / pdf.js), which already isolates the PDF's JS from the
|
|
374
|
+
// page — so a sandbox adds nothing for PDF content while BLOCKING
|
|
375
|
+
// Chrome's PDF viewer entirely ("This page has been blocked by
|
|
376
|
+
// Chrome"; Chrome refuses to render PDFs in ANY sandboxed iframe,
|
|
377
|
+
// regardless of allow-* tokens). `referrerPolicy="no-referrer"` and the
|
|
378
|
+
// http(s)/relative-only `safeDocSrc` check (blocks javascript:/data:/
|
|
379
|
+
// blob:) defend against SCHEME attacks; a URL that returns HTML instead
|
|
380
|
+
// of a PDF would run unsandboxed, so this path relies on the documented
|
|
381
|
+
// contract that the consumer frames its own trusted file URLs.
|
|
382
|
+
/>
|
|
383
|
+
) : (
|
|
384
|
+
<div
|
|
385
|
+
className={styles.stageError}
|
|
386
|
+
role="img"
|
|
387
|
+
/* Guarded, unlike before: an item with an empty `alt` produced
|
|
388
|
+
a name of ": Preview unavailable", leading with punctuation.
|
|
389
|
+
`role="img"` is safe HERE — the only child is text the label
|
|
390
|
+
already repeats, so children-presentational prunes nothing a
|
|
391
|
+
user needed. Do NOT copy this shape onto a tile containing a
|
|
392
|
+
control: that is what broke Image's Retry button (#496). */
|
|
393
|
+
aria-label={
|
|
394
|
+
currentItem.alt
|
|
395
|
+
? `${currentItem.alt}: ${t('lightbox.previewUnavailable')}`
|
|
396
|
+
: t('lightbox.previewUnavailable')
|
|
397
|
+
}
|
|
398
|
+
>
|
|
399
|
+
{t('lightbox.previewUnavailable')}
|
|
400
|
+
</div>
|
|
401
|
+
)
|
|
402
|
+
) : (
|
|
403
|
+
<>
|
|
404
|
+
<img
|
|
405
|
+
key={currentItem.src}
|
|
406
|
+
src={currentItem.src}
|
|
407
|
+
alt={currentItem.alt}
|
|
408
|
+
className={styles.image}
|
|
409
|
+
data-state={stageState}
|
|
410
|
+
onLoad={() => setStageState('loaded')}
|
|
411
|
+
onError={() => setStageState('error')}
|
|
412
|
+
/>
|
|
413
|
+
{stageState === 'loading' && (
|
|
414
|
+
<Skeleton variant="rectangular" className={styles.stageOverlay} />
|
|
415
|
+
)}
|
|
416
|
+
{stageState === 'error' && (
|
|
417
|
+
<div
|
|
418
|
+
className={styles.stageError}
|
|
419
|
+
role="img"
|
|
420
|
+
/* Concatenated, where Image's tile deliberately is NOT —
|
|
421
|
+
the difference is markup, not policy. Here the text is a
|
|
422
|
+
CHILD of `role="img"`, so children-presentational prunes
|
|
423
|
+
it and the name is the only thing left to say it. In Image
|
|
424
|
+
the text is a SIBLING that survives, so concatenating made
|
|
425
|
+
a reader hear the failure twice. `role="img"` stays on the
|
|
426
|
+
container here because the only child is that text; Image
|
|
427
|
+
had to move it onto the icon, whose Retry button the role
|
|
428
|
+
pruned outright. */
|
|
429
|
+
aria-label={
|
|
430
|
+
currentItem.alt
|
|
431
|
+
? `${currentItem.alt}: ${t('image.loadError')}`
|
|
432
|
+
: t('image.loadError')
|
|
433
|
+
}
|
|
434
|
+
>
|
|
435
|
+
{t('image.loadError')}
|
|
436
|
+
</div>
|
|
437
|
+
)}
|
|
438
|
+
</>
|
|
439
|
+
)}
|
|
440
|
+
</div>
|
|
441
|
+
|
|
442
|
+
{multi && (
|
|
443
|
+
<button
|
|
444
|
+
type="button"
|
|
445
|
+
className={clsx(styles.chev, styles.chevNext)}
|
|
446
|
+
aria-label={t('lightbox.next')}
|
|
447
|
+
onClick={goNext}
|
|
448
|
+
disabled={!loop && atEnd}
|
|
449
|
+
>
|
|
450
|
+
<ChevronRight size={28} aria-hidden="true" />
|
|
451
|
+
</button>
|
|
452
|
+
)}
|
|
453
|
+
</div>
|
|
454
|
+
|
|
455
|
+
{(currentItem.caption != null || multi) && (
|
|
456
|
+
<div className={styles.meta}>
|
|
457
|
+
{currentItem.caption != null && (
|
|
458
|
+
<div className={styles.caption}>{currentItem.caption}</div>
|
|
459
|
+
)}
|
|
460
|
+
{multi && (
|
|
461
|
+
<div className={styles.counter}>
|
|
462
|
+
{current + 1} / {n}
|
|
463
|
+
</div>
|
|
464
|
+
)}
|
|
465
|
+
</div>
|
|
466
|
+
)}
|
|
467
|
+
|
|
468
|
+
{multi && (
|
|
469
|
+
<div className={styles.thumbs}>
|
|
470
|
+
{items.map((it, i) => (
|
|
471
|
+
<div
|
|
472
|
+
key={i}
|
|
473
|
+
ref={(el) => {
|
|
474
|
+
thumbRefs.current[i] = el;
|
|
475
|
+
}}
|
|
476
|
+
className={clsx(styles.thumb, i === current && styles.thumbActive)}
|
|
477
|
+
>
|
|
478
|
+
{itemKind(it) === 'pdf' && !it.thumbnail ? (
|
|
479
|
+
<button
|
|
480
|
+
type="button"
|
|
481
|
+
className={styles.thumbDoc}
|
|
482
|
+
aria-label={it.alt}
|
|
483
|
+
onClick={() => goTo(i)}
|
|
484
|
+
>
|
|
485
|
+
<FileText size={20} aria-hidden="true" />
|
|
486
|
+
</button>
|
|
487
|
+
) : (
|
|
488
|
+
<Image
|
|
489
|
+
src={it.thumbnail ?? it.src}
|
|
490
|
+
alt=""
|
|
491
|
+
aspectRatio={1}
|
|
492
|
+
objectFit="cover"
|
|
493
|
+
interactive
|
|
494
|
+
onClick={() => goTo(i)}
|
|
495
|
+
ariaLabel={it.alt}
|
|
496
|
+
/>
|
|
497
|
+
)}
|
|
498
|
+
</div>
|
|
499
|
+
))}
|
|
500
|
+
</div>
|
|
501
|
+
)}
|
|
502
|
+
</div>,
|
|
503
|
+
document.body,
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
Lightbox.displayName = 'Lightbox';
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
@use '../../styles/mixins' as *;
|
|
2
|
+
@use './Link.tokens';
|
|
3
|
+
|
|
4
|
+
.link {
|
|
5
|
+
// A link-styled control rendered via `as` on a non-anchor (e.g. `as="button"`)
|
|
6
|
+
// gets no pointer cursor from the UA — only `<a>` does — so set it explicitly.
|
|
7
|
+
// Makes the affordance element-agnostic (like how Button owns its own cursor).
|
|
8
|
+
cursor: pointer;
|
|
9
|
+
font-family: inherit;
|
|
10
|
+
font-size: inherit;
|
|
11
|
+
color: inherit;
|
|
12
|
+
text-decoration: none;
|
|
13
|
+
border-radius: var(--link-radius);
|
|
14
|
+
transition:
|
|
15
|
+
color var(--transition-fast),
|
|
16
|
+
text-decoration-color var(--transition-fast);
|
|
17
|
+
|
|
18
|
+
&:focus-visible {
|
|
19
|
+
@include focus-ring;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// When the Link contains an icon (SVG), switch to inline-flex so the icon
|
|
23
|
+
// aligns vertically with the text and a default gap separates them. Pure
|
|
24
|
+
// text Links stay as native inline anchors so multi-word link text wraps
|
|
25
|
+
// naturally inside body copy.
|
|
26
|
+
&:has(svg) {
|
|
27
|
+
display: inline-flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
gap: var(--link-icon-gap);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.default {
|
|
34
|
+
color: var(--link-fg-default);
|
|
35
|
+
font-weight: var(--link-font-weight-default);
|
|
36
|
+
|
|
37
|
+
&:hover {
|
|
38
|
+
color: var(--link-fg-default-hover);
|
|
39
|
+
text-decoration: underline;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Already-bold text (headings, <strong>, table headers) keeps its own weight:
|
|
44
|
+
// an accent's link weight would otherwise render the link LIGHTER than its
|
|
45
|
+
// context. A semibold <Text> span isn't a bold element; see Link.md.
|
|
46
|
+
:is(strong, b, th, h1, h2, h3, h4, h5, h6) .default {
|
|
47
|
+
font-weight: inherit;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.muted {
|
|
51
|
+
color: var(--link-fg-muted);
|
|
52
|
+
|
|
53
|
+
&:hover {
|
|
54
|
+
color: var(--link-fg-muted-hover);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.subtle {
|
|
59
|
+
color: var(--link-fg-subtle);
|
|
60
|
+
|
|
61
|
+
&:hover {
|
|
62
|
+
color: var(--link-fg-subtle-hover);
|
|
63
|
+
text-decoration: underline;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// `underline` prop overrides. Combined with `.link` (always present on every
|
|
68
|
+
// Link element) each becomes a 2-class compound selector — 3 classes for the
|
|
69
|
+
// `:hover` override — so it reliably outranks a bare single-class variant
|
|
70
|
+
// rule (`.default`, `.muted`, `.subtle`) regardless of source order, without
|
|
71
|
+
// `!important`.
|
|
72
|
+
.link.underlineAlways {
|
|
73
|
+
text-decoration: underline;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.link.underlineNone:hover {
|
|
77
|
+
text-decoration: none;
|
|
78
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Link.tokens.scss — Component-scoped tokens for <Link>. Three variants:
|
|
2
|
+
// default (accent), muted (fg-muted -> accent on hover), subtle (fg -> accent
|
|
3
|
+
// on hover). Each variant has its own fg + fg-hover pair. Icon gap is shared.
|
|
4
|
+
:root {
|
|
5
|
+
// Shape + icon gap
|
|
6
|
+
--link-radius: var(--radius-sm);
|
|
7
|
+
--link-icon-gap: var(--space-1);
|
|
8
|
+
|
|
9
|
+
// Variant: default. --color-link-fg defaults to the accent; an accent set may
|
|
10
|
+
// override it when its accent is too close to body text to read as a link.
|
|
11
|
+
--link-fg-default: var(--color-link-fg);
|
|
12
|
+
--link-fg-default-hover: var(--color-link-fg-hover);
|
|
13
|
+
--link-font-weight-default: inherit;
|
|
14
|
+
|
|
15
|
+
// Variant: muted
|
|
16
|
+
--link-fg-muted: var(--color-fg-muted);
|
|
17
|
+
--link-fg-muted-hover: var(--color-accent);
|
|
18
|
+
|
|
19
|
+
// Variant: subtle
|
|
20
|
+
--link-fg-subtle: var(--color-fg);
|
|
21
|
+
--link-fg-subtle-hover: var(--color-accent);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Teal pine's accent sits close to the navy body text, so its default links
|
|
25
|
+
// also step up in weight (the colour alone can't carry the difference).
|
|
26
|
+
:root[data-accent='tealpine'] {
|
|
27
|
+
--link-font-weight-default: var(--font-weight-medium);
|
|
28
|
+
}
|