@rebasepro/ui 0.6.1 → 0.7.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/dist/icons/index.d.ts +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +2058 -16
- package/dist/index.es.js.map +1 -1
- package/dist/styles.d.ts +1 -1
- package/dist/views/CardView.d.ts +32 -0
- package/dist/views/CollectionView/CollectionCardView.d.ts +30 -0
- package/dist/views/CollectionView/CollectionKanbanView.d.ts +31 -0
- package/dist/views/CollectionView/CollectionListView.d.ts +30 -0
- package/dist/views/CollectionView/CollectionTableView.d.ts +37 -0
- package/dist/views/CollectionView/CollectionView.d.ts +121 -0
- package/dist/views/CollectionView/CollectionViewToolbar.d.ts +31 -0
- package/dist/views/CollectionView/CollectionViewTypes.d.ts +106 -0
- package/dist/views/CollectionView/DefaultCellRenderer.d.ts +9 -0
- package/dist/views/CollectionView/index.d.ts +24 -0
- package/dist/views/CollectionView/utils.d.ts +5 -0
- package/dist/views/Kanban/Board.d.ts +3 -0
- package/dist/views/Kanban/BoardColumn.d.ts +20 -0
- package/dist/views/Kanban/BoardColumnTitle.d.ts +8 -0
- package/dist/views/Kanban/BoardSortableList.d.ts +14 -0
- package/dist/views/Kanban/board_types.d.ts +61 -0
- package/dist/views/Kanban/index.d.ts +5 -0
- package/dist/views/KanbanView.d.ts +24 -0
- package/dist/views/ListView.d.ts +40 -0
- package/dist/views/TableView.d.ts +6 -0
- package/dist/views/index.d.ts +5 -0
- package/package.json +1 -1
- package/src/components/Sheet.tsx +8 -4
- package/src/icons/index.ts +3 -0
- package/src/index.ts +2 -0
- package/src/styles.ts +1 -1
- package/src/views/CardView.tsx +281 -0
- package/src/views/CollectionView/CollectionCardView.tsx +270 -0
- package/src/views/CollectionView/CollectionKanbanView.tsx +251 -0
- package/src/views/CollectionView/CollectionListView.tsx +245 -0
- package/src/views/CollectionView/CollectionTableView.tsx +229 -0
- package/src/views/CollectionView/CollectionView.tsx +388 -0
- package/src/views/CollectionView/CollectionViewToolbar.tsx +229 -0
- package/src/views/CollectionView/CollectionViewTypes.ts +137 -0
- package/src/views/CollectionView/DefaultCellRenderer.tsx +404 -0
- package/src/views/CollectionView/index.ts +44 -0
- package/src/views/CollectionView/utils.ts +14 -0
- package/src/views/Kanban/Board.tsx +421 -0
- package/src/views/Kanban/BoardColumn.tsx +135 -0
- package/src/views/Kanban/BoardColumnTitle.tsx +47 -0
- package/src/views/Kanban/BoardSortableList.tsx +170 -0
- package/src/views/Kanban/board_types.ts +70 -0
- package/src/views/Kanban/index.tsx +5 -0
- package/src/views/KanbanView.tsx +32 -0
- package/src/views/ListView.tsx +281 -0
- package/src/views/TableView.tsx +7 -0
- package/src/views/index.ts +5 -0
package/dist/index.es.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import * as React$1 from "react";
|
|
3
|
-
import React, { Children, createContext, createRef, forwardRef, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import React, { Children, createContext, createRef, forwardRef, memo, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { clsx } from "clsx";
|
|
5
5
|
import { twMerge } from "tailwind-merge";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
8
|
-
import { AlertCircleIcon, AlertCircleIcon as AlertCircleIcon$1, AlertTriangleIcon, AlignLeftIcon, AppWindow, ArrowDownToLineIcon, ArrowLeftIcon, ArrowLeftIcon as ArrowLeftIcon$1, ArrowRightFromLineIcon, ArrowRightIcon, ArrowRightToLineIcon, ArrowUpIcon, ArrowUpToLineIcon, BoldIcon, BookOpenIcon, CalendarIcon, CalendarIcon as CalendarIcon$1, CheckCircleIcon, CheckIcon, CheckIcon as CheckIcon$1, CheckSquareIcon, ChevronDownIcon, ChevronDownIcon as ChevronDownIcon$1, ChevronLeftIcon, ChevronLeftIcon as ChevronLeftIcon$1, ChevronRightIcon, ChevronRightIcon as ChevronRightIcon$1, ChevronUpIcon, ChevronUpIcon as ChevronUpIcon$1, ChevronsLeftIcon, ChevronsRightIcon, ChevronsUpDownIcon, CircleIcon, CircleUserIcon, CodeIcon, ColumnsIcon, CopyIcon, DatabaseIcon, DownloadIcon, ExternalLinkIcon, EyeIcon, EyeOffIcon, FileIcon, FileSearchIcon, FileTextIcon, FilterIcon, FilterIcon as FilterIcon$1, FilterXIcon, FlagIcon, FolderIcon, FolderPlusIcon, FolderUpIcon, FunctionSquareIcon, GitBranchIcon, GlobeIcon, HashIcon, Heading1Icon, Heading2Icon, Heading3Icon, HelpCircleIcon, HistoryIcon, HomeIcon, ImageIcon, ImageOffIcon, InfoIcon, ItalicIcon, KanbanIcon, KeyIcon, KeyRoundIcon, LanguagesIcon, LayoutGridIcon, LinkIcon, ListIcon, ListOrderedIcon, LoaderIcon, LogOutIcon, MailIcon, Maximize2Icon, MenuIcon, MinusCircleIcon, MinusIcon, MinusIcon as MinusIcon$1, MoonIcon, MoreVerticalIcon, Music2Icon, PanelLeftIcon, PauseIcon, PencilIcon, PhoneIcon, PlayIcon, PlusIcon, QuoteIcon, RefreshCcwIcon, RefreshCwIcon, RefreshCwIcon as RefreshCwIcon$1, RepeatIcon, Rows3Icon, SaveIcon, SearchIcon, SearchIcon as SearchIcon$1, SendIcon, SettingsIcon, ShieldAlertIcon, ShieldIcon, ShoppingCartIcon, SlidersHorizontalIcon, SquareIcon, StarIcon, StrikethroughIcon, SunIcon, SunMoonIcon, TableIcon, TagIcon, TerminalIcon, TextIcon, Trash2Icon, TypeIcon, UnderlineIcon, UndoIcon, UploadCloudIcon, UploadIcon, UserCheckIcon, UserIcon, VideoIcon, VoteIcon, Wand2Icon, XCircleIcon, XIcon, XIcon as XIcon$1, icons as lucideIcons } from "lucide-react";
|
|
8
|
+
import { AlertCircleIcon, AlertCircleIcon as AlertCircleIcon$1, AlertTriangleIcon, AlignLeftIcon, AppWindow, ArrowDownToLineIcon, ArrowLeftIcon, ArrowLeftIcon as ArrowLeftIcon$1, ArrowRightFromLineIcon, ArrowRightIcon, ArrowRightToLineIcon, ArrowUpIcon, ArrowUpToLineIcon, BoldIcon, BookOpenIcon, CalendarIcon, CalendarIcon as CalendarIcon$1, CheckCircleIcon, CheckIcon, CheckIcon as CheckIcon$1, CheckSquareIcon, ChevronDownIcon, ChevronDownIcon as ChevronDownIcon$1, ChevronLeftIcon, ChevronLeftIcon as ChevronLeftIcon$1, ChevronRightIcon, ChevronRightIcon as ChevronRightIcon$1, ChevronUpIcon, ChevronUpIcon as ChevronUpIcon$1, ChevronsLeftIcon, ChevronsRightIcon, ChevronsUpDownIcon, CircleIcon, CircleUserIcon, CodeIcon, ColumnsIcon, CopyIcon, DatabaseIcon, DownloadIcon, ExternalLinkIcon, EyeIcon, EyeOffIcon, FileIcon, FileSearchIcon, FileTextIcon, FilterIcon, FilterIcon as FilterIcon$1, FilterXIcon, FlagIcon, FolderIcon, FolderPlusIcon, FolderUpIcon, FunctionSquareIcon, GitBranchIcon, GlobeIcon, HashIcon, Heading1Icon, Heading2Icon, Heading3Icon, HelpCircleIcon, HistoryIcon, HomeIcon, ImageIcon, ImageIcon as ImageIcon$1, ImageOffIcon, InfoIcon, ItalicIcon, Kanban, KanbanIcon, KeyIcon, KeyRoundIcon, LanguagesIcon, LayoutGrid, LayoutGridIcon, LayoutList, Link2Icon, LinkIcon, ListIcon, ListOrderedIcon, LoaderIcon, LockIcon, LogOutIcon, MailIcon, Maximize2Icon, MenuIcon, MinusCircleIcon, MinusIcon, MinusIcon as MinusIcon$1, MoonIcon, MoreVerticalIcon, Music2Icon, PanelLeftIcon, PauseIcon, PencilIcon, PhoneIcon, PlayIcon, PlusIcon, QuoteIcon, RefreshCcwIcon, RefreshCwIcon, RefreshCwIcon as RefreshCwIcon$1, RepeatIcon, Rows3Icon, SaveIcon, SearchIcon, SearchIcon as SearchIcon$1, SendIcon, Settings2, SettingsIcon, ShieldAlertIcon, ShieldIcon, ShoppingCartIcon, SlidersHorizontalIcon, SquareIcon, StarIcon, StrikethroughIcon, SunIcon, SunMoonIcon, Table2, TableIcon, TagIcon, TerminalIcon, TextIcon, Trash2Icon, TypeIcon, UnderlineIcon, UndoIcon, UploadCloudIcon, UploadIcon, UserCheckIcon, UserIcon, UserPlus, VideoIcon, VoteIcon, Wand2Icon, XCircleIcon, XIcon, XIcon as XIcon$1, icons as lucideIcons } from "lucide-react";
|
|
9
9
|
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
10
10
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
11
11
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
@@ -23,13 +23,15 @@ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
|
23
23
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
24
24
|
import * as SliderPrimitive from "@radix-ui/react-slider";
|
|
25
25
|
import * as ReactDOM from "react-dom";
|
|
26
|
+
import { createPortal } from "react-dom";
|
|
26
27
|
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
|
27
28
|
import { FixedSizeList } from "react-window";
|
|
28
29
|
import useMeasure from "react-use-measure";
|
|
29
|
-
import { SortableContext, arrayMove, horizontalListSortingStrategy, useSortable } from "@dnd-kit/sortable";
|
|
30
|
-
import { DndContext, PointerSensor, closestCenter, useSensor, useSensors } from "@dnd-kit/core";
|
|
30
|
+
import { SortableContext, arrayMove, horizontalListSortingStrategy, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
31
|
+
import { DndContext, DragOverlay, PointerSensor, closestCenter, useDroppable, useSensor, useSensors } from "@dnd-kit/core";
|
|
31
32
|
import * as Portal from "@radix-ui/react-portal";
|
|
32
33
|
import { Slot } from "@radix-ui/react-slot";
|
|
34
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
33
35
|
//#region src/util/cls.ts
|
|
34
36
|
function cls(...classes) {
|
|
35
37
|
return twMerge(clsx(classes));
|
|
@@ -192,7 +194,7 @@ var fieldBackgroundMixin = "bg-surface-accent-200/50 dark:bg-black/30";
|
|
|
192
194
|
var fieldBackgroundInvisibleMixin = "bg-surface-accent-200/0 dark:bg-black/0";
|
|
193
195
|
var fieldBackgroundDisabledMixin = "bg-surface-accent-200/50 dark:bg-black/20";
|
|
194
196
|
var fieldBackgroundHoverMixin = "hover:bg-surface-accent-200/70 hover:dark:bg-black/50";
|
|
195
|
-
var defaultBorderMixin = "border-surface-200 dark:border-surface-700 ";
|
|
197
|
+
var defaultBorderMixin = "border-surface-200 dark:border-surface-700/60 ";
|
|
196
198
|
var paperMixin = "bg-white rounded-lg dark:bg-surface-900 border border-surface-200 dark:border-surface-700";
|
|
197
199
|
var cardMixin = "bg-white dark:bg-surface-900 rounded-lg border border-surface-200 dark:border-surface-700";
|
|
198
200
|
var cardClickableMixin = "hover:bg-primary/5 dark:hover:bg-primary/5 cursor-pointer transition-colors duration-150";
|
|
@@ -1609,7 +1611,7 @@ function ExpandablePanel({ title, children, invisible = false, expanded, onExpan
|
|
|
1609
1611
|
if (expanded !== void 0) setOpen(expanded);
|
|
1610
1612
|
}, [expanded]);
|
|
1611
1613
|
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Collapsible.Root, {
|
|
1612
|
-
className: cls(!invisible && "border-surface-200 dark:border-surface-700 border", "rounded-lg", "w-full", className),
|
|
1614
|
+
className: cls(!invisible && "border-surface-200 dark:border-surface-700/60 border", "rounded-lg", "w-full", className),
|
|
1613
1615
|
open,
|
|
1614
1616
|
onOpenChange: (updatedOpen) => {
|
|
1615
1617
|
onExpandedChange?.(updatedOpen);
|
|
@@ -1618,7 +1620,7 @@ function ExpandablePanel({ title, children, invisible = false, expanded, onExpan
|
|
|
1618
1620
|
children: [/* @__PURE__ */ jsx(Collapsible.Trigger, {
|
|
1619
1621
|
asChild: true,
|
|
1620
1622
|
children: /* @__PURE__ */ jsxs("div", {
|
|
1621
|
-
className: cls("rounded-t flex items-center justify-between w-full min-h-[52px]", "hover:bg-surface-accent-200 hover:bg-opacity-40 hover:bg-surface-accent-200/40 dark:hover:bg-surface-800 dark:hover:bg-opacity-40 dark:hover:bg-surface-800/40 active:bg-surface-accent-300/50 dark:active:bg-surface-700/50", invisible ? "border-b px-2" : "p-4", open ? "py-6" : "py-4", "transition-all duration-200", invisible && "border-surface-200 dark:border-surface-700 ", asField && "bg-surface-accent-200/50 dark:bg-black/30", titleClassName, "cursor-pointer"),
|
|
1623
|
+
className: cls("rounded-t flex items-center justify-between w-full min-h-[52px]", "hover:bg-surface-accent-200 hover:bg-opacity-40 hover:bg-surface-accent-200/40 dark:hover:bg-surface-800 dark:hover:bg-opacity-40 dark:hover:bg-surface-800/40 active:bg-surface-accent-300/50 dark:active:bg-surface-700/50", invisible ? "border-b px-2" : "p-4", open ? "py-6" : "py-4", "transition-all duration-200", invisible && "border-surface-200 dark:border-surface-700/60 ", asField && "bg-surface-accent-200/50 dark:bg-black/30", titleClassName, "cursor-pointer"),
|
|
1622
1624
|
role: "button",
|
|
1623
1625
|
tabIndex: 0,
|
|
1624
1626
|
"aria-expanded": open,
|
|
@@ -2292,7 +2294,7 @@ function ResizablePanels({ firstPanel, secondPanel, showFirstPanel = true, showS
|
|
|
2292
2294
|
children: firstPanel
|
|
2293
2295
|
}),
|
|
2294
2296
|
!stacked && showFirstPanel && showSecondPanel && /* @__PURE__ */ jsx("div", {
|
|
2295
|
-
className: cls("relative z-10 flex flex-shrink-0 items-center justify-center", "border-surface-200 dark:border-surface-700 ", isHorizontal ? "border-l w-px h-full cursor-col-resize" : "border-t h-px w-full cursor-row-resize"),
|
|
2297
|
+
className: cls("relative z-10 flex flex-shrink-0 items-center justify-center", "border-surface-200 dark:border-surface-700/60 ", isHorizontal ? "border-l w-px h-full cursor-col-resize" : "border-t h-px w-full cursor-row-resize"),
|
|
2296
2298
|
onMouseDown: handleResizeStart,
|
|
2297
2299
|
children: /* @__PURE__ */ jsx("div", {
|
|
2298
2300
|
className: cls("absolute flex items-center justify-center group", isHorizontal ? "w-4 h-full cursor-col-resize top-0" : "h-4 w-full cursor-row-resize left-0"),
|
|
@@ -2574,6 +2576,7 @@ Slider.displayName = "Slider";
|
|
|
2574
2576
|
//#region src/components/Sheet.tsx
|
|
2575
2577
|
var Sheet = ({ children, side = "right", title, modal = true, includeBackgroundOverlay = true, open, onOpenChange, onPointerDownOutside, onInteractOutside, transparent, className, style, overlayClassName, overlayZIndex = "z-50", overlayStyle, portalContainer, ...props }) => {
|
|
2576
2578
|
const [displayed, setDisplayed] = useState(false);
|
|
2579
|
+
const [contentEl, setContentEl] = useState(null);
|
|
2577
2580
|
const contextContainer = usePortalContainer();
|
|
2578
2581
|
const finalContainer = portalContainer ?? contextContainer ?? void 0;
|
|
2579
2582
|
useEffect(() => {
|
|
@@ -2605,17 +2608,19 @@ var Sheet = ({ children, side = "right", title, modal = true, includeBackgroundO
|
|
|
2605
2608
|
style: overlayStyle
|
|
2606
2609
|
}), /* @__PURE__ */ jsxs(DialogPrimitive.Content, {
|
|
2607
2610
|
...props,
|
|
2608
|
-
|
|
2611
|
+
ref: setContentEl,
|
|
2612
|
+
onOpenAutoFocus: (event) => event.preventDefault(),
|
|
2609
2613
|
onPointerDownOutside,
|
|
2610
2614
|
onInteractOutside,
|
|
2611
2615
|
className: cls("outline-none", borderClass[side], defaultBorderMixin, "transform-gpu", "will-change-transform", "text-surface-accent-900 dark:text-white", "fixed transform z-50 transition-[transform,opacity] ease-in-out", !displayed ? "duration-150" : "duration-100", "outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-0 focus:ring-0", transparent ? "" : "shadow-md bg-white dark:bg-surface-900", side === "top" || side === "bottom" ? "w-full" : "h-full", side === "left" || side === "top" ? "left-0 top-0" : "right-0 bottom-0", displayed && open ? "opacity-100" : "opacity-50", !displayed || !open ? transformValue[side] : "", className),
|
|
2612
2616
|
style,
|
|
2613
2617
|
children: [/* @__PURE__ */ jsx(DialogPrimitive.Title, {
|
|
2614
|
-
autoFocus: true,
|
|
2615
|
-
tabIndex: 0,
|
|
2616
2618
|
className: "sr-only outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-0 focus:ring-0",
|
|
2617
2619
|
children: title ?? "Sheet"
|
|
2618
|
-
}),
|
|
2620
|
+
}), /* @__PURE__ */ jsx(PortalContainerProvider, {
|
|
2621
|
+
container: contentEl,
|
|
2622
|
+
children
|
|
2623
|
+
})]
|
|
2619
2624
|
})]
|
|
2620
2625
|
})
|
|
2621
2626
|
});
|
|
@@ -2936,7 +2941,7 @@ function Tabs({ value, onValueChange, className, innerClassName, variant = "stan
|
|
|
2936
2941
|
disabled: !showLeftScroll,
|
|
2937
2942
|
"aria-label": "Scroll tabs left",
|
|
2938
2943
|
onClick: () => scroll("left"),
|
|
2939
|
-
className: cls("absolute left-0 top-1/2 -translate-y-1/2 z-10 flex items-center justify-center rounded-md transition-all h-8 w-6", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-surface-400", !showLeftScroll ? "pointer-events-none opacity-0" : "text-surface-600 dark:text-surface-400 hover:bg-surface-200 dark:hover:bg-surface-800", "bg-surface-50 dark:bg-surface-900 border shadow-sm", "border-surface-200 dark:border-surface-700 "),
|
|
2944
|
+
className: cls("absolute left-0 top-1/2 -translate-y-1/2 z-10 flex items-center justify-center rounded-md transition-all h-8 w-6", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-surface-400", !showLeftScroll ? "pointer-events-none opacity-0" : "text-surface-600 dark:text-surface-400 hover:bg-surface-200 dark:hover:bg-surface-800", "bg-surface-50 dark:bg-surface-900 border shadow-sm", "border-surface-200 dark:border-surface-700/60 "),
|
|
2940
2945
|
children: /* @__PURE__ */ jsx(ChevronLeftIcon$1, { size: iconSize.smallest })
|
|
2941
2946
|
}),
|
|
2942
2947
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -2948,7 +2953,7 @@ function Tabs({ value, onValueChange, className, innerClassName, variant = "stan
|
|
|
2948
2953
|
msOverflowStyle: "none"
|
|
2949
2954
|
},
|
|
2950
2955
|
children: /* @__PURE__ */ jsx(TabsPrimitive.List, {
|
|
2951
|
-
className: cls(variant === "standard" && "inline-flex h-9 items-center justify-start rounded-md bg-surface-50 p-1 text-surface-600 dark:bg-surface-900 dark:text-surface-400 gap-2 border", variant === "standard" && "border-surface-200 dark:border-surface-700 ", variant === "boxy" && "flex items-center h-full", variant === "pill" && "flex items-center gap-0.5", innerClassName),
|
|
2956
|
+
className: cls(variant === "standard" && "inline-flex h-9 items-center justify-start rounded-md bg-surface-50 p-1 text-surface-600 dark:bg-surface-900 dark:text-surface-400 gap-2 border", variant === "standard" && "border-surface-200 dark:border-surface-700/60 ", variant === "boxy" && "flex items-center h-full", variant === "pill" && "flex items-center gap-0.5", innerClassName),
|
|
2952
2957
|
children
|
|
2953
2958
|
})
|
|
2954
2959
|
}),
|
|
@@ -2957,7 +2962,7 @@ function Tabs({ value, onValueChange, className, innerClassName, variant = "stan
|
|
|
2957
2962
|
disabled: !showRightScroll,
|
|
2958
2963
|
"aria-label": "Scroll tabs right",
|
|
2959
2964
|
onClick: () => scroll("right"),
|
|
2960
|
-
className: cls("absolute right-0 top-1/2 -translate-y-1/2 z-10 flex items-center justify-center rounded-md transition-all h-8 w-6", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-surface-400", !showRightScroll ? "pointer-events-none opacity-0" : "text-surface-600 dark:text-surface-400 hover:bg-surface-200 dark:hover:bg-surface-800", "bg-surface-50 dark:bg-surface-900 border shadow-sm", "border-surface-200 dark:border-surface-700 "),
|
|
2965
|
+
className: cls("absolute right-0 top-1/2 -translate-y-1/2 z-10 flex items-center justify-center rounded-md transition-all h-8 w-6", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-surface-400", !showRightScroll ? "pointer-events-none opacity-0" : "text-surface-600 dark:text-surface-400 hover:bg-surface-200 dark:hover:bg-surface-800", "bg-surface-50 dark:bg-surface-900 border shadow-sm", "border-surface-200 dark:border-surface-700/60 "),
|
|
2961
2966
|
children: /* @__PURE__ */ jsx(ChevronRightIcon$1, { size: iconSize.smallest })
|
|
2962
2967
|
})
|
|
2963
2968
|
]
|
|
@@ -6089,6 +6094,2043 @@ function HandleIcon() {
|
|
|
6089
6094
|
});
|
|
6090
6095
|
}
|
|
6091
6096
|
//#endregion
|
|
6092
|
-
|
|
6097
|
+
//#region src/views/ListView.tsx
|
|
6098
|
+
function getEstimatedRowHeight(size) {
|
|
6099
|
+
switch (size) {
|
|
6100
|
+
case "xs": return 44;
|
|
6101
|
+
case "s": return 52;
|
|
6102
|
+
case "m": return 64;
|
|
6103
|
+
case "l": return 76;
|
|
6104
|
+
case "xl": return 88;
|
|
6105
|
+
default: return 64;
|
|
6106
|
+
}
|
|
6107
|
+
}
|
|
6108
|
+
var OVERSCAN_COUNT = 8;
|
|
6109
|
+
var LOAD_MORE_THRESHOLD = 400;
|
|
6110
|
+
function getScrollParent$1(element) {
|
|
6111
|
+
let parent = element?.parentElement ?? null;
|
|
6112
|
+
while (parent) {
|
|
6113
|
+
const style = getComputedStyle(parent);
|
|
6114
|
+
if (style.overflowY === "auto" || style.overflowY === "scroll" || style.overflow === "auto" || style.overflow === "scroll") return parent;
|
|
6115
|
+
parent = parent.parentElement;
|
|
6116
|
+
}
|
|
6117
|
+
return document.documentElement;
|
|
6118
|
+
}
|
|
6119
|
+
function ListView({ data, dataLoading = false, noMoreToLoad = false, dataLoadingError, itemCount, setItemCount, pageSize = 50, paginationEnabled = true, onItemClick, selectedIds, highlightedIds, selectionEnabled = true, onSelectionChange, emptyComponent, size = "m", selectedEntityId, renderRow }) {
|
|
6120
|
+
const containerRef = useRef(null);
|
|
6121
|
+
const isLoadingMore = useRef(false);
|
|
6122
|
+
useEffect(() => {
|
|
6123
|
+
if (!dataLoading) isLoadingMore.current = false;
|
|
6124
|
+
}, [dataLoading]);
|
|
6125
|
+
const estimatedRowHeight = getEstimatedRowHeight(size);
|
|
6126
|
+
const [effectiveScrollTop, setEffectiveScrollTop] = useState(0);
|
|
6127
|
+
const [viewportHeight, setViewportHeight] = useState(800);
|
|
6128
|
+
const paginationStateRef = useRef({
|
|
6129
|
+
paginationEnabled,
|
|
6130
|
+
noMoreToLoad,
|
|
6131
|
+
itemCount,
|
|
6132
|
+
pageSize
|
|
6133
|
+
});
|
|
6134
|
+
useEffect(() => {
|
|
6135
|
+
paginationStateRef.current = {
|
|
6136
|
+
paginationEnabled,
|
|
6137
|
+
noMoreToLoad,
|
|
6138
|
+
itemCount,
|
|
6139
|
+
pageSize
|
|
6140
|
+
};
|
|
6141
|
+
}, [
|
|
6142
|
+
paginationEnabled,
|
|
6143
|
+
noMoreToLoad,
|
|
6144
|
+
itemCount,
|
|
6145
|
+
pageSize
|
|
6146
|
+
]);
|
|
6147
|
+
useEffect(() => {
|
|
6148
|
+
const el = containerRef.current;
|
|
6149
|
+
if (!el) return;
|
|
6150
|
+
const scrollEl = getScrollParent$1(el);
|
|
6151
|
+
if (!scrollEl) return;
|
|
6152
|
+
let rafId = null;
|
|
6153
|
+
const update = () => {
|
|
6154
|
+
rafId = null;
|
|
6155
|
+
const scrollRect = scrollEl.getBoundingClientRect();
|
|
6156
|
+
const listTopRelative = el.getBoundingClientRect().top - scrollRect.top;
|
|
6157
|
+
setEffectiveScrollTop(Math.max(0, -listTopRelative));
|
|
6158
|
+
setViewportHeight(scrollRect.height);
|
|
6159
|
+
const { paginationEnabled: pe, noMoreToLoad: nm, itemCount: ic, pageSize: ps } = paginationStateRef.current;
|
|
6160
|
+
if (pe && !nm && !isLoadingMore.current && scrollEl.scrollHeight - scrollEl.scrollTop - scrollEl.clientHeight < LOAD_MORE_THRESHOLD) {
|
|
6161
|
+
isLoadingMore.current = true;
|
|
6162
|
+
setItemCount?.((ic ?? ps) + ps);
|
|
6163
|
+
}
|
|
6164
|
+
};
|
|
6165
|
+
const onScroll = () => {
|
|
6166
|
+
if (rafId === null) rafId = requestAnimationFrame(update);
|
|
6167
|
+
};
|
|
6168
|
+
scrollEl.addEventListener("scroll", onScroll, { passive: true });
|
|
6169
|
+
const ro = new ResizeObserver(() => update());
|
|
6170
|
+
ro.observe(scrollEl);
|
|
6171
|
+
update();
|
|
6172
|
+
return () => {
|
|
6173
|
+
scrollEl.removeEventListener("scroll", onScroll);
|
|
6174
|
+
ro.disconnect();
|
|
6175
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
6176
|
+
};
|
|
6177
|
+
}, [setItemCount]);
|
|
6178
|
+
const totalHeight = data.length * estimatedRowHeight;
|
|
6179
|
+
const startIndex = Math.max(0, Math.floor(effectiveScrollTop / estimatedRowHeight) - OVERSCAN_COUNT);
|
|
6180
|
+
const endIndex = Math.min(data.length, Math.ceil((effectiveScrollTop + viewportHeight) / estimatedRowHeight) + OVERSCAN_COUNT);
|
|
6181
|
+
const visibleData = data.slice(startIndex, endIndex);
|
|
6182
|
+
const offsetY = startIndex * estimatedRowHeight;
|
|
6183
|
+
const footerHeight = dataLoading ? 48 : !dataLoading && noMoreToLoad && data.length > 0 ? 32 : 0;
|
|
6184
|
+
const isInitialLoading = dataLoading && data.length === 0;
|
|
6185
|
+
const isEmpty = !dataLoading && data.length === 0 && !dataLoadingError;
|
|
6186
|
+
const getItemId = useCallback((item) => {
|
|
6187
|
+
if (item && typeof item === "object" && "id" in item) {
|
|
6188
|
+
const id = item.id;
|
|
6189
|
+
return typeof id === "number" ? id : String(id);
|
|
6190
|
+
}
|
|
6191
|
+
return String(item);
|
|
6192
|
+
}, []);
|
|
6193
|
+
const borderMixinClass = "border-surface-200 dark:border-surface-800";
|
|
6194
|
+
return /* @__PURE__ */ jsx("div", {
|
|
6195
|
+
ref: containerRef,
|
|
6196
|
+
className: cls("w-full", selectedEntityId === void 0 && `rounded-lg overflow-hidden border ${borderMixinClass}`),
|
|
6197
|
+
children: dataLoadingError && data.length === 0 ? /* @__PURE__ */ jsx("div", {
|
|
6198
|
+
className: "flex items-center justify-center p-8",
|
|
6199
|
+
children: /* @__PURE__ */ jsxs(Typography, {
|
|
6200
|
+
className: "text-red-500",
|
|
6201
|
+
children: ["Error loading data: ", dataLoadingError.message]
|
|
6202
|
+
})
|
|
6203
|
+
}) : isInitialLoading ? /* @__PURE__ */ jsx("div", {
|
|
6204
|
+
className: "flex items-center justify-center py-12 px-8",
|
|
6205
|
+
children: /* @__PURE__ */ jsx(CircularProgress, { size: "small" })
|
|
6206
|
+
}) : isEmpty ? /* @__PURE__ */ jsx("div", {
|
|
6207
|
+
className: "w-full flex items-center justify-center py-12 px-8",
|
|
6208
|
+
children: emptyComponent ?? /* @__PURE__ */ jsx(Typography, {
|
|
6209
|
+
variant: "label",
|
|
6210
|
+
color: "secondary",
|
|
6211
|
+
children: "No entries found"
|
|
6212
|
+
})
|
|
6213
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
6214
|
+
style: {
|
|
6215
|
+
height: totalHeight + footerHeight,
|
|
6216
|
+
position: "relative"
|
|
6217
|
+
},
|
|
6218
|
+
children: [
|
|
6219
|
+
/* @__PURE__ */ jsx("div", {
|
|
6220
|
+
style: {
|
|
6221
|
+
position: "absolute",
|
|
6222
|
+
top: offsetY,
|
|
6223
|
+
left: 0,
|
|
6224
|
+
right: 0
|
|
6225
|
+
},
|
|
6226
|
+
children: visibleData.map((item, i) => {
|
|
6227
|
+
const actualIndex = startIndex + i;
|
|
6228
|
+
const isLast = actualIndex === data.length - 1;
|
|
6229
|
+
const id = getItemId(item);
|
|
6230
|
+
const selected = selectedIds?.has(id) ?? false;
|
|
6231
|
+
const highlighted = highlightedIds?.has(id) ?? false;
|
|
6232
|
+
const handleClick = (e) => {
|
|
6233
|
+
if ((e.metaKey || e.ctrlKey) && selectionEnabled) {
|
|
6234
|
+
e.preventDefault();
|
|
6235
|
+
onSelectionChange?.(item, !selected);
|
|
6236
|
+
return;
|
|
6237
|
+
}
|
|
6238
|
+
onItemClick?.(item);
|
|
6239
|
+
};
|
|
6240
|
+
const handleSelectionChange = (val) => {
|
|
6241
|
+
onSelectionChange?.(item, val);
|
|
6242
|
+
};
|
|
6243
|
+
return /* @__PURE__ */ jsx(React.Fragment, { children: renderRow({
|
|
6244
|
+
item,
|
|
6245
|
+
index: actualIndex,
|
|
6246
|
+
style: { height: estimatedRowHeight },
|
|
6247
|
+
className: cls(!isLast && "border-b", !isLast && borderMixinClass),
|
|
6248
|
+
selected,
|
|
6249
|
+
highlighted,
|
|
6250
|
+
isLast,
|
|
6251
|
+
onClick: handleClick,
|
|
6252
|
+
onSelectionChange: handleSelectionChange
|
|
6253
|
+
}) }, id || actualIndex);
|
|
6254
|
+
})
|
|
6255
|
+
}),
|
|
6256
|
+
dataLoading && /* @__PURE__ */ jsx("div", {
|
|
6257
|
+
className: "flex items-center justify-center py-3",
|
|
6258
|
+
style: {
|
|
6259
|
+
position: "absolute",
|
|
6260
|
+
top: totalHeight,
|
|
6261
|
+
left: 0,
|
|
6262
|
+
right: 0
|
|
6263
|
+
},
|
|
6264
|
+
children: /* @__PURE__ */ jsx(CircularProgress, { size: "small" })
|
|
6265
|
+
}),
|
|
6266
|
+
!dataLoading && noMoreToLoad && data.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
6267
|
+
className: "flex items-center justify-center py-2 dark:bg-surface-900",
|
|
6268
|
+
style: {
|
|
6269
|
+
position: "absolute",
|
|
6270
|
+
top: totalHeight,
|
|
6271
|
+
left: 0,
|
|
6272
|
+
right: 0
|
|
6273
|
+
},
|
|
6274
|
+
children: /* @__PURE__ */ jsxs(Typography, {
|
|
6275
|
+
variant: "caption",
|
|
6276
|
+
color: "secondary",
|
|
6277
|
+
children: [
|
|
6278
|
+
"All ",
|
|
6279
|
+
data.length,
|
|
6280
|
+
" entries loaded"
|
|
6281
|
+
]
|
|
6282
|
+
})
|
|
6283
|
+
})
|
|
6284
|
+
]
|
|
6285
|
+
})
|
|
6286
|
+
});
|
|
6287
|
+
}
|
|
6288
|
+
//#endregion
|
|
6289
|
+
//#region src/views/CardView.tsx
|
|
6290
|
+
function getGridColumnsClass(size) {
|
|
6291
|
+
switch (size) {
|
|
6292
|
+
case "xs": return "grid-cols-4 sm:grid-cols-5 md:grid-cols-6 lg:grid-cols-8 xl:grid-cols-10";
|
|
6293
|
+
case "s": return "grid-cols-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-8";
|
|
6294
|
+
case "m": return "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6";
|
|
6295
|
+
case "l": return "grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-4";
|
|
6296
|
+
case "xl": return "grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3";
|
|
6297
|
+
default: return "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6";
|
|
6298
|
+
}
|
|
6299
|
+
}
|
|
6300
|
+
function getScrollParent(element) {
|
|
6301
|
+
if (!element) return null;
|
|
6302
|
+
let parent = element.parentElement;
|
|
6303
|
+
while (parent) {
|
|
6304
|
+
const overflowY = window.getComputedStyle(parent).overflowY;
|
|
6305
|
+
if (overflowY === "auto" || overflowY === "scroll") return parent;
|
|
6306
|
+
parent = parent.parentElement;
|
|
6307
|
+
}
|
|
6308
|
+
return document.documentElement;
|
|
6309
|
+
}
|
|
6310
|
+
function CardView({ data, dataLoading = false, noMoreToLoad = false, dataLoadingError, itemCount, setItemCount, pageSize = 50, paginationEnabled = true, onItemClick, selectedIds, highlightedIds, selectionEnabled = true, onSelectionChange, onScroll, initialScroll, size = "m", renderCard, emptyComponent }) {
|
|
6311
|
+
const containerRef = useRef(null);
|
|
6312
|
+
const hasRestoredScroll = useRef(false);
|
|
6313
|
+
const isLoadingMore = useRef(false);
|
|
6314
|
+
const paginationStateRef = useRef({
|
|
6315
|
+
paginationEnabled,
|
|
6316
|
+
noMoreToLoad,
|
|
6317
|
+
itemCount,
|
|
6318
|
+
pageSize
|
|
6319
|
+
});
|
|
6320
|
+
useEffect(() => {
|
|
6321
|
+
paginationStateRef.current = {
|
|
6322
|
+
paginationEnabled,
|
|
6323
|
+
noMoreToLoad,
|
|
6324
|
+
itemCount,
|
|
6325
|
+
pageSize
|
|
6326
|
+
};
|
|
6327
|
+
}, [
|
|
6328
|
+
paginationEnabled,
|
|
6329
|
+
noMoreToLoad,
|
|
6330
|
+
itemCount,
|
|
6331
|
+
pageSize
|
|
6332
|
+
]);
|
|
6333
|
+
useEffect(() => {
|
|
6334
|
+
if (!dataLoading) isLoadingMore.current = false;
|
|
6335
|
+
}, [dataLoading]);
|
|
6336
|
+
useEffect(() => {
|
|
6337
|
+
const el = containerRef.current;
|
|
6338
|
+
if (!el) return;
|
|
6339
|
+
const scrollEl = getScrollParent(el);
|
|
6340
|
+
if (!scrollEl) return;
|
|
6341
|
+
let rafId = null;
|
|
6342
|
+
const update = () => {
|
|
6343
|
+
rafId = null;
|
|
6344
|
+
const { paginationEnabled: pe, noMoreToLoad: nm, itemCount: ic, pageSize: ps } = paginationStateRef.current;
|
|
6345
|
+
if (pe && !nm && !isLoadingMore.current && scrollEl.scrollHeight - scrollEl.scrollTop - scrollEl.clientHeight < 400) {
|
|
6346
|
+
isLoadingMore.current = true;
|
|
6347
|
+
setItemCount?.((ic ?? ps) + ps);
|
|
6348
|
+
}
|
|
6349
|
+
};
|
|
6350
|
+
const onScrollEvent = () => {
|
|
6351
|
+
if (rafId === null) rafId = requestAnimationFrame(update);
|
|
6352
|
+
};
|
|
6353
|
+
scrollEl.addEventListener("scroll", onScrollEvent, { passive: true });
|
|
6354
|
+
const ro = new ResizeObserver(() => update());
|
|
6355
|
+
ro.observe(scrollEl);
|
|
6356
|
+
update();
|
|
6357
|
+
return () => {
|
|
6358
|
+
scrollEl.removeEventListener("scroll", onScrollEvent);
|
|
6359
|
+
ro.disconnect();
|
|
6360
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
6361
|
+
};
|
|
6362
|
+
}, [setItemCount]);
|
|
6363
|
+
useEffect(() => {
|
|
6364
|
+
if (!containerRef.current || !initialScroll || hasRestoredScroll.current || data.length === 0) return;
|
|
6365
|
+
const scrollEl = getScrollParent(containerRef.current);
|
|
6366
|
+
if (!scrollEl) return;
|
|
6367
|
+
let attempts = 0;
|
|
6368
|
+
const maxAttempts = 5;
|
|
6369
|
+
const tryRestore = () => {
|
|
6370
|
+
if (scrollEl.scrollHeight >= initialScroll || attempts >= maxAttempts) {
|
|
6371
|
+
scrollEl.scrollTop = initialScroll;
|
|
6372
|
+
hasRestoredScroll.current = true;
|
|
6373
|
+
} else {
|
|
6374
|
+
attempts++;
|
|
6375
|
+
requestAnimationFrame(tryRestore);
|
|
6376
|
+
}
|
|
6377
|
+
};
|
|
6378
|
+
requestAnimationFrame(tryRestore);
|
|
6379
|
+
}, [initialScroll, data.length]);
|
|
6380
|
+
const lastScrollOffset = useRef(0);
|
|
6381
|
+
useEffect(() => {
|
|
6382
|
+
const el = containerRef.current;
|
|
6383
|
+
if (!el || !onScroll) return;
|
|
6384
|
+
const scrollEl = getScrollParent(el);
|
|
6385
|
+
if (!scrollEl) return;
|
|
6386
|
+
const handleScroll = () => {
|
|
6387
|
+
const currentOffset = scrollEl.scrollTop;
|
|
6388
|
+
const direction = currentOffset > lastScrollOffset.current ? "forward" : "backward";
|
|
6389
|
+
lastScrollOffset.current = currentOffset;
|
|
6390
|
+
onScroll({
|
|
6391
|
+
scrollDirection: direction,
|
|
6392
|
+
scrollOffset: currentOffset,
|
|
6393
|
+
scrollUpdateWasRequested: false
|
|
6394
|
+
});
|
|
6395
|
+
};
|
|
6396
|
+
scrollEl.addEventListener("scroll", handleScroll, { passive: true });
|
|
6397
|
+
return () => scrollEl.removeEventListener("scroll", handleScroll);
|
|
6398
|
+
}, [onScroll]);
|
|
6399
|
+
const getItemId = useCallback((item) => {
|
|
6400
|
+
if (item && typeof item === "object" && "id" in item) {
|
|
6401
|
+
const id = item.id;
|
|
6402
|
+
return typeof id === "number" ? id : String(id);
|
|
6403
|
+
}
|
|
6404
|
+
return String(item);
|
|
6405
|
+
}, []);
|
|
6406
|
+
const gridColumnsClass = getGridColumnsClass(size);
|
|
6407
|
+
const isInitialLoading = dataLoading && data.length === 0 && !dataLoadingError;
|
|
6408
|
+
const isEmpty = !dataLoading && data.length === 0 && !dataLoadingError;
|
|
6409
|
+
return /* @__PURE__ */ jsx("div", {
|
|
6410
|
+
ref: containerRef,
|
|
6411
|
+
className: "w-full p-4",
|
|
6412
|
+
children: dataLoadingError && data.length === 0 ? /* @__PURE__ */ jsx("div", {
|
|
6413
|
+
className: "h-full flex items-center justify-center p-8",
|
|
6414
|
+
children: /* @__PURE__ */ jsxs(Typography, {
|
|
6415
|
+
className: "text-red-500",
|
|
6416
|
+
children: ["Error loading data: ", dataLoadingError.message]
|
|
6417
|
+
})
|
|
6418
|
+
}) : isInitialLoading ? /* @__PURE__ */ jsx("div", {
|
|
6419
|
+
className: "flex items-center justify-center py-12 px-8",
|
|
6420
|
+
children: /* @__PURE__ */ jsx(CircularProgress, { size: "small" })
|
|
6421
|
+
}) : isEmpty ? /* @__PURE__ */ jsx("div", {
|
|
6422
|
+
className: "w-full flex items-center justify-center py-12 px-8",
|
|
6423
|
+
children: emptyComponent ?? /* @__PURE__ */ jsx(Typography, {
|
|
6424
|
+
variant: "label",
|
|
6425
|
+
color: "secondary",
|
|
6426
|
+
children: "No entries found"
|
|
6427
|
+
})
|
|
6428
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
6429
|
+
className: "max-w-7xl mx-auto",
|
|
6430
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
6431
|
+
className: cls("grid gap-4", gridColumnsClass),
|
|
6432
|
+
children: data.map((item, index) => {
|
|
6433
|
+
const id = getItemId(item);
|
|
6434
|
+
const selected = selectedIds?.has(id) ?? false;
|
|
6435
|
+
const highlighted = highlightedIds?.has(id) ?? false;
|
|
6436
|
+
const handleClick = (e) => {
|
|
6437
|
+
if ((e.metaKey || e.ctrlKey) && selectionEnabled) {
|
|
6438
|
+
e.preventDefault();
|
|
6439
|
+
onSelectionChange?.(item, !selected);
|
|
6440
|
+
return;
|
|
6441
|
+
}
|
|
6442
|
+
onItemClick?.(item);
|
|
6443
|
+
};
|
|
6444
|
+
const handleSelectionChange = (val) => {
|
|
6445
|
+
onSelectionChange?.(item, val);
|
|
6446
|
+
};
|
|
6447
|
+
return /* @__PURE__ */ jsx(React.Fragment, { children: renderCard(item, {
|
|
6448
|
+
selected,
|
|
6449
|
+
highlighted,
|
|
6450
|
+
onSelectionChange: handleSelectionChange,
|
|
6451
|
+
onClick: handleClick
|
|
6452
|
+
}) }, id || index);
|
|
6453
|
+
})
|
|
6454
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
6455
|
+
className: "flex items-center justify-center py-8",
|
|
6456
|
+
children: [dataLoading && /* @__PURE__ */ jsx(CircularProgress, { size: "small" }), !dataLoading && noMoreToLoad && data.length > 0 && /* @__PURE__ */ jsxs(Typography, {
|
|
6457
|
+
variant: "caption",
|
|
6458
|
+
color: "secondary",
|
|
6459
|
+
children: [
|
|
6460
|
+
"All ",
|
|
6461
|
+
data.length,
|
|
6462
|
+
" entries loaded"
|
|
6463
|
+
]
|
|
6464
|
+
})]
|
|
6465
|
+
})]
|
|
6466
|
+
})
|
|
6467
|
+
});
|
|
6468
|
+
}
|
|
6469
|
+
//#endregion
|
|
6470
|
+
//#region src/views/Kanban/BoardSortableList.tsx
|
|
6471
|
+
function BoardSortableList({ columnId, items, ItemComponent, isDragging, isDragOverColumn, loading = false, hasMore = false, onLoadMore }) {
|
|
6472
|
+
const { setNodeRef } = useDroppable({
|
|
6473
|
+
id: columnId,
|
|
6474
|
+
data: { type: "ITEM-LIST" }
|
|
6475
|
+
});
|
|
6476
|
+
const sentinelRef = useRef(null);
|
|
6477
|
+
const isLoadingRef = useRef(loading);
|
|
6478
|
+
isLoadingRef.current = loading;
|
|
6479
|
+
const lastLoadTimeRef = useRef(0);
|
|
6480
|
+
useEffect(() => {
|
|
6481
|
+
if (!sentinelRef.current || !hasMore || !onLoadMore) return;
|
|
6482
|
+
const sentinel = sentinelRef.current;
|
|
6483
|
+
const observer = new IntersectionObserver((entries) => {
|
|
6484
|
+
const now = Date.now();
|
|
6485
|
+
if (entries[0].isIntersecting && hasMore && !isLoadingRef.current && now - lastLoadTimeRef.current > 500) {
|
|
6486
|
+
lastLoadTimeRef.current = now;
|
|
6487
|
+
onLoadMore();
|
|
6488
|
+
}
|
|
6489
|
+
}, { threshold: .1 });
|
|
6490
|
+
observer.observe(sentinel);
|
|
6491
|
+
const rect = sentinel.getBoundingClientRect();
|
|
6492
|
+
const containerRect = sentinel.parentElement?.getBoundingClientRect();
|
|
6493
|
+
if (containerRect && rect.top < containerRect.bottom && rect.bottom > containerRect.top) {
|
|
6494
|
+
const now = Date.now();
|
|
6495
|
+
if (hasMore && !isLoadingRef.current && now - lastLoadTimeRef.current > 500) {
|
|
6496
|
+
lastLoadTimeRef.current = now;
|
|
6497
|
+
onLoadMore();
|
|
6498
|
+
}
|
|
6499
|
+
}
|
|
6500
|
+
return () => observer.disconnect();
|
|
6501
|
+
}, [hasMore, onLoadMore]);
|
|
6502
|
+
return /* @__PURE__ */ jsx("div", {
|
|
6503
|
+
ref: setNodeRef,
|
|
6504
|
+
className: useMemo(() => cls("flex flex-col p-2 transition-opacity duration-100 transition-bg ease-linear w-full overflow-y-auto no-scrollbar flex-1 rounded-md", isDragging && isDragOverColumn ? "bg-surface-accent-200 dark:bg-surface-900" : isDragging ? "bg-surface-50 dark:bg-surface-900 hover:bg-surface-accent-100 dark:hover:bg-surface-800" : "bg-surface-50 dark:bg-surface-900"), [isDragging, isDragOverColumn]),
|
|
6505
|
+
style: { minHeight: 80 },
|
|
6506
|
+
children: /* @__PURE__ */ jsx(SortableContext, {
|
|
6507
|
+
items: items.map((i) => i.id),
|
|
6508
|
+
strategy: verticalListSortingStrategy,
|
|
6509
|
+
children: items.length === 0 && !loading ? /* @__PURE__ */ jsx("div", {
|
|
6510
|
+
className: "flex-1 flex items-center justify-center",
|
|
6511
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
6512
|
+
className: "text-xs text-surface-400 dark:text-surface-500",
|
|
6513
|
+
children: "No items"
|
|
6514
|
+
})
|
|
6515
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [items.map((item, index) => /* @__PURE__ */ jsx(SortableItem, {
|
|
6516
|
+
item,
|
|
6517
|
+
index,
|
|
6518
|
+
columnId,
|
|
6519
|
+
ItemComponent
|
|
6520
|
+
}, item.id)), (loading || hasMore) && /* @__PURE__ */ jsx("div", {
|
|
6521
|
+
ref: sentinelRef,
|
|
6522
|
+
className: "flex items-center justify-center py-2 min-h-6",
|
|
6523
|
+
children: loading && /* @__PURE__ */ jsx(CircularProgress, { size: "smallest" })
|
|
6524
|
+
})] })
|
|
6525
|
+
})
|
|
6526
|
+
});
|
|
6527
|
+
}
|
|
6528
|
+
var SortableItem = memo(function SortableItem({ item, index, columnId, ItemComponent }) {
|
|
6529
|
+
const { setNodeRef, attributes, listeners, isDragging: isItemBeingDragged, transform, transition } = useSortable({
|
|
6530
|
+
id: item.id,
|
|
6531
|
+
data: {
|
|
6532
|
+
type: "ITEM",
|
|
6533
|
+
columnId
|
|
6534
|
+
}
|
|
6535
|
+
});
|
|
6536
|
+
return /* @__PURE__ */ jsx("div", {
|
|
6537
|
+
ref: setNodeRef,
|
|
6538
|
+
style: useMemo(() => ({
|
|
6539
|
+
transform: CSS.Transform.toString(transform),
|
|
6540
|
+
transition,
|
|
6541
|
+
zIndex: isItemBeingDragged ? 2 : 1,
|
|
6542
|
+
opacity: isItemBeingDragged ? 0 : 1
|
|
6543
|
+
}), [
|
|
6544
|
+
transform,
|
|
6545
|
+
transition,
|
|
6546
|
+
isItemBeingDragged
|
|
6547
|
+
]),
|
|
6548
|
+
...attributes,
|
|
6549
|
+
...listeners,
|
|
6550
|
+
children: /* @__PURE__ */ jsx(ItemComponent, {
|
|
6551
|
+
item,
|
|
6552
|
+
isDragging: isItemBeingDragged,
|
|
6553
|
+
index
|
|
6554
|
+
})
|
|
6555
|
+
});
|
|
6556
|
+
});
|
|
6557
|
+
//#endregion
|
|
6558
|
+
//#region src/views/Kanban/BoardColumnTitle.tsx
|
|
6559
|
+
function BoardColumnTitle({ children, className, color, ...props }) {
|
|
6560
|
+
const colorScheme = useMemo(() => {
|
|
6561
|
+
if (!color) return void 0;
|
|
6562
|
+
if (typeof color === "string") return getColorSchemeForKey(color);
|
|
6563
|
+
return color;
|
|
6564
|
+
}, [color]);
|
|
6565
|
+
return /* @__PURE__ */ jsxs(Typography, {
|
|
6566
|
+
variant: "subtitle2",
|
|
6567
|
+
component: "h4",
|
|
6568
|
+
className: cls("py-3 px-3 transition-colors duration-200 flex-grow select-none relative outline-none focus:outline focus:outline-2 focus:outline-offset-2 flex items-center gap-3", className),
|
|
6569
|
+
...props,
|
|
6570
|
+
children: [colorScheme && /* @__PURE__ */ jsx("div", {
|
|
6571
|
+
className: "w-3 h-3 rounded-full flex-shrink-0",
|
|
6572
|
+
style: { backgroundColor: colorScheme.darkColor ?? colorScheme.color }
|
|
6573
|
+
}), children]
|
|
6574
|
+
});
|
|
6575
|
+
}
|
|
6576
|
+
//#endregion
|
|
6577
|
+
//#region src/views/Kanban/BoardColumn.tsx
|
|
6578
|
+
var BoardColumn = memo(function BoardColumn({ id, title, items, ItemComponent, isDragging, isDragOverColumn, allowReorder = false, loading = false, hasMore = false, onLoadMore, onAddItem, totalCount, color, style }) {
|
|
6579
|
+
const { setNodeRef, attributes, listeners, isDragging: isColumnBeingDragged, transform, transition } = useSortable({
|
|
6580
|
+
id,
|
|
6581
|
+
data: { type: "COLUMN" },
|
|
6582
|
+
disabled: !allowReorder
|
|
6583
|
+
});
|
|
6584
|
+
const combinedStyle = useMemo(() => ({
|
|
6585
|
+
...style,
|
|
6586
|
+
transform: CSS.Translate.toString(transform),
|
|
6587
|
+
transition,
|
|
6588
|
+
zIndex: isColumnBeingDragged ? 2 : 1
|
|
6589
|
+
}), [
|
|
6590
|
+
style,
|
|
6591
|
+
transform,
|
|
6592
|
+
transition,
|
|
6593
|
+
isColumnBeingDragged
|
|
6594
|
+
]);
|
|
6595
|
+
const dragListeners = allowReorder ? listeners : {};
|
|
6596
|
+
const columnClassName = useMemo(() => cls("border h-full w-80 min-w-80 mx-2 flex flex-col rounded-md border-surface-200 dark:border-surface-800", isColumnBeingDragged ? "ring-2 ring-primary" : ""), [isColumnBeingDragged]);
|
|
6597
|
+
const headerClassName = useMemo(() => cls("flex items-center justify-between px-2 rounded-t-md transition-colors duration-200 ease-in-out", isColumnBeingDragged ? "bg-surface-100 dark:bg-surface-700" : "bg-surface-50 hover:bg-surface-100 dark:bg-surface-800 dark:hover:bg-surface-700", allowReorder ? "cursor-grab" : ""), [isColumnBeingDragged, allowReorder]);
|
|
6598
|
+
const itemIds = useMemo(() => items.map((i) => i.id), [items]);
|
|
6599
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
6600
|
+
ref: setNodeRef,
|
|
6601
|
+
style: combinedStyle,
|
|
6602
|
+
...attributes,
|
|
6603
|
+
className: columnClassName,
|
|
6604
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
6605
|
+
...dragListeners,
|
|
6606
|
+
className: headerClassName,
|
|
6607
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
6608
|
+
className: "flex items-center gap-2",
|
|
6609
|
+
children: [/* @__PURE__ */ jsx(BoardColumnTitle, {
|
|
6610
|
+
"aria-label": `${title} item list`,
|
|
6611
|
+
color,
|
|
6612
|
+
children: title
|
|
6613
|
+
}), totalCount !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
6614
|
+
className: "text-xs text-surface-500 dark:text-surface-400",
|
|
6615
|
+
children: totalCount
|
|
6616
|
+
})]
|
|
6617
|
+
}), onAddItem && /* @__PURE__ */ jsx(IconButton, {
|
|
6618
|
+
size: "small",
|
|
6619
|
+
onClick: (e) => {
|
|
6620
|
+
e.stopPropagation();
|
|
6621
|
+
onAddItem();
|
|
6622
|
+
},
|
|
6623
|
+
className: "opacity-60 hover:opacity-100",
|
|
6624
|
+
children: /* @__PURE__ */ jsx(PlusIcon, { size: iconSize.small })
|
|
6625
|
+
})]
|
|
6626
|
+
}), /* @__PURE__ */ jsx(SortableContext, {
|
|
6627
|
+
items: itemIds,
|
|
6628
|
+
strategy: verticalListSortingStrategy,
|
|
6629
|
+
children: /* @__PURE__ */ jsx(BoardSortableList, {
|
|
6630
|
+
columnId: id,
|
|
6631
|
+
items,
|
|
6632
|
+
ItemComponent,
|
|
6633
|
+
isDragging,
|
|
6634
|
+
isDragOverColumn,
|
|
6635
|
+
loading,
|
|
6636
|
+
hasMore,
|
|
6637
|
+
onLoadMore
|
|
6638
|
+
})
|
|
6639
|
+
})]
|
|
6640
|
+
});
|
|
6641
|
+
});
|
|
6642
|
+
//#endregion
|
|
6643
|
+
//#region src/views/Kanban/Board.tsx
|
|
6644
|
+
function Board({ data, columns: columnsProp, columnLabels, columnColors, className, assignColumn, allowColumnReorder = false, onColumnReorder, onItemsReorder, ItemComponent, columnLoadingState, onLoadMoreColumn, onAddItemToColumn, AddColumnComponent }) {
|
|
6645
|
+
const [activeItem, setActiveItem] = useState(null);
|
|
6646
|
+
const [activeColumn, setActiveColumn] = useState(null);
|
|
6647
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
6648
|
+
const [dragOverColumnId, setDragOverColumnId] = useState(null);
|
|
6649
|
+
const grabOffsetRef = useRef({
|
|
6650
|
+
x: 0,
|
|
6651
|
+
y: 0
|
|
6652
|
+
});
|
|
6653
|
+
const [overlayPos, setOverlayPos] = useState(null);
|
|
6654
|
+
const handleMouseMove = useCallback((e) => {
|
|
6655
|
+
setOverlayPos({
|
|
6656
|
+
x: e.clientX - grabOffsetRef.current.x,
|
|
6657
|
+
y: e.clientY - grabOffsetRef.current.y
|
|
6658
|
+
});
|
|
6659
|
+
}, []);
|
|
6660
|
+
useEffect(() => {
|
|
6661
|
+
return () => {
|
|
6662
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
6663
|
+
window.removeEventListener("pointermove", handleMouseMove);
|
|
6664
|
+
};
|
|
6665
|
+
}, [handleMouseMove]);
|
|
6666
|
+
const [itemMapState, setItemMapState] = useState(() => {
|
|
6667
|
+
const dataColumnMap = data.reduce((prev, item) => ({
|
|
6668
|
+
...prev,
|
|
6669
|
+
[item.id]: assignColumn(item)
|
|
6670
|
+
}), {});
|
|
6671
|
+
return columnsProp.reduce((previous, column) => ({
|
|
6672
|
+
...previous,
|
|
6673
|
+
[column]: data.filter((item) => dataColumnMap[item.id] === column)
|
|
6674
|
+
}), {});
|
|
6675
|
+
});
|
|
6676
|
+
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 5 } }));
|
|
6677
|
+
useEffect(() => {
|
|
6678
|
+
if (isDragging) return;
|
|
6679
|
+
const dataColumnMap = data.reduce((prev, item) => ({
|
|
6680
|
+
...prev,
|
|
6681
|
+
[item.id]: assignColumn(item)
|
|
6682
|
+
}), {});
|
|
6683
|
+
const newItemMap = columnsProp.reduce((previous, column) => ({
|
|
6684
|
+
...previous,
|
|
6685
|
+
[column]: data.filter((item) => dataColumnMap[item.id] === column)
|
|
6686
|
+
}), {});
|
|
6687
|
+
setItemMapState((prevMap) => {
|
|
6688
|
+
let changed = false;
|
|
6689
|
+
for (const col of columnsProp) {
|
|
6690
|
+
const prevItems = prevMap[col] ?? [];
|
|
6691
|
+
const newItems = newItemMap[col] ?? [];
|
|
6692
|
+
if (prevItems.length !== newItems.length) {
|
|
6693
|
+
changed = true;
|
|
6694
|
+
continue;
|
|
6695
|
+
}
|
|
6696
|
+
for (let i = 0; i < prevItems.length; i++) if (prevItems[i].id !== newItems[i].id || prevItems[i].data !== newItems[i].data) {
|
|
6697
|
+
changed = true;
|
|
6698
|
+
break;
|
|
6699
|
+
}
|
|
6700
|
+
}
|
|
6701
|
+
if (!changed) return prevMap;
|
|
6702
|
+
const updated = {};
|
|
6703
|
+
for (const col of columnsProp) {
|
|
6704
|
+
const prevItems = prevMap[col] ?? [];
|
|
6705
|
+
const newItems = newItemMap[col] ?? [];
|
|
6706
|
+
const prevById = /* @__PURE__ */ new Map();
|
|
6707
|
+
for (const item of prevItems) prevById.set(item.id, item);
|
|
6708
|
+
updated[col] = newItems.map((newItem) => {
|
|
6709
|
+
const prev = prevById.get(newItem.id);
|
|
6710
|
+
if (prev && prev.data === newItem.data) return prev;
|
|
6711
|
+
return newItem;
|
|
6712
|
+
});
|
|
6713
|
+
}
|
|
6714
|
+
return updated;
|
|
6715
|
+
});
|
|
6716
|
+
}, [
|
|
6717
|
+
data,
|
|
6718
|
+
columnsProp,
|
|
6719
|
+
assignColumn
|
|
6720
|
+
]);
|
|
6721
|
+
const findColumnByItemId = (id) => {
|
|
6722
|
+
return Object.keys(itemMapState).find((col) => itemMapState[col]?.some((i) => i.id === id));
|
|
6723
|
+
};
|
|
6724
|
+
const handleDragStart = (event) => {
|
|
6725
|
+
setIsDragging(true);
|
|
6726
|
+
setDragOverColumnId(null);
|
|
6727
|
+
const { active } = event;
|
|
6728
|
+
const activatorEvt = event.activatorEvent;
|
|
6729
|
+
if (activatorEvt) {
|
|
6730
|
+
const target = activatorEvt.target;
|
|
6731
|
+
const rect = (target.closest("[role='button']") ?? target).getBoundingClientRect();
|
|
6732
|
+
grabOffsetRef.current = {
|
|
6733
|
+
x: activatorEvt.clientX - rect.left,
|
|
6734
|
+
y: activatorEvt.clientY - rect.top
|
|
6735
|
+
};
|
|
6736
|
+
setOverlayPos({
|
|
6737
|
+
x: rect.left,
|
|
6738
|
+
y: rect.top
|
|
6739
|
+
});
|
|
6740
|
+
}
|
|
6741
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
6742
|
+
window.addEventListener("pointermove", handleMouseMove);
|
|
6743
|
+
if (active.data.current?.type === "COLUMN") {
|
|
6744
|
+
const columnId = active.id;
|
|
6745
|
+
const column = columnsProp.find((col) => String(col) === columnId);
|
|
6746
|
+
if (column) setActiveColumn(column);
|
|
6747
|
+
} else if (active.data.current?.type === "ITEM") {
|
|
6748
|
+
const columnId = findColumnByItemId(active.id);
|
|
6749
|
+
if (columnId) {
|
|
6750
|
+
const item = itemMapState[columnId]?.find((i) => i.id === active.id);
|
|
6751
|
+
setActiveItem(item || null);
|
|
6752
|
+
}
|
|
6753
|
+
}
|
|
6754
|
+
};
|
|
6755
|
+
const handleDragOver = (event) => {
|
|
6756
|
+
const { active, over } = event;
|
|
6757
|
+
if (!over) {
|
|
6758
|
+
setDragOverColumnId(null);
|
|
6759
|
+
return;
|
|
6760
|
+
}
|
|
6761
|
+
let currentHoveredColumnId = null;
|
|
6762
|
+
const overId = over.id;
|
|
6763
|
+
const overDataType = over.data.current?.type;
|
|
6764
|
+
if (overDataType === "ITEM-LIST" || overDataType === "COLUMN") currentHoveredColumnId = overId;
|
|
6765
|
+
else if (overDataType === "ITEM") currentHoveredColumnId = findColumnByItemId(overId) || null;
|
|
6766
|
+
else if (columnsProp.includes(overId)) currentHoveredColumnId = overId;
|
|
6767
|
+
setDragOverColumnId(currentHoveredColumnId);
|
|
6768
|
+
if (active.data.current?.type !== "ITEM") return;
|
|
6769
|
+
const activeId = active.id;
|
|
6770
|
+
const activeColumn = findColumnByItemId(activeId);
|
|
6771
|
+
let overColumnForMove = findColumnByItemId(overId);
|
|
6772
|
+
if (!overColumnForMove && overDataType === "ITEM-LIST") overColumnForMove = overId;
|
|
6773
|
+
if (!overColumnForMove && columnsProp.includes(overId)) overColumnForMove = overId;
|
|
6774
|
+
if (!activeColumn || !overColumnForMove) return;
|
|
6775
|
+
if (activeColumn === overColumnForMove) return;
|
|
6776
|
+
if (itemMapState[overColumnForMove]?.some((i) => i.id === activeId)) return;
|
|
6777
|
+
setItemMapState((currentMap) => {
|
|
6778
|
+
const activeItems = [...currentMap[activeColumn] || []];
|
|
6779
|
+
const overItems = [...currentMap[overColumnForMove] || []];
|
|
6780
|
+
const activeIndex = activeItems.findIndex((i) => i.id === activeId);
|
|
6781
|
+
if (activeIndex === -1) return currentMap;
|
|
6782
|
+
let overIndex;
|
|
6783
|
+
if (overDataType === "ITEM-LIST" || columnsProp.includes(overId) && !findColumnByItemId(overId)) overIndex = overItems.length;
|
|
6784
|
+
else {
|
|
6785
|
+
overIndex = overItems.findIndex((i) => i.id === overId);
|
|
6786
|
+
if (overIndex !== -1) {
|
|
6787
|
+
const modifier = (active.rect.current.translated?.top ?? 0) + (active.rect.current.translated?.height ?? 0) / 2 > (over?.rect.top ?? 0) + (over?.rect.height ?? 0) / 2 ? 1 : 0;
|
|
6788
|
+
overIndex = overIndex >= 0 ? overIndex + modifier : overItems.length;
|
|
6789
|
+
} else overIndex = overItems.length;
|
|
6790
|
+
}
|
|
6791
|
+
const newItemMap = { ...currentMap };
|
|
6792
|
+
const [moved] = activeItems.splice(activeIndex, 1);
|
|
6793
|
+
overItems.splice(overIndex, 0, moved);
|
|
6794
|
+
newItemMap[activeColumn] = activeItems;
|
|
6795
|
+
newItemMap[overColumnForMove] = overItems;
|
|
6796
|
+
return newItemMap;
|
|
6797
|
+
});
|
|
6798
|
+
};
|
|
6799
|
+
const handleDragEnd = (event) => {
|
|
6800
|
+
const { active, over } = event;
|
|
6801
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
6802
|
+
window.removeEventListener("pointermove", handleMouseMove);
|
|
6803
|
+
setOverlayPos(null);
|
|
6804
|
+
setIsDragging(false);
|
|
6805
|
+
setActiveItem(null);
|
|
6806
|
+
setActiveColumn(null);
|
|
6807
|
+
setDragOverColumnId(null);
|
|
6808
|
+
if (!over) return;
|
|
6809
|
+
const activeId = active.id;
|
|
6810
|
+
const overId = over.id;
|
|
6811
|
+
if (active.data.current?.type === "COLUMN") {
|
|
6812
|
+
if (activeId !== overId) {
|
|
6813
|
+
const oldIndex = columnsProp.indexOf(activeId);
|
|
6814
|
+
const newIndex = columnsProp.indexOf(overId);
|
|
6815
|
+
if (oldIndex !== -1 && newIndex !== -1) {
|
|
6816
|
+
const reordered = arrayMove(columnsProp, oldIndex, newIndex);
|
|
6817
|
+
onColumnReorder?.(reordered);
|
|
6818
|
+
}
|
|
6819
|
+
}
|
|
6820
|
+
return;
|
|
6821
|
+
}
|
|
6822
|
+
const activeCol = findColumnByItemId(activeId);
|
|
6823
|
+
let overCol = findColumnByItemId(overId);
|
|
6824
|
+
if (!overCol) {
|
|
6825
|
+
if (over.data.current?.type === "ITEM-LIST" || columnsProp.includes(overId)) overCol = overId;
|
|
6826
|
+
}
|
|
6827
|
+
if (!activeCol || !overCol) return;
|
|
6828
|
+
const isSameColumn = activeCol === overCol;
|
|
6829
|
+
const activeItems = itemMapState[activeCol] || [];
|
|
6830
|
+
const overItems = itemMapState[overCol] || [];
|
|
6831
|
+
const activeIndex = activeItems.findIndex((i) => i.id === activeId);
|
|
6832
|
+
let overIndex;
|
|
6833
|
+
if (over.id === overCol) overIndex = overItems.length;
|
|
6834
|
+
else overIndex = overItems.findIndex((i) => i.id === overId);
|
|
6835
|
+
if (activeIndex === -1 || overIndex === -1) return;
|
|
6836
|
+
let finalItems = [];
|
|
6837
|
+
if (isSameColumn) finalItems = arrayMove(activeItems, activeIndex, overIndex);
|
|
6838
|
+
else {
|
|
6839
|
+
const newActiveItems = [...activeItems];
|
|
6840
|
+
const newOverItems = [...overItems];
|
|
6841
|
+
const [moved] = newActiveItems.splice(activeIndex, 1);
|
|
6842
|
+
newOverItems.splice(overIndex, 0, moved);
|
|
6843
|
+
finalItems = [...newActiveItems, ...newOverItems];
|
|
6844
|
+
}
|
|
6845
|
+
const fullFlattenedList = [];
|
|
6846
|
+
columnsProp.forEach((col) => {
|
|
6847
|
+
if (col === activeCol) if (isSameColumn) fullFlattenedList.push(...finalItems);
|
|
6848
|
+
else fullFlattenedList.push(...activeItems.filter((i) => i.id !== activeId));
|
|
6849
|
+
else if (col === overCol) {
|
|
6850
|
+
const newOverItems = [...overItems];
|
|
6851
|
+
const [moved] = [...activeItems].splice(activeIndex, 1);
|
|
6852
|
+
newOverItems.splice(overIndex, 0, moved);
|
|
6853
|
+
fullFlattenedList.push(...newOverItems);
|
|
6854
|
+
} else fullFlattenedList.push(...itemMapState[col] || []);
|
|
6855
|
+
});
|
|
6856
|
+
onItemsReorder?.(fullFlattenedList, {
|
|
6857
|
+
itemId: activeId,
|
|
6858
|
+
sourceColumn: activeCol,
|
|
6859
|
+
targetColumn: overCol
|
|
6860
|
+
});
|
|
6861
|
+
};
|
|
6862
|
+
return /* @__PURE__ */ jsxs(DndContext, {
|
|
6863
|
+
sensors,
|
|
6864
|
+
onDragStart: handleDragStart,
|
|
6865
|
+
onDragOver: handleDragOver,
|
|
6866
|
+
onDragEnd: handleDragEnd,
|
|
6867
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
6868
|
+
className: cls("flex flex-row h-full w-full overflow-x-auto p-4 select-none items-start", className),
|
|
6869
|
+
children: [/* @__PURE__ */ jsx(SortableContext, {
|
|
6870
|
+
items: columnsProp,
|
|
6871
|
+
children: columnsProp.map((col, index) => {
|
|
6872
|
+
const colItems = itemMapState[col] || [];
|
|
6873
|
+
const loadingState = columnLoadingState?.[col];
|
|
6874
|
+
return /* @__PURE__ */ jsx(BoardColumn, {
|
|
6875
|
+
id: String(col),
|
|
6876
|
+
title: columnLabels?.[col] ?? String(col),
|
|
6877
|
+
items: colItems,
|
|
6878
|
+
index,
|
|
6879
|
+
ItemComponent,
|
|
6880
|
+
isDragging,
|
|
6881
|
+
isDragOverColumn: dragOverColumnId === String(col),
|
|
6882
|
+
allowReorder: allowColumnReorder,
|
|
6883
|
+
loading: loadingState?.loading,
|
|
6884
|
+
hasMore: loadingState?.hasMore,
|
|
6885
|
+
totalCount: loadingState?.totalCount,
|
|
6886
|
+
color: columnColors?.[col],
|
|
6887
|
+
onLoadMore: onLoadMoreColumn ? () => onLoadMoreColumn(col) : void 0,
|
|
6888
|
+
onAddItem: onAddItemToColumn ? () => onAddItemToColumn(col) : void 0
|
|
6889
|
+
}, String(col));
|
|
6890
|
+
})
|
|
6891
|
+
}), AddColumnComponent]
|
|
6892
|
+
}), typeof document !== "undefined" && createPortal(/* @__PURE__ */ jsx(DragOverlay, {
|
|
6893
|
+
dropAnimation: null,
|
|
6894
|
+
children: isDragging && activeItem && /* @__PURE__ */ jsx("div", {
|
|
6895
|
+
style: {
|
|
6896
|
+
position: "fixed",
|
|
6897
|
+
left: overlayPos?.x ?? 0,
|
|
6898
|
+
top: overlayPos?.y ?? 0,
|
|
6899
|
+
pointerEvents: "none",
|
|
6900
|
+
zIndex: 9999
|
|
6901
|
+
},
|
|
6902
|
+
children: /* @__PURE__ */ jsx(ItemComponent, {
|
|
6903
|
+
item: activeItem,
|
|
6904
|
+
isDragging: true,
|
|
6905
|
+
isClone: true
|
|
6906
|
+
})
|
|
6907
|
+
})
|
|
6908
|
+
}), document.body)]
|
|
6909
|
+
});
|
|
6910
|
+
}
|
|
6911
|
+
//#endregion
|
|
6912
|
+
//#region src/views/KanbanView.tsx
|
|
6913
|
+
function KanbanView(props) {
|
|
6914
|
+
return /* @__PURE__ */ jsx(Board, { ...props });
|
|
6915
|
+
}
|
|
6916
|
+
//#endregion
|
|
6917
|
+
//#region src/views/CollectionView/CollectionViewToolbar.tsx
|
|
6918
|
+
var VIEW_MODE_ICONS = {
|
|
6919
|
+
list: /* @__PURE__ */ jsx(LayoutList, { size: iconSize.small }),
|
|
6920
|
+
table: /* @__PURE__ */ jsx(Table2, { size: iconSize.small }),
|
|
6921
|
+
cards: /* @__PURE__ */ jsx(LayoutGrid, { size: iconSize.small }),
|
|
6922
|
+
kanban: /* @__PURE__ */ jsx(Kanban, { size: iconSize.small })
|
|
6923
|
+
};
|
|
6924
|
+
var VIEW_MODE_LABELS = {
|
|
6925
|
+
list: "List",
|
|
6926
|
+
table: "Table",
|
|
6927
|
+
cards: "Cards",
|
|
6928
|
+
kanban: "Board"
|
|
6929
|
+
};
|
|
6930
|
+
var SIZE_LABELS = {
|
|
6931
|
+
xs: "Extra Small",
|
|
6932
|
+
s: "Small",
|
|
6933
|
+
m: "Medium",
|
|
6934
|
+
l: "Large",
|
|
6935
|
+
xl: "Extra Large"
|
|
6936
|
+
};
|
|
6937
|
+
/**
|
|
6938
|
+
* Toolbar for the headless CollectionView.
|
|
6939
|
+
*
|
|
6940
|
+
* Renders a search bar, view mode toggle (popover with toggle button group),
|
|
6941
|
+
* optional size selector, optional kanban property selector, and action slots.
|
|
6942
|
+
*
|
|
6943
|
+
* @group Collection View
|
|
6944
|
+
*/
|
|
6945
|
+
function CollectionViewToolbar({ viewMode, onViewModeChange, enabledViews = [
|
|
6946
|
+
"list",
|
|
6947
|
+
"table",
|
|
6948
|
+
"cards",
|
|
6949
|
+
"kanban"
|
|
6950
|
+
], size = "m", onSizeChange, searchString, onSearchChange, loading, actionsStart, actionsEnd, compact, kanbanPropertyOptions, selectedKanbanProperty, onKanbanPropertyChange }) {
|
|
6951
|
+
const [popoverOpen, setPopoverOpen] = useState(false);
|
|
6952
|
+
const viewOptions = enabledViews.map((mode) => ({
|
|
6953
|
+
value: mode,
|
|
6954
|
+
label: VIEW_MODE_LABELS[mode],
|
|
6955
|
+
icon: VIEW_MODE_ICONS[mode]
|
|
6956
|
+
}));
|
|
6957
|
+
const handleViewModeChange = useCallback((mode) => {
|
|
6958
|
+
onViewModeChange?.(mode);
|
|
6959
|
+
}, [onViewModeChange]);
|
|
6960
|
+
const handleSizeChange = useCallback((value) => {
|
|
6961
|
+
onSizeChange?.(value);
|
|
6962
|
+
}, [onSizeChange]);
|
|
6963
|
+
const handleKanbanPropertyChange = useCallback((value) => {
|
|
6964
|
+
onKanbanPropertyChange?.(value);
|
|
6965
|
+
}, [onKanbanPropertyChange]);
|
|
6966
|
+
const showViewToggle = onViewModeChange && enabledViews.length > 1;
|
|
6967
|
+
const showSizeSelector = onSizeChange && viewMode !== "kanban";
|
|
6968
|
+
const showKanbanSelector = kanbanPropertyOptions && kanbanPropertyOptions.length > 0 && viewMode === "kanban" && onKanbanPropertyChange;
|
|
6969
|
+
const showPopover = showViewToggle || showSizeSelector || showKanbanSelector;
|
|
6970
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
6971
|
+
className: cls("flex items-center gap-2 px-2 flex-shrink-0", "border-b border-surface-200 dark:border-surface-800", compact ? "py-0.5 gap-1" : "py-1"),
|
|
6972
|
+
children: [
|
|
6973
|
+
actionsStart,
|
|
6974
|
+
onSearchChange && /* @__PURE__ */ jsx(SearchBar, {
|
|
6975
|
+
onTextSearch: onSearchChange,
|
|
6976
|
+
size: "small",
|
|
6977
|
+
initialValue: searchString,
|
|
6978
|
+
loading,
|
|
6979
|
+
expandable: true
|
|
6980
|
+
}),
|
|
6981
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
6982
|
+
actionsEnd,
|
|
6983
|
+
showPopover && /* @__PURE__ */ jsx(Popover, {
|
|
6984
|
+
open: popoverOpen,
|
|
6985
|
+
onOpenChange: setPopoverOpen,
|
|
6986
|
+
side: "bottom",
|
|
6987
|
+
align: "end",
|
|
6988
|
+
trigger: /* @__PURE__ */ jsx(IconButton, {
|
|
6989
|
+
size: "small",
|
|
6990
|
+
onClick: () => setPopoverOpen((prev) => !prev),
|
|
6991
|
+
children: /* @__PURE__ */ jsx(Settings2, { size: iconSize.small })
|
|
6992
|
+
}),
|
|
6993
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
6994
|
+
className: "p-3 min-w-[200px] flex flex-col gap-3",
|
|
6995
|
+
children: [
|
|
6996
|
+
showViewToggle && /* @__PURE__ */ jsxs("div", {
|
|
6997
|
+
className: "flex flex-col gap-1",
|
|
6998
|
+
children: [/* @__PURE__ */ jsx(Typography, {
|
|
6999
|
+
variant: "caption",
|
|
7000
|
+
color: "secondary",
|
|
7001
|
+
className: "font-medium uppercase tracking-wider",
|
|
7002
|
+
children: "View"
|
|
7003
|
+
}), /* @__PURE__ */ jsx(ToggleButtonGroup, {
|
|
7004
|
+
value: viewMode,
|
|
7005
|
+
onValueChange: handleViewModeChange,
|
|
7006
|
+
options: viewOptions
|
|
7007
|
+
})]
|
|
7008
|
+
}),
|
|
7009
|
+
showSizeSelector && /* @__PURE__ */ jsxs("div", {
|
|
7010
|
+
className: "flex flex-col gap-1",
|
|
7011
|
+
children: [/* @__PURE__ */ jsx(Typography, {
|
|
7012
|
+
variant: "caption",
|
|
7013
|
+
color: "secondary",
|
|
7014
|
+
className: "font-medium uppercase tracking-wider",
|
|
7015
|
+
children: "Size"
|
|
7016
|
+
}), /* @__PURE__ */ jsx(Select, {
|
|
7017
|
+
value: size,
|
|
7018
|
+
onValueChange: handleSizeChange,
|
|
7019
|
+
size: "small",
|
|
7020
|
+
children: Object.keys(SIZE_LABELS).map((sizeKey) => /* @__PURE__ */ jsx(SelectItem, {
|
|
7021
|
+
value: sizeKey,
|
|
7022
|
+
children: SIZE_LABELS[sizeKey]
|
|
7023
|
+
}, sizeKey))
|
|
7024
|
+
})]
|
|
7025
|
+
}),
|
|
7026
|
+
showKanbanSelector && /* @__PURE__ */ jsxs("div", {
|
|
7027
|
+
className: "flex flex-col gap-1",
|
|
7028
|
+
children: [/* @__PURE__ */ jsx(Typography, {
|
|
7029
|
+
variant: "caption",
|
|
7030
|
+
color: "secondary",
|
|
7031
|
+
className: "font-medium uppercase tracking-wider",
|
|
7032
|
+
children: "Group by"
|
|
7033
|
+
}), /* @__PURE__ */ jsx(Select, {
|
|
7034
|
+
value: selectedKanbanProperty,
|
|
7035
|
+
onValueChange: handleKanbanPropertyChange,
|
|
7036
|
+
size: "small",
|
|
7037
|
+
children: kanbanPropertyOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, {
|
|
7038
|
+
value: option.key,
|
|
7039
|
+
children: option.label
|
|
7040
|
+
}, option.key))
|
|
7041
|
+
})]
|
|
7042
|
+
})
|
|
7043
|
+
]
|
|
7044
|
+
})
|
|
7045
|
+
})
|
|
7046
|
+
]
|
|
7047
|
+
});
|
|
7048
|
+
}
|
|
7049
|
+
//#endregion
|
|
7050
|
+
//#region src/views/CollectionView/DefaultCellRenderer.tsx
|
|
7051
|
+
/**
|
|
7052
|
+
* Resolve an enum key to its display label and optional color.
|
|
7053
|
+
*/
|
|
7054
|
+
function resolveEnumLabel(enumValues, value) {
|
|
7055
|
+
if (!enumValues) return void 0;
|
|
7056
|
+
const key = String(value);
|
|
7057
|
+
if (enumValues instanceof Map) {
|
|
7058
|
+
const config = enumValues.get(value);
|
|
7059
|
+
if (!config) return void 0;
|
|
7060
|
+
if (typeof config === "string") return { label: config };
|
|
7061
|
+
return {
|
|
7062
|
+
label: config.label,
|
|
7063
|
+
color: config.color
|
|
7064
|
+
};
|
|
7065
|
+
}
|
|
7066
|
+
const config = enumValues[key];
|
|
7067
|
+
if (!config) return void 0;
|
|
7068
|
+
if (typeof config === "string") return { label: config };
|
|
7069
|
+
return {
|
|
7070
|
+
label: config.label,
|
|
7071
|
+
color: config.color
|
|
7072
|
+
};
|
|
7073
|
+
}
|
|
7074
|
+
/**
|
|
7075
|
+
* Format a date value using Intl.DateTimeFormat.
|
|
7076
|
+
*/
|
|
7077
|
+
function formatDate(value, includeTime) {
|
|
7078
|
+
if (value == null) return "—";
|
|
7079
|
+
const date = value instanceof Date ? value : new Date(String(value));
|
|
7080
|
+
if (isNaN(date.getTime())) return String(value);
|
|
7081
|
+
const options = includeTime ? {
|
|
7082
|
+
year: "numeric",
|
|
7083
|
+
month: "short",
|
|
7084
|
+
day: "numeric",
|
|
7085
|
+
hour: "2-digit",
|
|
7086
|
+
minute: "2-digit"
|
|
7087
|
+
} : {
|
|
7088
|
+
year: "numeric",
|
|
7089
|
+
month: "short",
|
|
7090
|
+
day: "numeric"
|
|
7091
|
+
};
|
|
7092
|
+
return new Intl.DateTimeFormat(void 0, options).format(date);
|
|
7093
|
+
}
|
|
7094
|
+
/**
|
|
7095
|
+
* Type guard for geopoint-like objects.
|
|
7096
|
+
*/
|
|
7097
|
+
function isGeoPoint(value) {
|
|
7098
|
+
if (typeof value !== "object" || value === null) return false;
|
|
7099
|
+
const obj = value;
|
|
7100
|
+
return typeof obj.lat === "number" && typeof obj.lng === "number";
|
|
7101
|
+
}
|
|
7102
|
+
/**
|
|
7103
|
+
* Default cell renderer for the headless CollectionView.
|
|
7104
|
+
* Handles all built-in property types without depending on any Rebase core types.
|
|
7105
|
+
*
|
|
7106
|
+
* @group Preview components
|
|
7107
|
+
*/
|
|
7108
|
+
function DefaultCellRenderer({ row, propertyKey, property, value, size, width, height }) {
|
|
7109
|
+
if (value === null || value === void 0) return /* @__PURE__ */ jsx(Typography, {
|
|
7110
|
+
variant: "body2",
|
|
7111
|
+
color: "secondary",
|
|
7112
|
+
className: "px-1",
|
|
7113
|
+
children: "—"
|
|
7114
|
+
});
|
|
7115
|
+
if (property.Preview) {
|
|
7116
|
+
const PreviewComponent = property.Preview;
|
|
7117
|
+
return /* @__PURE__ */ jsx(PreviewComponent, {
|
|
7118
|
+
row,
|
|
7119
|
+
propertyKey,
|
|
7120
|
+
property,
|
|
7121
|
+
value,
|
|
7122
|
+
size,
|
|
7123
|
+
width,
|
|
7124
|
+
height
|
|
7125
|
+
});
|
|
7126
|
+
}
|
|
7127
|
+
switch (property.type) {
|
|
7128
|
+
case "string": return renderString(property, value);
|
|
7129
|
+
case "number": return renderNumber(property, value);
|
|
7130
|
+
case "boolean": return renderBoolean(value);
|
|
7131
|
+
case "date": return renderDate(property, value);
|
|
7132
|
+
case "array": return renderArray(property, value);
|
|
7133
|
+
case "map": return renderMap(value);
|
|
7134
|
+
case "reference":
|
|
7135
|
+
case "relation": return renderReference(value);
|
|
7136
|
+
case "geopoint": return renderGeopoint(value);
|
|
7137
|
+
default: return /* @__PURE__ */ jsx(Typography, {
|
|
7138
|
+
variant: "body2",
|
|
7139
|
+
color: "secondary",
|
|
7140
|
+
noWrap: true,
|
|
7141
|
+
className: "px-1",
|
|
7142
|
+
children: JSON.stringify(value)
|
|
7143
|
+
});
|
|
7144
|
+
}
|
|
7145
|
+
}
|
|
7146
|
+
function renderString(property, value) {
|
|
7147
|
+
const strValue = String(value);
|
|
7148
|
+
if (property.enum) {
|
|
7149
|
+
const resolved = resolveEnumLabel(property.enum, value);
|
|
7150
|
+
return /* @__PURE__ */ jsx(Chip, {
|
|
7151
|
+
size: "small",
|
|
7152
|
+
colorScheme: resolved?.color ? {
|
|
7153
|
+
color: resolved.color,
|
|
7154
|
+
text: "#fff"
|
|
7155
|
+
} : void 0,
|
|
7156
|
+
children: resolved?.label ?? strValue
|
|
7157
|
+
});
|
|
7158
|
+
}
|
|
7159
|
+
if (property.previewAsTag) return /* @__PURE__ */ jsx(Chip, {
|
|
7160
|
+
size: "small",
|
|
7161
|
+
children: strValue
|
|
7162
|
+
});
|
|
7163
|
+
if (property.url) return /* @__PURE__ */ jsx(Typography, {
|
|
7164
|
+
variant: "body2",
|
|
7165
|
+
noWrap: true,
|
|
7166
|
+
component: "a",
|
|
7167
|
+
href: typeof property.url === "string" ? property.url : strValue,
|
|
7168
|
+
target: "_blank",
|
|
7169
|
+
rel: "noopener noreferrer",
|
|
7170
|
+
className: cls("px-1 text-primary hover:underline cursor-pointer"),
|
|
7171
|
+
children: strValue
|
|
7172
|
+
});
|
|
7173
|
+
if (property.email) return /* @__PURE__ */ jsx(Typography, {
|
|
7174
|
+
variant: "body2",
|
|
7175
|
+
noWrap: true,
|
|
7176
|
+
component: "a",
|
|
7177
|
+
href: `mailto:${strValue}`,
|
|
7178
|
+
className: cls("px-1 text-primary hover:underline cursor-pointer"),
|
|
7179
|
+
children: strValue
|
|
7180
|
+
});
|
|
7181
|
+
if (property.markdown) return /* @__PURE__ */ jsx("div", {
|
|
7182
|
+
className: "px-1 max-h-[100px] overflow-hidden",
|
|
7183
|
+
children: /* @__PURE__ */ jsx(Markdown, {
|
|
7184
|
+
source: strValue,
|
|
7185
|
+
size: "small"
|
|
7186
|
+
})
|
|
7187
|
+
});
|
|
7188
|
+
if (property.storage) return /* @__PURE__ */ jsxs("div", {
|
|
7189
|
+
className: cls("px-1 flex items-center justify-center", "w-[40px] h-[40px] rounded overflow-hidden"),
|
|
7190
|
+
children: [strValue ? /* @__PURE__ */ jsx("img", {
|
|
7191
|
+
src: strValue,
|
|
7192
|
+
alt: "",
|
|
7193
|
+
className: "w-full h-full object-cover",
|
|
7194
|
+
onError: (e) => {
|
|
7195
|
+
const target = e.currentTarget;
|
|
7196
|
+
target.style.display = "none";
|
|
7197
|
+
const fallback = target.nextElementSibling;
|
|
7198
|
+
if (fallback instanceof HTMLElement) fallback.style.display = "flex";
|
|
7199
|
+
}
|
|
7200
|
+
}) : null, /* @__PURE__ */ jsx("div", {
|
|
7201
|
+
className: cls("w-full h-full items-center justify-center rounded", "bg-surface-100 dark:bg-surface-800 text-text-secondary dark:text-text-secondary-dark", strValue ? "hidden" : "flex"),
|
|
7202
|
+
children: /* @__PURE__ */ jsx(ImageIcon$1, { size: iconSize.small })
|
|
7203
|
+
})]
|
|
7204
|
+
});
|
|
7205
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
7206
|
+
title: strValue.length > 50 ? strValue : void 0,
|
|
7207
|
+
side: "bottom",
|
|
7208
|
+
children: /* @__PURE__ */ jsx(Typography, {
|
|
7209
|
+
variant: "body2",
|
|
7210
|
+
noWrap: true,
|
|
7211
|
+
className: "px-1",
|
|
7212
|
+
children: strValue
|
|
7213
|
+
})
|
|
7214
|
+
});
|
|
7215
|
+
}
|
|
7216
|
+
function renderNumber(property, value) {
|
|
7217
|
+
const numStr = String(value);
|
|
7218
|
+
if (property.enum) {
|
|
7219
|
+
const resolved = resolveEnumLabel(property.enum, value);
|
|
7220
|
+
return /* @__PURE__ */ jsx(Chip, {
|
|
7221
|
+
size: "small",
|
|
7222
|
+
colorScheme: resolved?.color ? {
|
|
7223
|
+
color: resolved.color,
|
|
7224
|
+
text: "#fff"
|
|
7225
|
+
} : void 0,
|
|
7226
|
+
children: resolved?.label ?? numStr
|
|
7227
|
+
});
|
|
7228
|
+
}
|
|
7229
|
+
return /* @__PURE__ */ jsx(Typography, {
|
|
7230
|
+
variant: "body2",
|
|
7231
|
+
noWrap: true,
|
|
7232
|
+
align: "right",
|
|
7233
|
+
className: "px-1 tabular-nums",
|
|
7234
|
+
children: numStr
|
|
7235
|
+
});
|
|
7236
|
+
}
|
|
7237
|
+
function renderBoolean(value) {
|
|
7238
|
+
return /* @__PURE__ */ jsx("div", {
|
|
7239
|
+
className: "px-1 flex items-center",
|
|
7240
|
+
children: /* @__PURE__ */ jsx(BooleanSwitch, {
|
|
7241
|
+
value: !!value,
|
|
7242
|
+
size: "small",
|
|
7243
|
+
disabled: true
|
|
7244
|
+
})
|
|
7245
|
+
});
|
|
7246
|
+
}
|
|
7247
|
+
function renderDate(property, value) {
|
|
7248
|
+
return /* @__PURE__ */ jsx(Typography, {
|
|
7249
|
+
variant: "body2",
|
|
7250
|
+
noWrap: true,
|
|
7251
|
+
className: "px-1 tabular-nums",
|
|
7252
|
+
children: formatDate(value, property.mode === "date_time")
|
|
7253
|
+
});
|
|
7254
|
+
}
|
|
7255
|
+
function renderArray(property, value) {
|
|
7256
|
+
if (!Array.isArray(value)) return /* @__PURE__ */ jsx(Typography, {
|
|
7257
|
+
variant: "body2",
|
|
7258
|
+
color: "secondary",
|
|
7259
|
+
className: "px-1",
|
|
7260
|
+
children: "—"
|
|
7261
|
+
});
|
|
7262
|
+
if (property.of?.enum && value.length > 0) return /* @__PURE__ */ jsx("div", {
|
|
7263
|
+
className: "px-1 flex flex-wrap gap-1 overflow-hidden",
|
|
7264
|
+
children: value.map((item, i) => {
|
|
7265
|
+
const resolved = resolveEnumLabel(property.of.enum, item);
|
|
7266
|
+
return /* @__PURE__ */ jsx(Chip, {
|
|
7267
|
+
size: "smallest",
|
|
7268
|
+
colorScheme: resolved?.color ? {
|
|
7269
|
+
color: resolved.color,
|
|
7270
|
+
text: "#fff"
|
|
7271
|
+
} : void 0,
|
|
7272
|
+
children: resolved?.label ?? String(item)
|
|
7273
|
+
}, i);
|
|
7274
|
+
})
|
|
7275
|
+
});
|
|
7276
|
+
if (value.length > 0 && value.every((item) => typeof item === "string")) return /* @__PURE__ */ jsx(Typography, {
|
|
7277
|
+
variant: "body2",
|
|
7278
|
+
noWrap: true,
|
|
7279
|
+
className: "px-1",
|
|
7280
|
+
children: value.join(", ")
|
|
7281
|
+
});
|
|
7282
|
+
return /* @__PURE__ */ jsxs(Typography, {
|
|
7283
|
+
variant: "body2",
|
|
7284
|
+
color: "secondary",
|
|
7285
|
+
className: "px-1",
|
|
7286
|
+
children: [
|
|
7287
|
+
value.length,
|
|
7288
|
+
" ",
|
|
7289
|
+
value.length === 1 ? "item" : "items"
|
|
7290
|
+
]
|
|
7291
|
+
});
|
|
7292
|
+
}
|
|
7293
|
+
function renderMap(value) {
|
|
7294
|
+
if (typeof value !== "object" || value === null) return /* @__PURE__ */ jsx(Typography, {
|
|
7295
|
+
variant: "body2",
|
|
7296
|
+
color: "secondary",
|
|
7297
|
+
className: "px-1",
|
|
7298
|
+
children: "—"
|
|
7299
|
+
});
|
|
7300
|
+
const fieldCount = Object.keys(value).length;
|
|
7301
|
+
return /* @__PURE__ */ jsxs(Typography, {
|
|
7302
|
+
variant: "body2",
|
|
7303
|
+
color: "secondary",
|
|
7304
|
+
className: "px-1",
|
|
7305
|
+
children: [
|
|
7306
|
+
fieldCount,
|
|
7307
|
+
" ",
|
|
7308
|
+
fieldCount === 1 ? "field" : "fields"
|
|
7309
|
+
]
|
|
7310
|
+
});
|
|
7311
|
+
}
|
|
7312
|
+
function renderReference(value) {
|
|
7313
|
+
return /* @__PURE__ */ jsx(Typography, {
|
|
7314
|
+
variant: "body2",
|
|
7315
|
+
noWrap: true,
|
|
7316
|
+
className: "px-1",
|
|
7317
|
+
children: String(value)
|
|
7318
|
+
});
|
|
7319
|
+
}
|
|
7320
|
+
function renderGeopoint(value) {
|
|
7321
|
+
if (isGeoPoint(value)) return /* @__PURE__ */ jsxs(Typography, {
|
|
7322
|
+
variant: "body2",
|
|
7323
|
+
noWrap: true,
|
|
7324
|
+
className: "px-1 tabular-nums",
|
|
7325
|
+
children: [
|
|
7326
|
+
value.lat.toFixed(6),
|
|
7327
|
+
", ",
|
|
7328
|
+
value.lng.toFixed(6)
|
|
7329
|
+
]
|
|
7330
|
+
});
|
|
7331
|
+
return /* @__PURE__ */ jsx(Typography, {
|
|
7332
|
+
variant: "body2",
|
|
7333
|
+
color: "secondary",
|
|
7334
|
+
className: "px-1",
|
|
7335
|
+
children: String(value)
|
|
7336
|
+
});
|
|
7337
|
+
}
|
|
7338
|
+
//#endregion
|
|
7339
|
+
//#region src/views/CollectionView/utils.ts
|
|
7340
|
+
/**
|
|
7341
|
+
* Traverse an object by dot-separated path.
|
|
7342
|
+
* Returns `undefined` if any segment is missing.
|
|
7343
|
+
*/
|
|
7344
|
+
function getValueInPath(obj, path) {
|
|
7345
|
+
if (!obj) return void 0;
|
|
7346
|
+
const parts = path.split(".");
|
|
7347
|
+
let current = obj;
|
|
7348
|
+
for (const part of parts) {
|
|
7349
|
+
if (current === null || current === void 0 || typeof current !== "object") return void 0;
|
|
7350
|
+
current = current[part];
|
|
7351
|
+
}
|
|
7352
|
+
return current;
|
|
7353
|
+
}
|
|
7354
|
+
//#endregion
|
|
7355
|
+
//#region src/views/CollectionView/CollectionTableView.tsx
|
|
7356
|
+
var DEFAULT_COLUMN_WIDTHS = {
|
|
7357
|
+
string: 200,
|
|
7358
|
+
number: 140,
|
|
7359
|
+
date: 160,
|
|
7360
|
+
boolean: 120,
|
|
7361
|
+
array: 200,
|
|
7362
|
+
map: 200,
|
|
7363
|
+
reference: 200,
|
|
7364
|
+
relation: 200,
|
|
7365
|
+
geopoint: 180
|
|
7366
|
+
};
|
|
7367
|
+
var FALLBACK_COLUMN_WIDTH = 200;
|
|
7368
|
+
var SIZE_TO_ROW_HEIGHT = {
|
|
7369
|
+
xs: 36,
|
|
7370
|
+
s: 44,
|
|
7371
|
+
m: 52,
|
|
7372
|
+
l: 64,
|
|
7373
|
+
xl: 80
|
|
7374
|
+
};
|
|
7375
|
+
var SORTABLE_TYPES = new Set([
|
|
7376
|
+
"string",
|
|
7377
|
+
"number",
|
|
7378
|
+
"date"
|
|
7379
|
+
]);
|
|
7380
|
+
var VIEW_SIZE_TO_RENDERER_SIZE = {
|
|
7381
|
+
xs: "tiny",
|
|
7382
|
+
s: "small",
|
|
7383
|
+
m: "medium",
|
|
7384
|
+
l: "large",
|
|
7385
|
+
xl: "large"
|
|
7386
|
+
};
|
|
7387
|
+
/**
|
|
7388
|
+
* Headless table view that wraps {@link VirtualTable}.
|
|
7389
|
+
*
|
|
7390
|
+
* Converts property configurations into virtual table columns and wires up
|
|
7391
|
+
* sorting, pagination, and cell rendering without coupling to any data layer.
|
|
7392
|
+
*
|
|
7393
|
+
* @group Collection View
|
|
7394
|
+
*/
|
|
7395
|
+
function CollectionTableView({ dataController, properties, propertiesOrder, displayedColumnIds, onRowClick, cellRenderer, size = "m", emptyComponent, hoverRow = true, className, onColumnResize, onColumnsOrderChange }) {
|
|
7396
|
+
const columns = useMemo(() => {
|
|
7397
|
+
const order = propertiesOrder ?? Object.keys(properties);
|
|
7398
|
+
return (displayedColumnIds ? order.filter((key) => displayedColumnIds.includes(key)) : order.filter((key) => {
|
|
7399
|
+
const prop = properties[key];
|
|
7400
|
+
return prop && !prop.hideFromCollection;
|
|
7401
|
+
})).map((key) => {
|
|
7402
|
+
const prop = properties[key];
|
|
7403
|
+
if (!prop) return null;
|
|
7404
|
+
return {
|
|
7405
|
+
key,
|
|
7406
|
+
width: prop.columnWidth || DEFAULT_COLUMN_WIDTHS[prop.type] || FALLBACK_COLUMN_WIDTH,
|
|
7407
|
+
title: prop.name,
|
|
7408
|
+
sortable: SORTABLE_TYPES.has(prop.type),
|
|
7409
|
+
resizable: true
|
|
7410
|
+
};
|
|
7411
|
+
}).filter((col) => col !== null);
|
|
7412
|
+
}, [
|
|
7413
|
+
properties,
|
|
7414
|
+
propertiesOrder,
|
|
7415
|
+
displayedColumnIds
|
|
7416
|
+
]);
|
|
7417
|
+
const rowHeight = SIZE_TO_ROW_HEIGHT[size];
|
|
7418
|
+
const rendererSize = VIEW_SIZE_TO_RENDERER_SIZE[size];
|
|
7419
|
+
const tableCellRenderer = useCallback((params) => {
|
|
7420
|
+
if (!params.rowData) return null;
|
|
7421
|
+
const propertyConfig = properties[params.column.key];
|
|
7422
|
+
if (!propertyConfig) return null;
|
|
7423
|
+
const value = getValueInPath(params.rowData, params.column.key);
|
|
7424
|
+
const cellProps = {
|
|
7425
|
+
row: params.rowData,
|
|
7426
|
+
propertyKey: params.column.key,
|
|
7427
|
+
property: propertyConfig,
|
|
7428
|
+
value,
|
|
7429
|
+
size: rendererSize,
|
|
7430
|
+
width: params.width
|
|
7431
|
+
};
|
|
7432
|
+
if (cellRenderer) {
|
|
7433
|
+
const custom = cellRenderer(cellProps);
|
|
7434
|
+
if (custom !== void 0) return /* @__PURE__ */ jsx("div", {
|
|
7435
|
+
className: "flex items-center h-full px-1 overflow-hidden",
|
|
7436
|
+
children: custom
|
|
7437
|
+
});
|
|
7438
|
+
}
|
|
7439
|
+
return /* @__PURE__ */ jsx("div", {
|
|
7440
|
+
className: "flex items-center h-full px-1 overflow-hidden",
|
|
7441
|
+
children: /* @__PURE__ */ jsx(DefaultCellRenderer, { ...cellProps })
|
|
7442
|
+
});
|
|
7443
|
+
}, [
|
|
7444
|
+
properties,
|
|
7445
|
+
cellRenderer,
|
|
7446
|
+
rendererSize
|
|
7447
|
+
]);
|
|
7448
|
+
const handleRowClick = useCallback(({ rowData }) => {
|
|
7449
|
+
onRowClick?.(rowData);
|
|
7450
|
+
}, [onRowClick]);
|
|
7451
|
+
const handleEndReached = useCallback(() => {
|
|
7452
|
+
if (dataController.paginationEnabled && !dataController.noMoreToLoad) {
|
|
7453
|
+
const currentCount = dataController.itemCount ?? dataController.pageSize ?? 50;
|
|
7454
|
+
const pageSize = dataController.pageSize ?? 50;
|
|
7455
|
+
dataController.setItemCount?.(currentCount + pageSize);
|
|
7456
|
+
}
|
|
7457
|
+
}, [
|
|
7458
|
+
dataController.paginationEnabled,
|
|
7459
|
+
dataController.noMoreToLoad,
|
|
7460
|
+
dataController.itemCount,
|
|
7461
|
+
dataController.pageSize,
|
|
7462
|
+
dataController.setItemCount
|
|
7463
|
+
]);
|
|
7464
|
+
const handleColumnResize = useCallback((params) => {
|
|
7465
|
+
onColumnResize?.({
|
|
7466
|
+
key: params.key,
|
|
7467
|
+
width: params.width
|
|
7468
|
+
});
|
|
7469
|
+
}, [onColumnResize]);
|
|
7470
|
+
const handleColumnsOrderChange = useCallback((newColumns) => {
|
|
7471
|
+
onColumnsOrderChange?.(newColumns.map((col) => col.key));
|
|
7472
|
+
}, [onColumnsOrderChange]);
|
|
7473
|
+
return /* @__PURE__ */ jsx(VirtualTable, {
|
|
7474
|
+
data: dataController.data,
|
|
7475
|
+
columns,
|
|
7476
|
+
cellRenderer: tableCellRenderer,
|
|
7477
|
+
rowHeight,
|
|
7478
|
+
sortBy: dataController.sortBy,
|
|
7479
|
+
onSortByUpdate: dataController.setSortBy,
|
|
7480
|
+
onRowClick: handleRowClick,
|
|
7481
|
+
onEndReached: handleEndReached,
|
|
7482
|
+
onColumnResize: handleColumnResize,
|
|
7483
|
+
onColumnsOrderChange: handleColumnsOrderChange,
|
|
7484
|
+
loading: dataController.loading,
|
|
7485
|
+
emptyComponent,
|
|
7486
|
+
error: dataController.error,
|
|
7487
|
+
hoverRow,
|
|
7488
|
+
className: cls("h-full", className),
|
|
7489
|
+
onScroll: dataController.onScroll,
|
|
7490
|
+
initialScroll: dataController.initialScroll
|
|
7491
|
+
});
|
|
7492
|
+
}
|
|
7493
|
+
//#endregion
|
|
7494
|
+
//#region src/views/CollectionView/CollectionCardView.tsx
|
|
7495
|
+
/**
|
|
7496
|
+
* Headless card grid view that wraps {@link CardView}.
|
|
7497
|
+
*
|
|
7498
|
+
* Renders each item as a card with an optional image, title,
|
|
7499
|
+
* preview properties, and selection support.
|
|
7500
|
+
*
|
|
7501
|
+
* @group Collection View
|
|
7502
|
+
*/
|
|
7503
|
+
function CollectionCardView({ dataController, properties, propertiesOrder, idProperty = "id", titleProperty, onRowClick, cellRenderer, size = "m", selectionEnabled, selectionController, highlightedItems, emptyComponent, className }) {
|
|
7504
|
+
const order = useMemo(() => propertiesOrder ?? Object.keys(properties), [propertiesOrder, properties]);
|
|
7505
|
+
const titlePropertyKey = useMemo(() => {
|
|
7506
|
+
if (titleProperty) return titleProperty;
|
|
7507
|
+
for (const key of order) {
|
|
7508
|
+
const prop = properties[key];
|
|
7509
|
+
if (prop && prop.type === "string" && !prop.hideFromCollection && !prop.storage) return key;
|
|
7510
|
+
}
|
|
7511
|
+
return idProperty;
|
|
7512
|
+
}, [
|
|
7513
|
+
titleProperty,
|
|
7514
|
+
order,
|
|
7515
|
+
properties,
|
|
7516
|
+
idProperty
|
|
7517
|
+
]);
|
|
7518
|
+
const imageProperty = useMemo(() => {
|
|
7519
|
+
for (const key of order) {
|
|
7520
|
+
const prop = properties[key];
|
|
7521
|
+
if (prop && prop.type === "string" && prop.storage) return key;
|
|
7522
|
+
}
|
|
7523
|
+
}, [order, properties]);
|
|
7524
|
+
const previewProperties = useMemo(() => {
|
|
7525
|
+
const result = [];
|
|
7526
|
+
for (const key of order) {
|
|
7527
|
+
if (key === titlePropertyKey || key === imageProperty) continue;
|
|
7528
|
+
const prop = properties[key];
|
|
7529
|
+
if (prop && !prop.hideFromCollection) {
|
|
7530
|
+
result.push({
|
|
7531
|
+
key,
|
|
7532
|
+
property: prop
|
|
7533
|
+
});
|
|
7534
|
+
if (result.length >= 3) break;
|
|
7535
|
+
}
|
|
7536
|
+
}
|
|
7537
|
+
return result;
|
|
7538
|
+
}, [
|
|
7539
|
+
order,
|
|
7540
|
+
properties,
|
|
7541
|
+
titlePropertyKey,
|
|
7542
|
+
imageProperty
|
|
7543
|
+
]);
|
|
7544
|
+
const selectedIds = useMemo(() => {
|
|
7545
|
+
if (!selectionController?.selectedItems) return void 0;
|
|
7546
|
+
const ids = /* @__PURE__ */ new Set();
|
|
7547
|
+
for (const item of selectionController.selectedItems) {
|
|
7548
|
+
const id = getValueInPath(item, idProperty);
|
|
7549
|
+
if (id !== void 0 && id !== null) ids.add(id);
|
|
7550
|
+
}
|
|
7551
|
+
return ids;
|
|
7552
|
+
}, [selectionController?.selectedItems, idProperty]);
|
|
7553
|
+
const highlightedIds = useMemo(() => {
|
|
7554
|
+
if (!highlightedItems) return void 0;
|
|
7555
|
+
const ids = /* @__PURE__ */ new Set();
|
|
7556
|
+
for (const item of highlightedItems) {
|
|
7557
|
+
const id = getValueInPath(item, idProperty);
|
|
7558
|
+
if (id !== void 0 && id !== null) ids.add(id);
|
|
7559
|
+
}
|
|
7560
|
+
return ids;
|
|
7561
|
+
}, [highlightedItems, idProperty]);
|
|
7562
|
+
const handleSelectionChange = useCallback((item, selected) => {
|
|
7563
|
+
if (!selectionController) return;
|
|
7564
|
+
selectionController.setSelectedItems((prev) => {
|
|
7565
|
+
if (selected) return [...prev, item];
|
|
7566
|
+
const itemId = getValueInPath(item, idProperty);
|
|
7567
|
+
return prev.filter((existing) => {
|
|
7568
|
+
return getValueInPath(existing, idProperty) !== itemId;
|
|
7569
|
+
});
|
|
7570
|
+
});
|
|
7571
|
+
}, [selectionController, idProperty]);
|
|
7572
|
+
const renderCard = useCallback((item, extra) => {
|
|
7573
|
+
const titleValue = getValueInPath(item, titlePropertyKey);
|
|
7574
|
+
const imageValue = imageProperty ? getValueInPath(item, imageProperty) : void 0;
|
|
7575
|
+
const hasImage = typeof imageValue === "string" && imageValue.length > 0;
|
|
7576
|
+
return /* @__PURE__ */ jsxs(Card, {
|
|
7577
|
+
onClick: (e) => {
|
|
7578
|
+
if (e) extra.onClick(e);
|
|
7579
|
+
},
|
|
7580
|
+
className: cls("overflow-hidden relative", extra.selected && "bg-primary-bg/30 dark:bg-primary-bg/10 ring-1 ring-primary/75", extra.highlighted && !extra.selected && "ring-1 ring-primary/50"),
|
|
7581
|
+
children: [
|
|
7582
|
+
imageProperty && (hasImage ? /* @__PURE__ */ jsx("img", {
|
|
7583
|
+
src: imageValue,
|
|
7584
|
+
alt: "",
|
|
7585
|
+
className: "w-full h-32 object-cover rounded-t-lg"
|
|
7586
|
+
}) : /* @__PURE__ */ jsx("div", { className: cls("h-24 rounded-t-lg", "bg-surface-accent-200/50 dark:bg-black/30") })),
|
|
7587
|
+
selectionEnabled && /* @__PURE__ */ jsx("div", {
|
|
7588
|
+
className: "absolute top-2 right-2",
|
|
7589
|
+
onClick: (e) => e.stopPropagation(),
|
|
7590
|
+
children: /* @__PURE__ */ jsx(Checkbox, {
|
|
7591
|
+
checked: extra.selected,
|
|
7592
|
+
onCheckedChange: extra.onSelectionChange,
|
|
7593
|
+
size: "small"
|
|
7594
|
+
})
|
|
7595
|
+
}),
|
|
7596
|
+
/* @__PURE__ */ jsx(Typography, {
|
|
7597
|
+
variant: "subtitle2",
|
|
7598
|
+
noWrap: true,
|
|
7599
|
+
className: "px-3 pt-2 pb-1",
|
|
7600
|
+
children: String(titleValue ?? "")
|
|
7601
|
+
}),
|
|
7602
|
+
previewProperties.map(({ key, property }) => {
|
|
7603
|
+
const value = getValueInPath(item, key);
|
|
7604
|
+
if (cellRenderer) {
|
|
7605
|
+
const custom = cellRenderer({
|
|
7606
|
+
row: item,
|
|
7607
|
+
propertyKey: key,
|
|
7608
|
+
property,
|
|
7609
|
+
value,
|
|
7610
|
+
size: "small"
|
|
7611
|
+
});
|
|
7612
|
+
if (custom !== void 0) return /* @__PURE__ */ jsx("div", {
|
|
7613
|
+
className: "px-3 py-0.5",
|
|
7614
|
+
children: custom
|
|
7615
|
+
}, key);
|
|
7616
|
+
}
|
|
7617
|
+
return /* @__PURE__ */ jsx("div", {
|
|
7618
|
+
className: "px-3 py-0.5",
|
|
7619
|
+
children: /* @__PURE__ */ jsx(DefaultCellRenderer, {
|
|
7620
|
+
row: item,
|
|
7621
|
+
propertyKey: key,
|
|
7622
|
+
property,
|
|
7623
|
+
value,
|
|
7624
|
+
size: "small"
|
|
7625
|
+
})
|
|
7626
|
+
}, key);
|
|
7627
|
+
}),
|
|
7628
|
+
/* @__PURE__ */ jsx("div", { className: "pb-2" })
|
|
7629
|
+
]
|
|
7630
|
+
});
|
|
7631
|
+
}, [
|
|
7632
|
+
titlePropertyKey,
|
|
7633
|
+
imageProperty,
|
|
7634
|
+
previewProperties,
|
|
7635
|
+
cellRenderer,
|
|
7636
|
+
selectionEnabled
|
|
7637
|
+
]);
|
|
7638
|
+
return /* @__PURE__ */ jsx("div", {
|
|
7639
|
+
className: cls("w-full h-full overflow-auto", className),
|
|
7640
|
+
children: /* @__PURE__ */ jsx(CardView, {
|
|
7641
|
+
data: dataController.data,
|
|
7642
|
+
dataLoading: dataController.loading,
|
|
7643
|
+
noMoreToLoad: dataController.noMoreToLoad,
|
|
7644
|
+
dataLoadingError: dataController.error,
|
|
7645
|
+
itemCount: dataController.itemCount,
|
|
7646
|
+
setItemCount: dataController.setItemCount,
|
|
7647
|
+
pageSize: dataController.pageSize,
|
|
7648
|
+
paginationEnabled: dataController.paginationEnabled,
|
|
7649
|
+
onItemClick: onRowClick,
|
|
7650
|
+
selectedIds,
|
|
7651
|
+
highlightedIds,
|
|
7652
|
+
selectionEnabled: !!selectionEnabled,
|
|
7653
|
+
onSelectionChange: handleSelectionChange,
|
|
7654
|
+
size,
|
|
7655
|
+
renderCard,
|
|
7656
|
+
emptyComponent
|
|
7657
|
+
})
|
|
7658
|
+
});
|
|
7659
|
+
}
|
|
7660
|
+
//#endregion
|
|
7661
|
+
//#region src/views/CollectionView/CollectionListView.tsx
|
|
7662
|
+
/**
|
|
7663
|
+
* Headless list view that wraps {@link ListView}.
|
|
7664
|
+
*
|
|
7665
|
+
* Each row displays a title (bold), subtitle with 1–2 secondary property values,
|
|
7666
|
+
* and optional selection support.
|
|
7667
|
+
*
|
|
7668
|
+
* @group Collection View
|
|
7669
|
+
*/
|
|
7670
|
+
function CollectionListView({ dataController, properties, propertiesOrder, idProperty = "id", titleProperty, onRowClick, cellRenderer, size = "m", selectionEnabled, selectionController, highlightedItems, emptyComponent, className }) {
|
|
7671
|
+
const order = useMemo(() => propertiesOrder ?? Object.keys(properties), [propertiesOrder, properties]);
|
|
7672
|
+
const titlePropertyKey = useMemo(() => {
|
|
7673
|
+
if (titleProperty) return titleProperty;
|
|
7674
|
+
for (const key of order) {
|
|
7675
|
+
const prop = properties[key];
|
|
7676
|
+
if (prop && prop.type === "string" && !prop.hideFromCollection && !prop.storage) return key;
|
|
7677
|
+
}
|
|
7678
|
+
return idProperty;
|
|
7679
|
+
}, [
|
|
7680
|
+
titleProperty,
|
|
7681
|
+
order,
|
|
7682
|
+
properties,
|
|
7683
|
+
idProperty
|
|
7684
|
+
]);
|
|
7685
|
+
const subtitleProperties = useMemo(() => {
|
|
7686
|
+
const result = [];
|
|
7687
|
+
for (const key of order) {
|
|
7688
|
+
if (key === titlePropertyKey) continue;
|
|
7689
|
+
const prop = properties[key];
|
|
7690
|
+
if (prop && !prop.hideFromCollection) {
|
|
7691
|
+
result.push({
|
|
7692
|
+
key,
|
|
7693
|
+
property: prop
|
|
7694
|
+
});
|
|
7695
|
+
if (result.length >= 2) break;
|
|
7696
|
+
}
|
|
7697
|
+
}
|
|
7698
|
+
return result;
|
|
7699
|
+
}, [
|
|
7700
|
+
order,
|
|
7701
|
+
properties,
|
|
7702
|
+
titlePropertyKey
|
|
7703
|
+
]);
|
|
7704
|
+
const selectedIds = useMemo(() => {
|
|
7705
|
+
if (!selectionController?.selectedItems) return void 0;
|
|
7706
|
+
const ids = /* @__PURE__ */ new Set();
|
|
7707
|
+
for (const item of selectionController.selectedItems) {
|
|
7708
|
+
const id = getValueInPath(item, idProperty);
|
|
7709
|
+
if (id !== void 0 && id !== null) ids.add(id);
|
|
7710
|
+
}
|
|
7711
|
+
return ids;
|
|
7712
|
+
}, [selectionController?.selectedItems, idProperty]);
|
|
7713
|
+
const highlightedIds = useMemo(() => {
|
|
7714
|
+
if (!highlightedItems) return void 0;
|
|
7715
|
+
const ids = /* @__PURE__ */ new Set();
|
|
7716
|
+
for (const item of highlightedItems) {
|
|
7717
|
+
const id = getValueInPath(item, idProperty);
|
|
7718
|
+
if (id !== void 0 && id !== null) ids.add(id);
|
|
7719
|
+
}
|
|
7720
|
+
return ids;
|
|
7721
|
+
}, [highlightedItems, idProperty]);
|
|
7722
|
+
const handleSelectionChange = useCallback((item, selected) => {
|
|
7723
|
+
if (!selectionController) return;
|
|
7724
|
+
selectionController.setSelectedItems((prev) => {
|
|
7725
|
+
if (selected) return [...prev, item];
|
|
7726
|
+
const itemId = getValueInPath(item, idProperty);
|
|
7727
|
+
return prev.filter((existing) => {
|
|
7728
|
+
return getValueInPath(existing, idProperty) !== itemId;
|
|
7729
|
+
});
|
|
7730
|
+
});
|
|
7731
|
+
}, [selectionController, idProperty]);
|
|
7732
|
+
const renderRow = useCallback((params) => {
|
|
7733
|
+
const { item, style, className: rowClassName, selected, highlighted, onClick, onSelectionChange } = params;
|
|
7734
|
+
const titleValue = getValueInPath(item, titlePropertyKey);
|
|
7735
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
7736
|
+
style,
|
|
7737
|
+
className: cls("flex items-center gap-3 px-4 cursor-pointer", "hover:bg-surface-50 dark:hover:bg-surface-700", "transition-colors duration-100", selected && "bg-primary-50 dark:bg-primary-900/20", highlighted && "bg-surface-100 dark:bg-surface-800", rowClassName),
|
|
7738
|
+
onClick,
|
|
7739
|
+
children: [selectionEnabled && /* @__PURE__ */ jsx("div", {
|
|
7740
|
+
className: "flex-shrink-0",
|
|
7741
|
+
onClick: (e) => e.stopPropagation(),
|
|
7742
|
+
children: /* @__PURE__ */ jsx(Checkbox, {
|
|
7743
|
+
checked: selected,
|
|
7744
|
+
onCheckedChange: onSelectionChange,
|
|
7745
|
+
size: "small"
|
|
7746
|
+
})
|
|
7747
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
7748
|
+
className: "flex-1 min-w-0 py-1",
|
|
7749
|
+
children: [/* @__PURE__ */ jsx(Typography, {
|
|
7750
|
+
variant: "subtitle2",
|
|
7751
|
+
noWrap: true,
|
|
7752
|
+
children: String(titleValue ?? "")
|
|
7753
|
+
}), subtitleProperties.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
7754
|
+
className: "flex items-center gap-2",
|
|
7755
|
+
children: subtitleProperties.map(({ key, property }) => {
|
|
7756
|
+
const value = getValueInPath(item, key);
|
|
7757
|
+
if (cellRenderer) {
|
|
7758
|
+
const custom = cellRenderer({
|
|
7759
|
+
row: item,
|
|
7760
|
+
propertyKey: key,
|
|
7761
|
+
property,
|
|
7762
|
+
value,
|
|
7763
|
+
size: "tiny"
|
|
7764
|
+
});
|
|
7765
|
+
if (custom !== void 0) return /* @__PURE__ */ jsx(React.Fragment, { children: custom }, key);
|
|
7766
|
+
}
|
|
7767
|
+
return /* @__PURE__ */ jsx(React.Fragment, { children: /* @__PURE__ */ jsx(DefaultCellRenderer, {
|
|
7768
|
+
row: item,
|
|
7769
|
+
propertyKey: key,
|
|
7770
|
+
property,
|
|
7771
|
+
value,
|
|
7772
|
+
size: "tiny"
|
|
7773
|
+
}) }, key);
|
|
7774
|
+
})
|
|
7775
|
+
})]
|
|
7776
|
+
})]
|
|
7777
|
+
});
|
|
7778
|
+
}, [
|
|
7779
|
+
titlePropertyKey,
|
|
7780
|
+
subtitleProperties,
|
|
7781
|
+
cellRenderer,
|
|
7782
|
+
selectionEnabled
|
|
7783
|
+
]);
|
|
7784
|
+
return /* @__PURE__ */ jsx("div", {
|
|
7785
|
+
className: cls("w-full h-full overflow-auto", className),
|
|
7786
|
+
children: /* @__PURE__ */ jsx(ListView, {
|
|
7787
|
+
data: dataController.data,
|
|
7788
|
+
dataLoading: dataController.loading,
|
|
7789
|
+
noMoreToLoad: dataController.noMoreToLoad,
|
|
7790
|
+
dataLoadingError: dataController.error,
|
|
7791
|
+
itemCount: dataController.itemCount,
|
|
7792
|
+
setItemCount: dataController.setItemCount,
|
|
7793
|
+
pageSize: dataController.pageSize,
|
|
7794
|
+
paginationEnabled: dataController.paginationEnabled,
|
|
7795
|
+
onItemClick: onRowClick,
|
|
7796
|
+
selectedIds,
|
|
7797
|
+
highlightedIds,
|
|
7798
|
+
selectionEnabled: !!selectionEnabled,
|
|
7799
|
+
onSelectionChange: handleSelectionChange,
|
|
7800
|
+
size,
|
|
7801
|
+
renderRow,
|
|
7802
|
+
emptyComponent
|
|
7803
|
+
})
|
|
7804
|
+
});
|
|
7805
|
+
}
|
|
7806
|
+
//#endregion
|
|
7807
|
+
//#region src/views/CollectionView/CollectionKanbanView.tsx
|
|
7808
|
+
function getEnumLabel(enumConfig, key) {
|
|
7809
|
+
if (!enumConfig) return key;
|
|
7810
|
+
if (enumConfig instanceof Map) {
|
|
7811
|
+
const cfg = enumConfig.get(key);
|
|
7812
|
+
if (!cfg) return key;
|
|
7813
|
+
return typeof cfg === "string" ? cfg : cfg.label;
|
|
7814
|
+
}
|
|
7815
|
+
const cfg = enumConfig[key];
|
|
7816
|
+
if (!cfg) return key;
|
|
7817
|
+
return typeof cfg === "string" ? cfg : cfg.label;
|
|
7818
|
+
}
|
|
7819
|
+
/**
|
|
7820
|
+
* Headless kanban view that wraps {@link KanbanView}.
|
|
7821
|
+
*
|
|
7822
|
+
* Groups data by a kanban property's enum values into columns.
|
|
7823
|
+
* Each card displays a title and 1–2 preview properties.
|
|
7824
|
+
*
|
|
7825
|
+
* @group Collection View
|
|
7826
|
+
*/
|
|
7827
|
+
function CollectionKanbanView({ dataController, properties, propertiesOrder, idProperty = "id", titleProperty, kanbanProperty, onRowClick, cellRenderer, emptyComponent, onRowCreate, className }) {
|
|
7828
|
+
const order = useMemo(() => propertiesOrder ?? Object.keys(properties), [propertiesOrder, properties]);
|
|
7829
|
+
const columns = useMemo(() => {
|
|
7830
|
+
const kanbanConfig = properties[kanbanProperty];
|
|
7831
|
+
if (kanbanConfig?.enum) {
|
|
7832
|
+
if (kanbanConfig.enum instanceof Map) return Array.from(kanbanConfig.enum.keys()).map(String);
|
|
7833
|
+
return Object.keys(kanbanConfig.enum);
|
|
7834
|
+
}
|
|
7835
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7836
|
+
for (const row of dataController.data) {
|
|
7837
|
+
const val = getValueInPath(row, kanbanProperty);
|
|
7838
|
+
if (val !== null && val !== void 0) seen.add(String(val));
|
|
7839
|
+
}
|
|
7840
|
+
return Array.from(seen);
|
|
7841
|
+
}, [
|
|
7842
|
+
properties,
|
|
7843
|
+
kanbanProperty,
|
|
7844
|
+
dataController.data
|
|
7845
|
+
]);
|
|
7846
|
+
const columnLabels = useMemo(() => {
|
|
7847
|
+
const kanbanConfig = properties[kanbanProperty];
|
|
7848
|
+
const labels = {};
|
|
7849
|
+
for (const col of columns) labels[col] = getEnumLabel(kanbanConfig?.enum, col);
|
|
7850
|
+
return labels;
|
|
7851
|
+
}, [
|
|
7852
|
+
properties,
|
|
7853
|
+
kanbanProperty,
|
|
7854
|
+
columns
|
|
7855
|
+
]);
|
|
7856
|
+
const titlePropertyKey = useMemo(() => {
|
|
7857
|
+
if (titleProperty) return titleProperty;
|
|
7858
|
+
for (const key of order) {
|
|
7859
|
+
const prop = properties[key];
|
|
7860
|
+
if (prop && prop.type === "string" && !prop.hideFromCollection && !prop.storage) return key;
|
|
7861
|
+
}
|
|
7862
|
+
return idProperty;
|
|
7863
|
+
}, [
|
|
7864
|
+
titleProperty,
|
|
7865
|
+
order,
|
|
7866
|
+
properties,
|
|
7867
|
+
idProperty
|
|
7868
|
+
]);
|
|
7869
|
+
const previewProperties = useMemo(() => {
|
|
7870
|
+
const result = [];
|
|
7871
|
+
for (const key of order) {
|
|
7872
|
+
if (key === titlePropertyKey || key === kanbanProperty) continue;
|
|
7873
|
+
const prop = properties[key];
|
|
7874
|
+
if (prop && !prop.hideFromCollection) {
|
|
7875
|
+
result.push({
|
|
7876
|
+
key,
|
|
7877
|
+
property: prop
|
|
7878
|
+
});
|
|
7879
|
+
if (result.length >= 2) break;
|
|
7880
|
+
}
|
|
7881
|
+
}
|
|
7882
|
+
return result;
|
|
7883
|
+
}, [
|
|
7884
|
+
order,
|
|
7885
|
+
properties,
|
|
7886
|
+
titlePropertyKey,
|
|
7887
|
+
kanbanProperty
|
|
7888
|
+
]);
|
|
7889
|
+
const boardItems = useMemo(() => {
|
|
7890
|
+
return dataController.data.map((row, index) => {
|
|
7891
|
+
const id = getValueInPath(row, idProperty);
|
|
7892
|
+
return {
|
|
7893
|
+
id: id !== null && id !== void 0 ? String(id) : String(index),
|
|
7894
|
+
data: row
|
|
7895
|
+
};
|
|
7896
|
+
});
|
|
7897
|
+
}, [dataController.data, idProperty]);
|
|
7898
|
+
const assignColumn = useCallback((item) => {
|
|
7899
|
+
const val = getValueInPath(item.data, kanbanProperty);
|
|
7900
|
+
const strVal = val !== null && val !== void 0 ? String(val) : "";
|
|
7901
|
+
if (columns.includes(strVal)) return strVal;
|
|
7902
|
+
return columns[0] ?? "";
|
|
7903
|
+
}, [kanbanProperty, columns]);
|
|
7904
|
+
const ItemComponent = useMemo(() => {
|
|
7905
|
+
function KanbanCard(props) {
|
|
7906
|
+
const { item } = props;
|
|
7907
|
+
const titleValue = getValueInPath(item.data, titlePropertyKey);
|
|
7908
|
+
return /* @__PURE__ */ jsxs(Card, {
|
|
7909
|
+
onClick: () => onRowClick?.(item.data),
|
|
7910
|
+
className: cls("p-3", cardClickableMixin, props.isDragging && "bg-primary-bg/30 dark:bg-primary-bg/10 ring-1 ring-primary/75", props.isDragging && "shadow-lg opacity-75"),
|
|
7911
|
+
children: [/* @__PURE__ */ jsx(Typography, {
|
|
7912
|
+
variant: "subtitle2",
|
|
7913
|
+
noWrap: true,
|
|
7914
|
+
children: String(titleValue ?? "")
|
|
7915
|
+
}), previewProperties.map(({ key, property }) => {
|
|
7916
|
+
const value = getValueInPath(item.data, key);
|
|
7917
|
+
if (cellRenderer) {
|
|
7918
|
+
const custom = cellRenderer({
|
|
7919
|
+
row: item.data,
|
|
7920
|
+
propertyKey: key,
|
|
7921
|
+
property,
|
|
7922
|
+
value,
|
|
7923
|
+
size: "tiny"
|
|
7924
|
+
});
|
|
7925
|
+
if (custom !== void 0) return /* @__PURE__ */ jsx("div", {
|
|
7926
|
+
className: "mt-1",
|
|
7927
|
+
children: custom
|
|
7928
|
+
}, key);
|
|
7929
|
+
}
|
|
7930
|
+
return /* @__PURE__ */ jsx("div", {
|
|
7931
|
+
className: "mt-1",
|
|
7932
|
+
children: /* @__PURE__ */ jsx(DefaultCellRenderer, {
|
|
7933
|
+
row: item.data,
|
|
7934
|
+
propertyKey: key,
|
|
7935
|
+
property,
|
|
7936
|
+
value,
|
|
7937
|
+
size: "tiny"
|
|
7938
|
+
})
|
|
7939
|
+
}, key);
|
|
7940
|
+
})]
|
|
7941
|
+
});
|
|
7942
|
+
}
|
|
7943
|
+
return KanbanCard;
|
|
7944
|
+
}, [
|
|
7945
|
+
titlePropertyKey,
|
|
7946
|
+
previewProperties,
|
|
7947
|
+
cellRenderer,
|
|
7948
|
+
onRowClick
|
|
7949
|
+
]);
|
|
7950
|
+
const handleAddItemToColumn = useCallback((column) => {
|
|
7951
|
+
onRowCreate?.({ [kanbanProperty]: column });
|
|
7952
|
+
}, [onRowCreate, kanbanProperty]);
|
|
7953
|
+
if (columns.length === 0 && !dataController.loading) return /* @__PURE__ */ jsx("div", {
|
|
7954
|
+
className: "flex items-center justify-center p-8",
|
|
7955
|
+
children: emptyComponent ?? /* @__PURE__ */ jsx(Typography, {
|
|
7956
|
+
variant: "body2",
|
|
7957
|
+
color: "secondary",
|
|
7958
|
+
children: "No columns available for kanban view."
|
|
7959
|
+
})
|
|
7960
|
+
});
|
|
7961
|
+
return /* @__PURE__ */ jsx(KanbanView, {
|
|
7962
|
+
columns,
|
|
7963
|
+
columnLabels,
|
|
7964
|
+
data: boardItems,
|
|
7965
|
+
assignColumn,
|
|
7966
|
+
ItemComponent,
|
|
7967
|
+
onAddItemToColumn: onRowCreate ? handleAddItemToColumn : void 0,
|
|
7968
|
+
className
|
|
7969
|
+
});
|
|
7970
|
+
}
|
|
7971
|
+
//#endregion
|
|
7972
|
+
//#region src/views/CollectionView/CollectionView.tsx
|
|
7973
|
+
var DEFAULT_ENABLED_VIEWS = [
|
|
7974
|
+
"list",
|
|
7975
|
+
"table",
|
|
7976
|
+
"cards",
|
|
7977
|
+
"kanban"
|
|
7978
|
+
];
|
|
7979
|
+
/**
|
|
7980
|
+
* A data-agnostic collection view component that orchestrates table, card,
|
|
7981
|
+
* list, and kanban views — driven entirely by props.
|
|
7982
|
+
*
|
|
7983
|
+
* Zero imports from any entity or data layer. This component lives in
|
|
7984
|
+
* `@rebasepro/ui` and can be used with any data source.
|
|
7985
|
+
*
|
|
7986
|
+
* @example
|
|
7987
|
+
* ```tsx
|
|
7988
|
+
* import { CollectionView } from "@rebasepro/ui";
|
|
7989
|
+
*
|
|
7990
|
+
* <CollectionView
|
|
7991
|
+
* dataController={{ data: myRows, loading: false, noMoreToLoad: true }}
|
|
7992
|
+
* properties={{
|
|
7993
|
+
* name: { type: "string", name: "Name" },
|
|
7994
|
+
* email: { type: "string", name: "Email" },
|
|
7995
|
+
* }}
|
|
7996
|
+
* title="Contacts"
|
|
7997
|
+
* onRowClick={(row) => openDetail(row.id)}
|
|
7998
|
+
* />
|
|
7999
|
+
* ```
|
|
8000
|
+
*
|
|
8001
|
+
* @group Collection View
|
|
8002
|
+
*/
|
|
8003
|
+
function CollectionView({ dataController, properties, propertiesOrder, displayedColumnIds, idProperty = "id", titleProperty, title, viewMode: viewModeProp, defaultViewMode = "list", enabledViews = DEFAULT_ENABLED_VIEWS, onViewModeChange: onViewModeChangeProp, size: sizeProp, defaultSize = "m", onSizeChange: onSizeChangeProp, kanbanProperty: kanbanPropertyProp, kanbanPropertyOptions, onKanbanPropertyChange: onKanbanPropertyChangeProp, onRowClick, onRowCreate, canCreate = true, selectionEnabled, selectionController, highlightedItems, onMultipleDelete, cellRenderer, emptyComponent, toolbarActionsStart, toolbarActionsEnd, hideToolbar, hoverRow = true, onColumnResize, onColumnsOrderChange, className }) {
|
|
8004
|
+
const [internalViewMode, setInternalViewMode] = useState(defaultViewMode);
|
|
8005
|
+
const viewMode = viewModeProp ?? internalViewMode;
|
|
8006
|
+
const onViewModeChange = useCallback((mode) => {
|
|
8007
|
+
setInternalViewMode(mode);
|
|
8008
|
+
onViewModeChangeProp?.(mode);
|
|
8009
|
+
}, [onViewModeChangeProp]);
|
|
8010
|
+
const [internalSize, setInternalSize] = useState(defaultSize);
|
|
8011
|
+
const size = sizeProp ?? internalSize;
|
|
8012
|
+
const onSizeChange = useCallback((s) => {
|
|
8013
|
+
setInternalSize(s);
|
|
8014
|
+
onSizeChangeProp?.(s);
|
|
8015
|
+
}, [onSizeChangeProp]);
|
|
8016
|
+
const [internalKanbanProperty, setInternalKanbanProperty] = useState(kanbanPropertyProp);
|
|
8017
|
+
const kanbanProperty = kanbanPropertyProp ?? internalKanbanProperty;
|
|
8018
|
+
const onKanbanPropertyChange = useCallback((property) => {
|
|
8019
|
+
setInternalKanbanProperty(property);
|
|
8020
|
+
onKanbanPropertyChangeProp?.(property);
|
|
8021
|
+
}, [onKanbanPropertyChangeProp]);
|
|
8022
|
+
const resolvedKanbanProperty = useMemo(() => {
|
|
8023
|
+
if (kanbanProperty) return kanbanProperty;
|
|
8024
|
+
const order = propertiesOrder ?? Object.keys(properties);
|
|
8025
|
+
for (const key of order) {
|
|
8026
|
+
const prop = properties[key];
|
|
8027
|
+
if (prop && prop.type === "string" && prop.enum) return key;
|
|
8028
|
+
}
|
|
8029
|
+
}, [
|
|
8030
|
+
kanbanProperty,
|
|
8031
|
+
properties,
|
|
8032
|
+
propertiesOrder
|
|
8033
|
+
]);
|
|
8034
|
+
const resolvedKanbanPropertyOptions = useMemo(() => {
|
|
8035
|
+
if (kanbanPropertyOptions) return kanbanPropertyOptions;
|
|
8036
|
+
const options = [];
|
|
8037
|
+
const order = propertiesOrder ?? Object.keys(properties);
|
|
8038
|
+
for (const key of order) {
|
|
8039
|
+
const prop = properties[key];
|
|
8040
|
+
if (prop && prop.type === "string" && prop.enum) options.push({
|
|
8041
|
+
key,
|
|
8042
|
+
label: prop.name
|
|
8043
|
+
});
|
|
8044
|
+
}
|
|
8045
|
+
return options;
|
|
8046
|
+
}, [
|
|
8047
|
+
kanbanPropertyOptions,
|
|
8048
|
+
properties,
|
|
8049
|
+
propertiesOrder
|
|
8050
|
+
]);
|
|
8051
|
+
const sharedProps = {
|
|
8052
|
+
dataController,
|
|
8053
|
+
properties,
|
|
8054
|
+
propertiesOrder,
|
|
8055
|
+
idProperty,
|
|
8056
|
+
titleProperty,
|
|
8057
|
+
onRowClick,
|
|
8058
|
+
cellRenderer,
|
|
8059
|
+
selectionEnabled,
|
|
8060
|
+
selectionController,
|
|
8061
|
+
highlightedItems,
|
|
8062
|
+
emptyComponent
|
|
8063
|
+
};
|
|
8064
|
+
function renderView() {
|
|
8065
|
+
switch (viewMode) {
|
|
8066
|
+
case "table": return /* @__PURE__ */ jsx(CollectionTableView, {
|
|
8067
|
+
...sharedProps,
|
|
8068
|
+
displayedColumnIds,
|
|
8069
|
+
size,
|
|
8070
|
+
hoverRow,
|
|
8071
|
+
onColumnResize,
|
|
8072
|
+
onColumnsOrderChange
|
|
8073
|
+
});
|
|
8074
|
+
case "cards": return /* @__PURE__ */ jsx(CollectionCardView, {
|
|
8075
|
+
...sharedProps,
|
|
8076
|
+
size
|
|
8077
|
+
});
|
|
8078
|
+
case "kanban": return resolvedKanbanProperty ? /* @__PURE__ */ jsx(CollectionKanbanView, {
|
|
8079
|
+
...sharedProps,
|
|
8080
|
+
kanbanProperty: resolvedKanbanProperty,
|
|
8081
|
+
onRowCreate
|
|
8082
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
8083
|
+
className: "flex items-center justify-center p-8",
|
|
8084
|
+
children: /* @__PURE__ */ jsx(Typography, {
|
|
8085
|
+
variant: "body2",
|
|
8086
|
+
color: "secondary",
|
|
8087
|
+
children: "No enum property available for kanban grouping."
|
|
8088
|
+
})
|
|
8089
|
+
});
|
|
8090
|
+
default: return /* @__PURE__ */ jsx(CollectionListView, {
|
|
8091
|
+
...sharedProps,
|
|
8092
|
+
size
|
|
8093
|
+
});
|
|
8094
|
+
}
|
|
8095
|
+
}
|
|
8096
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
8097
|
+
className: cls("overflow-hidden h-full w-full rounded-md flex flex-col", "dark:bg-surface-800", className),
|
|
8098
|
+
children: [
|
|
8099
|
+
dataController.error && dataController.data.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
8100
|
+
className: "flex items-center gap-4 px-4 py-2 bg-red-50 dark:bg-red-900/20 border-b border-red-200 dark:border-red-800 flex-shrink-0",
|
|
8101
|
+
children: /* @__PURE__ */ jsxs(Typography, {
|
|
8102
|
+
variant: "body2",
|
|
8103
|
+
className: "text-red-700 dark:text-red-300 flex-1",
|
|
8104
|
+
children: [
|
|
8105
|
+
/* @__PURE__ */ jsx("strong", { children: "Warning:" }),
|
|
8106
|
+
" ",
|
|
8107
|
+
dataController.error.message || "Failed to update data."
|
|
8108
|
+
]
|
|
8109
|
+
})
|
|
8110
|
+
}),
|
|
8111
|
+
!hideToolbar && /* @__PURE__ */ jsx(CollectionViewToolbar, {
|
|
8112
|
+
viewMode,
|
|
8113
|
+
onViewModeChange: enabledViews.length > 1 ? onViewModeChange : void 0,
|
|
8114
|
+
enabledViews,
|
|
8115
|
+
size,
|
|
8116
|
+
onSizeChange,
|
|
8117
|
+
searchString: dataController.searchString,
|
|
8118
|
+
onSearchChange: dataController.setSearchString,
|
|
8119
|
+
loading: dataController.loading,
|
|
8120
|
+
actionsStart: toolbarActionsStart,
|
|
8121
|
+
actionsEnd: toolbarActionsEnd,
|
|
8122
|
+
kanbanPropertyOptions: viewMode === "kanban" ? resolvedKanbanPropertyOptions : void 0,
|
|
8123
|
+
selectedKanbanProperty: resolvedKanbanProperty,
|
|
8124
|
+
onKanbanPropertyChange
|
|
8125
|
+
}),
|
|
8126
|
+
/* @__PURE__ */ jsx("div", {
|
|
8127
|
+
className: "flex-1 overflow-hidden",
|
|
8128
|
+
children: renderView()
|
|
8129
|
+
})
|
|
8130
|
+
]
|
|
8131
|
+
});
|
|
8132
|
+
}
|
|
8133
|
+
//#endregion
|
|
8134
|
+
export { Alert, AlertCircleIcon, AlertTriangleIcon, AlignLeftIcon, AppWindow, ArrowDownToLineIcon, ArrowLeftIcon, ArrowRightFromLineIcon, ArrowRightIcon, ArrowRightToLineIcon, ArrowUpToLineIcon, Autocomplete, AutocompleteItem, Avatar, Badge, BoldIcon, BookOpenIcon, BooleanSwitch, BooleanSwitchWithLabel, Button, CHIP_COLORS, CalendarIcon, Card, CardView, CenteredView, CheckCircleIcon, CheckIcon, CheckSquareIcon, Checkbox, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronsLeftIcon, ChevronsRightIcon, ChevronsUpDownIcon, Chip, CircleIcon, CircleUserIcon, CircularProgress, CircularProgressCenter, CodeIcon, Collapse, CollectionCardView, CollectionKanbanView, CollectionListView, CollectionTableView, CollectionView, CollectionViewToolbar, ColorPicker, ColumnsIcon, Container, CopyIcon, DatabaseIcon, DateTimeField, DebouncedTextField, DefaultCellRenderer, Dialog, DialogActions, DialogContent, DialogTitle, DownloadIcon, ErrorBoundary, ExpandablePanel, ExternalLinkIcon, EyeIcon, EyeOffIcon, FileIcon, FileSearchIcon, FileTextIcon, FileUpload, FilterChip, FilterIcon, FilterXIcon, FlagIcon, FolderIcon, FolderPlusIcon, FolderUpIcon, FunctionSquareIcon, GitBranchIcon, GitHubIcon, GlobeIcon, HandleIcon, HashIcon, Heading1Icon, Heading2Icon, Heading3Icon, HelpCircleIcon, HistoryIcon, HomeIcon, IconButton, ImageIcon, ImageOffIcon, InfoIcon, InfoLabel, InputLabel, ItalicIcon, KanbanIcon, KanbanView, KeyIcon, KeyRoundIcon, Label, LanguagesIcon, LayoutGridIcon, Link2Icon, LinkIcon, ListIcon, ListOrderedIcon, ListView, LoaderIcon, LoadingButton, LockIcon, LogOutIcon, MailIcon, Markdown, Maximize2Icon, Menu, MenuIcon, MenuItem, Menubar, MenubarCheckboxItem, MenubarContent, MenubarItem, MenubarItemIndicator, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarSubTriggerIndicator, MenubarTrigger, MinusCircleIcon, MinusIcon, MoonIcon, MoreVerticalIcon, MultiSelect, MultiSelectContext, MultiSelectItem, Music2Icon, PanelLeftIcon, Paper, PauseIcon, PencilIcon, PhoneIcon, PlayIcon, PlusIcon, Popover, PopoverPrimitive, Portal, PortalContainerProvider, QuoteIcon, RadioGroup, RadioGroupItem, RefreshCcwIcon, RefreshCwIcon, RepeatIcon, ResizablePanels, Rows3Icon, SaveIcon, SearchBar, SearchIcon, Select, SelectGroup, SelectInputLabel, SelectItem, SendIcon, Separator, SettingsIcon, Sheet, ShieldIcon, ShoppingCartIcon, Skeleton, Slider, SlidersHorizontalIcon, Slot, SquareIcon, StarIcon, StrikethroughIcon, SunIcon, SunMoonIcon, Tab, Table, TableBody, TableCell, TableHeader, TableIcon, TableRow, VirtualTable as TableView, VirtualTable, Tabs, TagIcon, TerminalIcon, TextField, TextIcon, TextareaAutosize, ToggleButtonGroup, Tooltip, Trash2Icon, TypeIcon, Typography, UnderlineIcon, UndoIcon, UploadCloudIcon, UploadIcon, UserCheckIcon, UserIcon, UserPlus, VideoIcon, VoteIcon, Wand2Icon, XCircleIcon, XIcon, cardClickableMixin, cardMixin, cardSelectedMixin, cls, colorClassesMapping, coolIconKeys, debounce, defaultBorderMixin, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, fieldBackgroundInvisibleMixin, fieldBackgroundMixin, focusedClasses, focusedDisabled, focusedInvisibleMixin, getColorSchemeForKey, getColorSchemeForSeed, iconKeys, iconSize, keyToIconComponent, lucideIcons, paperMixin, useAutoComplete, useDebounceCallback, useDebounceValue, useDebouncedCallback, useInjectStyles, useOutsideAlerter, usePortalContainer };
|
|
6093
8135
|
|
|
6094
8136
|
//# sourceMappingURL=index.es.js.map
|