@stll/ui 0.8.0 → 0.9.0

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/README.md CHANGED
@@ -11,7 +11,7 @@ cannot reach into product code by accident. Lint enforces that boundary; the
11
11
  export map below is what "part of the design system" means.
12
12
 
13
13
  Peer dependencies: `react`, `react-dom`, `@base-ui/react`, `tailwindcss` (v4),
14
- `@dnd-kit/core`, and `@dnd-kit/sortable`.
14
+ `@dnd-kit/core`, `@dnd-kit/sortable`, and `@tanstack/react-virtual`.
15
15
 
16
16
  ## Import
17
17
 
@@ -58,10 +58,11 @@ spellings land on the same module for as long as they both exist.
58
58
 
59
59
  ## Sortable boards
60
60
 
61
- `@stll/ui/kanban` provides input and accessibility primitives only; the caller
62
- keeps item identifiers, order changes, and persisted mutations. Wrap the board
63
- in `KanbanSortableBoard`, render sortable items through `useKanbanSortable`,
64
- and attach the returned bindings to `KanbanDragHandle`.
61
+ `@stll/ui/kanban` provides board matrices, subgroup swimlanes, bounded virtual
62
+ cells, and input/accessibility primitives. The caller keeps domain identifiers,
63
+ card rendering, permissions, and persisted mutations. Wrap sortable boards in
64
+ `KanbanSortableBoard`, render items through `useKanbanSortable`, and attach the
65
+ returned bindings to `KanbanDragHandle`.
65
66
 
