@ai-matrx/design-system 0.86.360 → 0.86.362
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/CHANGELOG.md +24 -2
- package/README.md +2 -0
- package/dist/carousel.js +5 -5
- package/dist/{chunk-ZU2ZODDD.js → chunk-2QFA6CK4.js} +4 -4
- package/dist/{chunk-UCEKAKHP.js → chunk-3YTF4MH2.js} +2 -2
- package/dist/{chunk-T57DLONB.js → chunk-AKSKVT2M.js} +17 -9
- package/dist/chunk-AKSKVT2M.js.map +1 -0
- package/dist/{chunk-LU75R6YX.js → chunk-KOUHF4JC.js} +2 -2
- package/dist/{chunk-HISATFYI.js → chunk-LS3C7IUV.js} +2 -2
- package/dist/{chunk-QK7GPIEA.js → chunk-QJ6SQNXD.js} +4 -4
- package/dist/{chunk-TSETPQWU.js → chunk-RO5CRIOL.js} +2 -2
- package/dist/{chunk-WHERV3VC.js → chunk-SOCDBDFS.js} +4 -4
- package/dist/{chunk-C5HYUXR2.js → chunk-UGUVTE77.js} +2 -2
- package/dist/{chunk-FF524V6P.js → chunk-VOLSYNJY.js} +3 -3
- package/dist/{chunk-WOA6WHV2.js → chunk-WLKHQGX5.js} +2 -2
- package/dist/{chunk-42GFQMLA.js → chunk-WUI5OFCH.js} +2 -2
- package/dist/clipboard-fallback-dialog.js +2 -2
- package/dist/controls.cjs +16 -8
- package/dist/controls.cjs.map +1 -1
- package/dist/controls.js +5 -5
- package/dist/data-table/data-row-inspector.js +5 -5
- package/dist/data-table/data-row-window.js +6 -6
- package/dist/data-table/index.cjs +858 -772
- package/dist/data-table/index.cjs.map +1 -1
- package/dist/data-table/index.js +541 -461
- package/dist/data-table/index.js.map +1 -1
- package/dist/data-table/pagination.cjs +16 -8
- package/dist/data-table/pagination.cjs.map +1 -1
- package/dist/data-table/pagination.js +3 -3
- package/dist/data-table/uuid-cell.js +3 -3
- package/dist/desktop.cjs +16 -8
- package/dist/desktop.cjs.map +1 -1
- package/dist/desktop.js +5 -5
- package/dist/index.cjs +20 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +11 -11
- package/dist/index.js.map +1 -1
- package/dist/intro-stage.cjs +24 -3
- package/dist/intro-stage.cjs.map +1 -1
- package/dist/intro-stage.d.cts +9 -3
- package/dist/intro-stage.d.ts +9 -3
- package/dist/intro-stage.js +24 -3
- package/dist/intro-stage.js.map +1 -1
- package/dist/item.cjs +16 -8
- package/dist/item.cjs.map +1 -1
- package/dist/item.js +4 -4
- package/dist/lite-table.js +2 -2
- package/dist/menu-look.cjs +16 -8
- package/dist/menu-look.cjs.map +1 -1
- package/dist/menu-look.js +2 -2
- package/dist/record-list.cjs +16 -8
- package/dist/record-list.cjs.map +1 -1
- package/dist/record-list.js +4 -4
- package/dist/settings.js +3 -3
- package/dist/styles.css +18 -0
- package/dist/thumbnail-grid.cjs +27 -1
- package/dist/thumbnail-grid.cjs.map +1 -1
- package/dist/thumbnail-grid.d.cts +16 -2
- package/dist/thumbnail-grid.d.ts +16 -2
- package/dist/thumbnail-grid.js +27 -1
- package/dist/thumbnail-grid.js.map +1 -1
- package/dist/writing-field.cjs +3 -2
- package/dist/writing-field.cjs.map +1 -1
- package/dist/writing-field.js +6 -5
- package/dist/writing-field.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-T57DLONB.js.map +0 -1
- /package/dist/{chunk-ZU2ZODDD.js.map → chunk-2QFA6CK4.js.map} +0 -0
- /package/dist/{chunk-UCEKAKHP.js.map → chunk-3YTF4MH2.js.map} +0 -0
- /package/dist/{chunk-LU75R6YX.js.map → chunk-KOUHF4JC.js.map} +0 -0
- /package/dist/{chunk-HISATFYI.js.map → chunk-LS3C7IUV.js.map} +0 -0
- /package/dist/{chunk-QK7GPIEA.js.map → chunk-QJ6SQNXD.js.map} +0 -0
- /package/dist/{chunk-TSETPQWU.js.map → chunk-RO5CRIOL.js.map} +0 -0
- /package/dist/{chunk-WHERV3VC.js.map → chunk-SOCDBDFS.js.map} +0 -0
- /package/dist/{chunk-C5HYUXR2.js.map → chunk-UGUVTE77.js.map} +0 -0
- /package/dist/{chunk-FF524V6P.js.map → chunk-VOLSYNJY.js.map} +0 -0
- /package/dist/{chunk-WOA6WHV2.js.map → chunk-WLKHQGX5.js.map} +0 -0
- /package/dist/{chunk-42GFQMLA.js.map → chunk-WUI5OFCH.js.map} +0 -0
|
@@ -36,6 +36,11 @@ interface ThumbnailGridProps<T extends ThumbnailItem> {
|
|
|
36
36
|
columns?: number;
|
|
37
37
|
/** CSS aspect ratio of the frame. Default "3 / 4". */
|
|
38
38
|
aspectRatio?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Keep this thumbnail in view: whenever it changes (e.g. the page a viewer is on), the nearest
|
|
41
|
+
* scrolling ancestor scrolls just enough to show it. Only that ancestor moves, never the page.
|
|
42
|
+
*/
|
|
43
|
+
revealId?: string | null;
|
|
39
44
|
disabled?: boolean;
|
|
40
45
|
className?: string;
|
|
41
46
|
"aria-label": string;
|
|
@@ -47,9 +52,18 @@ interface ThumbnailGridProps<T extends ThumbnailItem> {
|
|
|
47
52
|
declare function reorderIds(ids: readonly string[], moved: readonly string[], overId: string): string[];
|
|
48
53
|
/** Nudge `moved` one place (-1 earlier, +1 later) or to an end (-Infinity / Infinity). */
|
|
49
54
|
declare function nudgeIds(ids: readonly string[], moved: readonly string[], by: number): string[];
|
|
55
|
+
/** The scrollTop that shows `el` inside `box` with the least movement (unchanged when already in view). */
|
|
56
|
+
declare function revealScrollTop(box: {
|
|
57
|
+
scrollTop: number;
|
|
58
|
+
top: number;
|
|
59
|
+
height: number;
|
|
60
|
+
}, el: {
|
|
61
|
+
top: number;
|
|
62
|
+
height: number;
|
|
63
|
+
}): number;
|
|
50
64
|
/** Ids from `a` to `b` inclusive, in grid order. */
|
|
51
65
|
declare function rangeIds(ids: readonly string[], a: string, b: string): string[];
|
|
52
|
-
declare function ThumbnailGrid<T extends ThumbnailItem>({ items, renderItem, selectedIds, onSelectedIdsChange, onReorder, onOpen, renderContextMenu, renderCaption, itemLabel, minThumbWidth, columns, aspectRatio, disabled, className, "aria-label": ariaLabel, }: ThumbnailGridProps<T>): React.JSX.Element;
|
|
66
|
+
declare function ThumbnailGrid<T extends ThumbnailItem>({ items, renderItem, selectedIds, onSelectedIdsChange, onReorder, onOpen, renderContextMenu, renderCaption, itemLabel, minThumbWidth, columns, aspectRatio, revealId, disabled, className, "aria-label": ariaLabel, }: ThumbnailGridProps<T>): React.JSX.Element;
|
|
53
67
|
|
|
54
|
-
export { ThumbnailGrid, nudgeIds, rangeIds, reorderIds };
|
|
68
|
+
export { ThumbnailGrid, nudgeIds, rangeIds, reorderIds, revealScrollTop };
|
|
55
69
|
export type { ThumbnailCellState, ThumbnailGridProps, ThumbnailItem };
|
package/dist/thumbnail-grid.d.ts
CHANGED
|
@@ -36,6 +36,11 @@ interface ThumbnailGridProps<T extends ThumbnailItem> {
|
|
|
36
36
|
columns?: number;
|
|
37
37
|
/** CSS aspect ratio of the frame. Default "3 / 4". */
|
|
38
38
|
aspectRatio?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Keep this thumbnail in view: whenever it changes (e.g. the page a viewer is on), the nearest
|
|
41
|
+
* scrolling ancestor scrolls just enough to show it. Only that ancestor moves, never the page.
|
|
42
|
+
*/
|
|
43
|
+
revealId?: string | null;
|
|
39
44
|
disabled?: boolean;
|
|
40
45
|
className?: string;
|
|
41
46
|
"aria-label": string;
|
|
@@ -47,9 +52,18 @@ interface ThumbnailGridProps<T extends ThumbnailItem> {
|
|
|
47
52
|
declare function reorderIds(ids: readonly string[], moved: readonly string[], overId: string): string[];
|
|
48
53
|
/** Nudge `moved` one place (-1 earlier, +1 later) or to an end (-Infinity / Infinity). */
|
|
49
54
|
declare function nudgeIds(ids: readonly string[], moved: readonly string[], by: number): string[];
|
|
55
|
+
/** The scrollTop that shows `el` inside `box` with the least movement (unchanged when already in view). */
|
|
56
|
+
declare function revealScrollTop(box: {
|
|
57
|
+
scrollTop: number;
|
|
58
|
+
top: number;
|
|
59
|
+
height: number;
|
|
60
|
+
}, el: {
|
|
61
|
+
top: number;
|
|
62
|
+
height: number;
|
|
63
|
+
}): number;
|
|
50
64
|
/** Ids from `a` to `b` inclusive, in grid order. */
|
|
51
65
|
declare function rangeIds(ids: readonly string[], a: string, b: string): string[];
|
|
52
|
-
declare function ThumbnailGrid<T extends ThumbnailItem>({ items, renderItem, selectedIds, onSelectedIdsChange, onReorder, onOpen, renderContextMenu, renderCaption, itemLabel, minThumbWidth, columns, aspectRatio, disabled, className, "aria-label": ariaLabel, }: ThumbnailGridProps<T>): React.JSX.Element;
|
|
66
|
+
declare function ThumbnailGrid<T extends ThumbnailItem>({ items, renderItem, selectedIds, onSelectedIdsChange, onReorder, onOpen, renderContextMenu, renderCaption, itemLabel, minThumbWidth, columns, aspectRatio, revealId, disabled, className, "aria-label": ariaLabel, }: ThumbnailGridProps<T>): React.JSX.Element;
|
|
53
67
|
|
|
54
|
-
export { ThumbnailGrid, nudgeIds, rangeIds, reorderIds };
|
|
68
|
+
export { ThumbnailGrid, nudgeIds, rangeIds, reorderIds, revealScrollTop };
|
|
55
69
|
export type { ThumbnailCellState, ThumbnailGridProps, ThumbnailItem };
|
package/dist/thumbnail-grid.js
CHANGED
|
@@ -50,6 +50,20 @@ function nudgeIds(ids, moved, by) {
|
|
|
50
50
|
const target = by === -Infinity ? 0 : by === Infinity ? rest.length : Math.min(rest.length, Math.max(0, first + by));
|
|
51
51
|
return [...rest.slice(0, target), ...group, ...rest.slice(target)];
|
|
52
52
|
}
|
|
53
|
+
function revealScrollTop(box, el) {
|
|
54
|
+
const above = el.top - box.top;
|
|
55
|
+
const below = el.top + el.height - (box.top + box.height);
|
|
56
|
+
if (above < 0) return box.scrollTop + above;
|
|
57
|
+
if (below > 0) return box.scrollTop + Math.min(below, above);
|
|
58
|
+
return box.scrollTop;
|
|
59
|
+
}
|
|
60
|
+
function scrollParent(el) {
|
|
61
|
+
for (let n = el.parentElement; n; n = n.parentElement) {
|
|
62
|
+
const { overflowY } = getComputedStyle(n);
|
|
63
|
+
if ((overflowY === "auto" || overflowY === "scroll") && n.scrollHeight > n.clientHeight) return n;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
53
67
|
function rangeIds(ids, a, b) {
|
|
54
68
|
const i = ids.indexOf(a), j = ids.indexOf(b);
|
|
55
69
|
if (i < 0 || j < 0) return [];
|
|
@@ -121,6 +135,7 @@ function ThumbnailGrid({
|
|
|
121
135
|
minThumbWidth = 120,
|
|
122
136
|
columns,
|
|
123
137
|
aspectRatio = "3 / 4",
|
|
138
|
+
revealId,
|
|
124
139
|
disabled = false,
|
|
125
140
|
className,
|
|
126
141
|
"aria-label": ariaLabel
|
|
@@ -134,6 +149,16 @@ function ThumbnailGrid({
|
|
|
134
149
|
const [dragIds, setDragIds] = React.useState(null);
|
|
135
150
|
const [activeId, setActiveId] = React.useState(null);
|
|
136
151
|
const [overId, setOverId] = React.useState(null);
|
|
152
|
+
React.useEffect(() => {
|
|
153
|
+
if (!revealId || dragIds) return;
|
|
154
|
+
const el = nodes.current.get(revealId);
|
|
155
|
+
const box = el && scrollParent(el);
|
|
156
|
+
if (!el || !box) return;
|
|
157
|
+
const b = box.getBoundingClientRect();
|
|
158
|
+
const r = el.getBoundingClientRect();
|
|
159
|
+
const top = revealScrollTop({ scrollTop: box.scrollTop, top: b.top, height: box.clientHeight }, { top: r.top, height: r.height });
|
|
160
|
+
if (top !== box.scrollTop) box.scrollTo({ top, behavior: "smooth" });
|
|
161
|
+
}, [revealId]);
|
|
137
162
|
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } }));
|
|
138
163
|
const stopId = focusId && byId.has(focusId) ? focusId : ids.find((id) => selected.has(id)) ?? ids[0] ?? null;
|
|
139
164
|
const shown = dragIds && overId ? reorderIds(ids, dragIds, overId) : ids;
|
|
@@ -324,6 +349,7 @@ export {
|
|
|
324
349
|
ThumbnailGrid,
|
|
325
350
|
nudgeIds,
|
|
326
351
|
rangeIds,
|
|
327
|
-
reorderIds
|
|
352
|
+
reorderIds,
|
|
353
|
+
revealScrollTop
|
|
328
354
|
};
|
|
329
355
|
//# sourceMappingURL=thumbnail-grid.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/thumbnail-grid/thumbnail-grid.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * ThumbnailGrid — page thumbnails you can select and reorder (the Organize grid of a PDF\n * workspace; any ordered set of previews). The control owns selection, focus, drag and keys; the\n * caller owns the order and what each thumbnail shows (`renderItem`, e.g. a rasterised page).\n *\n * Select: click selects one, Ctrl/Cmd+click toggles, Shift+click extends from the anchor,\n * Space toggles, Shift+arrows extend, Ctrl/Cmd+A selects all, Escape clears.\n * Move: drag a thumbnail (the whole selection moves when you drag a selected one) — the others\n * displace to open the slot, the dragged ones leave a dashed shadow placeholder where they were\n * lifted from, and a copy follows the pointer. Keyboard: Alt+arrow moves the selection one place\n * (Alt+Home/End to the ends). Both end in `onReorder(ids)` with the full new order.\n * Focus: one tab stop (roving), arrows move by one, Up/Down by a row, Home/End jump; Enter opens.\n *\n * Context menu: `renderContextMenu({ item, selectedIds })` returns `ContextMenuItem`s; a press on\n * an unselected thumbnail selects it first (so the menu acts on what it points at).\n *\n * No layout shift: the selection ring is a box-shadow (ring), the caption row is always there, and the\n * drag copy is portaled (`DragOverlay`). Drag holds the grabbing cursor (the cursor law).\n */\n\nimport {\n DndContext,\n DragOverlay,\n PointerSensor,\n closestCenter,\n useDraggable,\n useDroppable,\n useSensor,\n useSensors,\n type DragEndEvent,\n type DragOverEvent,\n type DragStartEvent,\n} from \"@dnd-kit/core\";\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { ContextMenu, ContextMenuContent, ContextMenuTrigger } from \"../context-menu\";\nimport { DragCursorMonitor } from \"../drag-cursor-monitor\";\n\nexport interface ThumbnailItem {\n id: string;\n}\n\nexport interface ThumbnailCellState {\n index: number;\n selected: boolean;\n focused: boolean;\n /** This thumbnail is part of the drag in flight. */\n dragging: boolean;\n}\n\nexport interface ThumbnailGridProps<T extends ThumbnailItem> {\n items: readonly T[];\n /** The thumbnail face (an <img>, a canvas, a skeleton). Fills the frame (aspect-[3/4] by default). */\n renderItem: (item: T, state: ThumbnailCellState) => React.ReactNode;\n /** Selected ids (controlled). */\n selectedIds: readonly string[];\n onSelectedIdsChange: (ids: string[]) => void;\n /** The full new order after a drag or Alt+arrow. `moved` are the ids that moved, in order. */\n onReorder?: (ids: string[], moved: string[]) => void;\n /** Enter or double-click on a thumbnail. */\n onOpen?: (item: T, index: number) => void;\n /** Items for the right-click menu, as `ContextMenuItem`s. */\n renderContextMenu?: (ctx: { item: T; selectedIds: string[] }) => React.ReactNode;\n /** Under-thumbnail caption; defaults to the 1-based position. */\n renderCaption?: (item: T, index: number) => React.ReactNode;\n /** Spoken name of one thumbnail; defaults to \"Page N\". */\n itemLabel?: (item: T, index: number) => string;\n /** Smallest thumbnail width, px (columns fill the width). Default 120. */\n minThumbWidth?: number;\n /** Fix the column count instead of filling (also steers Up/Down when layout is unmeasured). */\n columns?: number;\n /** CSS aspect ratio of the frame. Default \"3 / 4\". */\n aspectRatio?: string;\n disabled?: boolean;\n className?: string;\n \"aria-label\": string;\n}\n\n/* ---------------------------------- pure halves ---------------------------------- */\n\n/**\n * The order after dropping `moved` onto `overId`: dragging toward the end lands the group after\n * the target, toward the start before it. Dropping onto one of the moved ids changes nothing.\n */\nexport function reorderIds(ids: readonly string[], moved: readonly string[], overId: string): string[] {\n const movedSet = new Set(moved);\n const overIndex = ids.indexOf(overId);\n if (overIndex < 0 || movedSet.has(overId) || moved.length === 0) return [...ids];\n const firstMoved = Math.min(...moved.map((m) => ids.indexOf(m)).filter((i) => i >= 0));\n const rest = ids.filter((id) => !movedSet.has(id));\n const at = rest.indexOf(overId);\n const insertAt = firstMoved < overIndex ? at + 1 : at;\n const group = ids.filter((id) => movedSet.has(id));\n return [...rest.slice(0, insertAt), ...group, ...rest.slice(insertAt)];\n}\n\n/** Nudge `moved` one place (-1 earlier, +1 later) or to an end (-Infinity / Infinity). */\nexport function nudgeIds(ids: readonly string[], moved: readonly string[], by: number): string[] {\n const movedSet = new Set(moved);\n const group = ids.filter((id) => movedSet.has(id));\n if (group.length === 0) return [...ids];\n const rest = ids.filter((id) => !movedSet.has(id));\n const first = ids.indexOf(group[0]!);\n const target = by === -Infinity ? 0 : by === Infinity ? rest.length : Math.min(rest.length, Math.max(0, first + by));\n return [...rest.slice(0, target), ...group, ...rest.slice(target)];\n}\n\n/** Ids from `a` to `b` inclusive, in grid order. */\nexport function rangeIds(ids: readonly string[], a: string, b: string): string[] {\n const i = ids.indexOf(a), j = ids.indexOf(b);\n if (i < 0 || j < 0) return [];\n return ids.slice(Math.min(i, j), Math.max(i, j) + 1);\n}\n\n/* ------------------------------------ the cell ------------------------------------ */\n\ninterface CellProps<T extends ThumbnailItem> {\n item: T;\n index: number;\n state: ThumbnailCellState;\n label: string;\n caption: React.ReactNode;\n aspectRatio: string;\n tabStop: boolean;\n disabled: boolean;\n placeholder: boolean;\n face: React.ReactNode;\n registerRef: (id: string, el: HTMLElement | null) => void;\n onPress: (e: React.MouseEvent, item: T) => void;\n onKeyDown: (e: React.KeyboardEvent, item: T, index: number) => void;\n onFocus: (id: string) => void;\n onMenuPress: (item: T) => void;\n onOpen?: ((item: T, index: number) => void) | undefined;\n}\n\nfunction Cell<T extends ThumbnailItem>(p: CellProps<T>) {\n const drag = useDraggable({ id: p.item.id, disabled: p.disabled });\n const drop = useDroppable({ id: p.item.id, disabled: p.disabled });\n const setRef = (el: HTMLElement | null) => {\n drag.setNodeRef(el);\n drop.setNodeRef(el);\n p.registerRef(p.item.id, el);\n };\n return (\n <div\n ref={setRef}\n role=\"option\"\n aria-selected={p.state.selected}\n aria-label={p.label}\n tabIndex={p.tabStop ? 0 : -1}\n data-thumb-id={p.item.id}\n data-selected={p.state.selected ? \"\" : undefined}\n data-placeholder={p.placeholder ? \"\" : undefined}\n {...(p.disabled ? {} : drag.listeners)}\n onClick={(e) => p.onPress(e, p.item)}\n onDoubleClick={() => p.onOpen?.(p.item, p.index)}\n onKeyDown={(e) => p.onKeyDown(e, p.item, p.index)}\n onFocus={() => p.onFocus(p.item.id)}\n onContextMenu={() => p.onMenuPress(p.item)}\n className=\"flex min-w-0 flex-col gap-1 rounded-md p-1 outline-none select-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <div\n className={cn(\n \"relative w-full overflow-hidden rounded-sm border border-border bg-muted\",\n p.state.selected && \"ring-2 ring-primary\",\n p.placeholder && \"border-dashed bg-transparent ring-0\",\n )}\n style={{ aspectRatio: p.aspectRatio }}\n >\n <div className={cn(\"size-full\", p.placeholder && \"invisible\")}>{p.face}</div>\n </div>\n <div\n className={cn(\n \"min-h-4 truncate text-center text-xs leading-4\",\n p.state.selected ? \"text-foreground\" : \"text-muted-foreground\",\n )}\n >\n {p.caption}\n </div>\n </div>\n );\n}\n\n/* ------------------------------------ the grid ------------------------------------ */\n\nexport function ThumbnailGrid<T extends ThumbnailItem>({\n items,\n renderItem,\n selectedIds,\n onSelectedIdsChange,\n onReorder,\n onOpen,\n renderContextMenu,\n renderCaption,\n itemLabel,\n minThumbWidth = 120,\n columns,\n aspectRatio = \"3 / 4\",\n disabled = false,\n className,\n \"aria-label\": ariaLabel,\n}: ThumbnailGridProps<T>) {\n const ids = React.useMemo(() => items.map((i) => i.id), [items]);\n const byId = React.useMemo(() => new Map(items.map((i) => [i.id, i])), [items]);\n const selected = React.useMemo(() => new Set(selectedIds), [selectedIds]);\n const nodes = React.useRef(new Map<string, HTMLElement>());\n const anchor = React.useRef<string | null>(null);\n const [focusId, setFocusId] = React.useState<string | null>(null);\n const [dragIds, setDragIds] = React.useState<string[] | null>(null);\n const [activeId, setActiveId] = React.useState<string | null>(null);\n const [overId, setOverId] = React.useState<string | null>(null);\n\n const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } }));\n const stopId = focusId && byId.has(focusId) ? focusId : (ids.find((id) => selected.has(id)) ?? ids[0] ?? null);\n\n // What is drawn while dragging: the live preview order (others displaced).\n const shown = dragIds && overId ? reorderIds(ids, dragIds, overId) : ids;\n const draggingSet = new Set(dragIds ?? []);\n\n const select = (next: string[]) => onSelectedIdsChange(ids.filter((id) => next.includes(id)));\n const focusItem = (id: string | undefined) => {\n if (!id) return;\n setFocusId(id);\n nodes.current.get(id)?.focus();\n };\n const columnCount = (): number => {\n if (columns) return columns;\n const tops = ids.map((id) => nodes.current.get(id)?.offsetTop ?? 0);\n const first = tops[0] ?? 0;\n const n = tops.findIndex((t) => t !== first);\n return n === -1 ? Math.max(1, ids.length) : n;\n };\n\n const press = (e: React.MouseEvent, item: T) => {\n if (disabled) return;\n setFocusId(item.id);\n if (e.shiftKey && anchor.current) select(rangeIds(ids, anchor.current, item.id));\n else if (e.metaKey || e.ctrlKey) {\n select(selected.has(item.id) ? selectedIds.filter((x) => x !== item.id) : [...selectedIds, item.id]);\n anchor.current = item.id;\n } else {\n select([item.id]);\n anchor.current = item.id;\n }\n };\n\n const keyDown = (e: React.KeyboardEvent, item: T, index: number) => {\n if (disabled) return;\n const cols = columnCount();\n const mod = e.metaKey || e.ctrlKey;\n const step: Record<string, number> = { ArrowLeft: -1, ArrowRight: 1, ArrowUp: -cols, ArrowDown: cols };\n if (e.altKey && (e.key in step || e.key === \"Home\" || e.key === \"End\")) {\n e.preventDefault();\n const moved = selected.has(item.id) ? ids.filter((id) => selected.has(id)) : [item.id];\n const by = e.key === \"Home\" ? -Infinity : e.key === \"End\" ? Infinity : step[e.key]!;\n const next = nudgeIds(ids, moved, by);\n if (next.join(\"\\0\") !== ids.join(\"\\0\")) {\n onReorder?.(next, moved);\n requestAnimationFrame(() => focusItem(item.id));\n }\n return;\n }\n if (e.key in step || e.key === \"Home\" || e.key === \"End\") {\n e.preventDefault();\n const to = e.key === \"Home\" ? 0 : e.key === \"End\" ? ids.length - 1 : Math.min(ids.length - 1, Math.max(0, index + step[e.key]!));\n const target = ids[to];\n if (!target) return;\n focusItem(target);\n if (e.shiftKey) {\n const from = anchor.current ?? item.id;\n anchor.current = from;\n select(rangeIds(ids, from, target));\n }\n } else if (e.key === \" \") {\n e.preventDefault();\n select(selected.has(item.id) ? selectedIds.filter((x) => x !== item.id) : [...selectedIds, item.id]);\n anchor.current = item.id;\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n onOpen?.(item, index);\n } else if (mod && e.key.toLowerCase() === \"a\") {\n e.preventDefault();\n select(ids);\n } else if (e.key === \"Escape\" && selectedIds.length > 0) {\n select([]);\n }\n };\n\n const onDragStart = (e: DragStartEvent) => {\n const id = String(e.active.id);\n setActiveId(id);\n setOverId(null);\n setDragIds(selected.has(id) ? ids.filter((x) => selected.has(x)) : [id]);\n if (!selected.has(id)) select([id]);\n };\n const onDragOver = (e: DragOverEvent) => setOverId(e.over ? String(e.over.id) : null);\n const onDragEnd = (e: DragEndEvent) => {\n const moved = dragIds ?? [];\n const target = e.over ? String(e.over.id) : null;\n setActiveId(null);\n setDragIds(null);\n setOverId(null);\n if (!target || moved.length === 0) return;\n const next = reorderIds(ids, moved, target);\n if (next.join(\"\\0\") !== ids.join(\"\\0\")) onReorder?.(next, moved);\n };\n const onDragCancel = () => {\n setActiveId(null);\n setDragIds(null);\n setOverId(null);\n };\n\n const gridStyle: React.CSSProperties = {\n gridTemplateColumns: columns\n ? `repeat(${columns}, minmax(0, 1fr))`\n : `repeat(auto-fill, minmax(${minThumbWidth}px, 1fr))`,\n };\n const activeItem = activeId ? byId.get(activeId) : undefined;\n const activeIndex = activeItem ? ids.indexOf(activeItem.id) : -1;\n\n return (\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n onDragStart={onDragStart}\n onDragOver={onDragOver}\n onDragEnd={onDragEnd}\n onDragCancel={onDragCancel}\n >\n <DragCursorMonitor />\n <div\n role=\"listbox\"\n aria-label={ariaLabel}\n aria-multiselectable\n aria-orientation=\"horizontal\"\n data-matrx-thumbnail-grid=\"\"\n data-dragging={dragIds ? \"\" : undefined}\n className={cn(\"grid gap-2\", className)}\n style={gridStyle}\n >\n {shown.map((id) => {\n const item = byId.get(id);\n if (!item) return null;\n const index = ids.indexOf(id);\n const state: ThumbnailCellState = {\n index,\n selected: selected.has(id),\n focused: stopId === id,\n dragging: draggingSet.has(id),\n };\n const cell = (\n <Cell\n key={id}\n item={item}\n index={index}\n state={state}\n label={itemLabel ? itemLabel(item, index) : `Page ${index + 1}`}\n caption={renderCaption ? renderCaption(item, index) : index + 1}\n aspectRatio={aspectRatio}\n tabStop={stopId === id}\n disabled={disabled}\n placeholder={draggingSet.has(id) && overId !== null}\n face={renderItem(item, state)}\n registerRef={(k, el) => {\n if (el) nodes.current.set(k, el);\n else nodes.current.delete(k);\n }}\n onPress={press}\n onKeyDown={keyDown}\n onFocus={setFocusId}\n onMenuPress={(it) => {\n if (!selected.has(it.id)) {\n select([it.id]);\n anchor.current = it.id;\n }\n }}\n onOpen={onOpen}\n />\n );\n if (!renderContextMenu) return cell;\n return (\n <ContextMenu key={id}>\n {/* display:contents wrapper: the trigger listens for the bubbled contextmenu, the cell keeps its own props */}\n <ContextMenuTrigger asChild>\n <div role=\"presentation\" className=\"contents\">{cell}</div>\n </ContextMenuTrigger>\n <ContextMenuContent>\n {renderContextMenu({\n item,\n selectedIds: selected.has(id) ? ids.filter((x) => selected.has(x)) : [id],\n })}\n </ContextMenuContent>\n </ContextMenu>\n );\n })}\n </div>\n <DragOverlay dropAnimation={null}>\n {activeItem ? (\n <div\n className=\"relative overflow-hidden rounded-sm border border-border bg-muted shadow-lg\"\n style={{ aspectRatio, width: minThumbWidth }}\n >\n {renderItem(activeItem, { index: activeIndex, selected: true, focused: false, dragging: true })}\n {dragIds && dragIds.length > 1 ? (\n <span className=\"absolute right-1 top-1 rounded-full bg-primary px-1.5 text-xs leading-4 text-primary-foreground\">\n {dragIds.length}\n </span>\n ) : null}\n </div>\n ) : null}\n </DragOverlay>\n </DndContext>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/thumbnail-grid/thumbnail-grid.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * ThumbnailGrid — page thumbnails you can select and reorder (the Organize grid of a PDF\n * workspace; any ordered set of previews). The control owns selection, focus, drag and keys; the\n * caller owns the order and what each thumbnail shows (`renderItem`, e.g. a rasterised page).\n *\n * Select: click selects one, Ctrl/Cmd+click toggles, Shift+click extends from the anchor,\n * Space toggles, Shift+arrows extend, Ctrl/Cmd+A selects all, Escape clears.\n * Move: drag a thumbnail (the whole selection moves when you drag a selected one) — the others\n * displace to open the slot, the dragged ones leave a dashed shadow placeholder where they were\n * lifted from, and a copy follows the pointer. Keyboard: Alt+arrow moves the selection one place\n * (Alt+Home/End to the ends). Both end in `onReorder(ids)` with the full new order.\n * Focus: one tab stop (roving), arrows move by one, Up/Down by a row, Home/End jump; Enter opens.\n *\n * Context menu: `renderContextMenu({ item, selectedIds })` returns `ContextMenuItem`s; a press on\n * an unselected thumbnail selects it first (so the menu acts on what it points at).\n *\n * No layout shift: the selection ring is a box-shadow (ring), the caption row is always there, and the\n * drag copy is portaled (`DragOverlay`). Drag holds the grabbing cursor (the cursor law).\n */\n\nimport {\n DndContext,\n DragOverlay,\n PointerSensor,\n closestCenter,\n useDraggable,\n useDroppable,\n useSensor,\n useSensors,\n type DragEndEvent,\n type DragOverEvent,\n type DragStartEvent,\n} from \"@dnd-kit/core\";\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { ContextMenu, ContextMenuContent, ContextMenuTrigger } from \"../context-menu\";\nimport { DragCursorMonitor } from \"../drag-cursor-monitor\";\n\nexport interface ThumbnailItem {\n id: string;\n}\n\nexport interface ThumbnailCellState {\n index: number;\n selected: boolean;\n focused: boolean;\n /** This thumbnail is part of the drag in flight. */\n dragging: boolean;\n}\n\nexport interface ThumbnailGridProps<T extends ThumbnailItem> {\n items: readonly T[];\n /** The thumbnail face (an <img>, a canvas, a skeleton). Fills the frame (aspect-[3/4] by default). */\n renderItem: (item: T, state: ThumbnailCellState) => React.ReactNode;\n /** Selected ids (controlled). */\n selectedIds: readonly string[];\n onSelectedIdsChange: (ids: string[]) => void;\n /** The full new order after a drag or Alt+arrow. `moved` are the ids that moved, in order. */\n onReorder?: (ids: string[], moved: string[]) => void;\n /** Enter or double-click on a thumbnail. */\n onOpen?: (item: T, index: number) => void;\n /** Items for the right-click menu, as `ContextMenuItem`s. */\n renderContextMenu?: (ctx: { item: T; selectedIds: string[] }) => React.ReactNode;\n /** Under-thumbnail caption; defaults to the 1-based position. */\n renderCaption?: (item: T, index: number) => React.ReactNode;\n /** Spoken name of one thumbnail; defaults to \"Page N\". */\n itemLabel?: (item: T, index: number) => string;\n /** Smallest thumbnail width, px (columns fill the width). Default 120. */\n minThumbWidth?: number;\n /** Fix the column count instead of filling (also steers Up/Down when layout is unmeasured). */\n columns?: number;\n /** CSS aspect ratio of the frame. Default \"3 / 4\". */\n aspectRatio?: string;\n /**\n * Keep this thumbnail in view: whenever it changes (e.g. the page a viewer is on), the nearest\n * scrolling ancestor scrolls just enough to show it. Only that ancestor moves, never the page.\n */\n revealId?: string | null;\n disabled?: boolean;\n className?: string;\n \"aria-label\": string;\n}\n\n/* ---------------------------------- pure halves ---------------------------------- */\n\n/**\n * The order after dropping `moved` onto `overId`: dragging toward the end lands the group after\n * the target, toward the start before it. Dropping onto one of the moved ids changes nothing.\n */\nexport function reorderIds(ids: readonly string[], moved: readonly string[], overId: string): string[] {\n const movedSet = new Set(moved);\n const overIndex = ids.indexOf(overId);\n if (overIndex < 0 || movedSet.has(overId) || moved.length === 0) return [...ids];\n const firstMoved = Math.min(...moved.map((m) => ids.indexOf(m)).filter((i) => i >= 0));\n const rest = ids.filter((id) => !movedSet.has(id));\n const at = rest.indexOf(overId);\n const insertAt = firstMoved < overIndex ? at + 1 : at;\n const group = ids.filter((id) => movedSet.has(id));\n return [...rest.slice(0, insertAt), ...group, ...rest.slice(insertAt)];\n}\n\n/** Nudge `moved` one place (-1 earlier, +1 later) or to an end (-Infinity / Infinity). */\nexport function nudgeIds(ids: readonly string[], moved: readonly string[], by: number): string[] {\n const movedSet = new Set(moved);\n const group = ids.filter((id) => movedSet.has(id));\n if (group.length === 0) return [...ids];\n const rest = ids.filter((id) => !movedSet.has(id));\n const first = ids.indexOf(group[0]!);\n const target = by === -Infinity ? 0 : by === Infinity ? rest.length : Math.min(rest.length, Math.max(0, first + by));\n return [...rest.slice(0, target), ...group, ...rest.slice(target)];\n}\n\n/** The scrollTop that shows `el` inside `box` with the least movement (unchanged when already in view). */\nexport function revealScrollTop(box: { scrollTop: number; top: number; height: number }, el: { top: number; height: number }): number {\n const above = el.top - box.top;\n const below = el.top + el.height - (box.top + box.height);\n if (above < 0) return box.scrollTop + above;\n if (below > 0) return box.scrollTop + Math.min(below, above);\n return box.scrollTop;\n}\n\nfunction scrollParent(el: HTMLElement): HTMLElement | null {\n for (let n = el.parentElement; n; n = n.parentElement) {\n const { overflowY } = getComputedStyle(n);\n if ((overflowY === \"auto\" || overflowY === \"scroll\") && n.scrollHeight > n.clientHeight) return n;\n }\n return null;\n}\n\n/** Ids from `a` to `b` inclusive, in grid order. */\nexport function rangeIds(ids: readonly string[], a: string, b: string): string[] {\n const i = ids.indexOf(a), j = ids.indexOf(b);\n if (i < 0 || j < 0) return [];\n return ids.slice(Math.min(i, j), Math.max(i, j) + 1);\n}\n\n/* ------------------------------------ the cell ------------------------------------ */\n\ninterface CellProps<T extends ThumbnailItem> {\n item: T;\n index: number;\n state: ThumbnailCellState;\n label: string;\n caption: React.ReactNode;\n aspectRatio: string;\n tabStop: boolean;\n disabled: boolean;\n placeholder: boolean;\n face: React.ReactNode;\n registerRef: (id: string, el: HTMLElement | null) => void;\n onPress: (e: React.MouseEvent, item: T) => void;\n onKeyDown: (e: React.KeyboardEvent, item: T, index: number) => void;\n onFocus: (id: string) => void;\n onMenuPress: (item: T) => void;\n onOpen?: ((item: T, index: number) => void) | undefined;\n}\n\nfunction Cell<T extends ThumbnailItem>(p: CellProps<T>) {\n const drag = useDraggable({ id: p.item.id, disabled: p.disabled });\n const drop = useDroppable({ id: p.item.id, disabled: p.disabled });\n const setRef = (el: HTMLElement | null) => {\n drag.setNodeRef(el);\n drop.setNodeRef(el);\n p.registerRef(p.item.id, el);\n };\n return (\n <div\n ref={setRef}\n role=\"option\"\n aria-selected={p.state.selected}\n aria-label={p.label}\n tabIndex={p.tabStop ? 0 : -1}\n data-thumb-id={p.item.id}\n data-selected={p.state.selected ? \"\" : undefined}\n data-placeholder={p.placeholder ? \"\" : undefined}\n {...(p.disabled ? {} : drag.listeners)}\n onClick={(e) => p.onPress(e, p.item)}\n onDoubleClick={() => p.onOpen?.(p.item, p.index)}\n onKeyDown={(e) => p.onKeyDown(e, p.item, p.index)}\n onFocus={() => p.onFocus(p.item.id)}\n onContextMenu={() => p.onMenuPress(p.item)}\n className=\"flex min-w-0 flex-col gap-1 rounded-md p-1 outline-none select-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <div\n className={cn(\n \"relative w-full overflow-hidden rounded-sm border border-border bg-muted\",\n p.state.selected && \"ring-2 ring-primary\",\n p.placeholder && \"border-dashed bg-transparent ring-0\",\n )}\n style={{ aspectRatio: p.aspectRatio }}\n >\n <div className={cn(\"size-full\", p.placeholder && \"invisible\")}>{p.face}</div>\n </div>\n <div\n className={cn(\n \"min-h-4 truncate text-center text-xs leading-4\",\n p.state.selected ? \"text-foreground\" : \"text-muted-foreground\",\n )}\n >\n {p.caption}\n </div>\n </div>\n );\n}\n\n/* ------------------------------------ the grid ------------------------------------ */\n\nexport function ThumbnailGrid<T extends ThumbnailItem>({\n items,\n renderItem,\n selectedIds,\n onSelectedIdsChange,\n onReorder,\n onOpen,\n renderContextMenu,\n renderCaption,\n itemLabel,\n minThumbWidth = 120,\n columns,\n aspectRatio = \"3 / 4\",\n revealId,\n disabled = false,\n className,\n \"aria-label\": ariaLabel,\n}: ThumbnailGridProps<T>) {\n const ids = React.useMemo(() => items.map((i) => i.id), [items]);\n const byId = React.useMemo(() => new Map(items.map((i) => [i.id, i])), [items]);\n const selected = React.useMemo(() => new Set(selectedIds), [selectedIds]);\n const nodes = React.useRef(new Map<string, HTMLElement>());\n const anchor = React.useRef<string | null>(null);\n const [focusId, setFocusId] = React.useState<string | null>(null);\n const [dragIds, setDragIds] = React.useState<string[] | null>(null);\n const [activeId, setActiveId] = React.useState<string | null>(null);\n const [overId, setOverId] = React.useState<string | null>(null);\n\n // Follow `revealId` inside the rail's own scroller; a drag in flight is never yanked.\n React.useEffect(() => {\n if (!revealId || dragIds) return;\n const el = nodes.current.get(revealId);\n const box = el && scrollParent(el);\n if (!el || !box) return;\n const b = box.getBoundingClientRect();\n const r = el.getBoundingClientRect();\n const top = revealScrollTop({ scrollTop: box.scrollTop, top: b.top, height: box.clientHeight }, { top: r.top, height: r.height });\n if (top !== box.scrollTop) box.scrollTo({ top, behavior: \"smooth\" });\n // eslint-disable-next-line react-hooks/exhaustive-deps -- runs when the revealed id changes, not on every drag tick\n }, [revealId]);\n\n const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } }));\n const stopId = focusId && byId.has(focusId) ? focusId : (ids.find((id) => selected.has(id)) ?? ids[0] ?? null);\n\n // What is drawn while dragging: the live preview order (others displaced).\n const shown = dragIds && overId ? reorderIds(ids, dragIds, overId) : ids;\n const draggingSet = new Set(dragIds ?? []);\n\n const select = (next: string[]) => onSelectedIdsChange(ids.filter((id) => next.includes(id)));\n const focusItem = (id: string | undefined) => {\n if (!id) return;\n setFocusId(id);\n nodes.current.get(id)?.focus();\n };\n const columnCount = (): number => {\n if (columns) return columns;\n const tops = ids.map((id) => nodes.current.get(id)?.offsetTop ?? 0);\n const first = tops[0] ?? 0;\n const n = tops.findIndex((t) => t !== first);\n return n === -1 ? Math.max(1, ids.length) : n;\n };\n\n const press = (e: React.MouseEvent, item: T) => {\n if (disabled) return;\n setFocusId(item.id);\n if (e.shiftKey && anchor.current) select(rangeIds(ids, anchor.current, item.id));\n else if (e.metaKey || e.ctrlKey) {\n select(selected.has(item.id) ? selectedIds.filter((x) => x !== item.id) : [...selectedIds, item.id]);\n anchor.current = item.id;\n } else {\n select([item.id]);\n anchor.current = item.id;\n }\n };\n\n const keyDown = (e: React.KeyboardEvent, item: T, index: number) => {\n if (disabled) return;\n const cols = columnCount();\n const mod = e.metaKey || e.ctrlKey;\n const step: Record<string, number> = { ArrowLeft: -1, ArrowRight: 1, ArrowUp: -cols, ArrowDown: cols };\n if (e.altKey && (e.key in step || e.key === \"Home\" || e.key === \"End\")) {\n e.preventDefault();\n const moved = selected.has(item.id) ? ids.filter((id) => selected.has(id)) : [item.id];\n const by = e.key === \"Home\" ? -Infinity : e.key === \"End\" ? Infinity : step[e.key]!;\n const next = nudgeIds(ids, moved, by);\n if (next.join(\"\\0\") !== ids.join(\"\\0\")) {\n onReorder?.(next, moved);\n requestAnimationFrame(() => focusItem(item.id));\n }\n return;\n }\n if (e.key in step || e.key === \"Home\" || e.key === \"End\") {\n e.preventDefault();\n const to = e.key === \"Home\" ? 0 : e.key === \"End\" ? ids.length - 1 : Math.min(ids.length - 1, Math.max(0, index + step[e.key]!));\n const target = ids[to];\n if (!target) return;\n focusItem(target);\n if (e.shiftKey) {\n const from = anchor.current ?? item.id;\n anchor.current = from;\n select(rangeIds(ids, from, target));\n }\n } else if (e.key === \" \") {\n e.preventDefault();\n select(selected.has(item.id) ? selectedIds.filter((x) => x !== item.id) : [...selectedIds, item.id]);\n anchor.current = item.id;\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n onOpen?.(item, index);\n } else if (mod && e.key.toLowerCase() === \"a\") {\n e.preventDefault();\n select(ids);\n } else if (e.key === \"Escape\" && selectedIds.length > 0) {\n select([]);\n }\n };\n\n const onDragStart = (e: DragStartEvent) => {\n const id = String(e.active.id);\n setActiveId(id);\n setOverId(null);\n setDragIds(selected.has(id) ? ids.filter((x) => selected.has(x)) : [id]);\n if (!selected.has(id)) select([id]);\n };\n const onDragOver = (e: DragOverEvent) => setOverId(e.over ? String(e.over.id) : null);\n const onDragEnd = (e: DragEndEvent) => {\n const moved = dragIds ?? [];\n const target = e.over ? String(e.over.id) : null;\n setActiveId(null);\n setDragIds(null);\n setOverId(null);\n if (!target || moved.length === 0) return;\n const next = reorderIds(ids, moved, target);\n if (next.join(\"\\0\") !== ids.join(\"\\0\")) onReorder?.(next, moved);\n };\n const onDragCancel = () => {\n setActiveId(null);\n setDragIds(null);\n setOverId(null);\n };\n\n const gridStyle: React.CSSProperties = {\n gridTemplateColumns: columns\n ? `repeat(${columns}, minmax(0, 1fr))`\n : `repeat(auto-fill, minmax(${minThumbWidth}px, 1fr))`,\n };\n const activeItem = activeId ? byId.get(activeId) : undefined;\n const activeIndex = activeItem ? ids.indexOf(activeItem.id) : -1;\n\n return (\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n onDragStart={onDragStart}\n onDragOver={onDragOver}\n onDragEnd={onDragEnd}\n onDragCancel={onDragCancel}\n >\n <DragCursorMonitor />\n <div\n role=\"listbox\"\n aria-label={ariaLabel}\n aria-multiselectable\n aria-orientation=\"horizontal\"\n data-matrx-thumbnail-grid=\"\"\n data-dragging={dragIds ? \"\" : undefined}\n className={cn(\"grid gap-2\", className)}\n style={gridStyle}\n >\n {shown.map((id) => {\n const item = byId.get(id);\n if (!item) return null;\n const index = ids.indexOf(id);\n const state: ThumbnailCellState = {\n index,\n selected: selected.has(id),\n focused: stopId === id,\n dragging: draggingSet.has(id),\n };\n const cell = (\n <Cell\n key={id}\n item={item}\n index={index}\n state={state}\n label={itemLabel ? itemLabel(item, index) : `Page ${index + 1}`}\n caption={renderCaption ? renderCaption(item, index) : index + 1}\n aspectRatio={aspectRatio}\n tabStop={stopId === id}\n disabled={disabled}\n placeholder={draggingSet.has(id) && overId !== null}\n face={renderItem(item, state)}\n registerRef={(k, el) => {\n if (el) nodes.current.set(k, el);\n else nodes.current.delete(k);\n }}\n onPress={press}\n onKeyDown={keyDown}\n onFocus={setFocusId}\n onMenuPress={(it) => {\n if (!selected.has(it.id)) {\n select([it.id]);\n anchor.current = it.id;\n }\n }}\n onOpen={onOpen}\n />\n );\n if (!renderContextMenu) return cell;\n return (\n <ContextMenu key={id}>\n {/* display:contents wrapper: the trigger listens for the bubbled contextmenu, the cell keeps its own props */}\n <ContextMenuTrigger asChild>\n <div role=\"presentation\" className=\"contents\">{cell}</div>\n </ContextMenuTrigger>\n <ContextMenuContent>\n {renderContextMenu({\n item,\n selectedIds: selected.has(id) ? ids.filter((x) => selected.has(x)) : [id],\n })}\n </ContextMenuContent>\n </ContextMenu>\n );\n })}\n </div>\n <DragOverlay dropAnimation={null}>\n {activeItem ? (\n <div\n className=\"relative overflow-hidden rounded-sm border border-border bg-muted shadow-lg\"\n style={{ aspectRatio, width: minThumbWidth }}\n >\n {renderItem(activeItem, { index: activeIndex, selected: true, focused: false, dragging: true })}\n {dragIds && dragIds.length > 1 ? (\n <span className=\"absolute right-1 top-1 rounded-full bg-primary px-1.5 text-xs leading-4 text-primary-foreground\">\n {dragIds.length}\n </span>\n ) : null}\n </div>\n ) : null}\n </DragOverlay>\n </DndContext>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/writing-field.cjs
CHANGED
|
@@ -3665,6 +3665,7 @@ var ProTextarea = React16.forwardRef(
|
|
|
3665
3665
|
const menuShown = !disabled && (showMenu || voiceInMenu || expandInMenu || menuActions === "none" && enableVoice);
|
|
3666
3666
|
const audioSettingsInMenu = menuShown && enableVoice;
|
|
3667
3667
|
const hasCoarseControls = enableVoice && isAudioAvailable && !disabled || showMenu;
|
|
3668
|
+
const clusterCanShow = hasCoarseControls || !!onSubmit || expandable && !editor || menuShown;
|
|
3668
3669
|
const Stats = addOns.TextStats;
|
|
3669
3670
|
const showTextStats = enableTextStats && showMenu && !!Stats;
|
|
3670
3671
|
React16.useEffect(() => {
|
|
@@ -3696,9 +3697,9 @@ var ProTextarea = React16.forwardRef(
|
|
|
3696
3697
|
hero ? "pr-5" : "pr-3",
|
|
3697
3698
|
className,
|
|
3698
3699
|
// AFTER the caller's className: the reserved control row always wins (a floor, never a ceiling).
|
|
3699
|
-
!inlineControls && !controlsHost &&
|
|
3700
|
+
!inlineControls && !controlsHost && clusterCanShow && (editor?.singleLine && !onSubmit ? "pr-24 pointer-coarse:pr-32" : hero ? "pb-[max(3.5rem,var(--matrx-textarea-end,0px))]" : "pb-[max(2.75rem,var(--matrx-textarea-end,0px))]")
|
|
3700
3701
|
);
|
|
3701
|
-
const reservesRow = !inlineControls && !controlsHost &&
|
|
3702
|
+
const reservesRow = !inlineControls && !controlsHost && clusterCanShow && !editor?.singleLine;
|
|
3702
3703
|
const fieldStyle = {
|
|
3703
3704
|
...style,
|
|
3704
3705
|
minHeight: effectiveMinHeight !== void 0 ? `${effectiveMinHeight}px` : style?.minHeight,
|