gridsmith-ui 0.21.0 → 0.23.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/chat.js +3 -3
- package/dist/chunk-3BRQRKDO.js +72 -0
- package/dist/chunk-3BRQRKDO.js.map +1 -0
- package/dist/{chunk-GGVASDXT.js → chunk-6PL7FXYH.js} +284 -521
- package/dist/chunk-6PL7FXYH.js.map +1 -0
- package/dist/chunk-7TOJ4G7S.js +197 -0
- package/dist/chunk-7TOJ4G7S.js.map +1 -0
- package/dist/chunk-CKWITUSH.js +40 -0
- package/dist/chunk-CKWITUSH.js.map +1 -0
- package/dist/{chunk-ILIODA7W.js → chunk-CXMV7SXJ.js} +4 -3
- package/dist/chunk-CXMV7SXJ.js.map +1 -0
- package/dist/{chunk-EQDR57AM.js → chunk-EYMGLK4M.js} +3 -3
- package/dist/{chunk-EQDR57AM.js.map → chunk-EYMGLK4M.js.map} +1 -1
- package/dist/chunk-ICNWPNMM.js +1363 -0
- package/dist/chunk-ICNWPNMM.js.map +1 -0
- package/dist/chunk-IVCVNAXG.js +115 -0
- package/dist/chunk-IVCVNAXG.js.map +1 -0
- package/dist/{chunk-XYDIBW3J.js → chunk-SBTBMAIU.js} +4 -3
- package/dist/chunk-SBTBMAIU.js.map +1 -0
- package/dist/data-grid.d.ts +38 -4
- package/dist/data-grid.js +305 -264
- package/dist/data-grid.js.map +1 -1
- package/dist/editor.js +10 -3
- package/dist/editor.js.map +1 -1
- package/dist/index.d.ts +122 -146
- package/dist/index.js +1091 -1885
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +4 -2
- package/dist/kanban.js.map +1 -1
- package/dist/resizable.d.ts +1 -1
- package/dist/resizable.js +26 -14
- package/dist/resizable.js.map +1 -1
- package/dist/roots.css +24 -4
- package/dist/{table-utils-GounRE6s.d.ts → table-utils-BkjNEWts.d.ts} +5 -1
- package/dist/tokens.css +20 -3
- package/dist/use-pagination-DiJo0aW5.d.ts +153 -0
- package/dist/virtualized.d.ts +11 -1
- package/dist/virtualized.js +69 -18
- package/dist/virtualized.js.map +1 -1
- package/dist-static/tokens.css +20 -3
- package/package.json +1 -1
- package/dist/chunk-GGVASDXT.js.map +0 -1
- package/dist/chunk-ILIODA7W.js.map +0 -1
- package/dist/chunk-JN37OVTP.js +0 -67
- package/dist/chunk-JN37OVTP.js.map +0 -1
- package/dist/chunk-TKVTZWBN.js +0 -50
- package/dist/chunk-TKVTZWBN.js.map +0 -1
- package/dist/chunk-XYDIBW3J.js.map +0 -1
package/dist/kanban.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Badge } from './chunk-
|
|
2
|
-
import {
|
|
1
|
+
import { Badge } from './chunk-SBTBMAIU.js';
|
|
2
|
+
import { useFramesItself } from './chunk-CKWITUSH.js';
|
|
3
|
+
import { useTextOverflow, Tooltip } from './chunk-CXMV7SXJ.js';
|
|
3
4
|
import './chunk-7Q46JXSK.js';
|
|
4
5
|
import './chunk-WH2FUFAC.js';
|
|
5
6
|
import { Icon } from './chunk-4LDYR7QP.js';
|
|
@@ -251,6 +252,7 @@ function KanbanBoard({
|
|
|
251
252
|
onCardClick,
|
|
252
253
|
className
|
|
253
254
|
}) {
|
|
255
|
+
useFramesItself();
|
|
254
256
|
const [seenProp, setSeenProp] = useState(columnsProp);
|
|
255
257
|
const [holds, setHoldsState] = useState([]);
|
|
256
258
|
const [preview, setPreviewState] = useState(null);
|
package/dist/kanban.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../showcase/src/components/KanbanBoard.tsx"],"names":[],"mappings":"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","file":"kanban.js","sourcesContent":["import { useLayoutEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport {\n DndContext,\n closestCorners,\n KeyboardSensor,\n PointerSensor,\n useSensor,\n useSensors,\n type Announcements,\n type DragCancelEvent,\n type DragEndEvent,\n type DragOverEvent,\n DragOverlay,\n type DragStartEvent,\n type KeyboardCoordinateGetter,\n useDroppable,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\n arrayMove,\n sortableKeyboardCoordinates,\n verticalListSortingStrategy,\n useSortable,\n} from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\nimport { Tooltip } from \"./Tooltip\";\nimport { useTextOverflow } from \"../lib/use-text-overflow\";\nimport { Badge } from \"./Badge\";\n\nexport interface KanbanCard {\n id: string;\n title: string;\n description?: string;\n tags?: string[];\n avatar?: string;\n}\n\nexport interface KanbanColumn {\n id: string;\n title: string;\n cards: KanbanCard[];\n color?: string;\n}\n\nexport interface KanbanBoardProps {\n /**\n * The board's cards by column. Authoritative: the board shows what it is given, with one exception — a card just\n * dropped stays where it was dropped until `columns` shows the move, the save fails, or `columns` changes some other\n * way (see onCardMove). A re-render that passes the same cards again, or an array rebuilt with the same cards,\n * never puts a dropped card back.\n */\n columns: KanbanColumn[];\n /**\n * The columns after a move, once on drop (Sprint 25.7, C2: it used to fire on every hover step). Its return value\n * counts as onCardMove's does.\n */\n onColumnsChange?: (columns: KanbanColumn[]) => unknown;\n /**\n * A card was dropped at a new place: its column and its index there, once on drop — a move between columns, into an\n * empty one, or a reorder within one. Save the move here (or in onColumnsChange); a board with neither saves nothing.\n * The index counts the cards the board shows: when `columns` is filtered, it is the place among the cards passed.\n *\n * Return the save's promise (an async function, or a mutation's mutateAsync) and the card stays where it was dropped\n * while it saves, and while an earlier move of the same card still saves, whatever `columns` arrive meanwhile; when\n * it rejects, the card goes back to where `columns` has it, a screen reader hears so, and the app says why (a toast\n * inside the app shell). The save must settle (give a request a timeout): one that never does holds the card. A\n * handler that throws refuses a move the same way (a column that is full). An app that updates `columns` at once,\n * then saves, puts the card back itself when its save fails; the board still says the move was not saved.\n */\n onCardMove?: (card: KanbanCard, toColumnId: string, index: number) => unknown;\n /** A board to look at, not rearrange: no dragging and no grab cursor; cards still open with onCardClick. */\n readOnly?: boolean;\n renderCard?: (card: KanbanCard) => ReactNode;\n /**\n * Opens a card (a detail drawer, a route). The board's own card surface is the control: click, or Enter with the\n * card focused, opens it; Space picks the card up for a keyboard drag. Never wire a clickable element inside\n * renderCard — a role=\"button\" div fights the drag listeners and the judge cites it (Sprint 25.4 K-1).\n */\n onCardClick?: (card: KanbanCard) => void;\n className?: string;\n}\n\nfunction SortableCard({\n card,\n renderCard,\n onCardClick,\n readOnly,\n}: {\n card: KanbanCard;\n renderCard?: (card: KanbanCard) => ReactNode;\n onCardClick?: (card: KanbanCard) => void;\n readOnly?: boolean;\n}) {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id: card.id, disabled: readOnly });\n\n if (readOnly) {\n // nothing to pick up: a card that opens is a button (Enter and Space), one that does not is a plain surface\n const open = onCardClick ? () => onCardClick(card) : undefined;\n return (\n <div\n ref={setNodeRef}\n {...(open ? { role: \"button\", tabIndex: 0 } : {})}\n onClick={open}\n onKeyDown={open ? (e) => { if (e.key === \"Enter\" || e.key === \" \") { e.preventDefault(); open(); } } : undefined}\n data-kanban-card={card.id}\n className={cn(\n \"rounded-[var(--ds-radius-md)] border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"bg-[var(--ds-bg-surface)] p-ds-3 shadow-[var(--ds-shadow-button)]\",\n open ? \"cursor-pointer\" : \"cursor-default\",\n \"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]\",\n )}\n >\n {renderCard ? renderCard(card) : <DefaultCard card={card} />}\n </div>\n );\n }\n\n const style = {\n transform: CSS.Transform.toString(transform),\n transition,\n };\n\n return (\n <div\n ref={setNodeRef}\n style={style}\n {...attributes}\n {...listeners}\n // the surface is the control (K-1): a click opens (the pointer sensor needs 5 px of movement to start a drag),\n // Enter opens, Space stays the keyboard drag's pick-up\n onClick={onCardClick ? () => onCardClick(card) : undefined}\n onKeyDown={(e) => {\n if (onCardClick && e.key === \"Enter\") { e.preventDefault(); onCardClick(card); return; }\n listeners?.onKeyDown?.(e);\n }}\n data-kanban-card={card.id}\n className={cn(\n \"rounded-[var(--ds-radius-md)] border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"bg-[var(--ds-bg-surface)] p-ds-3 active:cursor-grabbing\",\n onCardClick ? \"cursor-pointer\" : \"cursor-grab\",\n \"shadow-[var(--ds-shadow-button)]\",\n \"transition-shadow duration-[var(--ds-transition-speed)]\",\n \"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]\",\n // no scale on the card left behind: the drag overlay takes its size from it, and 2% wider made the cards\n // below count as \"to the right\" of it, so a keyboard drag's arrow keys landed on them (Sprint 25.7, C2)\n isDragging && \"opacity-30\",\n )}\n >\n {renderCard ? (\n renderCard(card)\n ) : (\n <DefaultCard card={card} />\n )}\n </div>\n );\n}\n\nfunction ClampedDescription({ children }: { children: string }) {\n const { ref, isTruncated } = useTextOverflow({ lines: 2 });\n const el = <p ref={ref} className=\"text-xs text-[var(--ds-text-secondary)] line-clamp-2\">{children}</p>;\n if (!isTruncated) return el;\n return <Tooltip content={children}>{el}</Tooltip>;\n}\n\nfunction TruncTitle({ children }: { children: string }) {\n const { ref, isTruncated } = useTextOverflow({ lines: 1 });\n const el = <p ref={ref} className=\"text-sm font-medium text-[var(--ds-text-primary)] truncate\">{children}</p>;\n if (!isTruncated) return el;\n return <Tooltip content={children}>{el}</Tooltip>;\n}\n\nfunction DefaultCard({ card }: { card: KanbanCard }) {\n return (\n <div className=\"space-y-ds-2\">\n <TruncTitle>{card.title}</TruncTitle>\n {card.description && (\n <ClampedDescription>{card.description}</ClampedDescription>\n )}\n {card.tags && card.tags.length > 0 && (\n <div className=\"flex flex-wrap gap-ds-1\">\n {card.tags.map((tag) => (\n <Badge key={tag} variant=\"subtle\" size=\"sm\">{tag}</Badge>\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction OverlayCard({\n card,\n renderCard,\n}: {\n card: KanbanCard;\n renderCard?: (card: KanbanCard) => ReactNode;\n}) {\n return (\n <div\n className={cn(\n \"rounded-[var(--ds-radius-md)] border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"bg-[var(--ds-bg-surface)] p-ds-3 shadow-[var(--ds-shadow-card)]\",\n )}\n >\n {renderCard ? renderCard(card) : <DefaultCard card={card} />}\n </div>\n );\n}\n\n/** A column's drop area has its own id, so it never collides with a card id. */\nconst DROP_PREFIX = \"kanban-column:\";\nconst columnDropId = (id: string) => `${DROP_PREFIX}${id}`;\nconst droppedColumnId = (id: string) => (id.startsWith(DROP_PREFIX) ? id.slice(DROP_PREFIX.length) : null);\n\n/**\n * Sprint 25.7, C2: a keyboard drag goes column to column. Left and Right move the card to the top of the next column's\n * list — an empty column included — and Up and Down reorder within the column (dnd-kit's own handler). dnd-kit's\n * handler alone picks the nearest drop area to the right of the card's edge, which is often a card in the same column\n * or the card's own new place, so every other arrow key did nothing.\n */\nconst boardCoordinates: KeyboardCoordinateGetter = (event, args) => {\n if (event.code !== \"ArrowLeft\" && event.code !== \"ArrowRight\") return sortableKeyboardCoordinates(event, args);\n event.preventDefault();\n const { collisionRect, droppableRects, droppableContainers } = args.context;\n if (!collisionRect) return undefined;\n const columns = droppableContainers.getEnabled()\n .filter((c) => String(c.id).startsWith(DROP_PREFIX))\n .map((c) => droppableRects.get(c.id))\n .filter((r): r is NonNullable<typeof r> => r != null)\n .sort((a, b) => a.left - b.left);\n const centre = collisionRect.left + collisionRect.width / 2;\n const current = columns.findIndex((r) => centre >= r.left && centre <= r.left + r.width);\n const next = current < 0 ? undefined : columns[current + (event.code === \"ArrowRight\" ? 1 : -1)];\n if (!next) return undefined;\n return { x: next.left + (next.width - collisionRect.width) / 2, y: next.top };\n};\n\n/** Where a card is: its column's id and its index there. */\nfunction locate(cols: KanbanColumn[], cardId: string): { col: KanbanColumn; index: number } | null {\n for (const col of cols) {\n const index = col.cards.findIndex((c) => c.id === cardId);\n if (index >= 0) return { col, index };\n }\n return null;\n}\n\n/** The columns after a drop on `overId`: within the column the preview put the card in, a drop on another card reorders it. */\nfunction landing(cols: KanbanColumn[], cardId: string, overId: string): KanbanColumn[] {\n const at = locate(cols, cardId);\n const overAt = locate(cols, overId);\n if (!at || !overAt || overAt.col.id !== at.col.id || overAt.index === at.index) return cols;\n return cols.map((col) => (col.id === at.col.id ? { ...col, cards: arrayMove(col.cards, at.index, overAt.index) } : col));\n}\n\n/** A card's place, to re-apply to other columns: its column, the card after it (null when last) and its index. */\ninterface Placement {\n cardId: string;\n toColumnId: string;\n beforeId: string | null;\n index: number;\n}\n\nfunction placementIn(cols: KanbanColumn[], cardId: string): Placement | null {\n const at = locate(cols, cardId);\n return at ? { cardId, toColumnId: at.col.id, beforeId: at.col.cards[at.index + 1]?.id ?? null, index: at.index } : null;\n}\n\n/** The columns with a card put at a placement: into its column, before the same card (else at its index). */\nfunction place(cols: KanbanColumn[], p: Placement): KanbanColumn[] {\n const from = locate(cols, p.cardId);\n if (!from || !cols.some((col) => col.id === p.toColumnId)) return cols;\n const card = from.col.cards[from.index];\n return cols.map((col) => {\n if (col.id !== p.toColumnId && col.id !== from.col.id) return col;\n const cards = col.cards.filter((c) => c.id !== p.cardId);\n if (col.id === p.toColumnId) {\n const i = p.beforeId == null ? cards.length : cards.findIndex((c) => c.id === p.beforeId);\n cards.splice(i >= 0 ? i : Math.min(p.index, cards.length), 0, card);\n }\n return { ...col, cards };\n });\n}\n\n/**\n * A drag's move so far, re-applied to new columns: the card goes into the same column, before the same card, so a\n * change that arrives while a card is held shows at once and the drop keeps it.\n */\nfunction rebase(next: KanbanColumn[], shown: KanbanColumn[], cardId: string): KanbanColumn[] {\n const p = placementIn(shown, cardId);\n return p ? place(next, p) : next;\n}\n\n/**\n * A dropped card the board holds where it was dropped (Sprint 25.7, the owner's call of 26 September 2026: a card must\n * not jump back while its move saves). The pattern Atlassian's drag-and-drop guidance sets for Trello and Jira: the move\n * shows at once, before it is saved; data that arrives meanwhile has it replayed over it; a failed save lets the data\n * win, so the card goes back. One hold per card: a later move of the card replaces its place and adds its save to the\n * ones in flight.\n */\ninterface HeldMove extends Placement {\n /** The latest drop's key: only its save's failure puts the card back. */\n key: number;\n /** Saves for this card not yet settled, a replaced move's included: while one is out, nothing the columns show ends the hold. */\n inFlight: number;\n /** Where `columns` had the card before the first drop of this run of moves. */\n origin: Placement;\n /** The places of the moves this one replaced: columns showing one of them are behind, not a decision. */\n earlier: Placement[];\n /** The cards and their order in `columns` at the drop, or when its last save settled: with the card at its origin, a change ends the hold. */\n layout: string;\n}\n\n/** Which cards each column holds, in order: what a hold compares. A card's own fields changing is not a move. */\nconst layoutOf = (cols: KanbanColumn[]) => cols.map((col) => `${col.id}:${col.cards.map((c) => c.id).join(\",\")}`).join(\"|\");\n\n/** The columns show the card at a placement: in its column, before the same card (null: last). */\nfunction isAt(cols: KanbanColumn[], p: Placement): boolean {\n const at = locate(cols, p.cardId);\n return at != null && at.col.id === p.toColumnId && (at.col.cards[at.index + 1]?.id ?? null) === p.beforeId;\n}\n\n/**\n * The holds new columns keep. While a save for the card is out, every one (stale data, a card a filter hides, a card\n * that happens to sit where it was dropped). Once none is: a hold ends when its card or column is gone; with the card\n * at its origin, when the columns change some other way (the app's data has moved on — or, for a card moved back, has\n * caught up); when the columns show the card where it was dropped; or somewhere that is none of its own places (the\n * app's data decided). Columns showing one of its earlier places are behind, and the hold stays.\n */\nfunction keptHolds(holds: HeldMove[], cols: KanbanColumn[]): HeldMove[] {\n const layout = layoutOf(cols);\n const kept = holds.filter((h) => {\n if (h.inFlight > 0) return true;\n if (!locate(cols, h.cardId) || !cols.some((col) => col.id === h.toColumnId)) return false;\n // first, as a card moved back sits at its origin in data that has not caught up yet as well as in data that has\n if (isAt(cols, h.origin)) return layout === h.layout;\n if (isAt(cols, h)) return false;\n return h.earlier.some((p) => isAt(cols, p));\n });\n return kept.length === holds.length ? holds : kept;\n}\n\nconst replayHolds = (cols: KanbanColumn[], holds: HeldMove[]) => holds.reduce(place, cols);\n\nconst isThenable = (value: unknown): value is PromiseLike<unknown> =>\n value != null && typeof (value as { then?: unknown }).then === \"function\";\n\n/** A card's place, for the live region: \"To do, position 2 of 3\". */\nconst placeWords = (at: { col: KanbanColumn; index: number }) => `${at.col.title}, position ${at.index + 1} of ${at.col.cards.length}`;\n\n/** Read to a screen reader on every card that can be dragged (dnd-kit's aria-describedby). */\nconst MOVE_INSTRUCTIONS = \"Press Space to pick up the card. Use the Left and Right arrow keys to move it between columns, \"\n + \"and the Up and Down arrow keys to move it within a column. Press Space again to drop it, or Escape to cancel.\";\n\nfunction BoardColumn({\n col,\n readOnly,\n children,\n}: {\n col: KanbanColumn;\n readOnly?: boolean;\n children: ReactNode;\n}) {\n // Sprint 25.7, C2: the column is a drop area as well as a sortable list, so an empty column takes a card\n const { setNodeRef, isOver } = useDroppable({ id: columnDropId(col.id), disabled: readOnly });\n return (\n <div\n className={cn(\n \"flex flex-col shrink-0 w-[calc(100vw-4rem)] sm:w-[280px] snap-center\",\n \"bg-[var(--ds-bg-muted)] rounded-[var(--ds-radius-lg)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n )}\n >\n <div className=\"flex items-center justify-between px-ds-3 py-ds-2.5\">\n <div className=\"flex items-center gap-ds-2\">\n {col.color && (\n <span\n className=\"w-2.5 h-2.5 rounded-[var(--ds-radius-full)] shrink-0\"\n style={{ backgroundColor: col.color }}\n />\n )}\n <span className=\"text-sm font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]\">\n {col.title}\n </span>\n <span className=\"text-xs text-[var(--ds-text-muted)] tabular-nums\">\n {col.cards.length}\n </span>\n </div>\n <Icon name=\"plus\" size={14} className=\"text-[var(--ds-text-muted)]\" />\n </div>\n\n <SortableContext\n items={col.cards.map((c) => c.id)}\n strategy={verticalListSortingStrategy}\n id={col.id}\n >\n <div\n ref={setNodeRef}\n data-kanban-column={col.id}\n className={cn(\n \"flex flex-col gap-ds-2.5 px-ds-3 pb-ds-3 min-h-[60px] rounded-b-[var(--ds-radius-lg)] transition-colors\",\n isOver && col.cards.length === 0 && \"bg-[var(--ds-bg-surface)]/60\",\n )}\n >\n {children}\n </div>\n </SortableContext>\n </div>\n );\n}\n\nexport function KanbanBoard({\n columns: columnsProp,\n onColumnsChange,\n onCardMove,\n readOnly,\n renderCard,\n onCardClick,\n className,\n}: KanbanBoardProps) {\n // Sprint 25.7, C2: `columns` is authoritative — a new array replaces what the board shows. A move is previewed while\n // the card is dragged and held once dropped (HeldMove) until `columns` shows it; a cancelled drag (Escape) leaves the\n // board as it was.\n const [seenProp, setSeenProp] = useState(columnsProp);\n const [holds, setHoldsState] = useState<HeldMove[]>([]);\n // the preview lives in a ref as well, so a drop in the same tick as the last hover still reads it\n const [preview, setPreviewState] = useState<KanbanColumn[] | null>(null);\n const previewRef = useRef<KanbanColumn[] | null>(null);\n const setPreview = (next: KanbanColumn[] | null) => { previewRef.current = next; setPreviewState(next); };\n const [activeCard, setActiveCard] = useState<KanbanCard | null>(null);\n // the holds, the columns and the card being dragged, for a save that settles after this render\n const holdsRef = useRef<HeldMove[]>([]);\n const columnsRef = useRef(columnsProp);\n const activeRef = useRef<string | null>(null);\n const setHolds = (next: HeldMove[]) => { holdsRef.current = next; setHoldsState(next); };\n if (columnsProp !== seenProp) {\n setSeenProp(columnsProp);\n // new columns (a save landing, a refetch, another user's move): the holds they settle end, the rest replay over them\n const kept = keptHolds(holds, columnsProp);\n if (kept !== holds) setHoldsState(kept);\n // new columns while a card is held: the preview is rebuilt from them\n if (preview && activeCard) setPreviewState(rebase(replayHolds(columnsProp, kept), preview, activeCard.id));\n }\n // a preview or holds updated while rendering reach their refs before any drag event or settled save reads them\n useLayoutEffect(() => { previewRef.current = preview; }, [preview]);\n useLayoutEffect(() => { holdsRef.current = holds; }, [holds]);\n useLayoutEffect(() => { columnsRef.current = columnsProp; }, [columnsProp]);\n const committed = useMemo(() => replayHolds(columnsProp, holds), [columnsProp, holds]);\n const columns = preview ?? committed;\n\n // The live region speaks card and column titles, never ids. Each handler words its news in `said`, and dnd-kit\n // announces it straight after calling the handler. A move is said when the card's landing place changes.\n const said = useRef<string | undefined>(undefined);\n const lastPlace = useRef<string | null>(null);\n const announcements = useMemo<Announcements>(() => {\n const take = () => { const text = said.current; said.current = undefined; return text; };\n return { onDragStart: take, onDragOver: take, onDragEnd: take, onDragCancel: take };\n }, []);\n const instructions = { draggable: onCardClick ? `Press Enter to open the card. ${MOVE_INSTRUCTIONS}` : MOVE_INSTRUCTIONS };\n // A save that fails after the drag is over has no dnd-kit event to speak in: the board's own status line says it,\n // every failure since the last pick-up together, so two that land at once are both heard.\n const [notice, setNotice] = useState(\"\");\n const noticeParts = useRef<string[]>([]);\n const say = (text: string) => { noticeParts.current = [...noticeParts.current, text]; setNotice(noticeParts.current.join(\" \")); };\n // The card to focus once a failed save has put it back: its element is rendered anew in the column it returns to.\n const rootRef = useRef<HTMLDivElement>(null);\n const refocus = useRef<string | null>(null);\n useLayoutEffect(() => {\n const id = refocus.current;\n if (id == null) return;\n refocus.current = null;\n const cards = rootRef.current?.querySelectorAll<HTMLElement>(\"[data-kanban-card]\") ?? [];\n [...cards].find((el) => el.getAttribute(\"data-kanban-card\") === id)?.focus();\n });\n const holdKey = useRef(0);\n\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\n useSensor(KeyboardSensor, {\n coordinateGetter: boardCoordinates,\n // Space picks up and drops; Enter is the card's open key (onCardClick)\n keyboardCodes: { start: [\"Space\"], cancel: [\"Escape\"], end: [\"Space\"] },\n }),\n );\n // read-only: no sensors at all (an absent list would give dnd-kit's defaults)\n const noSensors = useSensors();\n\n const handleDragStart = (event: DragStartEvent) => {\n const at = locate(committed, String(event.active.id));\n if (!at) return;\n noticeParts.current = [];\n setNotice(\"\");\n activeRef.current = at.col.cards[at.index].id;\n setActiveCard(at.col.cards[at.index]);\n setPreview(committed);\n lastPlace.current = placeWords(at);\n said.current = `Picked up ${at.col.cards[at.index].title} in ${lastPlace.current}.`;\n };\n\n // Across columns, the preview moves the card as it is dragged; the parent hears nothing until the drop.\n const handleDragOver = (event: DragOverEvent) => {\n const { active, over } = event;\n const activeId = String(active.id);\n const overId = over ? String(over.id) : null;\n const cols = previewRef.current ?? committed;\n const from = locate(cols, activeId);\n const toColumnId = overId == null || overId === activeId ? null : droppedColumnId(overId) ?? locate(cols, overId)?.col.id;\n if (from && toColumnId && from.col.id !== toColumnId) {\n const card = from.col.cards[from.index];\n setPreview(cols.map((col) => {\n if (col.id === from.col.id) return { ...col, cards: col.cards.filter((c) => c.id !== activeId) };\n if (col.id !== toColumnId) return col;\n const overIndex = col.cards.findIndex((c) => c.id === overId);\n const cards = [...col.cards];\n cards.splice(overIndex >= 0 ? overIndex : cards.length, 0, card);\n return { ...col, cards };\n }));\n }\n // where a drop now would put the card\n const now = overId == null ? null : locate(landing(previewRef.current ?? committed, activeId, overId), activeId);\n const where = now ? placeWords(now) : null;\n if (where === lastPlace.current) return;\n lastPlace.current = where;\n const title = now ? now.col.cards[now.index].title : activeCard?.title;\n said.current = now ? `${title} is over ${where}.` : `${title} is not over a column.`;\n };\n\n /** A card's move failed: the hold ends and the card shows where `columns` has it, said on the status line. */\n const putBack = (hold: HeldMove) => {\n const rest = holdsRef.current.filter((h) => h.cardId !== hold.cardId);\n const shown = replayHolds(columnsRef.current, rest);\n const back = locate(shown, hold.cardId);\n const card = back?.col.cards[back.index];\n // focus follows the card only from this board (two boards over the same data each render it)\n const focused = document.activeElement;\n if (focused && rootRef.current?.contains(focused) && focused.closest?.(\"[data-kanban-card]\")?.getAttribute(\"data-kanban-card\") === hold.cardId) {\n refocus.current = hold.cardId;\n }\n setHolds(rest);\n // a card held mid-drag: the preview is rebuilt without the failed move, so the drop cannot carry it\n if (previewRef.current && activeRef.current) setPreview(rebase(shown, previewRef.current, activeRef.current));\n if (!back || !card) return;\n const to = columnsRef.current.find((col) => col.id === hold.toColumnId)?.title;\n say(isAt(columnsRef.current, hold.origin) || !to\n ? `Move not saved. ${card.title} is back in ${placeWords(back)}.`\n : `Move not saved. ${card.title} could not move to ${to}.`);\n };\n\n /** A save for a card has settled. The latest move's failure puts the card back; otherwise, once none is out, the hold is judged against the columns. */\n const settle = (cardId: string, key: number, ok: boolean) => {\n const hold = holdsRef.current.find((h) => h.cardId === cardId);\n if (!hold) return;\n if (!ok && hold.key === key) return putBack(hold);\n const inFlight = hold.inFlight - 1;\n const next = holdsRef.current.map((h) => (h === hold ? { ...h, inFlight, layout: inFlight > 0 ? h.layout : layoutOf(columnsRef.current) } : h));\n // the columns may already show the card elsewhere (a refetch that landed before the save resolved)\n setHolds(inFlight > 0 ? next : keptHolds(next, columnsRef.current));\n };\n\n const handleDragEnd = (event: DragEndEvent) => {\n const { active, over } = event;\n const activeId = String(active.id);\n const cols = previewRef.current ?? committed;\n activeRef.current = null;\n setActiveCard(null);\n setPreview(null);\n const final = over ? landing(cols, activeId, String(over.id)) : committed;\n const before = locate(committed, activeId);\n const after = locate(final, activeId);\n if (!before || !after || (before.col.id === after.col.id && before.index === after.index)) {\n if (before) said.current = `Dropped ${before.col.cards[before.index].title} back in ${placeWords(before)}.`;\n return;\n }\n said.current = `Dropped ${after.col.cards[after.index].title} in ${placeWords(after)}.`;\n const key = ++holdKey.current;\n // a new move of a card replaces its hold's place; the replaced move's save stays in flight\n const prev = holdsRef.current.find((h) => h.cardId === activeId);\n const hold: HeldMove = {\n ...placementIn(final, activeId)!,\n key,\n inFlight: prev?.inFlight ?? 0,\n origin: prev?.origin ?? placementIn(columnsProp, activeId) ?? placementIn(committed, activeId)!,\n earlier: prev ? [...prev.earlier, { cardId: prev.cardId, toColumnId: prev.toColumnId, beforeId: prev.beforeId, index: prev.index }] : [],\n layout: layoutOf(columnsProp),\n };\n setHolds([...holdsRef.current.filter((h) => h.cardId !== activeId), hold]);\n const saves: PromiseLike<unknown>[] = [];\n try {\n for (const result of [onColumnsChange?.(final), onCardMove?.(after.col.cards[after.index], after.col.id, after.index)]) {\n if (isThenable(result)) saves.push(result);\n }\n } catch (error) {\n // a handler that throws refuses the move, as a rejected save does; the error still reaches the console\n console.error(\"KanbanBoard: a move handler threw, so the move is refused.\", error);\n return putBack(hold);\n }\n if (!saves.length) return;\n setHolds(holdsRef.current.map((h) => (h.key === key ? { ...h, inFlight: h.inFlight + 1 } : h)));\n // every save settles before the move counts as saved; any failure refuses it\n Promise.allSettled(saves).then((results) => settle(activeId, key, results.every((r) => r.status === \"fulfilled\")));\n };\n\n const handleDragCancel = (event: DragCancelEvent) => {\n activeRef.current = null;\n setActiveCard(null);\n setPreview(null);\n const at = locate(committed, String(event.active.id));\n if (at) said.current = `Move cancelled. ${at.col.cards[at.index].title} is back in ${placeWords(at)}.`;\n };\n\n return (\n <DndContext\n sensors={readOnly ? noSensors : sensors}\n accessibility={{ announcements, screenReaderInstructions: instructions }}\n collisionDetection={closestCorners}\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDragEnd={handleDragEnd}\n onDragCancel={handleDragCancel}\n >\n <div ref={rootRef} className={cn(\"flex gap-ds-4 overflow-x-auto pb-ds-2 snap-x snap-mandatory sm:snap-none\", className)}>\n {columns.map((col) => (\n <BoardColumn key={col.id} col={col} readOnly={readOnly}>\n {col.cards.map((card) => (\n <SortableCard\n key={card.id}\n card={card}\n renderCard={renderCard}\n onCardClick={onCardClick}\n readOnly={readOnly}\n />\n ))}\n </BoardColumn>\n ))}\n {/* inside the board's root, so a board in a spaced stack stays one element */}\n <div role=\"status\" className=\"sr-only\">{notice}</div>\n </div>\n\n <DragOverlay>\n {activeCard && <OverlayCard card={activeCard} renderCard={renderCard} />}\n </DragOverlay>\n </DndContext>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/components/KanbanBoard.tsx"],"names":[],"mappings":"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","file":"kanban.js","sourcesContent":["import { useLayoutEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport {\n DndContext,\n closestCorners,\n KeyboardSensor,\n PointerSensor,\n useSensor,\n useSensors,\n type Announcements,\n type DragCancelEvent,\n type DragEndEvent,\n type DragOverEvent,\n DragOverlay,\n type DragStartEvent,\n type KeyboardCoordinateGetter,\n useDroppable,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\n arrayMove,\n sortableKeyboardCoordinates,\n verticalListSortingStrategy,\n useSortable,\n} from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\nimport { Tooltip } from \"./Tooltip\";\nimport { useTextOverflow } from \"../lib/use-text-overflow\";\nimport { Badge } from \"./Badge\";\nimport { useFramesItself } from \"../lib/surface-context\";\n\nexport interface KanbanCard {\n id: string;\n title: string;\n description?: string;\n tags?: string[];\n avatar?: string;\n}\n\nexport interface KanbanColumn {\n id: string;\n title: string;\n cards: KanbanCard[];\n color?: string;\n}\n\nexport interface KanbanBoardProps {\n /**\n * The board's cards by column. Authoritative: the board shows what it is given, with one exception — a card just\n * dropped stays where it was dropped until `columns` shows the move, the save fails, or `columns` changes some other\n * way (see onCardMove). A re-render that passes the same cards again, or an array rebuilt with the same cards,\n * never puts a dropped card back.\n */\n columns: KanbanColumn[];\n /**\n * The columns after a move, once on drop (Sprint 25.7, C2: it used to fire on every hover step). Its return value\n * counts as onCardMove's does.\n */\n onColumnsChange?: (columns: KanbanColumn[]) => unknown;\n /**\n * A card was dropped at a new place: its column and its index there, once on drop — a move between columns, into an\n * empty one, or a reorder within one. Save the move here (or in onColumnsChange); a board with neither saves nothing.\n * The index counts the cards the board shows: when `columns` is filtered, it is the place among the cards passed.\n *\n * Return the save's promise (an async function, or a mutation's mutateAsync) and the card stays where it was dropped\n * while it saves, and while an earlier move of the same card still saves, whatever `columns` arrive meanwhile; when\n * it rejects, the card goes back to where `columns` has it, a screen reader hears so, and the app says why (a toast\n * inside the app shell). The save must settle (give a request a timeout): one that never does holds the card. A\n * handler that throws refuses a move the same way (a column that is full). An app that updates `columns` at once,\n * then saves, puts the card back itself when its save fails; the board still says the move was not saved.\n */\n onCardMove?: (card: KanbanCard, toColumnId: string, index: number) => unknown;\n /** A board to look at, not rearrange: no dragging and no grab cursor; cards still open with onCardClick. */\n readOnly?: boolean;\n renderCard?: (card: KanbanCard) => ReactNode;\n /**\n * Opens a card (a detail drawer, a route). The board's own card surface is the control: click, or Enter with the\n * card focused, opens it; Space picks the card up for a keyboard drag. Never wire a clickable element inside\n * renderCard — a role=\"button\" div fights the drag listeners and the judge cites it (Sprint 25.4 K-1).\n */\n onCardClick?: (card: KanbanCard) => void;\n className?: string;\n}\n\nfunction SortableCard({\n card,\n renderCard,\n onCardClick,\n readOnly,\n}: {\n card: KanbanCard;\n renderCard?: (card: KanbanCard) => ReactNode;\n onCardClick?: (card: KanbanCard) => void;\n readOnly?: boolean;\n}) {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id: card.id, disabled: readOnly });\n\n if (readOnly) {\n // nothing to pick up: a card that opens is a button (Enter and Space), one that does not is a plain surface\n const open = onCardClick ? () => onCardClick(card) : undefined;\n return (\n <div\n ref={setNodeRef}\n {...(open ? { role: \"button\", tabIndex: 0 } : {})}\n onClick={open}\n onKeyDown={open ? (e) => { if (e.key === \"Enter\" || e.key === \" \") { e.preventDefault(); open(); } } : undefined}\n data-kanban-card={card.id}\n className={cn(\n \"rounded-[var(--ds-radius-md)] border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"bg-[var(--ds-bg-surface)] p-ds-3 shadow-[var(--ds-shadow-button)]\",\n open ? \"cursor-pointer\" : \"cursor-default\",\n \"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]\",\n )}\n >\n {renderCard ? renderCard(card) : <DefaultCard card={card} />}\n </div>\n );\n }\n\n const style = {\n transform: CSS.Transform.toString(transform),\n transition,\n };\n\n return (\n <div\n ref={setNodeRef}\n style={style}\n {...attributes}\n {...listeners}\n // the surface is the control (K-1): a click opens (the pointer sensor needs 5 px of movement to start a drag),\n // Enter opens, Space stays the keyboard drag's pick-up\n onClick={onCardClick ? () => onCardClick(card) : undefined}\n onKeyDown={(e) => {\n if (onCardClick && e.key === \"Enter\") { e.preventDefault(); onCardClick(card); return; }\n listeners?.onKeyDown?.(e);\n }}\n data-kanban-card={card.id}\n className={cn(\n \"rounded-[var(--ds-radius-md)] border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"bg-[var(--ds-bg-surface)] p-ds-3 active:cursor-grabbing\",\n onCardClick ? \"cursor-pointer\" : \"cursor-grab\",\n \"shadow-[var(--ds-shadow-button)]\",\n \"transition-shadow duration-[var(--ds-transition-speed)]\",\n \"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]\",\n // no scale on the card left behind: the drag overlay takes its size from it, and 2% wider made the cards\n // below count as \"to the right\" of it, so a keyboard drag's arrow keys landed on them (Sprint 25.7, C2)\n isDragging && \"opacity-30\",\n )}\n >\n {renderCard ? (\n renderCard(card)\n ) : (\n <DefaultCard card={card} />\n )}\n </div>\n );\n}\n\nfunction ClampedDescription({ children }: { children: string }) {\n const { ref, isTruncated } = useTextOverflow({ lines: 2 });\n const el = <p ref={ref} className=\"text-xs text-[var(--ds-text-secondary)] line-clamp-2\">{children}</p>;\n if (!isTruncated) return el;\n return <Tooltip content={children}>{el}</Tooltip>;\n}\n\nfunction TruncTitle({ children }: { children: string }) {\n const { ref, isTruncated } = useTextOverflow({ lines: 1 });\n const el = <p ref={ref} className=\"text-sm font-medium text-[var(--ds-text-primary)] truncate\">{children}</p>;\n if (!isTruncated) return el;\n return <Tooltip content={children}>{el}</Tooltip>;\n}\n\nfunction DefaultCard({ card }: { card: KanbanCard }) {\n return (\n <div className=\"space-y-ds-2\">\n <TruncTitle>{card.title}</TruncTitle>\n {card.description && (\n <ClampedDescription>{card.description}</ClampedDescription>\n )}\n {card.tags && card.tags.length > 0 && (\n <div className=\"flex flex-wrap gap-ds-1\">\n {card.tags.map((tag) => (\n <Badge key={tag} variant=\"subtle\" size=\"sm\">{tag}</Badge>\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction OverlayCard({\n card,\n renderCard,\n}: {\n card: KanbanCard;\n renderCard?: (card: KanbanCard) => ReactNode;\n}) {\n return (\n <div\n className={cn(\n \"rounded-[var(--ds-radius-md)] border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"bg-[var(--ds-bg-surface)] p-ds-3 shadow-[var(--ds-shadow-card)]\",\n )}\n >\n {renderCard ? renderCard(card) : <DefaultCard card={card} />}\n </div>\n );\n}\n\n/** A column's drop area has its own id, so it never collides with a card id. */\nconst DROP_PREFIX = \"kanban-column:\";\nconst columnDropId = (id: string) => `${DROP_PREFIX}${id}`;\nconst droppedColumnId = (id: string) => (id.startsWith(DROP_PREFIX) ? id.slice(DROP_PREFIX.length) : null);\n\n/**\n * Sprint 25.7, C2: a keyboard drag goes column to column. Left and Right move the card to the top of the next column's\n * list — an empty column included — and Up and Down reorder within the column (dnd-kit's own handler). dnd-kit's\n * handler alone picks the nearest drop area to the right of the card's edge, which is often a card in the same column\n * or the card's own new place, so every other arrow key did nothing.\n */\nconst boardCoordinates: KeyboardCoordinateGetter = (event, args) => {\n if (event.code !== \"ArrowLeft\" && event.code !== \"ArrowRight\") return sortableKeyboardCoordinates(event, args);\n event.preventDefault();\n const { collisionRect, droppableRects, droppableContainers } = args.context;\n if (!collisionRect) return undefined;\n const columns = droppableContainers.getEnabled()\n .filter((c) => String(c.id).startsWith(DROP_PREFIX))\n .map((c) => droppableRects.get(c.id))\n .filter((r): r is NonNullable<typeof r> => r != null)\n .sort((a, b) => a.left - b.left);\n const centre = collisionRect.left + collisionRect.width / 2;\n const current = columns.findIndex((r) => centre >= r.left && centre <= r.left + r.width);\n const next = current < 0 ? undefined : columns[current + (event.code === \"ArrowRight\" ? 1 : -1)];\n if (!next) return undefined;\n return { x: next.left + (next.width - collisionRect.width) / 2, y: next.top };\n};\n\n/** Where a card is: its column's id and its index there. */\nfunction locate(cols: KanbanColumn[], cardId: string): { col: KanbanColumn; index: number } | null {\n for (const col of cols) {\n const index = col.cards.findIndex((c) => c.id === cardId);\n if (index >= 0) return { col, index };\n }\n return null;\n}\n\n/** The columns after a drop on `overId`: within the column the preview put the card in, a drop on another card reorders it. */\nfunction landing(cols: KanbanColumn[], cardId: string, overId: string): KanbanColumn[] {\n const at = locate(cols, cardId);\n const overAt = locate(cols, overId);\n if (!at || !overAt || overAt.col.id !== at.col.id || overAt.index === at.index) return cols;\n return cols.map((col) => (col.id === at.col.id ? { ...col, cards: arrayMove(col.cards, at.index, overAt.index) } : col));\n}\n\n/** A card's place, to re-apply to other columns: its column, the card after it (null when last) and its index. */\ninterface Placement {\n cardId: string;\n toColumnId: string;\n beforeId: string | null;\n index: number;\n}\n\nfunction placementIn(cols: KanbanColumn[], cardId: string): Placement | null {\n const at = locate(cols, cardId);\n return at ? { cardId, toColumnId: at.col.id, beforeId: at.col.cards[at.index + 1]?.id ?? null, index: at.index } : null;\n}\n\n/** The columns with a card put at a placement: into its column, before the same card (else at its index). */\nfunction place(cols: KanbanColumn[], p: Placement): KanbanColumn[] {\n const from = locate(cols, p.cardId);\n if (!from || !cols.some((col) => col.id === p.toColumnId)) return cols;\n const card = from.col.cards[from.index];\n return cols.map((col) => {\n if (col.id !== p.toColumnId && col.id !== from.col.id) return col;\n const cards = col.cards.filter((c) => c.id !== p.cardId);\n if (col.id === p.toColumnId) {\n const i = p.beforeId == null ? cards.length : cards.findIndex((c) => c.id === p.beforeId);\n cards.splice(i >= 0 ? i : Math.min(p.index, cards.length), 0, card);\n }\n return { ...col, cards };\n });\n}\n\n/**\n * A drag's move so far, re-applied to new columns: the card goes into the same column, before the same card, so a\n * change that arrives while a card is held shows at once and the drop keeps it.\n */\nfunction rebase(next: KanbanColumn[], shown: KanbanColumn[], cardId: string): KanbanColumn[] {\n const p = placementIn(shown, cardId);\n return p ? place(next, p) : next;\n}\n\n/**\n * A dropped card the board holds where it was dropped (Sprint 25.7, the owner's call of 26 September 2026: a card must\n * not jump back while its move saves). The pattern Atlassian's drag-and-drop guidance sets for Trello and Jira: the move\n * shows at once, before it is saved; data that arrives meanwhile has it replayed over it; a failed save lets the data\n * win, so the card goes back. One hold per card: a later move of the card replaces its place and adds its save to the\n * ones in flight.\n */\ninterface HeldMove extends Placement {\n /** The latest drop's key: only its save's failure puts the card back. */\n key: number;\n /** Saves for this card not yet settled, a replaced move's included: while one is out, nothing the columns show ends the hold. */\n inFlight: number;\n /** Where `columns` had the card before the first drop of this run of moves. */\n origin: Placement;\n /** The places of the moves this one replaced: columns showing one of them are behind, not a decision. */\n earlier: Placement[];\n /** The cards and their order in `columns` at the drop, or when its last save settled: with the card at its origin, a change ends the hold. */\n layout: string;\n}\n\n/** Which cards each column holds, in order: what a hold compares. A card's own fields changing is not a move. */\nconst layoutOf = (cols: KanbanColumn[]) => cols.map((col) => `${col.id}:${col.cards.map((c) => c.id).join(\",\")}`).join(\"|\");\n\n/** The columns show the card at a placement: in its column, before the same card (null: last). */\nfunction isAt(cols: KanbanColumn[], p: Placement): boolean {\n const at = locate(cols, p.cardId);\n return at != null && at.col.id === p.toColumnId && (at.col.cards[at.index + 1]?.id ?? null) === p.beforeId;\n}\n\n/**\n * The holds new columns keep. While a save for the card is out, every one (stale data, a card a filter hides, a card\n * that happens to sit where it was dropped). Once none is: a hold ends when its card or column is gone; with the card\n * at its origin, when the columns change some other way (the app's data has moved on — or, for a card moved back, has\n * caught up); when the columns show the card where it was dropped; or somewhere that is none of its own places (the\n * app's data decided). Columns showing one of its earlier places are behind, and the hold stays.\n */\nfunction keptHolds(holds: HeldMove[], cols: KanbanColumn[]): HeldMove[] {\n const layout = layoutOf(cols);\n const kept = holds.filter((h) => {\n if (h.inFlight > 0) return true;\n if (!locate(cols, h.cardId) || !cols.some((col) => col.id === h.toColumnId)) return false;\n // first, as a card moved back sits at its origin in data that has not caught up yet as well as in data that has\n if (isAt(cols, h.origin)) return layout === h.layout;\n if (isAt(cols, h)) return false;\n return h.earlier.some((p) => isAt(cols, p));\n });\n return kept.length === holds.length ? holds : kept;\n}\n\nconst replayHolds = (cols: KanbanColumn[], holds: HeldMove[]) => holds.reduce(place, cols);\n\nconst isThenable = (value: unknown): value is PromiseLike<unknown> =>\n value != null && typeof (value as { then?: unknown }).then === \"function\";\n\n/** A card's place, for the live region: \"To do, position 2 of 3\". */\nconst placeWords = (at: { col: KanbanColumn; index: number }) => `${at.col.title}, position ${at.index + 1} of ${at.col.cards.length}`;\n\n/** Read to a screen reader on every card that can be dragged (dnd-kit's aria-describedby). */\nconst MOVE_INSTRUCTIONS = \"Press Space to pick up the card. Use the Left and Right arrow keys to move it between columns, \"\n + \"and the Up and Down arrow keys to move it within a column. Press Space again to drop it, or Escape to cancel.\";\n\nfunction BoardColumn({\n col,\n readOnly,\n children,\n}: {\n col: KanbanColumn;\n readOnly?: boolean;\n children: ReactNode;\n}) {\n // Sprint 25.7, C2: the column is a drop area as well as a sortable list, so an empty column takes a card\n const { setNodeRef, isOver } = useDroppable({ id: columnDropId(col.id), disabled: readOnly });\n return (\n <div\n className={cn(\n \"flex flex-col shrink-0 w-[calc(100vw-4rem)] sm:w-[280px] snap-center\",\n \"bg-[var(--ds-bg-muted)] rounded-[var(--ds-radius-lg)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n )}\n >\n <div className=\"flex items-center justify-between px-ds-3 py-ds-2.5\">\n <div className=\"flex items-center gap-ds-2\">\n {col.color && (\n <span\n className=\"w-2.5 h-2.5 rounded-[var(--ds-radius-full)] shrink-0\"\n style={{ backgroundColor: col.color }}\n />\n )}\n <span className=\"text-sm font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]\">\n {col.title}\n </span>\n <span className=\"text-xs text-[var(--ds-text-muted)] tabular-nums\">\n {col.cards.length}\n </span>\n </div>\n <Icon name=\"plus\" size={14} className=\"text-[var(--ds-text-muted)]\" />\n </div>\n\n <SortableContext\n items={col.cards.map((c) => c.id)}\n strategy={verticalListSortingStrategy}\n id={col.id}\n >\n <div\n ref={setNodeRef}\n data-kanban-column={col.id}\n className={cn(\n \"flex flex-col gap-ds-2.5 px-ds-3 pb-ds-3 min-h-[60px] rounded-b-[var(--ds-radius-lg)] transition-colors\",\n isOver && col.cards.length === 0 && \"bg-[var(--ds-bg-surface)]/60\",\n )}\n >\n {children}\n </div>\n </SortableContext>\n </div>\n );\n}\n\nexport function KanbanBoard({\n columns: columnsProp,\n onColumnsChange,\n onCardMove,\n readOnly,\n renderCard,\n onCardClick,\n className,\n}: KanbanBoardProps) {\n // Sprint 25.14 A44: a board frames itself, so a SplitView's list pane draws nothing behind it\n useFramesItself();\n // Sprint 25.7, C2: `columns` is authoritative — a new array replaces what the board shows. A move is previewed while\n // the card is dragged and held once dropped (HeldMove) until `columns` shows it; a cancelled drag (Escape) leaves the\n // board as it was.\n const [seenProp, setSeenProp] = useState(columnsProp);\n const [holds, setHoldsState] = useState<HeldMove[]>([]);\n // the preview lives in a ref as well, so a drop in the same tick as the last hover still reads it\n const [preview, setPreviewState] = useState<KanbanColumn[] | null>(null);\n const previewRef = useRef<KanbanColumn[] | null>(null);\n const setPreview = (next: KanbanColumn[] | null) => { previewRef.current = next; setPreviewState(next); };\n const [activeCard, setActiveCard] = useState<KanbanCard | null>(null);\n // the holds, the columns and the card being dragged, for a save that settles after this render\n const holdsRef = useRef<HeldMove[]>([]);\n const columnsRef = useRef(columnsProp);\n const activeRef = useRef<string | null>(null);\n const setHolds = (next: HeldMove[]) => { holdsRef.current = next; setHoldsState(next); };\n if (columnsProp !== seenProp) {\n setSeenProp(columnsProp);\n // new columns (a save landing, a refetch, another user's move): the holds they settle end, the rest replay over them\n const kept = keptHolds(holds, columnsProp);\n if (kept !== holds) setHoldsState(kept);\n // new columns while a card is held: the preview is rebuilt from them\n if (preview && activeCard) setPreviewState(rebase(replayHolds(columnsProp, kept), preview, activeCard.id));\n }\n // a preview or holds updated while rendering reach their refs before any drag event or settled save reads them\n useLayoutEffect(() => { previewRef.current = preview; }, [preview]);\n useLayoutEffect(() => { holdsRef.current = holds; }, [holds]);\n useLayoutEffect(() => { columnsRef.current = columnsProp; }, [columnsProp]);\n const committed = useMemo(() => replayHolds(columnsProp, holds), [columnsProp, holds]);\n const columns = preview ?? committed;\n\n // The live region speaks card and column titles, never ids. Each handler words its news in `said`, and dnd-kit\n // announces it straight after calling the handler. A move is said when the card's landing place changes.\n const said = useRef<string | undefined>(undefined);\n const lastPlace = useRef<string | null>(null);\n const announcements = useMemo<Announcements>(() => {\n const take = () => { const text = said.current; said.current = undefined; return text; };\n return { onDragStart: take, onDragOver: take, onDragEnd: take, onDragCancel: take };\n }, []);\n const instructions = { draggable: onCardClick ? `Press Enter to open the card. ${MOVE_INSTRUCTIONS}` : MOVE_INSTRUCTIONS };\n // A save that fails after the drag is over has no dnd-kit event to speak in: the board's own status line says it,\n // every failure since the last pick-up together, so two that land at once are both heard.\n const [notice, setNotice] = useState(\"\");\n const noticeParts = useRef<string[]>([]);\n const say = (text: string) => { noticeParts.current = [...noticeParts.current, text]; setNotice(noticeParts.current.join(\" \")); };\n // The card to focus once a failed save has put it back: its element is rendered anew in the column it returns to.\n const rootRef = useRef<HTMLDivElement>(null);\n const refocus = useRef<string | null>(null);\n useLayoutEffect(() => {\n const id = refocus.current;\n if (id == null) return;\n refocus.current = null;\n const cards = rootRef.current?.querySelectorAll<HTMLElement>(\"[data-kanban-card]\") ?? [];\n [...cards].find((el) => el.getAttribute(\"data-kanban-card\") === id)?.focus();\n });\n const holdKey = useRef(0);\n\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\n useSensor(KeyboardSensor, {\n coordinateGetter: boardCoordinates,\n // Space picks up and drops; Enter is the card's open key (onCardClick)\n keyboardCodes: { start: [\"Space\"], cancel: [\"Escape\"], end: [\"Space\"] },\n }),\n );\n // read-only: no sensors at all (an absent list would give dnd-kit's defaults)\n const noSensors = useSensors();\n\n const handleDragStart = (event: DragStartEvent) => {\n const at = locate(committed, String(event.active.id));\n if (!at) return;\n noticeParts.current = [];\n setNotice(\"\");\n activeRef.current = at.col.cards[at.index].id;\n setActiveCard(at.col.cards[at.index]);\n setPreview(committed);\n lastPlace.current = placeWords(at);\n said.current = `Picked up ${at.col.cards[at.index].title} in ${lastPlace.current}.`;\n };\n\n // Across columns, the preview moves the card as it is dragged; the parent hears nothing until the drop.\n const handleDragOver = (event: DragOverEvent) => {\n const { active, over } = event;\n const activeId = String(active.id);\n const overId = over ? String(over.id) : null;\n const cols = previewRef.current ?? committed;\n const from = locate(cols, activeId);\n const toColumnId = overId == null || overId === activeId ? null : droppedColumnId(overId) ?? locate(cols, overId)?.col.id;\n if (from && toColumnId && from.col.id !== toColumnId) {\n const card = from.col.cards[from.index];\n setPreview(cols.map((col) => {\n if (col.id === from.col.id) return { ...col, cards: col.cards.filter((c) => c.id !== activeId) };\n if (col.id !== toColumnId) return col;\n const overIndex = col.cards.findIndex((c) => c.id === overId);\n const cards = [...col.cards];\n cards.splice(overIndex >= 0 ? overIndex : cards.length, 0, card);\n return { ...col, cards };\n }));\n }\n // where a drop now would put the card\n const now = overId == null ? null : locate(landing(previewRef.current ?? committed, activeId, overId), activeId);\n const where = now ? placeWords(now) : null;\n if (where === lastPlace.current) return;\n lastPlace.current = where;\n const title = now ? now.col.cards[now.index].title : activeCard?.title;\n said.current = now ? `${title} is over ${where}.` : `${title} is not over a column.`;\n };\n\n /** A card's move failed: the hold ends and the card shows where `columns` has it, said on the status line. */\n const putBack = (hold: HeldMove) => {\n const rest = holdsRef.current.filter((h) => h.cardId !== hold.cardId);\n const shown = replayHolds(columnsRef.current, rest);\n const back = locate(shown, hold.cardId);\n const card = back?.col.cards[back.index];\n // focus follows the card only from this board (two boards over the same data each render it)\n const focused = document.activeElement;\n if (focused && rootRef.current?.contains(focused) && focused.closest?.(\"[data-kanban-card]\")?.getAttribute(\"data-kanban-card\") === hold.cardId) {\n refocus.current = hold.cardId;\n }\n setHolds(rest);\n // a card held mid-drag: the preview is rebuilt without the failed move, so the drop cannot carry it\n if (previewRef.current && activeRef.current) setPreview(rebase(shown, previewRef.current, activeRef.current));\n if (!back || !card) return;\n const to = columnsRef.current.find((col) => col.id === hold.toColumnId)?.title;\n say(isAt(columnsRef.current, hold.origin) || !to\n ? `Move not saved. ${card.title} is back in ${placeWords(back)}.`\n : `Move not saved. ${card.title} could not move to ${to}.`);\n };\n\n /** A save for a card has settled. The latest move's failure puts the card back; otherwise, once none is out, the hold is judged against the columns. */\n const settle = (cardId: string, key: number, ok: boolean) => {\n const hold = holdsRef.current.find((h) => h.cardId === cardId);\n if (!hold) return;\n if (!ok && hold.key === key) return putBack(hold);\n const inFlight = hold.inFlight - 1;\n const next = holdsRef.current.map((h) => (h === hold ? { ...h, inFlight, layout: inFlight > 0 ? h.layout : layoutOf(columnsRef.current) } : h));\n // the columns may already show the card elsewhere (a refetch that landed before the save resolved)\n setHolds(inFlight > 0 ? next : keptHolds(next, columnsRef.current));\n };\n\n const handleDragEnd = (event: DragEndEvent) => {\n const { active, over } = event;\n const activeId = String(active.id);\n const cols = previewRef.current ?? committed;\n activeRef.current = null;\n setActiveCard(null);\n setPreview(null);\n const final = over ? landing(cols, activeId, String(over.id)) : committed;\n const before = locate(committed, activeId);\n const after = locate(final, activeId);\n if (!before || !after || (before.col.id === after.col.id && before.index === after.index)) {\n if (before) said.current = `Dropped ${before.col.cards[before.index].title} back in ${placeWords(before)}.`;\n return;\n }\n said.current = `Dropped ${after.col.cards[after.index].title} in ${placeWords(after)}.`;\n const key = ++holdKey.current;\n // a new move of a card replaces its hold's place; the replaced move's save stays in flight\n const prev = holdsRef.current.find((h) => h.cardId === activeId);\n const hold: HeldMove = {\n ...placementIn(final, activeId)!,\n key,\n inFlight: prev?.inFlight ?? 0,\n origin: prev?.origin ?? placementIn(columnsProp, activeId) ?? placementIn(committed, activeId)!,\n earlier: prev ? [...prev.earlier, { cardId: prev.cardId, toColumnId: prev.toColumnId, beforeId: prev.beforeId, index: prev.index }] : [],\n layout: layoutOf(columnsProp),\n };\n setHolds([...holdsRef.current.filter((h) => h.cardId !== activeId), hold]);\n const saves: PromiseLike<unknown>[] = [];\n try {\n for (const result of [onColumnsChange?.(final), onCardMove?.(after.col.cards[after.index], after.col.id, after.index)]) {\n if (isThenable(result)) saves.push(result);\n }\n } catch (error) {\n // a handler that throws refuses the move, as a rejected save does; the error still reaches the console\n console.error(\"KanbanBoard: a move handler threw, so the move is refused.\", error);\n return putBack(hold);\n }\n if (!saves.length) return;\n setHolds(holdsRef.current.map((h) => (h.key === key ? { ...h, inFlight: h.inFlight + 1 } : h)));\n // every save settles before the move counts as saved; any failure refuses it\n Promise.allSettled(saves).then((results) => settle(activeId, key, results.every((r) => r.status === \"fulfilled\")));\n };\n\n const handleDragCancel = (event: DragCancelEvent) => {\n activeRef.current = null;\n setActiveCard(null);\n setPreview(null);\n const at = locate(committed, String(event.active.id));\n if (at) said.current = `Move cancelled. ${at.col.cards[at.index].title} is back in ${placeWords(at)}.`;\n };\n\n return (\n <DndContext\n sensors={readOnly ? noSensors : sensors}\n accessibility={{ announcements, screenReaderInstructions: instructions }}\n collisionDetection={closestCorners}\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDragEnd={handleDragEnd}\n onDragCancel={handleDragCancel}\n >\n <div ref={rootRef} className={cn(\"flex gap-ds-4 overflow-x-auto pb-ds-2 snap-x snap-mandatory sm:snap-none\", className)}>\n {columns.map((col) => (\n <BoardColumn key={col.id} col={col} readOnly={readOnly}>\n {col.cards.map((card) => (\n <SortableCard\n key={card.id}\n card={card}\n renderCard={renderCard}\n onCardClick={onCardClick}\n readOnly={readOnly}\n />\n ))}\n </BoardColumn>\n ))}\n {/* inside the board's root, so a board in a spaced stack stays one element */}\n <div role=\"status\" className=\"sr-only\">{notice}</div>\n </div>\n\n <DragOverlay>\n {activeCard && <OverlayCard card={activeCard} renderCard={renderCard} />}\n </DragOverlay>\n </DndContext>\n );\n}\n"]}
|
package/dist/resizable.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ interface SplitViewProps {
|
|
|
42
42
|
list: ReactNode;
|
|
43
43
|
/** The selected item (a thread, a record): it fills the height and scrolls on its own. */
|
|
44
44
|
detail: ReactNode;
|
|
45
|
-
/** Context beside the detail (a contact, properties). The pane
|
|
45
|
+
/** Context beside the detail (a contact, properties). The pane insets it as the Drawer it collapses into does (the page's gutter, Sprint 25.14 A36), so pass content with no padding classes (round 8). Collapses to a toggle that opens it in a Drawer when the layout is narrower than `asideCollapseBelow`. */
|
|
46
46
|
aside?: ReactNode;
|
|
47
47
|
/** Names the aside's toggle and Drawer. */
|
|
48
48
|
asideTitle?: string;
|
package/dist/resizable.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { useCompact, useElementWidth, useBelow, useAppShell,
|
|
2
|
-
import {
|
|
3
|
-
import { SplitPaneCtx } from './chunk-TKVTZWBN.js';
|
|
1
|
+
import { useCompact, useElementWidth, useBelow, useAppShell, Drawer } from './chunk-6PL7FXYH.js';
|
|
2
|
+
import { Button } from './chunk-7TOJ4G7S.js';
|
|
4
3
|
import { useBreakpoint } from './chunk-CRQ6KCRD.js';
|
|
5
|
-
import './chunk-
|
|
4
|
+
import { isTabStop, tabStops, rememberFocus } from './chunk-RT7RYGC3.js';
|
|
5
|
+
import { SurfaceBoundary } from './chunk-CKWITUSH.js';
|
|
6
|
+
import './chunk-CXMV7SXJ.js';
|
|
6
7
|
import './chunk-7Q46JXSK.js';
|
|
7
8
|
import './chunk-WH2FUFAC.js';
|
|
8
9
|
import { Icon } from './chunk-4LDYR7QP.js';
|
|
9
10
|
import { cn } from './chunk-M2QRNBDQ.js';
|
|
10
11
|
import { Group, Panel, Separator } from 'react-resizable-panels';
|
|
11
|
-
import { createContext, useContext, useRef, useState, useLayoutEffect } from 'react';
|
|
12
|
+
import { createContext, useContext, useRef, useState, useCallback, useLayoutEffect } from 'react';
|
|
12
13
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
13
14
|
|
|
14
15
|
var DirectionCtx = createContext("horizontal");
|
|
@@ -130,16 +131,26 @@ function SplitView({
|
|
|
130
131
|
const asideOpen = asideCollapsed && asideWantsOpen;
|
|
131
132
|
const region = ariaLabel ? { role: "region", "aria-label": ariaLabel } : {};
|
|
132
133
|
const isFill = frame === "fill";
|
|
134
|
+
const listHolds = useRef({ framed: 0, scrolls: 0 });
|
|
135
|
+
const [framesItself, setFramesItself] = useState(false);
|
|
136
|
+
const reportToList = useCallback((kind, present) => {
|
|
137
|
+
const held = listHolds.current;
|
|
138
|
+
held[kind] = Math.max(0, held[kind] + (present ? 1 : -1));
|
|
139
|
+
setFramesItself(held.framed > 0 && held.scrolls === 0);
|
|
140
|
+
}, []);
|
|
141
|
+
const onCanvas = isFill || framesItself;
|
|
133
142
|
const shell = useAppShell();
|
|
134
143
|
const fillStyle = isFill && shell?.hasFooter ? { height: "var(--ds-main-height, 100%)" } : void 0;
|
|
135
|
-
const itemSurface = isFill ? "bg-[var(--ds-bg-surface)]" :
|
|
144
|
+
const itemSurface = !onCanvas ? void 0 : isFill ? "bg-[var(--ds-bg-surface)]" : cn("bg-[var(--ds-bg-surface)] rounded-[var(--ds-radius-md)] overflow-hidden", bordered && "border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]");
|
|
136
145
|
const surface = cn(
|
|
137
146
|
"h-full min-h-0 w-full",
|
|
138
|
-
!
|
|
147
|
+
!onCanvas && "bg-[var(--ds-bg-surface)]",
|
|
139
148
|
isFill && "rounded-none border-0",
|
|
140
|
-
bordered && !
|
|
149
|
+
bordered && !onCanvas && "border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] rounded-[var(--ds-radius-md)] overflow-hidden",
|
|
141
150
|
className
|
|
142
151
|
);
|
|
152
|
+
const listContent = /* @__PURE__ */ jsx(SurfaceBoundary, { pane: true, framer: reportToList, children: list });
|
|
153
|
+
const detailContent = /* @__PURE__ */ jsx(SurfaceBoundary, { pane: true, children: detail });
|
|
143
154
|
const [listPct, setListPct] = useState(listWidth);
|
|
144
155
|
const paneRef = useRef(null);
|
|
145
156
|
const shown = useRef(null);
|
|
@@ -176,13 +187,14 @@ function SplitView({
|
|
|
176
187
|
const showDetail2 = detailMode === "stack" && detailOpen;
|
|
177
188
|
const phoneAside = showDetail2 && !!aside;
|
|
178
189
|
return /* @__PURE__ */ jsxs("div", { ref: rootRef, "data-split-view": showDetail2 ? "detail" : "list", "data-frame": frame, ...region, className: cn(surface, "flex flex-col"), style: fillStyle, children: [
|
|
179
|
-
showDetail2
|
|
190
|
+
showDetail2 && /* @__PURE__ */ jsxs("div", { className: cn("flex-1 min-h-0 flex flex-col", itemSurface), children: [
|
|
180
191
|
/* @__PURE__ */ jsxs("div", { className: "shrink-0 flex items-center justify-between gap-ds-2 px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", children: [
|
|
181
192
|
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", iconLeft: /* @__PURE__ */ jsx(Icon, { name: "arrow-left", size: 14 }), onClick: onDetailClose, children: backLabel }),
|
|
182
193
|
phoneAside && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", iconLeft: /* @__PURE__ */ jsx(Icon, { name: "info", size: 14 }), onClick: () => setAsideWantsOpen(true), "aria-expanded": asideWantsOpen, children: asideTitle })
|
|
183
194
|
] }),
|
|
184
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children:
|
|
185
|
-
] })
|
|
195
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: detailContent })
|
|
196
|
+
] }),
|
|
197
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", hidden: showDetail2 || void 0, children: listContent }),
|
|
186
198
|
phoneAside && /* @__PURE__ */ jsx(Drawer, { open: asideWantsOpen, onClose: () => setAsideWantsOpen(false), title: asideTitle, position: "right", children: aside })
|
|
187
199
|
] });
|
|
188
200
|
}
|
|
@@ -207,17 +219,17 @@ function SplitView({
|
|
|
207
219
|
children: [
|
|
208
220
|
/* @__PURE__ */ jsx(ResizablePanel, { id: "list", defaultSize: `${hiding ? detailOpen ? listPct : 100 : listWidth}%`, minSize: `${listMinWidth}%`, children: /* @__PURE__ */ jsx("div", { "data-pane": "list", className: "h-full min-h-0 overflow-y-auto", onFocus: hiding ? (e) => {
|
|
209
221
|
lastInList.current = e.target;
|
|
210
|
-
} : void 0, children:
|
|
222
|
+
} : void 0, children: listContent }) }),
|
|
211
223
|
showDetail && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
212
224
|
/* @__PURE__ */ jsx(ResizableHandle, { withHandle: true }),
|
|
213
225
|
/* @__PURE__ */ jsx(ResizablePanel, { id: "detail", minSize: "30%", children: /* @__PURE__ */ jsxs("div", { ref: paneRef, "data-pane": "detail", className: cn("h-full min-h-0 flex flex-col", itemSurface), onKeyDown: hiding ? onPaneKeyDown : void 0, children: [
|
|
214
226
|
paneBar,
|
|
215
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children:
|
|
227
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: detailContent })
|
|
216
228
|
] }) })
|
|
217
229
|
] }),
|
|
218
230
|
showAside && !asideCollapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
219
231
|
/* @__PURE__ */ jsx(ResizableHandle, { withHandle: true }),
|
|
220
|
-
/* @__PURE__ */ jsx(ResizablePanel, { id: "aside", defaultSize: `${asideWidth}%`, minSize: "15%", children: /* @__PURE__ */ jsx("div", { "data-pane": "aside", className: cn("h-full min-h-0 overflow-y-auto
|
|
232
|
+
/* @__PURE__ */ jsx(ResizablePanel, { id: "aside", defaultSize: `${asideWidth}%`, minSize: "15%", children: /* @__PURE__ */ jsx("div", { "data-pane": "aside", className: cn("h-full min-h-0 overflow-y-auto py-ds-5 px-[var(--ds-page-gutter)]", itemSurface), children: /* @__PURE__ */ jsx(SurfaceBoundary, { pane: true, children: aside }) }) })
|
|
221
233
|
] })
|
|
222
234
|
]
|
|
223
235
|
}
|
package/dist/resizable.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../showcase/src/components/ResizablePanels.tsx","../../../showcase/src/components/SplitView.tsx"],"names":["PanelGroup","PanelResizeHandle","showDetail","jsx"],"mappings":"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","file":"resizable.js","sourcesContent":["import {\n Panel,\n Group as PanelGroup,\n Separator as PanelResizeHandle,\n} from \"react-resizable-panels\";\nimport { createContext, useContext, type ComponentProps } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useBreakpoint } from \"../lib/use-breakpoint\";\nimport { Icon } from \"../lib/icons\";\n\ntype PanelGroupProps = ComponentProps<typeof PanelGroup>;\n\ntype Direction = \"horizontal\" | \"vertical\";\nconst DirectionCtx = createContext<Direction>(\"horizontal\");\nconst MobileCtx = createContext(false);\n\nexport interface ResizablePanelGroupProps\n extends Omit<PanelGroupProps, \"className\" | \"orientation\"> {\n direction?: Direction;\n stackOnMobile?: boolean;\n className?: string;\n /** Map of panel id → percentage (0–100). Must be an object, never an array. Panels need matching id props. */\n defaultLayout?: { [panelId: string]: number };\n /** Called after resize ends. Receives { [panelId]: number }, not number[]. */\n onLayoutChanged?: (layout: { [panelId: string]: number }) => void;\n}\n\nexport function ResizablePanelGroup({\n className,\n direction = \"horizontal\",\n stackOnMobile = true,\n ...props\n}: ResizablePanelGroupProps) {\n const isMobile = useBreakpoint(\"sm\");\n const shouldStack = stackOnMobile && isMobile && direction === \"horizontal\";\n const effectiveDirection = shouldStack ? \"vertical\" : direction;\n\n return (\n <DirectionCtx.Provider value={effectiveDirection}>\n <MobileCtx.Provider value={isMobile}>\n <PanelGroup\n className={cn(\n \"flex h-full w-full\",\n effectiveDirection === \"vertical\" && \"flex-col\",\n className,\n )}\n orientation={effectiveDirection}\n {...props}\n />\n </MobileCtx.Provider>\n </DirectionCtx.Provider>\n );\n}\n\ntype PanelProps = ComponentProps<typeof Panel>;\n\nexport interface ResizablePanelProps extends Omit<PanelProps, \"className\"> {\n className?: string;\n id?: string;\n /** number = px. \"30%\" or \"30\" = percent. \"28rem\" / \"400px\" also valid. */\n defaultSize?: number | string;\n minSize?: number | string;\n maxSize?: number | string;\n collapsible?: boolean;\n}\n\nexport function ResizablePanel({ className, ...props }: ResizablePanelProps) {\n return <Panel className={cn(\"\", className)} {...props} />;\n}\n\ntype PanelResizeHandleProps = ComponentProps<typeof PanelResizeHandle>;\n\nexport interface ResizableHandleProps\n extends Omit<PanelResizeHandleProps, \"className\"> {\n withHandle?: boolean;\n className?: string;\n}\n\nexport function ResizableHandle({\n withHandle,\n className,\n ...props\n}: ResizableHandleProps) {\n const direction = useContext(DirectionCtx);\n const isMobile = useContext(MobileCtx);\n const isVertical = direction === \"vertical\";\n\n return (\n <PanelResizeHandle\n className={cn(\n \"relative flex items-center justify-center bg-[var(--ds-border-default)]\",\n isVertical\n ? cn(\n \"h-[var(--ds-border-width)] w-full after:absolute after:left-0 after:right-0 after:content-['']\",\n isMobile ? \"after:-top-3 after:-bottom-3\" : \"after:-top-1 after:-bottom-1\"\n )\n : cn(\n \"w-[var(--ds-border-width)] after:absolute after:inset-y-0 after:content-['']\",\n isMobile ? \"after:-left-3 after:-right-3\" : \"after:-left-1 after:-right-1\"\n ),\n \"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]\",\n \"[&[data-resize-handle-state=drag]]:bg-[var(--ds-accent-primary)]\",\n \"[&[data-resize-handle-state=hover]]:bg-[var(--ds-accent-primary)]\",\n className,\n )}\n {...props}\n >\n {withHandle && (\n <div\n className={cn(\n \"z-10 flex items-center justify-center rounded-[var(--ds-radius-sm)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n \"bg-[var(--ds-bg-surface)]\",\n isVertical\n ? (isMobile ? \"h-4 w-8\" : \"h-3 w-4\")\n : (isMobile ? \"h-8 w-4\" : \"h-4 w-3\"),\n )}\n >\n <Icon\n name=\"grip-vertical\"\n size={isMobile ? 12 : 10}\n className={cn(\n \"text-[var(--ds-text-muted)]\",\n isVertical && \"rotate-90\",\n )}\n />\n </div>\n )}\n </PanelResizeHandle>\n );\n}\n","import { useLayoutEffect, useRef, useState, type KeyboardEvent, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useBelow, useCompact, useElementWidth } from \"../lib/use-compact\";\nimport { ResizablePanelGroup, ResizablePanel, ResizableHandle } from \"./ResizablePanels\";\nimport { Button } from \"./Button\";\nimport { Drawer } from \"./Drawer\";\nimport { Icon } from \"../lib/icons\";\nimport { useAppShell } from \"./AppShell\";\nimport { SplitPaneCtx } from \"../lib/surface-context\";\nimport { isTabStop, rememberFocus, tabStops, type RememberedFocus } from \"../lib/focus\";\n\nexport type SplitViewFrame = \"fill\" | \"page\";\n\n/**\n * How far past a threshold the layout must go before a collapsed part comes back, in px: a classic scrollbar's width\n * (15 px on a Mac with a mouse, 17 on Windows), whose coming and going with the aside moved the layout back and forth\n * across the threshold (round 27 review). No wider: inside the band the answer depends on the way the width came, so a\n * wider band could keep the aside collapsed at a width where it fits.\n */\nconst THRESHOLD_BAND = 17;\n\nexport interface SplitViewProps {\n /** The list (an inbox, a queue): it scrolls on its own. */\n list: ReactNode;\n /** The selected item (a thread, a record): it fills the height and scrolls on its own. */\n detail: ReactNode;\n /** Context beside the detail (a contact, properties). The pane pads it (16 px, like the Drawer it collapses into), so pass content with no padding classes (round 8). Collapses to a toggle that opens it in a Drawer when the layout is narrower than `asideCollapseBelow`. */\n aside?: ReactNode;\n /** Names the aside's toggle and Drawer. */\n asideTitle?: string;\n /**\n * Below `collapseBelow` the list shows alone; with `detailOpen` the detail replaces it, with a Back button that calls\n * `onDetailClose` (detailMode \"stack\"). The page owns the selection, so it owns this flag.\n */\n detailOpen?: boolean;\n onDetailClose?: () => void;\n /** \"stack\" (default): the detail stacks over the list below the collapse width. \"route\": the app navigates to the detail's own route instead, and this renders the list alone there. */\n detailMode?: \"stack\" | \"route\";\n /**\n * \"shown\" (default): above the collapse width the detail pane is always there — an inbox's reading pane may show a\n * placeholder. \"hidden\" (Sprint 25.7, C3): `detailOpen` decides at every width. Closed, the list takes the whole\n * width; open, the pane appears beside it at the width the user last gave it, with a close control that calls\n * `onDetailClose`. For boards, timelines and lists of records. The list stays mounted, so a board or a timeline keeps\n * its scroll and zoom.\n */\n closedDetail?: \"shown\" | \"hidden\";\n /** The open pane's close control, named for a screen reader (closedDetail=\"hidden\"). Default \"Close\". */\n closeLabel?: string;\n backLabel?: string;\n /** Percent of the width the list takes; the divider is draggable. */\n listWidth?: number;\n listMinWidth?: number;\n asideWidth?: number;\n /** Below this width of the layout itself (px) the list and detail stop sitting side by side. */\n collapseBelow?: number;\n /** Below this width of the layout itself (px) the aside becomes a toggle. */\n asideCollapseBelow?: number;\n /**\n * The narrowest the open item's pane may be beside an aside (px). When the list and the aside would leave it less,\n * the aside becomes its toggle and Drawer, so the item keeps the room its content needs: the aside is the secondary\n * content (round 27, R27-13, the owner: \"which information is more important\"). An item that holds a wide table or a\n * card grid may need more: pass it.\n */\n detailMinWidth?: number;\n /** A bordered, rounded surface (inside a page with padding) instead of edge to edge (filling <main>). */\n bordered?: boolean;\n /** \"fill\": the page root, flush to the shell, h-full against main, each pane owns its inset. \"page\" (default): inside a PageContainer under a PageHeader. */\n frame?: SplitViewFrame;\n \"aria-label\"?: string;\n className?: string;\n}\n\n/**\n * The reading-pane composition (Sprint 25.2, R3): one surface with dividers —\n * list, detail and an optional aside — that fills the height it is given (an\n * AppShell's <main> already gives it) and never three cards with gaps. The\n * panels compose ResizablePanelGroup, so the dividers drag. Below the collapse\n * width, measured on the layout itself, the list shows alone and the detail\n * stacks over it (or the app routes to it); the aside collapses to a toggle.\n * The page owns the selection and assembles the contents; keyboard movement\n * through the list is the list's job (StackedList selectedId).\n */\nexport function SplitView({\n list,\n detail,\n aside,\n asideTitle = \"Details\",\n detailOpen = false,\n onDetailClose,\n detailMode = \"stack\",\n closedDetail = \"shown\",\n closeLabel = \"Close\",\n backLabel = \"Back\",\n listWidth = 35,\n listMinWidth = 25,\n asideWidth = 25,\n collapseBelow = 768,\n asideCollapseBelow = 1024,\n detailMinWidth = 480,\n bordered = false,\n frame = \"page\",\n \"aria-label\": ariaLabel,\n className,\n}: SplitViewProps) {\n const rootRef = useRef<HTMLDivElement>(null);\n const compact = useCompact(rootRef, collapseBelow, THRESHOLD_BAND);\n const layoutWidth = useElementWidth(rootRef);\n // The panels' shares as the user left them (the review: the defaults were read, so a list dragged wider left the item\n // under its minimum beside the aside); the aside's last share stands in while it is collapsed.\n const [shares, setShares] = useState<{ list?: number; aside?: number }>({});\n const listShare = shares.list ?? listWidth;\n const asideShare = shares.aside ?? asideWidth;\n // the aside yields when the layout is narrow, or when beside it the item would have less than its minimum\n const itemShare = (100 - listShare - asideShare) / 100;\n const itemBesideAside = aside ? layoutWidth * itemShare : 0;\n // the item moves by its share of the scrollbar's width, so its band is that share of the layout's\n const itemSqueezed = useBelow(itemBesideAside, detailMinWidth, THRESHOLD_BAND * Math.max(0, itemShare));\n const asideCollapsed = useBelow(layoutWidth, asideCollapseBelow, THRESHOLD_BAND) || itemSqueezed;\n const [asideWantsOpen, setAsideWantsOpen] = useState(false);\n const hiding = closedDetail === \"hidden\";\n // Hidden: the aside belongs to the open item, so it (its pane, its toggle, its Drawer) goes with the pane, and a\n // Drawer left open does not come back with the next item (render-time state adjustment).\n const showAside = !!aside && (!hiding || detailOpen);\n if (hiding && !detailOpen && asideWantsOpen) setAsideWantsOpen(false);\n // on a phone the aside's Drawer belongs to the item on screen: Back closes it with the item\n if (compact && !detailOpen && asideWantsOpen) setAsideWantsOpen(false);\n const asideOpen = asideCollapsed && asideWantsOpen;\n const region = ariaLabel ? { role: \"region\" as const, \"aria-label\": ariaLabel } : {};\n // fill: the page root, flush to the shell on every side (no border, no radius, no padding of its own); h-full\n // resolves against <main> because the shell is a flex column down to it. page: inside a PageContainer under a\n // PageHeader, where `bordered` draws the surface. Each pane owns its own inset either way.\n const isFill = frame === \"fill\";\n // In a shell with an app footer the children wrapper has no definite height, so h-full cannot resolve; the shell\n // publishes main's height and fill takes it (the footer then sits below the fold, as it must under a full pane).\n const shell = useAppShell();\n const fillStyle = isFill && shell?.hasFooter ? { height: \"var(--ds-main-height, 100%)\" } : undefined;\n // Edge to edge the list sits on the page's canvas, like every other page, and the open item (its detail and its aside)\n // on the surface (round 27, R27-12, the owner: the whole split on the surface read as a different page). A page frame,\n // bordered or not, stays one surface: a card on the canvas.\n const itemSurface = isFill ? \"bg-[var(--ds-bg-surface)]\" : undefined;\n const surface = cn(\n \"h-full min-h-0 w-full\",\n !isFill && \"bg-[var(--ds-bg-surface)]\",\n isFill && \"rounded-none border-0\",\n bordered && !isFill && \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] rounded-[var(--ds-radius-md)] overflow-hidden\",\n className,\n );\n\n // closedDetail=\"hidden\" (C3): the pane opens beside the list at the width the user last gave it; closing it returns\n // focus to the item the pane shows, or its neighbour if that item is gone (D14(e)): the list's selected item, else\n // the last list item that took focus, checked on each render while the pane is open, so switching items is followed.\n // A selection kept in the URL changes the path, so the item is remembered whatever the route does. With no item\n // (opened on load, or from outside the list) focus goes to the list's first Tab stop. No overlay layer: an\n // assistant opened earlier keeps Escape.\n const [listPct, setListPct] = useState(listWidth);\n const paneRef = useRef<HTMLDivElement>(null);\n const shown = useRef<RememberedFocus | null>(null);\n const lastInList = useRef<HTMLElement | null>(null);\n const wasOpen = useRef(false);\n useLayoutEffect(() => {\n if (!hiding) return;\n const listPane = rootRef.current?.querySelector<HTMLElement>('[data-pane=\"list\"]') ?? null;\n if (detailOpen) {\n wasOpen.current = true;\n const selected = listPane?.querySelector<HTMLElement>('[aria-current=\"true\"], [aria-selected=\"true\"]');\n const last = lastInList.current;\n const item = (selected && (isTabStop(selected) ? selected : tabStops(selected)[0]))\n || (last?.isConnected && listPane?.contains(last) ? last : null);\n if (item && item !== shown.current?.el) shown.current = rememberFocus(item, { ignoreRoute: true });\n return;\n }\n if (!wasOpen.current) return;\n wasOpen.current = false;\n const r = shown.current;\n shown.current = null;\n const active = document.activeElement;\n if (active && active !== document.body && active.isConnected) return;\n const first = listPane ? tabStops(listPane)[0] : undefined;\n if (!r?.restore(first)) first?.focus();\n });\n const onPaneKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key !== \"Escape\" || e.defaultPrevented || !onDetailClose) return;\n const t = e.target as HTMLElement;\n // the pane's own DOM only — a portalled popup inside it bubbles here in React's tree — and never from a field\n if (!paneRef.current?.contains(t) || t.closest(\"input, textarea, select, [contenteditable='true']\")) return;\n e.preventDefault();\n onDetailClose();\n };\n\n if (compact) {\n const showDetail = detailMode === \"stack\" && detailOpen;\n // on a phone the item's aside is a toggle beside Back that opens it in a Drawer, as it is on a narrow desktop (the\n // round 27 review: below the collapse width it could not be reached at all)\n const phoneAside = showDetail && !!aside;\n return (\n <div ref={rootRef} data-split-view={showDetail ? \"detail\" : \"list\"} data-frame={frame} {...region} className={cn(surface, \"flex flex-col\")} style={fillStyle}>\n {showDetail ? (\n <div className={cn(\"flex-1 min-h-0 flex flex-col\", itemSurface)}>\n <div className=\"shrink-0 flex items-center justify-between gap-ds-2 px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"arrow-left\" size={14} />} onClick={onDetailClose}>{backLabel}</Button>\n {phoneAside && <Button type=\"button\" variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"info\" size={14} />} onClick={() => setAsideWantsOpen(true)} aria-expanded={asideWantsOpen}>{asideTitle}</Button>}\n </div>\n <div className=\"flex-1 min-h-0 overflow-y-auto\"><SplitPaneCtx value={true}>{detail}</SplitPaneCtx></div>\n </div>\n ) : (\n <div className=\"flex-1 min-h-0 overflow-y-auto\"><SplitPaneCtx value={true}>{list}</SplitPaneCtx></div>\n )}\n {phoneAside && (\n <Drawer open={asideWantsOpen} onClose={() => setAsideWantsOpen(false)} title={asideTitle} position=\"right\">\n {aside}\n </Drawer>\n )}\n </div>\n );\n }\n\n const asideButton = showAside && asideCollapsed\n ? <Button type=\"button\" variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"info\" size={14} />} onClick={() => setAsideWantsOpen(true)} aria-expanded={asideOpen}>{asideTitle}</Button>\n : null;\n const closeButton = hiding && onDetailClose\n ? <Button type=\"button\" variant=\"ghost\" size=\"icon-sm\" aria-label={closeLabel} onClick={onDetailClose}><Icon name=\"close\" size={14} /></Button>\n : null;\n const paneBar = asideButton || closeButton ? (\n <div className=\"shrink-0 flex items-center justify-end gap-ds-1 px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\">\n {asideButton}\n {closeButton}\n </div>\n ) : null;\n const showDetail = !hiding || detailOpen;\n\n return (\n <div ref={rootRef} data-split-view={hiding && !detailOpen ? \"list\" : \"split\"} data-frame={frame} {...region} className={surface} style={fillStyle}>\n <ResizablePanelGroup\n direction=\"horizontal\"\n stackOnMobile={false}\n className=\"h-full\"\n // the width the user gives the list is kept, so a closed pane reopens at it; the shares decide when the aside yields\n onLayoutChanged={(layout) => {\n setShares((prev) => (prev.list === (layout.list ?? prev.list) && prev.aside === (layout.aside ?? prev.aside) ? prev : { list: layout.list ?? prev.list, aside: layout.aside ?? prev.aside }));\n if (hiding && layout.detail != null && layout.list != null) setListPct(layout.list);\n }}\n >\n <ResizablePanel id=\"list\" defaultSize={`${hiding ? (detailOpen ? listPct : 100) : listWidth}%`} minSize={`${listMinWidth}%`}>\n <div data-pane=\"list\" className=\"h-full min-h-0 overflow-y-auto\" onFocus={hiding ? (e) => { lastInList.current = e.target; } : undefined}>\n <SplitPaneCtx value={true}>{list}</SplitPaneCtx>\n </div>\n </ResizablePanel>\n {showDetail && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel id=\"detail\" minSize=\"30%\">\n <div ref={paneRef} data-pane=\"detail\" className={cn(\"h-full min-h-0 flex flex-col\", itemSurface)} onKeyDown={hiding ? onPaneKeyDown : undefined}>\n {paneBar}\n <div className=\"flex-1 min-h-0 overflow-y-auto\"><SplitPaneCtx value={true}>{detail}</SplitPaneCtx></div>\n </div>\n </ResizablePanel>\n </>\n )}\n {showAside && !asideCollapsed && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel id=\"aside\" defaultSize={`${asideWidth}%`} minSize=\"15%\">\n <div data-pane=\"aside\" className={cn(\"h-full min-h-0 overflow-y-auto p-ds-4\", itemSurface)}><SplitPaneCtx value={true}>{aside}</SplitPaneCtx></div>\n </ResizablePanel>\n </>\n )}\n </ResizablePanelGroup>\n {showAside && asideCollapsed && (\n <Drawer open={asideOpen} onClose={() => setAsideWantsOpen(false)} title={asideTitle} position=\"right\">\n {aside}\n </Drawer>\n )}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/components/ResizablePanels.tsx","../../../showcase/src/components/SplitView.tsx"],"names":["PanelGroup","PanelResizeHandle","jsx","showDetail"],"mappings":"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","file":"resizable.js","sourcesContent":["import {\n Panel,\n Group as PanelGroup,\n Separator as PanelResizeHandle,\n} from \"react-resizable-panels\";\nimport { createContext, useContext, type ComponentProps } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useBreakpoint } from \"../lib/use-breakpoint\";\nimport { Icon } from \"../lib/icons\";\n\ntype PanelGroupProps = ComponentProps<typeof PanelGroup>;\n\ntype Direction = \"horizontal\" | \"vertical\";\nconst DirectionCtx = createContext<Direction>(\"horizontal\");\nconst MobileCtx = createContext(false);\n\nexport interface ResizablePanelGroupProps\n extends Omit<PanelGroupProps, \"className\" | \"orientation\"> {\n direction?: Direction;\n stackOnMobile?: boolean;\n className?: string;\n /** Map of panel id → percentage (0–100). Must be an object, never an array. Panels need matching id props. */\n defaultLayout?: { [panelId: string]: number };\n /** Called after resize ends. Receives { [panelId]: number }, not number[]. */\n onLayoutChanged?: (layout: { [panelId: string]: number }) => void;\n}\n\nexport function ResizablePanelGroup({\n className,\n direction = \"horizontal\",\n stackOnMobile = true,\n ...props\n}: ResizablePanelGroupProps) {\n const isMobile = useBreakpoint(\"sm\");\n const shouldStack = stackOnMobile && isMobile && direction === \"horizontal\";\n const effectiveDirection = shouldStack ? \"vertical\" : direction;\n\n return (\n <DirectionCtx.Provider value={effectiveDirection}>\n <MobileCtx.Provider value={isMobile}>\n <PanelGroup\n className={cn(\n \"flex h-full w-full\",\n effectiveDirection === \"vertical\" && \"flex-col\",\n className,\n )}\n orientation={effectiveDirection}\n {...props}\n />\n </MobileCtx.Provider>\n </DirectionCtx.Provider>\n );\n}\n\ntype PanelProps = ComponentProps<typeof Panel>;\n\nexport interface ResizablePanelProps extends Omit<PanelProps, \"className\"> {\n className?: string;\n id?: string;\n /** number = px. \"30%\" or \"30\" = percent. \"28rem\" / \"400px\" also valid. */\n defaultSize?: number | string;\n minSize?: number | string;\n maxSize?: number | string;\n collapsible?: boolean;\n}\n\nexport function ResizablePanel({ className, ...props }: ResizablePanelProps) {\n return <Panel className={cn(\"\", className)} {...props} />;\n}\n\ntype PanelResizeHandleProps = ComponentProps<typeof PanelResizeHandle>;\n\nexport interface ResizableHandleProps\n extends Omit<PanelResizeHandleProps, \"className\"> {\n withHandle?: boolean;\n className?: string;\n}\n\nexport function ResizableHandle({\n withHandle,\n className,\n ...props\n}: ResizableHandleProps) {\n const direction = useContext(DirectionCtx);\n const isMobile = useContext(MobileCtx);\n const isVertical = direction === \"vertical\";\n\n return (\n <PanelResizeHandle\n className={cn(\n \"relative flex items-center justify-center bg-[var(--ds-border-default)]\",\n isVertical\n ? cn(\n \"h-[var(--ds-border-width)] w-full after:absolute after:left-0 after:right-0 after:content-['']\",\n isMobile ? \"after:-top-3 after:-bottom-3\" : \"after:-top-1 after:-bottom-1\"\n )\n : cn(\n \"w-[var(--ds-border-width)] after:absolute after:inset-y-0 after:content-['']\",\n isMobile ? \"after:-left-3 after:-right-3\" : \"after:-left-1 after:-right-1\"\n ),\n \"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]\",\n \"[&[data-resize-handle-state=drag]]:bg-[var(--ds-accent-primary)]\",\n \"[&[data-resize-handle-state=hover]]:bg-[var(--ds-accent-primary)]\",\n className,\n )}\n {...props}\n >\n {withHandle && (\n <div\n className={cn(\n \"z-10 flex items-center justify-center rounded-[var(--ds-radius-sm)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n \"bg-[var(--ds-bg-surface)]\",\n isVertical\n ? (isMobile ? \"h-4 w-8\" : \"h-3 w-4\")\n : (isMobile ? \"h-8 w-4\" : \"h-4 w-3\"),\n )}\n >\n <Icon\n name=\"grip-vertical\"\n size={isMobile ? 12 : 10}\n className={cn(\n \"text-[var(--ds-text-muted)]\",\n isVertical && \"rotate-90\",\n )}\n />\n </div>\n )}\n </PanelResizeHandle>\n );\n}\n","import { useCallback, useLayoutEffect, useRef, useState, type KeyboardEvent, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useBelow, useCompact, useElementWidth } from \"../lib/use-compact\";\nimport { ResizablePanelGroup, ResizablePanel, ResizableHandle } from \"./ResizablePanels\";\nimport { Button } from \"./Button\";\nimport { Drawer } from \"./Drawer\";\nimport { Icon } from \"../lib/icons\";\nimport { useAppShell } from \"./AppShell\";\nimport { SurfaceBoundary, type SplitListReport } from \"../lib/surface-context\";\nimport { isTabStop, rememberFocus, tabStops, type RememberedFocus } from \"../lib/focus\";\n\nexport type SplitViewFrame = \"fill\" | \"page\";\n\n/**\n * How far past a threshold the layout must go before a collapsed part comes back, in px: a classic scrollbar's width\n * (15 px on a Mac with a mouse, 17 on Windows), whose coming and going with the aside moved the layout back and forth\n * across the threshold (round 27 review). No wider: inside the band the answer depends on the way the width came, so a\n * wider band could keep the aside collapsed at a width where it fits.\n */\nconst THRESHOLD_BAND = 17;\n\nexport interface SplitViewProps {\n /** The list (an inbox, a queue): it scrolls on its own. */\n list: ReactNode;\n /** The selected item (a thread, a record): it fills the height and scrolls on its own. */\n detail: ReactNode;\n /** Context beside the detail (a contact, properties). The pane insets it as the Drawer it collapses into does (the page's gutter, Sprint 25.14 A36), so pass content with no padding classes (round 8). Collapses to a toggle that opens it in a Drawer when the layout is narrower than `asideCollapseBelow`. */\n aside?: ReactNode;\n /** Names the aside's toggle and Drawer. */\n asideTitle?: string;\n /**\n * Below `collapseBelow` the list shows alone; with `detailOpen` the detail replaces it, with a Back button that calls\n * `onDetailClose` (detailMode \"stack\"). The page owns the selection, so it owns this flag.\n */\n detailOpen?: boolean;\n onDetailClose?: () => void;\n /** \"stack\" (default): the detail stacks over the list below the collapse width. \"route\": the app navigates to the detail's own route instead, and this renders the list alone there. */\n detailMode?: \"stack\" | \"route\";\n /**\n * \"shown\" (default): above the collapse width the detail pane is always there — an inbox's reading pane may show a\n * placeholder. \"hidden\" (Sprint 25.7, C3): `detailOpen` decides at every width. Closed, the list takes the whole\n * width; open, the pane appears beside it at the width the user last gave it, with a close control that calls\n * `onDetailClose`. For boards, timelines and lists of records. The list stays mounted, so a board or a timeline keeps\n * its scroll and zoom.\n */\n closedDetail?: \"shown\" | \"hidden\";\n /** The open pane's close control, named for a screen reader (closedDetail=\"hidden\"). Default \"Close\". */\n closeLabel?: string;\n backLabel?: string;\n /** Percent of the width the list takes; the divider is draggable. */\n listWidth?: number;\n listMinWidth?: number;\n asideWidth?: number;\n /** Below this width of the layout itself (px) the list and detail stop sitting side by side. */\n collapseBelow?: number;\n /** Below this width of the layout itself (px) the aside becomes a toggle. */\n asideCollapseBelow?: number;\n /**\n * The narrowest the open item's pane may be beside an aside (px). When the list and the aside would leave it less,\n * the aside becomes its toggle and Drawer, so the item keeps the room its content needs: the aside is the secondary\n * content (round 27, R27-13, the owner: \"which information is more important\"). An item that holds a wide table or a\n * card grid may need more: pass it.\n */\n detailMinWidth?: number;\n /** A bordered, rounded surface (inside a page with padding) instead of edge to edge (filling <main>). */\n bordered?: boolean;\n /** \"fill\": the page root, flush to the shell, h-full against main, each pane owns its inset. \"page\" (default): inside a PageContainer under a PageHeader. */\n frame?: SplitViewFrame;\n \"aria-label\"?: string;\n className?: string;\n}\n\n/**\n * The reading-pane composition (Sprint 25.2, R3): one surface with dividers —\n * list, detail and an optional aside — that fills the height it is given (an\n * AppShell's <main> already gives it) and never three cards with gaps. The\n * panels compose ResizablePanelGroup, so the dividers drag. Below the collapse\n * width, measured on the layout itself, the list shows alone and the detail\n * stacks over it (or the app routes to it); the aside collapses to a toggle.\n * The page owns the selection and assembles the contents; keyboard movement\n * through the list is the list's job (StackedList selectedId).\n */\nexport function SplitView({\n list,\n detail,\n aside,\n asideTitle = \"Details\",\n detailOpen = false,\n onDetailClose,\n detailMode = \"stack\",\n closedDetail = \"shown\",\n closeLabel = \"Close\",\n backLabel = \"Back\",\n listWidth = 35,\n listMinWidth = 25,\n asideWidth = 25,\n collapseBelow = 768,\n asideCollapseBelow = 1024,\n detailMinWidth = 480,\n bordered = false,\n frame = \"page\",\n \"aria-label\": ariaLabel,\n className,\n}: SplitViewProps) {\n const rootRef = useRef<HTMLDivElement>(null);\n const compact = useCompact(rootRef, collapseBelow, THRESHOLD_BAND);\n const layoutWidth = useElementWidth(rootRef);\n // The panels' shares as the user left them (the review: the defaults were read, so a list dragged wider left the item\n // under its minimum beside the aside); the aside's last share stands in while it is collapsed.\n const [shares, setShares] = useState<{ list?: number; aside?: number }>({});\n const listShare = shares.list ?? listWidth;\n const asideShare = shares.aside ?? asideWidth;\n // the aside yields when the layout is narrow, or when beside it the item would have less than its minimum\n const itemShare = (100 - listShare - asideShare) / 100;\n const itemBesideAside = aside ? layoutWidth * itemShare : 0;\n // the item moves by its share of the scrollbar's width, so its band is that share of the layout's\n const itemSqueezed = useBelow(itemBesideAside, detailMinWidth, THRESHOLD_BAND * Math.max(0, itemShare));\n const asideCollapsed = useBelow(layoutWidth, asideCollapseBelow, THRESHOLD_BAND) || itemSqueezed;\n const [asideWantsOpen, setAsideWantsOpen] = useState(false);\n const hiding = closedDetail === \"hidden\";\n // Hidden: the aside belongs to the open item, so it (its pane, its toggle, its Drawer) goes with the pane, and a\n // Drawer left open does not come back with the next item (render-time state adjustment).\n const showAside = !!aside && (!hiding || detailOpen);\n if (hiding && !detailOpen && asideWantsOpen) setAsideWantsOpen(false);\n // on a phone the aside's Drawer belongs to the item on screen: Back closes it with the item\n if (compact && !detailOpen && asideWantsOpen) setAsideWantsOpen(false);\n const asideOpen = asideCollapsed && asideWantsOpen;\n const region = ariaLabel ? { role: \"region\" as const, \"aria-label\": ariaLabel } : {};\n // fill: the page root, flush to the shell on every side (no border, no radius, no padding of its own); h-full\n // resolves against <main> because the shell is a flex column down to it. page: inside a PageContainer under a\n // PageHeader, where `bordered` draws the surface. Each pane owns its own inset either way.\n const isFill = frame === \"fill\";\n // Sprint 25.14 A44 (P32): the list pane's content reports what it is, as a wrapped PageHeader does to its\n // PageContainer: content that draws its own frame or cards (a KanbanBoard, a CardGrid, a Table), or content with no\n // frame of its own that scrolls inside the pane (a StackedList, a Gantt). No frame around what frames itself: when the\n // pane holds only the first kind, the list sits on the canvas with nothing drawn behind it and the open item on the\n // surface, whatever `bordered` says. Anything that scrolls inside keeps the hairline, which shows where it scrolls.\n const listHolds = useRef({ framed: 0, scrolls: 0 });\n const [framesItself, setFramesItself] = useState(false);\n const reportToList = useCallback<SplitListReport>((kind, present) => {\n const held = listHolds.current;\n held[kind] = Math.max(0, held[kind] + (present ? 1 : -1));\n setFramesItself(held.framed > 0 && held.scrolls === 0);\n }, []);\n const onCanvas = isFill || framesItself;\n // In a shell with an app footer the children wrapper has no definite height, so h-full cannot resolve; the shell\n // publishes main's height and fill takes it (the footer then sits below the fold, as it must under a full pane).\n const shell = useAppShell();\n const fillStyle = isFill && shell?.hasFooter ? { height: \"var(--ds-main-height, 100%)\" } : undefined;\n // Edge to edge the list sits on the page's canvas, like every other page, and the open item (its detail and its aside)\n // on the surface (round 27, R27-12, the owner: the whole split on the surface read as a different page). A page frame,\n // bordered or not, stays one surface: a card on the canvas. Beside a list that frames itself, a page frame's open item\n // is that card (rounded, and bordered when the view is), as the page's other cards are; edge to edge it is square.\n const itemSurface = !onCanvas ? undefined : isFill\n ? \"bg-[var(--ds-bg-surface)]\"\n : cn(\"bg-[var(--ds-bg-surface)] rounded-[var(--ds-radius-md)] overflow-hidden\", bordered && \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\");\n const surface = cn(\n \"h-full min-h-0 w-full\",\n !onCanvas && \"bg-[var(--ds-bg-surface)]\",\n isFill && \"rounded-none border-0\",\n bordered && !onCanvas && \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] rounded-[var(--ds-radius-md)] overflow-hidden\",\n className,\n );\n // each pane is a surface of its own: what a Card around the view, or the list pane, tells content stops at its edge\n const listContent = <SurfaceBoundary pane framer={reportToList}>{list}</SurfaceBoundary>;\n const detailContent = <SurfaceBoundary pane>{detail}</SurfaceBoundary>;\n\n // closedDetail=\"hidden\" (C3): the pane opens beside the list at the width the user last gave it; closing it returns\n // focus to the item the pane shows, or its neighbour if that item is gone (D14(e)): the list's selected item, else\n // the last list item that took focus, checked on each render while the pane is open, so switching items is followed.\n // A selection kept in the URL changes the path, so the item is remembered whatever the route does. With no item\n // (opened on load, or from outside the list) focus goes to the list's first Tab stop. No overlay layer: an\n // assistant opened earlier keeps Escape.\n const [listPct, setListPct] = useState(listWidth);\n const paneRef = useRef<HTMLDivElement>(null);\n const shown = useRef<RememberedFocus | null>(null);\n const lastInList = useRef<HTMLElement | null>(null);\n const wasOpen = useRef(false);\n useLayoutEffect(() => {\n if (!hiding) return;\n const listPane = rootRef.current?.querySelector<HTMLElement>('[data-pane=\"list\"]') ?? null;\n if (detailOpen) {\n wasOpen.current = true;\n const selected = listPane?.querySelector<HTMLElement>('[aria-current=\"true\"], [aria-selected=\"true\"]');\n const last = lastInList.current;\n const item = (selected && (isTabStop(selected) ? selected : tabStops(selected)[0]))\n || (last?.isConnected && listPane?.contains(last) ? last : null);\n if (item && item !== shown.current?.el) shown.current = rememberFocus(item, { ignoreRoute: true });\n return;\n }\n if (!wasOpen.current) return;\n wasOpen.current = false;\n const r = shown.current;\n shown.current = null;\n const active = document.activeElement;\n if (active && active !== document.body && active.isConnected) return;\n const first = listPane ? tabStops(listPane)[0] : undefined;\n if (!r?.restore(first)) first?.focus();\n });\n const onPaneKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key !== \"Escape\" || e.defaultPrevented || !onDetailClose) return;\n const t = e.target as HTMLElement;\n // the pane's own DOM only — a portalled popup inside it bubbles here in React's tree — and never from a field\n if (!paneRef.current?.contains(t) || t.closest(\"input, textarea, select, [contenteditable='true']\")) return;\n e.preventDefault();\n onDetailClose();\n };\n\n if (compact) {\n const showDetail = detailMode === \"stack\" && detailOpen;\n // on a phone the item's aside is a toggle beside Back that opens it in a Drawer, as it is on a narrow desktop (the\n // round 27 review: below the collapse width it could not be reached at all)\n const phoneAside = showDetail && !!aside;\n return (\n <div ref={rootRef} data-split-view={showDetail ? \"detail\" : \"list\"} data-frame={frame} {...region} className={cn(surface, \"flex flex-col\")} style={fillStyle}>\n {showDetail && (\n <div className={cn(\"flex-1 min-h-0 flex flex-col\", itemSurface)}>\n <div className=\"shrink-0 flex items-center justify-between gap-ds-2 px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"arrow-left\" size={14} />} onClick={onDetailClose}>{backLabel}</Button>\n {phoneAside && <Button type=\"button\" variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"info\" size={14} />} onClick={() => setAsideWantsOpen(true)} aria-expanded={asideWantsOpen}>{asideTitle}</Button>}\n </div>\n <div className=\"flex-1 min-h-0 overflow-y-auto\">{detailContent}</div>\n </div>\n )}\n {/* Sprint 25.14 A44 (the review of 30 September): the list stays mounted while the stacked detail is shown, as it\n does beside it on a wider screen, so a board keeps its scroll and its report (the view kept its frame\n off only while the board was on screen), and Back finds the list as the user left it */}\n <div className=\"flex-1 min-h-0 overflow-y-auto\" hidden={showDetail || undefined}>{listContent}</div>\n {phoneAside && (\n <Drawer open={asideWantsOpen} onClose={() => setAsideWantsOpen(false)} title={asideTitle} position=\"right\">\n {aside}\n </Drawer>\n )}\n </div>\n );\n }\n\n const asideButton = showAside && asideCollapsed\n ? <Button type=\"button\" variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"info\" size={14} />} onClick={() => setAsideWantsOpen(true)} aria-expanded={asideOpen}>{asideTitle}</Button>\n : null;\n const closeButton = hiding && onDetailClose\n ? <Button type=\"button\" variant=\"ghost\" size=\"icon-sm\" aria-label={closeLabel} onClick={onDetailClose}><Icon name=\"close\" size={14} /></Button>\n : null;\n const paneBar = asideButton || closeButton ? (\n <div className=\"shrink-0 flex items-center justify-end gap-ds-1 px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\">\n {asideButton}\n {closeButton}\n </div>\n ) : null;\n const showDetail = !hiding || detailOpen;\n\n return (\n <div ref={rootRef} data-split-view={hiding && !detailOpen ? \"list\" : \"split\"} data-frame={frame} {...region} className={surface} style={fillStyle}>\n <ResizablePanelGroup\n direction=\"horizontal\"\n stackOnMobile={false}\n className=\"h-full\"\n // the width the user gives the list is kept, so a closed pane reopens at it; the shares decide when the aside yields\n onLayoutChanged={(layout) => {\n setShares((prev) => (prev.list === (layout.list ?? prev.list) && prev.aside === (layout.aside ?? prev.aside) ? prev : { list: layout.list ?? prev.list, aside: layout.aside ?? prev.aside }));\n if (hiding && layout.detail != null && layout.list != null) setListPct(layout.list);\n }}\n >\n <ResizablePanel id=\"list\" defaultSize={`${hiding ? (detailOpen ? listPct : 100) : listWidth}%`} minSize={`${listMinWidth}%`}>\n <div data-pane=\"list\" className=\"h-full min-h-0 overflow-y-auto\" onFocus={hiding ? (e) => { lastInList.current = e.target; } : undefined}>\n {listContent}\n </div>\n </ResizablePanel>\n {showDetail && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel id=\"detail\" minSize=\"30%\">\n <div ref={paneRef} data-pane=\"detail\" className={cn(\"h-full min-h-0 flex flex-col\", itemSurface)} onKeyDown={hiding ? onPaneKeyDown : undefined}>\n {paneBar}\n <div className=\"flex-1 min-h-0 overflow-y-auto\">{detailContent}</div>\n </div>\n </ResizablePanel>\n </>\n )}\n {showAside && !asideCollapsed && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel id=\"aside\" defaultSize={`${asideWidth}%`} minSize=\"15%\">\n {/* the Drawer's body inset, so the aside's content sits where it will in the Drawer (Sprint 25.14 A36) */}\n <div data-pane=\"aside\" className={cn(\"h-full min-h-0 overflow-y-auto py-ds-5 px-[var(--ds-page-gutter)]\", itemSurface)}><SurfaceBoundary pane>{aside}</SurfaceBoundary></div>\n </ResizablePanel>\n </>\n )}\n </ResizablePanelGroup>\n {showAside && asideCollapsed && (\n <Drawer open={asideOpen} onClose={() => setAsideWantsOpen(false)} title={asideTitle} position=\"right\">\n {aside}\n </Drawer>\n )}\n </div>\n );\n}\n"]}
|
package/dist/roots.css
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
tailwindcss still gets preflight (base) under the components layer and the utilities over it. */
|
|
3
3
|
@layer theme, base, components, utilities;
|
|
4
4
|
|
|
5
|
+
/* A table row's tint (Sprint 25.13 A35), registered as a colour so it can be animated: a row's pinned cells paint it over
|
|
6
|
+
their solid ground while the other cells show the row's own background, and the two fade in together when the row is
|
|
7
|
+
hovered or selected. Unregistered, the pinned cells changed at once and the rest faded in after them (the owner, 30
|
|
8
|
+
September 2026: "a tiny delay in setting each side"). */
|
|
9
|
+
@property --gs-row-tint {
|
|
10
|
+
syntax: "<color>";
|
|
11
|
+
inherits: true;
|
|
12
|
+
initial-value: transparent;
|
|
13
|
+
}
|
|
14
|
+
|
|
5
15
|
/* ==========================================================================
|
|
6
16
|
Root Control Engine
|
|
7
17
|
Derives all design tokens from user-configurable root values.
|
|
@@ -228,6 +238,13 @@
|
|
|
228
238
|
spacing below it so call sites don't hand-add margins. */
|
|
229
239
|
--ds-heading-gap: var(--ds-space-4);
|
|
230
240
|
|
|
241
|
+
/* The page's gutter: PageContainer's default inline padding, and the inset of an overlay's header, body and footer
|
|
242
|
+
(Drawer, Sheet, Dialog) and of SplitView's aside, so they line up with each other and with the page (Sprint 25.14
|
|
243
|
+
A36, D34). The theme's space-6: 21 px on a phone at the default density, 21–24 px on a desktop, more on a roomier
|
|
244
|
+
theme (run 75's is 27 px on a phone). A theme whose header floats insets a phone's page column less, and an overlay
|
|
245
|
+
keeps this. */
|
|
246
|
+
--ds-page-gutter: var(--ds-space-6);
|
|
247
|
+
|
|
231
248
|
/* ── L1: Density & Breakpoints ─────────────────────────────────── */
|
|
232
249
|
|
|
233
250
|
--ds-density: 1;
|
|
@@ -429,8 +446,10 @@
|
|
|
429
446
|
--ds-tab-active-bg: var(--ds-bg-surface);
|
|
430
447
|
|
|
431
448
|
--ds-input-bg: oklch(1 0 0);
|
|
432
|
-
|
|
433
|
-
|
|
449
|
+
/* Sprint 25.14 A20: a control's edge at 3:1 against every ground it sits on (the page, a card, a muted strip such as a
|
|
450
|
+
table's header, a raised panel); hovered, further from them */
|
|
451
|
+
--ds-input-border: oklch(0.615 calc(0.010 * var(--ds-sat-neutral)) var(--ds-hue-neutral));
|
|
452
|
+
--ds-input-border-hover: var(--ds-neutral-500);
|
|
434
453
|
--ds-input-focus-ring: var(--ds-ring-active);
|
|
435
454
|
--ds-input-shadow: 0 0 #0000;
|
|
436
455
|
|
|
@@ -551,8 +570,9 @@
|
|
|
551
570
|
|
|
552
571
|
/* Inputs */
|
|
553
572
|
--ds-input-bg: var(--ds-neutral-800);
|
|
554
|
-
|
|
555
|
-
--ds-input-border
|
|
573
|
+
/* Sprint 25.14 A20: 3:1 against every ground, the lightest being a muted strip or a raised panel (between 400 and 500) */
|
|
574
|
+
--ds-input-border: oklch(0.645 calc(0.008 * var(--ds-sat-neutral)) var(--ds-hue-neutral));
|
|
575
|
+
--ds-input-border-hover: var(--ds-neutral-400);
|
|
556
576
|
|
|
557
577
|
/* Shadows — amplified alpha so they're visible on dark surfaces */
|
|
558
578
|
--ds-shadow-sm:
|