66
67
  ```tsx
67
68
  import {
@@ -100,6 +101,41 @@ auto-scroll options, and an `overlay` render function.
100
101
  `input: "keyboard"` and require source and target indices, so every move has a
101
102
  logical edge without relying on ambiguous geometry.
102
103
 
104
+ For Group/Sub-group boards, build one canonical matrix and render it with the
105
+ installable layout and virtual cell:
106
+
107
+ ```tsx
108
+ import {
109
+ KanbanSubgroupBoard,
110
+ KanbanVirtualCell,
111
+ buildKanbanBoardMatrix,
112
+ } from "@stll/ui/kanban";
113
+
114
+ const matrix = buildKanbanBoardMatrix({
115
+ group,
116
+ subgroup,
117
+ rows,
118
+ resolveGroupValue,
119
+ uncategorizedLabel: "No value",
120
+ });
121
+
122
+ <KanbanSubgroupBoard
123
+ matrix={matrix}
124
+ renderColumnHeader={({ column, count }) => (
125
+ <ColumnHeader column={column} count={count} />
126
+ )}
127
+ renderLaneIdentity={({ group: lane }) => <Lane group={lane} />}
128
+ renderCell={({ cell }) => (
129
+ <KanbanVirtualCell
130
+ getRowKey={(row) => row.id}
131
+ pagination={{ type: "none" }}
132
+ renderRow={(row) => <Card row={row} />}
133
+ rows={cell.rows}
134
+ />
135
+ )}
136
+ />;
137
+ ```
138
+
103
139
  ## Styles
104
140
 
105
141
  No compiled CSS ships. The components carry Tailwind class names, so the
package/dist/index.d.ts CHANGED
@@ -75,6 +75,9 @@ import { KANBAN_DIRECTIONS, KANBAN_HORIZONTAL_EDGES, KanbanDirection, KanbanHori
75
75
  import { KANBAN_BOARD_AUTO_SCROLL_SOURCES, RegisterKanbanBoardAutoScrollOptions, RegisterKanbanCardDragOptions, registerKanbanBoardAutoScroll, registerKanbanCardDrag } from "./kanban/drag-interactions.js";
76
76
  import { ColorVariants, OptionColor, emptyColor, optionColors, resolveOptionColor } from "./lib/option-color.js";
77
77
  import { KanbanBuiltInGroup, KanbanGroup, KanbanGroupOption, KanbanGrouping, KanbanSchema, ResolveKanbanGroupingParams, getKanbanGroupingPropertyId, getKanbanGroups, isKanbanGroupingRenderable, resolveKanbanGroupOptions, resolveKanbanGrouping, selectKanbanRows } from "./kanban/grouping.js";
78
+ import { BuildKanbanBoardMatrixParams, CreateKanbanDropIntentParams, KANBAN_BOARD_AXES, KanbanBoardAxis, KanbanBoardCell, KanbanBoardCoordinate, KanbanBoardLane, KanbanBoardMatrix, KanbanDropAxisChange, KanbanDropIntent, OrderKanbanCellsByColumnsParams, ResolveKanbanGroupValueParams, buildKanbanBoardMatrix, createKanbanDropIntent, orderKanbanCellsByColumns } from "./kanban/matrix.js";
79
+ import { KanbanSubgroupBoard, KanbanSubgroupBoardProps, KanbanSubgroupCellContext, KanbanSubgroupColumnHeaderContext, KanbanSubgroupLaneIdentityContext } from "./kanban/subgroup-board.js";
80
+ import { KANBAN_VIRTUAL_CELL_PAGINATION, KanbanVirtualCell, KanbanVirtualCellPagination, KanbanVirtualCellProps } from "./kanban/virtual-cell.js";
78
81
  import "./kanban/index.js";
79
82
  import { getInitials } from "./lib/initials.js";
80
83
  import { cn, composeRefs } from "./lib/utils.js";
@@ -86,4 +89,4 @@ import { ReviewDiffDeletion, ReviewDiffInsertion, ReviewDiffSegment, ReviewDiffS
86
89
  import { ReviewOutOfDateNotice, ReviewOutOfDateReason, ReviewOutOfDateTone } from "./review/review-out-of-date-notice.js";
87
90
  import { ReviewStatusBadge, ReviewStatusSize, ReviewStatusTone, ReviewStatusVariant } from "./review/review-status-badge.js";
88
91
  import { ReviewSeverityDot, ReviewSeverityLevel, ReviewStatusDot, reviewSeverityTone } from "./review/review-severity-dot.js";
89
- export { APPLICATION_RAIL_BUTTON_SIZE, APPLICATION_RAIL_ICON_SIZE, APPLICATION_RAIL_WIDTH, Accordion, AccordionPanel as AccordionContent, AccordionPanel, AccordionItem, AccordionTrigger, AlertDialog, AlertDialogBackdrop, AlertDialogBackdrop as AlertDialogOverlay, AlertDialogClose, AlertDialogPopup as AlertDialogContent, AlertDialogPopup, AlertDialogCreateHandle, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPanel, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertDialogViewport, AnchoredToastProvider, ApplicationRail, ApplicationRailButton, ApplicationRailContent, ApplicationRailFooter, ApplicationRailHeader, ApplicationRailMenu, ApplicationRailSeparator, ApplicationShell, type ApplicationShellProps, Avatar, AvatarFallback, AvatarImage, type BidiDirection, BidiText, type BidiTextProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CONTROL_SIZE, CONTROL_SIZES, CalendarCell, type CalendarDateRange, CalendarEntryButton, CalendarEntrySurface, CalendarGrid, CalendarHeaderCell, CalendarHeaderRow, Checkbox, ColorPicker, ColorPickerContent, type ColorPickerContentProps, type ColorPickerProps, type ColorPreset, ColorVariants, Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxClear, ComboboxCollection, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, ComboboxList, ComboboxPopup, ComboboxRow, ComboboxSeparator, ComboboxStatus, ComboboxTrigger, ComboboxValue, Command, CommandCollection, CommandDialog, CommandDialogPopup, CommandDialogTrigger, CommandEmpty, CommandFooter, CommandGroup, CommandGroupLabel, CommandInput, CommandItem, CommandList, CommandPanel, CommandSeparator, CommandShortcut, type ControlSize, DEFAULT_PRESETS, DataTable, type DataTableAriaSort, type DataTableColumn, type DataTableProps, type DataTableRowAction, DatePickerPopover, type DatePickerPopoverProps, DestructiveActionConfirmation, DestructiveConfirmDialog, type DestructiveConfirmDialogProps, Dialog, DialogBackdrop, DialogBackdrop as DialogOverlay, DialogClose, DialogPopup as DialogContent, DialogPopup, DialogCreateHandle, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPortal, DialogTitle, DialogTrigger, DialogViewport, DirectionalIcon, DiscordLogoIcon, Menu as DropdownMenu, Menu, MenuCheckboxItem as DropdownMenuCheckboxItem, MenuCheckboxItem, MenuPopup as DropdownMenuContent, MenuPopup, MenuCreateHandle as DropdownMenuCreateHandle, MenuCreateHandle, MenuGroup as DropdownMenuGroup, MenuGroup, MenuItem as DropdownMenuItem, MenuItem, MenuGroupLabel as DropdownMenuLabel, MenuGroupLabel, MenuPortal as DropdownMenuPortal, MenuPortal, MenuRadioGroup as DropdownMenuRadioGroup, MenuRadioGroup, MenuRadioItem as DropdownMenuRadioItem, MenuRadioItem, MenuSeparator as DropdownMenuSeparator, MenuSeparator, MenuShortcut as DropdownMenuShortcut, MenuShortcut, MenuSub as DropdownMenuSub, MenuSub, MenuSubPopup as DropdownMenuSubContent, MenuSubPopup, MenuSubTrigger as DropdownMenuSubTrigger, MenuSubTrigger, MenuTrigger as DropdownMenuTrigger, MenuTrigger, Field, FieldControl, FieldDescription, FieldError, FieldItem, FieldLabel, FieldValidity, Form, Frame, FrameDescription, FrameFooter, FrameHeader, FramePanel, FrameTitle, GitHubLogoIcon, HexColorPicker, type HexColorPickerProps, PreviewCard as HoverCard, PreviewCard, PreviewCardPopup as HoverCardContent, PreviewCardPopup, PreviewCardTrigger as HoverCardTrigger, PreviewCardTrigger, INSPECTOR_CONTENT_MIN_WIDTH, INSPECTOR_PANE_DEFAULT_WIDTH, INSPECTOR_PANE_KEYBOARD_PAGE_STEP, INSPECTOR_PANE_KEYBOARD_STEP, INSPECTOR_PANE_MAX_WIDTH, INSPECTOR_PANE_MIN_WIDTH, INSPECTOR_RAIL_WIDTH, Input, InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, type InputProps, Inspector, InspectorActions, InspectorContent, InspectorDescription, InspectorDock, InspectorEmptyRow, InspectorHeader, InspectorHeaderText, InspectorProperty, InspectorPropertyLabel, InspectorPropertyList, InspectorPropertyValue, InspectorRail, InspectorRailCell, InspectorRailIconButton, InspectorRailTab, InspectorSection, InspectorSectionTitle, InspectorTab, InspectorTabList, InspectorTabPanel, InspectorTabs, InspectorTitle, KANBAN_BOARD_AUTO_SCROLL_SOURCES, KANBAN_DIRECTIONS, KANBAN_HORIZONTAL_EDGES, KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, type KanbanBuiltInGroup, type KanbanCardFieldSelection, KanbanCardShell, type KanbanCardShellProps, KanbanColumnHeader, type KanbanColumnHeaderProps, type KanbanDirection, KanbanDragHandle, type KanbanDragHandleProps, type KanbanGroup, type KanbanGroupOption, type KanbanGrouping, type KanbanHorizontalEdge, type KanbanSchema, type KanbanSortableBindings, KanbanSortableBoard, type KanbanSortableBoardProps, KanbanSortableColumns, type KanbanSortableColumnsProps, KanbanSortableList, type KanbanSortableListProps, Label, MenuPreviewLayout, OVERLAY_LAYER_CLASS_NAMES, OptionColor, OutlineItem, OutlineRail, OutlineRailProps, OverlayLayer, PROPERTY_ROW_GRID, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverClose, PopoverPopup as PopoverContent, PopoverPopup, PopoverCreateHandle, PopoverDescription, PopoverPanel, PopoverTitle, PopoverTrigger, PreviewCardPrimitive, PreviewPane, type RegisterKanbanBoardAutoScrollOptions, type RegisterKanbanCardDragOptions, type ResolveKanbanGroupingParams, ResourceCalendar, type ResourceCalendarColumn, type ResourceCalendarEntry, type ResourceCalendarEntryTone, type ResourceCalendarLaneLayout, type ResourceCalendarLanePlacement, type ResourceCalendarPlacement, type ResourceCalendarResource, ReviewAuthorAvatar, ReviewCommentAuthor, ReviewCommentCard, ReviewDecisionActions, ReviewDecisionSize, ReviewDecisionState, ReviewDiffDeletion, ReviewDiffInsertion, ReviewDiffSegment, ReviewDiffSegmentType, ReviewDiffText, ReviewOutOfDateNotice, ReviewOutOfDateReason, ReviewOutOfDateTone, ReviewSeverityDot, ReviewSeverityLevel, ReviewStatusBadge, ReviewStatusDot, ReviewStatusSize, ReviewStatusTone, ReviewStatusVariant, SIDE_RAIL_CONTAINER_CLASS, SIDE_RAIL_ICON_BUTTON_SIZE, SIDE_RAIL_TAB_ICON_SIZE, SIDE_RAIL_WIDTH, ScrollArea, ScrollBar, ScrollToTop, ScrollToTopProps, SecretInput, type SecretInputProps, SegmentedIconToggle, Select, SelectPopup as SelectContent, SelectPopup, SelectGroup, SelectGroupLabel, SelectItem, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetBackdrop, SheetBackdrop as SheetOverlay, SheetClose, SheetPopup as SheetContent, SheetPopup, SheetDescription, SheetFooter, SheetHeader, SheetPanel, SheetPortal, type SheetSide, SheetTitle, SheetTrigger, Skeleton, type SortDirection, SortableHead, StellaMark, StellaWordmarkLatin, TOAST_RIGHT_OFFSET_VAR, TOOLBAR_ROW_HEIGHT, TOOLBAR_ROW_HEIGHT_PX, TRACKED_DELETION_STYLE, TRACKED_INSERTION_STYLE, Table, TableBody, TableCaption, TableCell, type TableColumnCapabilities, type TableColumnDescriptor, TableFooter, TableHead, TableHeader, TableRow, type TableSchema, Tabs, TabsPanel as TabsContent, TabsPanel, TabsList, TabsTab, TabsTab as TabsTrigger, TextSeparator, Textarea, type TextareaProps, type ToastPosition, ToastProvider, Tooltip, TooltipPopup as TooltipContent, TooltipPopup, TooltipCreateHandle, TooltipProvider, TooltipTrigger, UNKNOWN_AUTHOR_LABEL, type UseKanbanSortableOptions, UserText, assertConsecutiveCalendarDates, buttonAccessibleDisabledClass, buttonVariants, cn, composeRefs, containedEventHandler, containedHandler, contentDir, duplicateColumnIds, emptyColor, findTableColumn, getFirstWeekday, getInitials, getKanbanGroupingPropertyId, getKanbanGroups, getKanbanHorizontalEdge, getLocaleWeekInfo, getResourceCalendarPlacement, getWeekendDays, hideableColumnIds, isKanbanGroupingRenderable, isStructuredInputType, layoutResourceCalendarEntries, nextCalendarDate, optionColors, parsePersistedPaneWidth, registerKanbanBoardAutoScroll, registerKanbanCardDrag, resolveDragWidth, resolveInspectorDockWidth, resolveInspectorPaneMaxWidth, resolveInspectorPaneWidth, resolveKanbanGroupOptions, resolveKanbanGrouping, resolveKeyboardWidth, resolveOptionColor, reviewDiffSegmentKeys, reviewSeverityTone, selectKanbanCardFieldIds, selectKanbanRows, shouldForceSidebarCollapsed, sortableColumnIds, stellaToast, tableColumnIds, tableColumnSizing, useComboboxFilter, useContentDir, useDestructiveActionConfirmation, useInspectorPaneWidth, useIsMobile, useKanbanSortable, useKanbanSortableSensors, useLatest, useViewportWidth, visibleColumnIds };
92
+ export { APPLICATION_RAIL_BUTTON_SIZE, APPLICATION_RAIL_ICON_SIZE, APPLICATION_RAIL_WIDTH, Accordion, AccordionPanel as AccordionContent, AccordionPanel, AccordionItem, AccordionTrigger, AlertDialog, AlertDialogBackdrop, AlertDialogBackdrop as AlertDialogOverlay, AlertDialogClose, AlertDialogPopup as AlertDialogContent, AlertDialogPopup, AlertDialogCreateHandle, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPanel, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertDialogViewport, AnchoredToastProvider, ApplicationRail, ApplicationRailButton, ApplicationRailContent, ApplicationRailFooter, ApplicationRailHeader, ApplicationRailMenu, ApplicationRailSeparator, ApplicationShell, type ApplicationShellProps, Avatar, AvatarFallback, AvatarImage, type BidiDirection, BidiText, type BidiTextProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, type BuildKanbanBoardMatrixParams, Button, CONTROL_SIZE, CONTROL_SIZES, CalendarCell, type CalendarDateRange, CalendarEntryButton, CalendarEntrySurface, CalendarGrid, CalendarHeaderCell, CalendarHeaderRow, Checkbox, ColorPicker, ColorPickerContent, type ColorPickerContentProps, type ColorPickerProps, type ColorPreset, ColorVariants, Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxClear, ComboboxCollection, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, ComboboxList, ComboboxPopup, ComboboxRow, ComboboxSeparator, ComboboxStatus, ComboboxTrigger, ComboboxValue, Command, CommandCollection, CommandDialog, CommandDialogPopup, CommandDialogTrigger, CommandEmpty, CommandFooter, CommandGroup, CommandGroupLabel, CommandInput, CommandItem, CommandList, CommandPanel, CommandSeparator, CommandShortcut, type ControlSize, type CreateKanbanDropIntentParams, DEFAULT_PRESETS, DataTable, type DataTableAriaSort, type DataTableColumn, type DataTableProps, type DataTableRowAction, DatePickerPopover, type DatePickerPopoverProps, DestructiveActionConfirmation, DestructiveConfirmDialog, type DestructiveConfirmDialogProps, Dialog, DialogBackdrop, DialogBackdrop as DialogOverlay, DialogClose, DialogPopup as DialogContent, DialogPopup, DialogCreateHandle, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPortal, DialogTitle, DialogTrigger, DialogViewport, DirectionalIcon, DiscordLogoIcon, Menu as DropdownMenu, Menu, MenuCheckboxItem as DropdownMenuCheckboxItem, MenuCheckboxItem, MenuPopup as DropdownMenuContent, MenuPopup, MenuCreateHandle as DropdownMenuCreateHandle, MenuCreateHandle, MenuGroup as DropdownMenuGroup, MenuGroup, MenuItem as DropdownMenuItem, MenuItem, MenuGroupLabel as DropdownMenuLabel, MenuGroupLabel, MenuPortal as DropdownMenuPortal, MenuPortal, MenuRadioGroup as DropdownMenuRadioGroup, MenuRadioGroup, MenuRadioItem as DropdownMenuRadioItem, MenuRadioItem, MenuSeparator as DropdownMenuSeparator, MenuSeparator, MenuShortcut as DropdownMenuShortcut, MenuShortcut, MenuSub as DropdownMenuSub, MenuSub, MenuSubPopup as DropdownMenuSubContent, MenuSubPopup, MenuSubTrigger as DropdownMenuSubTrigger, MenuSubTrigger, MenuTrigger as DropdownMenuTrigger, MenuTrigger, Field, FieldControl, FieldDescription, FieldError, FieldItem, FieldLabel, FieldValidity, Form, Frame, FrameDescription, FrameFooter, FrameHeader, FramePanel, FrameTitle, GitHubLogoIcon, HexColorPicker, type HexColorPickerProps, PreviewCard as HoverCard, PreviewCard, PreviewCardPopup as HoverCardContent, PreviewCardPopup, PreviewCardTrigger as HoverCardTrigger, PreviewCardTrigger, INSPECTOR_CONTENT_MIN_WIDTH, INSPECTOR_PANE_DEFAULT_WIDTH, INSPECTOR_PANE_KEYBOARD_PAGE_STEP, INSPECTOR_PANE_KEYBOARD_STEP, INSPECTOR_PANE_MAX_WIDTH, INSPECTOR_PANE_MIN_WIDTH, INSPECTOR_RAIL_WIDTH, Input, InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, type InputProps, Inspector, InspectorActions, InspectorContent, InspectorDescription, InspectorDock, InspectorEmptyRow, InspectorHeader, InspectorHeaderText, InspectorProperty, InspectorPropertyLabel, InspectorPropertyList, InspectorPropertyValue, InspectorRail, InspectorRailCell, InspectorRailIconButton, InspectorRailTab, InspectorSection, InspectorSectionTitle, InspectorTab, InspectorTabList, InspectorTabPanel, InspectorTabs, InspectorTitle, KANBAN_BOARD_AUTO_SCROLL_SOURCES, KANBAN_BOARD_AXES, KANBAN_DIRECTIONS, KANBAN_HORIZONTAL_EDGES, KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, KANBAN_VIRTUAL_CELL_PAGINATION, type KanbanBoardAxis, type KanbanBoardCell, type KanbanBoardCoordinate, type KanbanBoardLane, type KanbanBoardMatrix, type KanbanBuiltInGroup, type KanbanCardFieldSelection, KanbanCardShell, type KanbanCardShellProps, KanbanColumnHeader, type KanbanColumnHeaderProps, type KanbanDirection, KanbanDragHandle, type KanbanDragHandleProps, type KanbanDropAxisChange, type KanbanDropIntent, type KanbanGroup, type KanbanGroupOption, type KanbanGrouping, type KanbanHorizontalEdge, type KanbanSchema, type KanbanSortableBindings, KanbanSortableBoard, type KanbanSortableBoardProps, KanbanSortableColumns, type KanbanSortableColumnsProps, KanbanSortableList, type KanbanSortableListProps, KanbanSubgroupBoard, type KanbanSubgroupBoardProps, type KanbanSubgroupCellContext, type KanbanSubgroupColumnHeaderContext, type KanbanSubgroupLaneIdentityContext, KanbanVirtualCell, type KanbanVirtualCellPagination, type KanbanVirtualCellProps, Label, MenuPreviewLayout, OVERLAY_LAYER_CLASS_NAMES, OptionColor, type OrderKanbanCellsByColumnsParams, OutlineItem, OutlineRail, OutlineRailProps, OverlayLayer, PROPERTY_ROW_GRID, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverClose, PopoverPopup as PopoverContent, PopoverPopup, PopoverCreateHandle, PopoverDescription, PopoverPanel, PopoverTitle, PopoverTrigger, PreviewCardPrimitive, PreviewPane, type RegisterKanbanBoardAutoScrollOptions, type RegisterKanbanCardDragOptions, type ResolveKanbanGroupValueParams, type ResolveKanbanGroupingParams, ResourceCalendar, type ResourceCalendarColumn, type ResourceCalendarEntry, type ResourceCalendarEntryTone, type ResourceCalendarLaneLayout, type ResourceCalendarLanePlacement, type ResourceCalendarPlacement, type ResourceCalendarResource, ReviewAuthorAvatar, ReviewCommentAuthor, ReviewCommentCard, ReviewDecisionActions, ReviewDecisionSize, ReviewDecisionState, ReviewDiffDeletion, ReviewDiffInsertion, ReviewDiffSegment, ReviewDiffSegmentType, ReviewDiffText, ReviewOutOfDateNotice, ReviewOutOfDateReason, ReviewOutOfDateTone, ReviewSeverityDot, ReviewSeverityLevel, ReviewStatusBadge, ReviewStatusDot, ReviewStatusSize, ReviewStatusTone, ReviewStatusVariant, SIDE_RAIL_CONTAINER_CLASS, SIDE_RAIL_ICON_BUTTON_SIZE, SIDE_RAIL_TAB_ICON_SIZE, SIDE_RAIL_WIDTH, ScrollArea, ScrollBar, ScrollToTop, ScrollToTopProps, SecretInput, type SecretInputProps, SegmentedIconToggle, Select, SelectPopup as SelectContent, SelectPopup, SelectGroup, SelectGroupLabel, SelectItem, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetBackdrop, SheetBackdrop as SheetOverlay, SheetClose, SheetPopup as SheetContent, SheetPopup, SheetDescription, SheetFooter, SheetHeader, SheetPanel, SheetPortal, type SheetSide, SheetTitle, SheetTrigger, Skeleton, type SortDirection, SortableHead, StellaMark, StellaWordmarkLatin, TOAST_RIGHT_OFFSET_VAR, TOOLBAR_ROW_HEIGHT, TOOLBAR_ROW_HEIGHT_PX, TRACKED_DELETION_STYLE, TRACKED_INSERTION_STYLE, Table, TableBody, TableCaption, TableCell, type TableColumnCapabilities, type TableColumnDescriptor, TableFooter, TableHead, TableHeader, TableRow, type TableSchema, Tabs, TabsPanel as TabsContent, TabsPanel, TabsList, TabsTab, TabsTab as TabsTrigger, TextSeparator, Textarea, type TextareaProps, type ToastPosition, ToastProvider, Tooltip, TooltipPopup as TooltipContent, TooltipPopup, TooltipCreateHandle, TooltipProvider, TooltipTrigger, UNKNOWN_AUTHOR_LABEL, type UseKanbanSortableOptions, UserText, assertConsecutiveCalendarDates, buildKanbanBoardMatrix, buttonAccessibleDisabledClass, buttonVariants, cn, composeRefs, containedEventHandler, containedHandler, contentDir, createKanbanDropIntent, duplicateColumnIds, emptyColor, findTableColumn, getFirstWeekday, getInitials, getKanbanGroupingPropertyId, getKanbanGroups, getKanbanHorizontalEdge, getLocaleWeekInfo, getResourceCalendarPlacement, getWeekendDays, hideableColumnIds, isKanbanGroupingRenderable, isStructuredInputType, layoutResourceCalendarEntries, nextCalendarDate, optionColors, orderKanbanCellsByColumns, parsePersistedPaneWidth, registerKanbanBoardAutoScroll, registerKanbanCardDrag, resolveDragWidth, resolveInspectorDockWidth, resolveInspectorPaneMaxWidth, resolveInspectorPaneWidth, resolveKanbanGroupOptions, resolveKanbanGrouping, resolveKeyboardWidth, resolveOptionColor, reviewDiffSegmentKeys, reviewSeverityTone, selectKanbanCardFieldIds, selectKanbanRows, shouldForceSidebarCollapsed, sortableColumnIds, stellaToast, tableColumnIds, tableColumnSizing, useComboboxFilter, useContentDir, useDestructiveActionConfirmation, useInspectorPaneWidth, useIsMobile, useKanbanSortable, useKanbanSortableSensors, useLatest, useViewportWidth, visibleColumnIds };
package/dist/index.js CHANGED
@@ -73,6 +73,9 @@ import { KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, K
73
73
  import { KANBAN_DIRECTIONS, KANBAN_HORIZONTAL_EDGES, getKanbanHorizontalEdge } from "./kanban/sortable-edge.js";
74
74
  import { KANBAN_BOARD_AUTO_SCROLL_SOURCES, registerKanbanBoardAutoScroll, registerKanbanCardDrag } from "./kanban/drag-interactions.js";
75
75
  import { getKanbanGroupingPropertyId, getKanbanGroups, isKanbanGroupingRenderable, resolveKanbanGroupOptions, resolveKanbanGrouping, selectKanbanRows } from "./kanban/grouping.js";
76
+ import { KANBAN_BOARD_AXES, buildKanbanBoardMatrix, createKanbanDropIntent, orderKanbanCellsByColumns } from "./kanban/matrix.js";
77
+ import { KanbanSubgroupBoard } from "./kanban/subgroup-board.js";
78
+ import { KANBAN_VIRTUAL_CELL_PAGINATION, KanbanVirtualCell } from "./kanban/virtual-cell.js";
76
79
  import { getInitials } from "./lib/initials.js";
77
80
  import { emptyColor, optionColors, resolveOptionColor } from "./lib/option-color.js";
78
81
  import { ReviewAuthorAvatar, UNKNOWN_AUTHOR_LABEL } from "./review/review-author-avatar.js";
@@ -82,4 +85,4 @@ import { ReviewDiffDeletion, ReviewDiffInsertion, ReviewDiffText, TRACKED_DELETI
82
85
  import { ReviewOutOfDateNotice } from "./review/review-out-of-date-notice.js";
83
86
  import { ReviewSeverityDot, ReviewStatusDot, reviewSeverityTone } from "./review/review-severity-dot.js";
84
87
  import { ReviewStatusBadge } from "./review/review-status-badge.js";
85
- export { APPLICATION_RAIL_BUTTON_SIZE, APPLICATION_RAIL_ICON_SIZE, APPLICATION_RAIL_WIDTH, Accordion, AccordionPanel as AccordionContent, AccordionPanel, AccordionItem, AccordionTrigger, AlertDialog, AlertDialogBackdrop, AlertDialogBackdrop as AlertDialogOverlay, AlertDialogClose, AlertDialogPopup as AlertDialogContent, AlertDialogPopup, AlertDialogCreateHandle, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPanel, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertDialogViewport, AnchoredToastProvider, ApplicationRail, ApplicationRailButton, ApplicationRailContent, ApplicationRailFooter, ApplicationRailHeader, ApplicationRailMenu, ApplicationRailSeparator, ApplicationShell, Avatar, AvatarFallback, AvatarImage, BidiText, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CONTROL_SIZE, CONTROL_SIZES, CalendarCell, CalendarEntryButton, CalendarEntrySurface, CalendarGrid, CalendarHeaderCell, CalendarHeaderRow, Checkbox, ColorPicker, ColorPickerContent, Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxClear, ComboboxCollection, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, ComboboxList, ComboboxPopup, ComboboxRow, ComboboxSeparator, ComboboxStatus, ComboboxTrigger, ComboboxValue, Command, CommandCollection, CommandDialog, CommandDialogPopup, CommandDialogTrigger, CommandEmpty, CommandFooter, CommandGroup, CommandGroupLabel, CommandInput, CommandItem, CommandList, CommandPanel, CommandSeparator, CommandShortcut, DEFAULT_PRESETS, DataTable, DatePickerPopover, DestructiveActionConfirmation, DestructiveConfirmDialog, Dialog, DialogBackdrop, DialogBackdrop as DialogOverlay, DialogClose, DialogPopup as DialogContent, DialogPopup, DialogCreateHandle, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPortal, DialogTitle, DialogTrigger, DialogViewport, DirectionalIcon, DiscordLogoIcon, Menu as DropdownMenu, Menu, MenuCheckboxItem as DropdownMenuCheckboxItem, MenuCheckboxItem, MenuPopup as DropdownMenuContent, MenuPopup, MenuCreateHandle as DropdownMenuCreateHandle, MenuCreateHandle, MenuGroup as DropdownMenuGroup, MenuGroup, MenuItem as DropdownMenuItem, MenuItem, MenuGroupLabel as DropdownMenuLabel, MenuGroupLabel, MenuPortal as DropdownMenuPortal, MenuPortal, MenuRadioGroup as DropdownMenuRadioGroup, MenuRadioGroup, MenuRadioItem as DropdownMenuRadioItem, MenuRadioItem, MenuSeparator as DropdownMenuSeparator, MenuSeparator, MenuShortcut as DropdownMenuShortcut, MenuShortcut, MenuSub as DropdownMenuSub, MenuSub, MenuSubPopup as DropdownMenuSubContent, MenuSubPopup, MenuSubTrigger as DropdownMenuSubTrigger, MenuSubTrigger, MenuTrigger as DropdownMenuTrigger, MenuTrigger, Field, FieldControl, FieldDescription, FieldError, FieldItem, FieldLabel, FieldValidity, Form, Frame, FrameDescription, FrameFooter, FrameHeader, FramePanel, FrameTitle, GitHubLogoIcon, HexColorPicker, PreviewCard as HoverCard, PreviewCard, PreviewCardPopup as HoverCardContent, PreviewCardPopup, PreviewCardTrigger as HoverCardTrigger, PreviewCardTrigger, INSPECTOR_CONTENT_MIN_WIDTH, INSPECTOR_PANE_DEFAULT_WIDTH, INSPECTOR_PANE_KEYBOARD_PAGE_STEP, INSPECTOR_PANE_KEYBOARD_STEP, INSPECTOR_PANE_MAX_WIDTH, INSPECTOR_PANE_MIN_WIDTH, INSPECTOR_RAIL_WIDTH, Input, InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Inspector, InspectorActions, InspectorContent, InspectorDescription, InspectorDock, InspectorEmptyRow, InspectorHeader, InspectorHeaderText, InspectorProperty, InspectorPropertyLabel, InspectorPropertyList, InspectorPropertyValue, InspectorRail, InspectorRailCell, InspectorRailIconButton, InspectorRailTab, InspectorSection, InspectorSectionTitle, InspectorTab, InspectorTabList, InspectorTabPanel, InspectorTabs, InspectorTitle, KANBAN_BOARD_AUTO_SCROLL_SOURCES, KANBAN_DIRECTIONS, KANBAN_HORIZONTAL_EDGES, KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, KanbanCardShell, KanbanColumnHeader, KanbanDragHandle, KanbanSortableBoard, KanbanSortableColumns, KanbanSortableList, Label, MenuPreviewLayout, OVERLAY_LAYER_CLASS_NAMES, OutlineRail, PROPERTY_ROW_GRID, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverClose, PopoverPopup as PopoverContent, PopoverPopup, PopoverCreateHandle, PopoverDescription, PopoverPanel, PopoverTitle, PopoverTrigger, PreviewCardPrimitive, PreviewPane, ResourceCalendar, ReviewAuthorAvatar, ReviewCommentCard, ReviewDecisionActions, ReviewDiffDeletion, ReviewDiffInsertion, ReviewDiffText, ReviewOutOfDateNotice, ReviewSeverityDot, ReviewStatusBadge, ReviewStatusDot, SIDE_RAIL_CONTAINER_CLASS, SIDE_RAIL_ICON_BUTTON_SIZE, SIDE_RAIL_TAB_ICON_SIZE, SIDE_RAIL_WIDTH, ScrollArea, ScrollBar, ScrollToTop, SecretInput, SegmentedIconToggle, Select, SelectPopup as SelectContent, SelectPopup, SelectGroup, SelectGroupLabel, SelectItem, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetBackdrop, SheetBackdrop as SheetOverlay, SheetClose, SheetPopup as SheetContent, SheetPopup, SheetDescription, SheetFooter, SheetHeader, SheetPanel, SheetPortal, SheetTitle, SheetTrigger, Skeleton, SortableHead, StellaMark, StellaWordmarkLatin, TOAST_RIGHT_OFFSET_VAR, TOOLBAR_ROW_HEIGHT, TOOLBAR_ROW_HEIGHT_PX, TRACKED_DELETION_STYLE, TRACKED_INSERTION_STYLE, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsPanel as TabsContent, TabsPanel, TabsList, TabsTab, TabsTab as TabsTrigger, TextSeparator, Textarea, ToastProvider, Tooltip, TooltipPopup as TooltipContent, TooltipPopup, TooltipCreateHandle, TooltipProvider, TooltipTrigger, UNKNOWN_AUTHOR_LABEL, UserText, assertConsecutiveCalendarDates, buttonAccessibleDisabledClass, buttonVariants, cn, composeRefs, containedEventHandler, containedHandler, contentDir, duplicateColumnIds, emptyColor, findTableColumn, getFirstWeekday, getInitials, getKanbanGroupingPropertyId, getKanbanGroups, getKanbanHorizontalEdge, getLocaleWeekInfo, getResourceCalendarPlacement, getWeekendDays, hideableColumnIds, isKanbanGroupingRenderable, isStructuredInputType, layoutResourceCalendarEntries, nextCalendarDate, optionColors, parsePersistedPaneWidth, registerKanbanBoardAutoScroll, registerKanbanCardDrag, resolveDragWidth, resolveInspectorDockWidth, resolveInspectorPaneMaxWidth, resolveInspectorPaneWidth, resolveKanbanGroupOptions, resolveKanbanGrouping, resolveKeyboardWidth, resolveOptionColor, reviewDiffSegmentKeys, reviewSeverityTone, selectKanbanCardFieldIds, selectKanbanRows, shouldForceSidebarCollapsed, sortableColumnIds, stellaToast, tableColumnIds, tableColumnSizing, useComboboxFilter, useContentDir, useDestructiveActionConfirmation, useInspectorPaneWidth, useIsMobile, useKanbanSortable, useKanbanSortableSensors, useLatest, useViewportWidth, visibleColumnIds };
88
+ export { APPLICATION_RAIL_BUTTON_SIZE, APPLICATION_RAIL_ICON_SIZE, APPLICATION_RAIL_WIDTH, Accordion, AccordionPanel as AccordionContent, AccordionPanel, AccordionItem, AccordionTrigger, AlertDialog, AlertDialogBackdrop, AlertDialogBackdrop as AlertDialogOverlay, AlertDialogClose, AlertDialogPopup as AlertDialogContent, AlertDialogPopup, AlertDialogCreateHandle, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPanel, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertDialogViewport, AnchoredToastProvider, ApplicationRail, ApplicationRailButton, ApplicationRailContent, ApplicationRailFooter, ApplicationRailHeader, ApplicationRailMenu, ApplicationRailSeparator, ApplicationShell, Avatar, AvatarFallback, AvatarImage, BidiText, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CONTROL_SIZE, CONTROL_SIZES, CalendarCell, CalendarEntryButton, CalendarEntrySurface, CalendarGrid, CalendarHeaderCell, CalendarHeaderRow, Checkbox, ColorPicker, ColorPickerContent, Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxClear, ComboboxCollection, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, ComboboxList, ComboboxPopup, ComboboxRow, ComboboxSeparator, ComboboxStatus, ComboboxTrigger, ComboboxValue, Command, CommandCollection, CommandDialog, CommandDialogPopup, CommandDialogTrigger, CommandEmpty, CommandFooter, CommandGroup, CommandGroupLabel, CommandInput, CommandItem, CommandList, CommandPanel, CommandSeparator, CommandShortcut, DEFAULT_PRESETS, DataTable, DatePickerPopover, DestructiveActionConfirmation, DestructiveConfirmDialog, Dialog, DialogBackdrop, DialogBackdrop as DialogOverlay, DialogClose, DialogPopup as DialogContent, DialogPopup, DialogCreateHandle, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPortal, DialogTitle, DialogTrigger, DialogViewport, DirectionalIcon, DiscordLogoIcon, Menu as DropdownMenu, Menu, MenuCheckboxItem as DropdownMenuCheckboxItem, MenuCheckboxItem, MenuPopup as DropdownMenuContent, MenuPopup, MenuCreateHandle as DropdownMenuCreateHandle, MenuCreateHandle, MenuGroup as DropdownMenuGroup, MenuGroup, MenuItem as DropdownMenuItem, MenuItem, MenuGroupLabel as DropdownMenuLabel, MenuGroupLabel, MenuPortal as DropdownMenuPortal, MenuPortal, MenuRadioGroup as DropdownMenuRadioGroup, MenuRadioGroup, MenuRadioItem as DropdownMenuRadioItem, MenuRadioItem, MenuSeparator as DropdownMenuSeparator, MenuSeparator, MenuShortcut as DropdownMenuShortcut, MenuShortcut, MenuSub as DropdownMenuSub, MenuSub, MenuSubPopup as DropdownMenuSubContent, MenuSubPopup, MenuSubTrigger as DropdownMenuSubTrigger, MenuSubTrigger, MenuTrigger as DropdownMenuTrigger, MenuTrigger, Field, FieldControl, FieldDescription, FieldError, FieldItem, FieldLabel, FieldValidity, Form, Frame, FrameDescription, FrameFooter, FrameHeader, FramePanel, FrameTitle, GitHubLogoIcon, HexColorPicker, PreviewCard as HoverCard, PreviewCard, PreviewCardPopup as HoverCardContent, PreviewCardPopup, PreviewCardTrigger as HoverCardTrigger, PreviewCardTrigger, INSPECTOR_CONTENT_MIN_WIDTH, INSPECTOR_PANE_DEFAULT_WIDTH, INSPECTOR_PANE_KEYBOARD_PAGE_STEP, INSPECTOR_PANE_KEYBOARD_STEP, INSPECTOR_PANE_MAX_WIDTH, INSPECTOR_PANE_MIN_WIDTH, INSPECTOR_RAIL_WIDTH, Input, InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Inspector, InspectorActions, InspectorContent, InspectorDescription, InspectorDock, InspectorEmptyRow, InspectorHeader, InspectorHeaderText, InspectorProperty, InspectorPropertyLabel, InspectorPropertyList, InspectorPropertyValue, InspectorRail, InspectorRailCell, InspectorRailIconButton, InspectorRailTab, InspectorSection, InspectorSectionTitle, InspectorTab, InspectorTabList, InspectorTabPanel, InspectorTabs, InspectorTitle, KANBAN_BOARD_AUTO_SCROLL_SOURCES, KANBAN_BOARD_AXES, KANBAN_DIRECTIONS, KANBAN_HORIZONTAL_EDGES, KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, KANBAN_VIRTUAL_CELL_PAGINATION, KanbanCardShell, KanbanColumnHeader, KanbanDragHandle, KanbanSortableBoard, KanbanSortableColumns, KanbanSortableList, KanbanSubgroupBoard, KanbanVirtualCell, Label, MenuPreviewLayout, OVERLAY_LAYER_CLASS_NAMES, OutlineRail, PROPERTY_ROW_GRID, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverClose, PopoverPopup as PopoverContent, PopoverPopup, PopoverCreateHandle, PopoverDescription, PopoverPanel, PopoverTitle, PopoverTrigger, PreviewCardPrimitive, PreviewPane, ResourceCalendar, ReviewAuthorAvatar, ReviewCommentCard, ReviewDecisionActions, ReviewDiffDeletion, ReviewDiffInsertion, ReviewDiffText, ReviewOutOfDateNotice, ReviewSeverityDot, ReviewStatusBadge, ReviewStatusDot, SIDE_RAIL_CONTAINER_CLASS, SIDE_RAIL_ICON_BUTTON_SIZE, SIDE_RAIL_TAB_ICON_SIZE, SIDE_RAIL_WIDTH, ScrollArea, ScrollBar, ScrollToTop, SecretInput, SegmentedIconToggle, Select, SelectPopup as SelectContent, SelectPopup, SelectGroup, SelectGroupLabel, SelectItem, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetBackdrop, SheetBackdrop as SheetOverlay, SheetClose, SheetPopup as SheetContent, SheetPopup, SheetDescription, SheetFooter, SheetHeader, SheetPanel, SheetPortal, SheetTitle, SheetTrigger, Skeleton, SortableHead, StellaMark, StellaWordmarkLatin, TOAST_RIGHT_OFFSET_VAR, TOOLBAR_ROW_HEIGHT, TOOLBAR_ROW_HEIGHT_PX, TRACKED_DELETION_STYLE, TRACKED_INSERTION_STYLE, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsPanel as TabsContent, TabsPanel, TabsList, TabsTab, TabsTab as TabsTrigger, TextSeparator, Textarea, ToastProvider, Tooltip, TooltipPopup as TooltipContent, TooltipPopup, TooltipCreateHandle, TooltipProvider, TooltipTrigger, UNKNOWN_AUTHOR_LABEL, UserText, assertConsecutiveCalendarDates, buildKanbanBoardMatrix, buttonAccessibleDisabledClass, buttonVariants, cn, composeRefs, containedEventHandler, containedHandler, contentDir, createKanbanDropIntent, duplicateColumnIds, emptyColor, findTableColumn, getFirstWeekday, getInitials, getKanbanGroupingPropertyId, getKanbanGroups, getKanbanHorizontalEdge, getLocaleWeekInfo, getResourceCalendarPlacement, getWeekendDays, hideableColumnIds, isKanbanGroupingRenderable, isStructuredInputType, layoutResourceCalendarEntries, nextCalendarDate, optionColors, orderKanbanCellsByColumns, parsePersistedPaneWidth, registerKanbanBoardAutoScroll, registerKanbanCardDrag, resolveDragWidth, resolveInspectorDockWidth, resolveInspectorPaneMaxWidth, resolveInspectorPaneWidth, resolveKanbanGroupOptions, resolveKanbanGrouping, resolveKeyboardWidth, resolveOptionColor, reviewDiffSegmentKeys, reviewSeverityTone, selectKanbanCardFieldIds, selectKanbanRows, shouldForceSidebarCollapsed, sortableColumnIds, stellaToast, tableColumnIds, tableColumnSizing, useComboboxFilter, useContentDir, useDestructiveActionConfirmation, useInspectorPaneWidth, useIsMobile, useKanbanSortable, useKanbanSortableSensors, useLatest, useViewportWidth, visibleColumnIds };
@@ -4,6 +4,7 @@ import { OptionColor } from "../lib/option-color.js";
4
4
  type KanbanGroupOption = {
5
5
  value: string;
6
6
  label: string;
7
+ image?: string | null | undefined;
7
8
  color?: string | undefined;
8
9
  colorBg?: string | undefined;
9
10
  optionColor?: OptionColor | undefined;
@@ -12,6 +13,7 @@ type KanbanGroupOption = {
12
13
  type KanbanGroup = {
13
14
  value: string | null;
14
15
  label: string;
16
+ image?: string | null | undefined;
15
17
  color?: string | undefined;
16
18
  colorBg?: string | undefined;
17
19
  optionColor?: OptionColor | undefined;
@@ -62,6 +62,7 @@ const getKanbanGroups = (options, uncategorizedLabel) => {
62
62
  const result = options.map((option) => ({
63
63
  value: option.value,
64
64
  label: option.label,
65
+ image: option.image,
65
66
  color: option.color,
66
67
  colorBg: option.colorBg,
67
68
  optionColor: option.optionColor
@@ -5,4 +5,7 @@ import { KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, K
5
5
  import { KANBAN_DIRECTIONS, KANBAN_HORIZONTAL_EDGES, KanbanDirection, KanbanHorizontalEdge, getKanbanHorizontalEdge } from "./sortable-edge.js";
6
6
  import { KANBAN_BOARD_AUTO_SCROLL_SOURCES, RegisterKanbanBoardAutoScrollOptions, RegisterKanbanCardDragOptions, registerKanbanBoardAutoScroll, registerKanbanCardDrag } from "./drag-interactions.js";
7
7
  import { KanbanBuiltInGroup, KanbanGroup, KanbanGroupOption, KanbanGrouping, KanbanSchema, ResolveKanbanGroupingParams, getKanbanGroupingPropertyId, getKanbanGroups, isKanbanGroupingRenderable, resolveKanbanGroupOptions, resolveKanbanGrouping, selectKanbanRows } from "./grouping.js";
8
- export { KANBAN_BOARD_AUTO_SCROLL_SOURCES, KANBAN_DIRECTIONS, KANBAN_HORIZONTAL_EDGES, KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, type KanbanBuiltInGroup, type KanbanCardFieldSelection, KanbanCardShell, type KanbanCardShellProps, KanbanColumnHeader, type KanbanColumnHeaderProps, type KanbanDirection, KanbanDragHandle, type KanbanDragHandleProps, type KanbanGroup, type KanbanGroupOption, type KanbanGrouping, type KanbanHorizontalEdge, type KanbanSchema, type KanbanSortableBindings, KanbanSortableBoard, type KanbanSortableBoardProps, KanbanSortableColumns, type KanbanSortableColumnsProps, KanbanSortableList, type KanbanSortableListProps, type RegisterKanbanBoardAutoScrollOptions, type RegisterKanbanCardDragOptions, type ResolveKanbanGroupingParams, type UseKanbanSortableOptions, getKanbanGroupingPropertyId, getKanbanGroups, getKanbanHorizontalEdge, isKanbanGroupingRenderable, registerKanbanBoardAutoScroll, registerKanbanCardDrag, resolveKanbanGroupOptions, resolveKanbanGrouping, selectKanbanCardFieldIds, selectKanbanRows, useKanbanSortable, useKanbanSortableSensors };
8
+ import { BuildKanbanBoardMatrixParams, CreateKanbanDropIntentParams, KANBAN_BOARD_AXES, KanbanBoardAxis, KanbanBoardCell, KanbanBoardCoordinate, KanbanBoardLane, KanbanBoardMatrix, KanbanDropAxisChange, KanbanDropIntent, OrderKanbanCellsByColumnsParams, ResolveKanbanGroupValueParams, buildKanbanBoardMatrix, createKanbanDropIntent, orderKanbanCellsByColumns } from "./matrix.js";
9
+ import { KanbanSubgroupBoard, KanbanSubgroupBoardProps, KanbanSubgroupCellContext, KanbanSubgroupColumnHeaderContext, KanbanSubgroupLaneIdentityContext } from "./subgroup-board.js";
10
+ import { KANBAN_VIRTUAL_CELL_PAGINATION, KanbanVirtualCell, KanbanVirtualCellPagination, KanbanVirtualCellProps } from "./virtual-cell.js";
11
+ export { type BuildKanbanBoardMatrixParams, type CreateKanbanDropIntentParams, KANBAN_BOARD_AUTO_SCROLL_SOURCES, KANBAN_BOARD_AXES, KANBAN_DIRECTIONS, KANBAN_HORIZONTAL_EDGES, KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, KANBAN_VIRTUAL_CELL_PAGINATION, type KanbanBoardAxis, type KanbanBoardCell, type KanbanBoardCoordinate, type KanbanBoardLane, type KanbanBoardMatrix, type KanbanBuiltInGroup, type KanbanCardFieldSelection, KanbanCardShell, type KanbanCardShellProps, KanbanColumnHeader, type KanbanColumnHeaderProps, type KanbanDirection, KanbanDragHandle, type KanbanDragHandleProps, type KanbanDropAxisChange, type KanbanDropIntent, type KanbanGroup, type KanbanGroupOption, type KanbanGrouping, type KanbanHorizontalEdge, type KanbanSchema, type KanbanSortableBindings, KanbanSortableBoard, type KanbanSortableBoardProps, KanbanSortableColumns, type KanbanSortableColumnsProps, KanbanSortableList, type KanbanSortableListProps, KanbanSubgroupBoard, type KanbanSubgroupBoardProps, type KanbanSubgroupCellContext, type KanbanSubgroupColumnHeaderContext, type KanbanSubgroupLaneIdentityContext, KanbanVirtualCell, type KanbanVirtualCellPagination, type KanbanVirtualCellProps, type OrderKanbanCellsByColumnsParams, type RegisterKanbanBoardAutoScrollOptions, type RegisterKanbanCardDragOptions, type ResolveKanbanGroupValueParams, type ResolveKanbanGroupingParams, type UseKanbanSortableOptions, buildKanbanBoardMatrix, createKanbanDropIntent, getKanbanGroupingPropertyId, getKanbanGroups, getKanbanHorizontalEdge, isKanbanGroupingRenderable, orderKanbanCellsByColumns, registerKanbanBoardAutoScroll, registerKanbanCardDrag, resolveKanbanGroupOptions, resolveKanbanGrouping, selectKanbanCardFieldIds, selectKanbanRows, useKanbanSortable, useKanbanSortableSensors };
@@ -5,4 +5,7 @@ import { KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, K
5
5
  import { KANBAN_DIRECTIONS, KANBAN_HORIZONTAL_EDGES, getKanbanHorizontalEdge } from "./sortable-edge.js";
6
6
  import { KANBAN_BOARD_AUTO_SCROLL_SOURCES, registerKanbanBoardAutoScroll, registerKanbanCardDrag } from "./drag-interactions.js";
7
7
  import { getKanbanGroupingPropertyId, getKanbanGroups, isKanbanGroupingRenderable, resolveKanbanGroupOptions, resolveKanbanGrouping, selectKanbanRows } from "./grouping.js";
8
- export { KANBAN_BOARD_AUTO_SCROLL_SOURCES, KANBAN_DIRECTIONS, KANBAN_HORIZONTAL_EDGES, KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, KanbanCardShell, KanbanColumnHeader, KanbanDragHandle, KanbanSortableBoard, KanbanSortableColumns, KanbanSortableList, getKanbanGroupingPropertyId, getKanbanGroups, getKanbanHorizontalEdge, isKanbanGroupingRenderable, registerKanbanBoardAutoScroll, registerKanbanCardDrag, resolveKanbanGroupOptions, resolveKanbanGrouping, selectKanbanCardFieldIds, selectKanbanRows, useKanbanSortable, useKanbanSortableSensors };
8
+ import { KANBAN_BOARD_AXES, buildKanbanBoardMatrix, createKanbanDropIntent, orderKanbanCellsByColumns } from "./matrix.js";
9
+ import { KanbanSubgroupBoard } from "./subgroup-board.js";
10
+ import { KANBAN_VIRTUAL_CELL_PAGINATION, KanbanVirtualCell } from "./virtual-cell.js";
11
+ export { KANBAN_BOARD_AUTO_SCROLL_SOURCES, KANBAN_BOARD_AXES, KANBAN_DIRECTIONS, KANBAN_HORIZONTAL_EDGES, KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, KANBAN_VIRTUAL_CELL_PAGINATION, KanbanCardShell, KanbanColumnHeader, KanbanDragHandle, KanbanSortableBoard, KanbanSortableColumns, KanbanSortableList, KanbanSubgroupBoard, KanbanVirtualCell, buildKanbanBoardMatrix, createKanbanDropIntent, getKanbanGroupingPropertyId, getKanbanGroups, getKanbanHorizontalEdge, isKanbanGroupingRenderable, orderKanbanCellsByColumns, registerKanbanBoardAutoScroll, registerKanbanCardDrag, resolveKanbanGroupOptions, resolveKanbanGrouping, selectKanbanCardFieldIds, selectKanbanRows, useKanbanSortable, useKanbanSortableSensors };
@@ -0,0 +1,85 @@
1
+ import { KanbanGroup, KanbanGrouping } from "./grouping.js";
2
+ //#region src/kanban/matrix.d.ts
3
+ /** Which axis of a board a grouping controls. */
4
+ declare const KANBAN_BOARD_AXES: {
5
+ readonly group: "group";
6
+ readonly subgroup: "subgroup";
7
+ };
8
+ type KanbanBoardAxis = (typeof KANBAN_BOARD_AXES)[keyof typeof KANBAN_BOARD_AXES];
9
+ /** The optional horizontal swimlane dimension is intentionally explicit. */
10
+ type KanbanBoardLane = {
11
+ type: "none";
12
+ } | {
13
+ group: KanbanGroup;
14
+ type: "group";
15
+ };
16
+ type KanbanBoardCoordinate = {
17
+ column: KanbanGroup;
18
+ lane: KanbanBoardLane;
19
+ };
20
+ type KanbanBoardCell<TRow> = {
21
+ coordinate: KanbanBoardCoordinate;
22
+ rows: TRow[];
23
+ };
24
+ /**
25
+ * The full, ordered cartesian board. Presentation may hide or collapse parts
26
+ * of it, but it must not derive cards independently: every board row is in
27
+ * exactly one cell here before that presentation step.
28
+ */
29
+ type KanbanBoardMatrix<TRow> = {
30
+ cells: KanbanBoardCell<TRow>[];
31
+ columns: KanbanGroup[];
32
+ lanes: KanbanBoardLane[];
33
+ rows: TRow[];
34
+ };
35
+ type ResolveKanbanGroupValueParams<TRow, TProperty> = {
36
+ grouping: KanbanGrouping<TRow, TProperty>;
37
+ row: TRow;
38
+ };
39
+ type BuildKanbanBoardMatrixParams<TRow, TProperty> = {
40
+ /** The vertical board columns. This must be a renderable grouping. */
41
+ group: KanbanGrouping<TRow, TProperty>;
42
+ /** Optional horizontal swimlanes. `none` makes this a one-lane board. */
43
+ subgroup: KanbanGrouping<TRow, TProperty>;
44
+ rows: readonly TRow[];
45
+ uncategorizedLabel: string;
46
+ resolveGroupValue: (params: ResolveKanbanGroupValueParams<TRow, TProperty>) => string | null;
47
+ };
48
+ type OrderKanbanCellsByColumnsParams<TRow> = {
49
+ cells: readonly KanbanBoardCell<TRow>[];
50
+ columns: readonly KanbanGroup[];
51
+ };
52
+ /** Apply the visible header order to any lane's cells. */
53
+ declare const orderKanbanCellsByColumns: <TRow>({ cells, columns }: OrderKanbanCellsByColumnsParams<TRow>) => KanbanBoardCell<TRow>[];
54
+ /**
55
+ * Resolve the board's one source of placement truth.
56
+ *
57
+ * A subgroup never filters the primary board scope. A row outside a subgroup's
58
+ * declared values goes to its explicit No value lane, rather than disappearing.
59
+ */
60
+ declare const buildKanbanBoardMatrix: <TRow, TProperty>({ group, subgroup, rows, uncategorizedLabel, resolveGroupValue }: BuildKanbanBoardMatrixParams<TRow, TProperty>) => KanbanBoardMatrix<TRow>;
61
+ type KanbanDropAxisChange = {
62
+ groupBy: string;
63
+ value: string | null;
64
+ };
65
+ /** A complete, atomic move request for a domain mutation adapter. */
66
+ type KanbanDropIntent<TCardId> = {
67
+ cardId: TCardId;
68
+ changes: readonly KanbanDropAxisChange[];
69
+ type: "move";
70
+ };
71
+ type CreateKanbanDropIntentParams<TRow, TProperty, TCardId> = {
72
+ cardId: TCardId;
73
+ group: KanbanGrouping<TRow, TProperty>;
74
+ source: KanbanBoardCoordinate;
75
+ subgroup: KanbanGrouping<TRow, TProperty>;
76
+ target: KanbanBoardCoordinate;
77
+ };
78
+ /**
79
+ * Builds a single mutation payload for a pointer, touch, or keyboard drop.
80
+ * Diagonal drops carry both changes together; an adapter must commit this
81
+ * intent atomically or reject it as a whole.
82
+ */
83
+ declare const createKanbanDropIntent: <TRow, TProperty, TCardId>({ cardId, group, source, subgroup, target }: CreateKanbanDropIntentParams<TRow, TProperty, TCardId>) => KanbanDropIntent<TCardId> | null;
84
+ //#endregion
85
+ export { BuildKanbanBoardMatrixParams, CreateKanbanDropIntentParams, KANBAN_BOARD_AXES, KanbanBoardAxis, KanbanBoardCell, KanbanBoardCoordinate, KanbanBoardLane, KanbanBoardMatrix, KanbanDropAxisChange, KanbanDropIntent, OrderKanbanCellsByColumnsParams, ResolveKanbanGroupValueParams, buildKanbanBoardMatrix, createKanbanDropIntent, orderKanbanCellsByColumns };
@@ -0,0 +1,121 @@
1
+ import { getKanbanGroupingPropertyId, getKanbanGroups, isKanbanGroupingRenderable, resolveKanbanGroupOptions, selectKanbanRows } from "./grouping.js";
2
+ import { panic } from "better-result";
3
+ //#region src/kanban/matrix.ts
4
+ /** Which axis of a board a grouping controls. */
5
+ const KANBAN_BOARD_AXES = {
6
+ group: "group",
7
+ subgroup: "subgroup"
8
+ };
9
+ const optionValueKey = (value) => value === null ? "null" : `string:${value.length}:${value}`;
10
+ /** Apply the visible header order to any lane's cells. */
11
+ const orderKanbanCellsByColumns = ({ cells, columns }) => {
12
+ const orderByValue = new Map(columns.map((column, index) => [optionValueKey(column.value), index]));
13
+ const getColumnOrder = (cell) => {
14
+ return orderByValue.get(optionValueKey(cell.coordinate.column.value)) ?? panic("Visible Kanban cell has no column order");
15
+ };
16
+ return cells.filter((cell) => orderByValue.has(optionValueKey(cell.coordinate.column.value))).toSorted((left, right) => getColumnOrder(left) - getColumnOrder(right));
17
+ };
18
+ const cellKey = ({ column, lane }) => `${optionValueKey(column.value)}|${lane.type === "none" ? "none" : optionValueKey(lane.group.value)}`;
19
+ const groupContainsValue = (groups, value) => groups.some((group) => group.value === value);
20
+ const normalizeGroupValue = (groups, value) => groupContainsValue(groups, value) ? value : null;
21
+ const getRenderableGroups = (grouping, uncategorizedLabel) => {
22
+ if (!isKanbanGroupingRenderable(grouping)) return [];
23
+ return getKanbanGroups(resolveKanbanGroupOptions(grouping), uncategorizedLabel);
24
+ };
25
+ const makeLanes = (subgroup, uncategorizedLabel) => {
26
+ if (subgroup.type === "none") return [{ type: "none" }];
27
+ return getRenderableGroups(subgroup, uncategorizedLabel).map((group) => ({
28
+ group,
29
+ type: "group"
30
+ }));
31
+ };
32
+ /**
33
+ * Resolve the board's one source of placement truth.
34
+ *
35
+ * A subgroup never filters the primary board scope. A row outside a subgroup's
36
+ * declared values goes to its explicit No value lane, rather than disappearing.
37
+ */
38
+ const buildKanbanBoardMatrix = ({ group, subgroup, rows, uncategorizedLabel, resolveGroupValue }) => {
39
+ if (!isKanbanGroupingRenderable(group)) return {
40
+ cells: [],
41
+ columns: [],
42
+ lanes: [],
43
+ rows: []
44
+ };
45
+ const columns = getRenderableGroups(group, uncategorizedLabel);
46
+ const scopedRows = selectKanbanRows(rows, group);
47
+ const hasRenderableSubgroup = isKanbanGroupingRenderable(subgroup);
48
+ const lanes = hasRenderableSubgroup ? makeLanes(subgroup, uncategorizedLabel) : [{ type: "none" }];
49
+ const cells = [];
50
+ const cellsByKey = /* @__PURE__ */ new Map();
51
+ for (const lane of lanes) for (const column of columns) {
52
+ const coordinate = {
53
+ column,
54
+ lane
55
+ };
56
+ const cell = {
57
+ coordinate,
58
+ rows: []
59
+ };
60
+ cells.push(cell);
61
+ cellsByKey.set(cellKey(coordinate), cell);
62
+ }
63
+ for (const row of scopedRows) {
64
+ const columnValue = normalizeGroupValue(columns, resolveGroupValue({
65
+ grouping: group,
66
+ row
67
+ }));
68
+ const lane = !hasRenderableSubgroup ? { type: "none" } : {
69
+ group: {
70
+ value: normalizeGroupValue(lanes.filter((candidate) => candidate.type === "group").map((candidate) => candidate.group), resolveGroupValue({
71
+ grouping: subgroup,
72
+ row
73
+ })),
74
+ label: ""
75
+ },
76
+ type: "group"
77
+ };
78
+ const column = columns.find((candidate) => candidate.value === columnValue);
79
+ const resolvedLane = lane.type === "none" ? lane : lanes.find((candidate) => candidate.type === "group" && candidate.group.value === lane.group.value);
80
+ if (column === void 0 || resolvedLane === void 0) return panic("Kanban matrix cannot place a row in a declared cell");
81
+ const cell = cellsByKey.get(cellKey({
82
+ column,
83
+ lane: resolvedLane
84
+ }));
85
+ if (cell === void 0) return panic("Kanban matrix cell declaration is incomplete");
86
+ cell.rows.push(row);
87
+ }
88
+ return {
89
+ cells,
90
+ columns,
91
+ lanes,
92
+ rows: scopedRows
93
+ };
94
+ };
95
+ /**
96
+ * Builds a single mutation payload for a pointer, touch, or keyboard drop.
97
+ * Diagonal drops carry both changes together; an adapter must commit this
98
+ * intent atomically or reject it as a whole.
99
+ */
100
+ const createKanbanDropIntent = ({ cardId, group, source, subgroup, target }) => {
101
+ const groupBy = getKanbanGroupingPropertyId(group);
102
+ const subgroupBy = getKanbanGroupingPropertyId(subgroup);
103
+ if (groupBy === null || subgroupBy !== null && subgroupBy === groupBy) return null;
104
+ const changes = [];
105
+ if (source.column.value !== target.column.value) changes.push({
106
+ groupBy,
107
+ value: target.column.value
108
+ });
109
+ if (subgroupBy !== null && source.lane.type === "group" && target.lane.type === "group" && source.lane.group.value !== target.lane.group.value) changes.push({
110
+ groupBy: subgroupBy,
111
+ value: target.lane.group.value
112
+ });
113
+ if (changes.length === 0) return null;
114
+ return {
115
+ cardId,
116
+ changes,
117
+ type: "move"
118
+ };
119
+ };
120
+ //#endregion
121
+ export { KANBAN_BOARD_AXES, buildKanbanBoardMatrix, createKanbanDropIntent, orderKanbanCellsByColumns };
@@ -0,0 +1,36 @@
1
+ import { KanbanGroup } from "./grouping.js";
2
+ import { KanbanBoardCell, KanbanBoardMatrix } from "./matrix.js";
3
+ import { ReactNode } from "react";
4
+ //#region src/kanban/subgroup-board.d.ts
5
+ type KanbanSubgroupColumnHeaderContext = {
6
+ column: KanbanGroup;
7
+ count: number;
8
+ };
9
+ type KanbanSubgroupLaneIdentityContext = {
10
+ group: KanbanGroup;
11
+ count: number;
12
+ };
13
+ type KanbanSubgroupCellContext<TRow> = {
14
+ cell: KanbanBoardCell<TRow>;
15
+ laneValue: string | null;
16
+ };
17
+ type KanbanSubgroupCollapseControl = {
18
+ isLaneCollapsed?: undefined;
19
+ onLaneCollapsedChange?: undefined;
20
+ } | {
21
+ isLaneCollapsed: (group: KanbanGroup, count: number) => boolean;
22
+ onLaneCollapsedChange: (group: KanbanGroup, collapsed: boolean) => void;
23
+ };
24
+ type KanbanSubgroupBoardProps<TRow> = {
25
+ matrix: KanbanBoardMatrix<TRow>;
26
+ renderColumnHeader: (context: KanbanSubgroupColumnHeaderContext) => ReactNode;
27
+ renderLaneIdentity: (context: KanbanSubgroupLaneIdentityContext) => ReactNode;
28
+ renderCell: (context: KanbanSubgroupCellContext<TRow>) => ReactNode;
29
+ formatCount?: ((count: number) => ReactNode) | undefined;
30
+ footer?: ReactNode;
31
+ className?: string | undefined;
32
+ } & KanbanSubgroupCollapseControl;
33
+ /** Reusable swimlane layout over the canonical two-axis Kanban matrix. */
34
+ declare const KanbanSubgroupBoard: <TRow>({ matrix, renderColumnHeader, renderLaneIdentity, renderCell, formatCount, isLaneCollapsed, onLaneCollapsedChange, footer, className }: KanbanSubgroupBoardProps<TRow>) => import("react").JSX.Element;
35
+ //#endregion
36
+ export { KanbanSubgroupBoard, KanbanSubgroupBoardProps, KanbanSubgroupCellContext, KanbanSubgroupColumnHeaderContext, KanbanSubgroupLaneIdentityContext };
@@ -0,0 +1,115 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { DirectionalIcon } from "../components/directional-icon.js";
3
+ import { ChevronDownIcon } from "lucide-react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { useMemo, useState } from "react";
6
+ //#region src/kanban/subgroup-board.tsx
7
+ const groupValueKey = (value) => value === null ? "null" : `value:${value.length}:${value}`;
8
+ /** Reusable swimlane layout over the canonical two-axis Kanban matrix. */
9
+ const KanbanSubgroupBoard = ({ matrix, renderColumnHeader, renderLaneIdentity, renderCell, formatCount = String, isLaneCollapsed, onLaneCollapsedChange, footer, className }) => {
10
+ const [collapsedLaneValues, setCollapsedLaneValues] = useState(() => /* @__PURE__ */ new Set());
11
+ const [expandedEmptyLaneValues, setExpandedEmptyLaneValues] = useState(() => /* @__PURE__ */ new Set());
12
+ const { cellsByLaneValue, countByColumnValue } = useMemo(() => {
13
+ const laneCells = /* @__PURE__ */ new Map();
14
+ const columnCounts = /* @__PURE__ */ new Map();
15
+ for (const cell of matrix.cells) {
16
+ columnCounts.set(cell.coordinate.column.value, (columnCounts.get(cell.coordinate.column.value) ?? 0) + cell.rows.length);
17
+ if (cell.coordinate.lane.type === "none") continue;
18
+ const laneValue = cell.coordinate.lane.group.value;
19
+ const currentLaneCells = laneCells.get(laneValue);
20
+ if (currentLaneCells) currentLaneCells.push(cell);
21
+ else laneCells.set(laneValue, [cell]);
22
+ }
23
+ return {
24
+ cellsByLaneValue: laneCells,
25
+ countByColumnValue: columnCounts
26
+ };
27
+ }, [matrix.cells]);
28
+ const setLaneCollapsed = (group, count, collapsed) => {
29
+ if (onLaneCollapsedChange) {
30
+ onLaneCollapsedChange(group, collapsed);
31
+ return;
32
+ }
33
+ const value = group.value;
34
+ if (count === 0) {
35
+ setExpandedEmptyLaneValues((current) => {
36
+ const next = new Set(current);
37
+ if (collapsed) next.delete(value);
38
+ else next.add(value);
39
+ return next;
40
+ });
41
+ return;
42
+ }
43
+ setCollapsedLaneValues((current) => {
44
+ const next = new Set(current);
45
+ if (collapsed) next.add(value);
46
+ else next.delete(value);
47
+ return next;
48
+ });
49
+ };
50
+ return /* @__PURE__ */ jsx("div", {
51
+ className: cn("h-full overflow-auto px-4 pb-4", className),
52
+ children: /* @__PURE__ */ jsxs("div", {
53
+ className: "min-w-max",
54
+ children: [
55
+ /* @__PURE__ */ jsx("div", {
56
+ className: "bg-background sticky top-0 z-20 flex gap-3 pt-4 pb-3",
57
+ children: matrix.columns.map((column) => /* @__PURE__ */ jsx("div", {
58
+ className: "w-[300px] shrink-0",
59
+ children: renderColumnHeader({
60
+ column,
61
+ count: countByColumnValue.get(column.value) ?? 0
62
+ })
63
+ }, groupValueKey(column.value)))
64
+ }),
65
+ matrix.lanes.map((lane) => {
66
+ if (lane.type === "none") return null;
67
+ const { group } = lane;
68
+ const cells = cellsByLaneValue.get(group.value) ?? [];
69
+ const count = cells.reduce((sum, cell) => sum + cell.rows.length, 0);
70
+ const defaultCollapsed = count === 0 ? !expandedEmptyLaneValues.has(group.value) : collapsedLaneValues.has(group.value);
71
+ const collapsed = isLaneCollapsed ? isLaneCollapsed(group, count) : defaultCollapsed;
72
+ return /* @__PURE__ */ jsxs("section", {
73
+ className: "border-border/60 border-b py-2 first:pt-0 last:border-b-0",
74
+ children: [/* @__PURE__ */ jsx("div", {
75
+ className: "bg-background/95 sticky start-0 z-10 flex min-h-11 items-center backdrop-blur-sm",
76
+ children: /* @__PURE__ */ jsxs("button", {
77
+ "aria-expanded": !collapsed,
78
+ className: "hover:bg-muted/60 flex min-h-11 items-center gap-2 rounded-lg px-2 text-start transition-[background-color]",
79
+ onClick: () => setLaneCollapsed(group, count, !collapsed),
80
+ type: "button",
81
+ children: [
82
+ /* @__PURE__ */ jsx(DirectionalIcon, {
83
+ className: cn("text-muted-foreground size-4 shrink-0 transition-transform", collapsed && "-rotate-90"),
84
+ flip: collapsed,
85
+ icon: ChevronDownIcon
86
+ }),
87
+ renderLaneIdentity({
88
+ group,
89
+ count
90
+ }),
91
+ /* @__PURE__ */ jsx("span", {
92
+ className: "text-muted-foreground text-xs tabular-nums",
93
+ children: formatCount(count)
94
+ })
95
+ ]
96
+ })
97
+ }), !collapsed && /* @__PURE__ */ jsx("div", {
98
+ className: "flex gap-3 pb-1",
99
+ children: cells.map((cell) => /* @__PURE__ */ jsx("div", {
100
+ className: "w-[300px] shrink-0",
101
+ children: renderCell({
102
+ cell,
103
+ laneValue: group.value
104
+ })
105
+ }, groupValueKey(cell.coordinate.column.value)))
106
+ })]
107
+ }, groupValueKey(group.value));
108
+ }),
109
+ footer
110
+ ]
111
+ })
112
+ });
113
+ };
114
+ //#endregion
115
+ export { KanbanSubgroupBoard };
@@ -0,0 +1,33 @@
1
+ import { Key, ReactNode, RefObject } from "react";
2
+ //#region src/kanban/virtual-cell.d.ts
3
+ declare const KANBAN_VIRTUAL_CELL_PAGINATION: {
4
+ readonly NONE: "none";
5
+ readonly CURSOR: "cursor";
6
+ };
7
+ type KanbanVirtualCellPagination = {
8
+ type: "none";
9
+ } | {
10
+ type: "cursor";
11
+ hasMore: boolean;
12
+ loading: boolean;
13
+ pageKey: string | number;
14
+ onRequestMore: () => void;
15
+ };
16
+ type KanbanVirtualCellProps<TRow> = {
17
+ rows: readonly TRow[];
18
+ getRowKey: (row: TRow) => Key;
19
+ renderRow: (row: TRow) => ReactNode;
20
+ pagination: KanbanVirtualCellPagination;
21
+ containerRef?: RefObject<HTMLDivElement | null> | undefined;
22
+ active?: boolean | undefined;
23
+ backgroundColor?: string | undefined;
24
+ footer?: ReactNode;
25
+ estimateSize?: number | undefined;
26
+ overscan?: number | undefined;
27
+ loadMoreThreshold?: number | undefined;
28
+ className?: string | undefined;
29
+ };
30
+ /** Bounded, virtualized Kanban cell with cursor-page request deduplication. */
31
+ declare const KanbanVirtualCell: <TRow>({ rows, getRowKey, renderRow, pagination, containerRef, active, backgroundColor, footer, estimateSize, overscan, loadMoreThreshold, className }: KanbanVirtualCellProps<TRow>) => import("react").JSX.Element;
32
+ //#endregion
33
+ export { KANBAN_VIRTUAL_CELL_PAGINATION, KanbanVirtualCell, KanbanVirtualCellPagination, KanbanVirtualCellProps };
@@ -0,0 +1,58 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useRef } from "react";
4
+ import { useVirtualizer } from "@tanstack/react-virtual";
5
+ //#region src/kanban/virtual-cell.tsx
6
+ const DEFAULT_ESTIMATE_SIZE_PX = 128;
7
+ const DEFAULT_OVERSCAN = 8;
8
+ const DEFAULT_LOAD_MORE_THRESHOLD_PX = 200;
9
+ const KANBAN_VIRTUAL_CELL_PAGINATION = {
10
+ NONE: "none",
11
+ CURSOR: "cursor"
12
+ };
13
+ /** Bounded, virtualized Kanban cell with cursor-page request deduplication. */
14
+ const KanbanVirtualCell = ({ rows, getRowKey, renderRow, pagination, containerRef, active = false, backgroundColor, footer, estimateSize = DEFAULT_ESTIMATE_SIZE_PX, overscan = DEFAULT_OVERSCAN, loadMoreThreshold = DEFAULT_LOAD_MORE_THRESHOLD_PX, className }) => {
15
+ const internalRef = useRef(null);
16
+ const scrollRef = containerRef ?? internalRef;
17
+ const requestedPageKeyRef = useRef(null);
18
+ const virtualizer = useVirtualizer({
19
+ count: rows.length,
20
+ estimateSize: () => estimateSize,
21
+ getItemKey: (index) => {
22
+ const row = rows.at(index);
23
+ return row === void 0 ? index : getRowKey(row);
24
+ },
25
+ getScrollElement: () => scrollRef.current,
26
+ overscan
27
+ });
28
+ const handleScroll = ({ currentTarget }) => {
29
+ if (pagination.type !== "cursor" || !pagination.hasMore || pagination.loading) return;
30
+ if (currentTarget.scrollHeight - currentTarget.scrollTop - currentTarget.clientHeight > loadMoreThreshold) return;
31
+ if (requestedPageKeyRef.current === pagination.pageKey) return;
32
+ requestedPageKeyRef.current = pagination.pageKey;
33
+ pagination.onRequestMore();
34
+ };
35
+ return /* @__PURE__ */ jsxs("div", {
36
+ className: cn("bg-muted/20 max-h-[min(60vh,40rem)] min-h-20 overflow-y-auto overscroll-y-contain rounded-xl p-2 transition-[background-color,outline-color]", active && "bg-primary/5 ring-primary/50 ring-2", className),
37
+ onScroll: handleScroll,
38
+ ref: scrollRef,
39
+ style: backgroundColor ? { backgroundColor } : void 0,
40
+ children: [/* @__PURE__ */ jsx("div", {
41
+ className: "relative",
42
+ style: { height: virtualizer.getTotalSize() },
43
+ children: virtualizer.getVirtualItems().map((virtualRow) => {
44
+ const row = rows.at(virtualRow.index);
45
+ if (row === void 0) return null;
46
+ return /* @__PURE__ */ jsx("div", {
47
+ className: "absolute inset-x-0 top-0 pb-2",
48
+ "data-index": virtualRow.index,
49
+ ref: virtualizer.measureElement,
50
+ style: { transform: `translateY(${virtualRow.start}px)` },
51
+ children: renderRow(row)
52
+ }, getRowKey(row));
53
+ })
54
+ }), footer]
55
+ });
56
+ };
57
+ //#endregion
58
+ export { KANBAN_VIRTUAL_CELL_PAGINATION, KanbanVirtualCell };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/ui",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Stella's design system: bidi-aware React primitives built on Base UI, the dockable inspector pane, and the Tailwind v4 theme they are styled with.",
5
5
  "keywords": [
6
6
  "base-ui",
@@ -557,6 +557,7 @@
557
557
  "prepack": "bun run build"
558
558
  },
559
559
  "dependencies": {
560
+ "better-result": "3.0.0",
560
561
  "class-variance-authority": "^0.7.1",
561
562
  "clsx": "^2.1.1",
562
563
  "input-otp": "^1.5.0",
@@ -571,6 +572,7 @@
571
572
  "@dnd-kit/sortable": "^10.0.0",
572
573
  "@playwright/test": "^1.62.0",
573
574
  "@stll/typescript-config": "0.0.0",
575
+ "@tanstack/react-virtual": "^3.14.10",
574
576
  "@types/react": "^19.2.17",
575
577
  "@types/react-dom": "^19.2.3",
576
578
  "bun-types": "1.4.0",
@@ -586,6 +588,7 @@
586
588
  "@base-ui/react": "^1.7.0",
587
589
  "@dnd-kit/core": "^6.3.1",
588
590
  "@dnd-kit/sortable": "^10.0.0",
591
+ "@tanstack/react-virtual": "^3.14.10",
589
592
  "react": ">=19",
590
593
  "react-dom": ">=19",
591
594
  "tailwindcss": "^4.3.0"