gridsmith-ui 0.9.0 → 0.9.1
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/charts.d.ts +22 -12
- package/dist/charts.js +84 -14
- package/dist/charts.js.map +1 -1
- package/dist/chat.js +4 -3
- package/dist/chat.js.map +1 -1
- package/dist/{chunk-RLNIRPOH.js → chunk-CQADS7JZ.js} +5 -45
- package/dist/chunk-CQADS7JZ.js.map +1 -0
- package/dist/{chunk-X27PSHOH.js → chunk-ENBESZS2.js} +3 -3
- package/dist/{chunk-X27PSHOH.js.map → chunk-ENBESZS2.js.map} +1 -1
- package/dist/chunk-FDIFQ5UF.js +67 -0
- package/dist/chunk-FDIFQ5UF.js.map +1 -0
- package/dist/{chunk-PHQWHAT3.js → chunk-OVVRMMCO.js} +3 -3
- package/dist/{chunk-PHQWHAT3.js.map → chunk-OVVRMMCO.js.map} +1 -1
- package/dist/chunk-PKLVP5ZB.js +49 -0
- package/dist/chunk-PKLVP5ZB.js.map +1 -0
- package/dist/chunk-RG4KUCRS.js +9 -0
- package/dist/chunk-RG4KUCRS.js.map +1 -0
- package/dist/chunk-Z37HO5NU.js +950 -0
- package/dist/chunk-Z37HO5NU.js.map +1 -0
- package/dist/data-grid.js +14 -10
- package/dist/data-grid.js.map +1 -1
- package/dist/index.d.ts +34 -54
- package/dist/index.js +1038 -1746
- package/dist/index.js.map +1 -1
- package/dist/kanban.d.ts +7 -1
- package/dist/kanban.js +23 -6
- package/dist/kanban.js.map +1 -1
- package/dist/resizable.d.ts +48 -2
- package/dist/resizable.js +151 -4
- package/dist/resizable.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-5B2ZFL2H.js +0 -89
- package/dist/chunk-5B2ZFL2H.js.map +0 -1
- package/dist/chunk-PDZL4A6K.js +0 -38
- package/dist/chunk-PDZL4A6K.js.map +0 -1
- package/dist/chunk-RLNIRPOH.js.map +0 -1
package/dist/kanban.d.ts
CHANGED
|
@@ -18,8 +18,14 @@ interface KanbanBoardProps {
|
|
|
18
18
|
columns: KanbanColumn[];
|
|
19
19
|
onColumnsChange?: (columns: KanbanColumn[]) => void;
|
|
20
20
|
renderCard?: (card: KanbanCard) => ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* Opens a card (a detail drawer, a route). The board's own card surface is the control: click, or Enter with the
|
|
23
|
+
* card focused, opens it; Space picks the card up for a keyboard drag. Never wire a clickable element inside
|
|
24
|
+
* renderCard — a role="button" div fights the drag listeners and the judge cites it (Sprint 25.4 K-1).
|
|
25
|
+
*/
|
|
26
|
+
onCardClick?: (card: KanbanCard) => void;
|
|
21
27
|
className?: string;
|
|
22
28
|
}
|
|
23
|
-
declare function KanbanBoard({ columns: controlledCols, onColumnsChange, renderCard, className, }: KanbanBoardProps): react_jsx_runtime.JSX.Element;
|
|
29
|
+
declare function KanbanBoard({ columns: controlledCols, onColumnsChange, renderCard, onCardClick, className, }: KanbanBoardProps): react_jsx_runtime.JSX.Element;
|
|
24
30
|
|
|
25
31
|
export { KanbanBoard };
|
package/dist/kanban.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Badge } from './chunk-
|
|
2
|
-
import { useTextOverflow, Tooltip } from './chunk-
|
|
1
|
+
import { Badge } from './chunk-OVVRMMCO.js';
|
|
2
|
+
import { useTextOverflow, Tooltip } from './chunk-CQADS7JZ.js';
|
|
3
|
+
import './chunk-PKLVP5ZB.js';
|
|
3
4
|
import './chunk-WH2FUFAC.js';
|
|
4
5
|
import { Icon } from './chunk-X4CNZFWC.js';
|
|
5
6
|
import { cn } from './chunk-4KVFH5KC.js';
|
|
@@ -11,7 +12,8 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
11
12
|
|
|
12
13
|
function SortableCard({
|
|
13
14
|
card,
|
|
14
|
-
renderCard
|
|
15
|
+
renderCard,
|
|
16
|
+
onCardClick
|
|
15
17
|
}) {
|
|
16
18
|
const {
|
|
17
19
|
attributes,
|
|
@@ -32,9 +34,20 @@ function SortableCard({
|
|
|
32
34
|
style,
|
|
33
35
|
...attributes,
|
|
34
36
|
...listeners,
|
|
37
|
+
onClick: onCardClick ? () => onCardClick(card) : void 0,
|
|
38
|
+
onKeyDown: (e) => {
|
|
39
|
+
if (onCardClick && e.key === "Enter") {
|
|
40
|
+
e.preventDefault();
|
|
41
|
+
onCardClick(card);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
listeners?.onKeyDown?.(e);
|
|
45
|
+
},
|
|
46
|
+
"data-kanban-card": card.id,
|
|
35
47
|
className: cn(
|
|
36
48
|
"rounded-[var(--ds-radius-md)] border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
37
|
-
"bg-[var(--ds-bg-surface)] p-ds-3
|
|
49
|
+
"bg-[var(--ds-bg-surface)] p-ds-3 active:cursor-grabbing",
|
|
50
|
+
onCardClick ? "cursor-pointer" : "cursor-grab",
|
|
38
51
|
"shadow-[var(--ds-shadow-button)]",
|
|
39
52
|
"transition-shadow duration-[var(--ds-transition-speed)]",
|
|
40
53
|
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
@@ -83,6 +96,7 @@ function KanbanBoard({
|
|
|
83
96
|
columns: controlledCols,
|
|
84
97
|
onColumnsChange,
|
|
85
98
|
renderCard,
|
|
99
|
+
onCardClick,
|
|
86
100
|
className
|
|
87
101
|
}) {
|
|
88
102
|
const [internalCols, setInternalCols] = useState(controlledCols);
|
|
@@ -101,7 +115,9 @@ function KanbanBoard({
|
|
|
101
115
|
const sensors = useSensors(
|
|
102
116
|
useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
|
|
103
117
|
useSensor(KeyboardSensor, {
|
|
104
|
-
coordinateGetter: sortableKeyboardCoordinates
|
|
118
|
+
coordinateGetter: sortableKeyboardCoordinates,
|
|
119
|
+
// Space picks up and drops; Enter is the card's open key (onCardClick)
|
|
120
|
+
keyboardCodes: { start: ["Space"], cancel: ["Escape"], end: ["Space"] }
|
|
105
121
|
})
|
|
106
122
|
);
|
|
107
123
|
const findColumnByCardId = (cardId) => columns.find((col) => col.cards.some((c) => c.id === cardId));
|
|
@@ -204,7 +220,8 @@ function KanbanBoard({
|
|
|
204
220
|
SortableCard,
|
|
205
221
|
{
|
|
206
222
|
card,
|
|
207
|
-
renderCard
|
|
223
|
+
renderCard,
|
|
224
|
+
onCardClick
|
|
208
225
|
},
|
|
209
226
|
card.id
|
|
210
227
|
)) })
|
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 { useState, type ReactNode } from \"react\";\nimport {\n DndContext,\n closestCorners,\n KeyboardSensor,\n PointerSensor,\n useSensor,\n useSensors,\n type DragEndEvent,\n type DragOverEvent,\n DragOverlay,\n type DragStartEvent,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\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 columns: KanbanColumn[];\n onColumnsChange?: (columns: KanbanColumn[]) => void;\n renderCard?: (card: KanbanCard) => ReactNode;\n className?: string;\n}\n\nfunction SortableCard({\n card,\n renderCard,\n}: {\n card: KanbanCard;\n renderCard?: (card: KanbanCard) => ReactNode;\n}) {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id: card.id });\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 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 cursor-grab active:cursor-grabbing\",\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 isDragging && \"opacity-30 scale-[1.02]\",\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 \"rotate-2\",\n )}\n >\n {renderCard ? renderCard(card) : <DefaultCard card={card} />}\n </div>\n );\n}\n\nexport function KanbanBoard({\n columns: controlledCols,\n onColumnsChange,\n renderCard,\n className,\n}: KanbanBoardProps) {\n const [internalCols, setInternalCols] = useState<KanbanColumn[]>(controlledCols);\n const columns = onColumnsChange ? controlledCols : internalCols;\n const setCols = (next: KanbanColumn[] | ((prev: KanbanColumn[]) => KanbanColumn[])) => {\n if (typeof next === \"function\") {\n const updated = next(columns);\n if (onColumnsChange) onColumnsChange(updated);\n else setInternalCols(updated);\n } else {\n if (onColumnsChange) onColumnsChange(next);\n else setInternalCols(next);\n }\n };\n\n const [activeCard, setActiveCard] = useState<KanbanCard | null>(null);\n\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\n }),\n );\n\n const findColumnByCardId = (cardId: string) =>\n columns.find((col) => col.cards.some((c) => c.id === cardId));\n\n const handleDragStart = (event: DragStartEvent) => {\n const col = findColumnByCardId(String(event.active.id));\n const card = col?.cards.find((c) => c.id === String(event.active.id));\n if (card) setActiveCard(card);\n };\n\n const handleDragOver = (event: DragOverEvent) => {\n const { active, over } = event;\n if (!over) return;\n\n const activeId = String(active.id);\n const overId = String(over.id);\n if (activeId === overId) return;\n\n const activeCol = findColumnByCardId(activeId);\n const overCol =\n findColumnByCardId(overId) ?? columns.find((c) => c.id === overId);\n\n if (!activeCol || !overCol || activeCol.id === overCol.id) return;\n\n setCols((prev) =>\n prev.map((col) => {\n if (col.id === activeCol.id) {\n return { ...col, cards: col.cards.filter((c) => c.id !== activeId) };\n }\n if (col.id === overCol.id) {\n const card = activeCol.cards.find((c) => c.id === activeId);\n if (!card) return col;\n const overIdx = col.cards.findIndex((c) => c.id === overId);\n const newCards = [...col.cards];\n if (overIdx >= 0) {\n newCards.splice(overIdx, 0, card);\n } else {\n newCards.push(card);\n }\n return { ...col, cards: newCards };\n }\n return col;\n }),\n );\n };\n\n const handleDragEnd = (event: DragEndEvent) => {\n const { active, over } = event;\n setActiveCard(null);\n if (!over || active.id === over.id) return;\n\n const activeId = String(active.id);\n const overId = String(over.id);\n\n const col = findColumnByCardId(activeId);\n if (!col) return;\n\n const oldIdx = col.cards.findIndex((c) => c.id === activeId);\n const newIdx = col.cards.findIndex((c) => c.id === overId);\n\n if (oldIdx >= 0 && newIdx >= 0 && oldIdx !== newIdx) {\n setCols((prev) =>\n prev.map((c) => {\n if (c.id !== col.id) return c;\n const newCards = [...c.cards];\n const [moved] = newCards.splice(oldIdx, 1);\n newCards.splice(newIdx, 0, moved);\n return { ...c, cards: newCards };\n }),\n );\n }\n };\n\n return (\n <DndContext\n sensors={sensors}\n collisionDetection={closestCorners}\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDragEnd={handleDragEnd}\n >\n <div 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 <div\n key={col.id}\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 className=\"flex flex-col gap-ds-2.5 px-ds-3 pb-ds-3 min-h-[60px]\">\n {col.cards.map((card) => (\n <SortableCard\n key={card.id}\n card={card}\n renderCard={renderCard}\n />\n ))}\n </div>\n </SortableContext>\n </div>\n ))}\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 { useState, type ReactNode } from \"react\";\nimport {\n DndContext,\n closestCorners,\n KeyboardSensor,\n PointerSensor,\n useSensor,\n useSensors,\n type DragEndEvent,\n type DragOverEvent,\n DragOverlay,\n type DragStartEvent,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\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 columns: KanbanColumn[];\n onColumnsChange?: (columns: KanbanColumn[]) => void;\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}: {\n card: KanbanCard;\n renderCard?: (card: KanbanCard) => ReactNode;\n onCardClick?: (card: KanbanCard) => void;\n}) {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id: card.id });\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 isDragging && \"opacity-30 scale-[1.02]\",\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 \"rotate-2\",\n )}\n >\n {renderCard ? renderCard(card) : <DefaultCard card={card} />}\n </div>\n );\n}\n\nexport function KanbanBoard({\n columns: controlledCols,\n onColumnsChange,\n renderCard,\n onCardClick,\n className,\n}: KanbanBoardProps) {\n const [internalCols, setInternalCols] = useState<KanbanColumn[]>(controlledCols);\n const columns = onColumnsChange ? controlledCols : internalCols;\n const setCols = (next: KanbanColumn[] | ((prev: KanbanColumn[]) => KanbanColumn[])) => {\n if (typeof next === \"function\") {\n const updated = next(columns);\n if (onColumnsChange) onColumnsChange(updated);\n else setInternalCols(updated);\n } else {\n if (onColumnsChange) onColumnsChange(next);\n else setInternalCols(next);\n }\n };\n\n const [activeCard, setActiveCard] = useState<KanbanCard | null>(null);\n\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\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\n const findColumnByCardId = (cardId: string) =>\n columns.find((col) => col.cards.some((c) => c.id === cardId));\n\n const handleDragStart = (event: DragStartEvent) => {\n const col = findColumnByCardId(String(event.active.id));\n const card = col?.cards.find((c) => c.id === String(event.active.id));\n if (card) setActiveCard(card);\n };\n\n const handleDragOver = (event: DragOverEvent) => {\n const { active, over } = event;\n if (!over) return;\n\n const activeId = String(active.id);\n const overId = String(over.id);\n if (activeId === overId) return;\n\n const activeCol = findColumnByCardId(activeId);\n const overCol =\n findColumnByCardId(overId) ?? columns.find((c) => c.id === overId);\n\n if (!activeCol || !overCol || activeCol.id === overCol.id) return;\n\n setCols((prev) =>\n prev.map((col) => {\n if (col.id === activeCol.id) {\n return { ...col, cards: col.cards.filter((c) => c.id !== activeId) };\n }\n if (col.id === overCol.id) {\n const card = activeCol.cards.find((c) => c.id === activeId);\n if (!card) return col;\n const overIdx = col.cards.findIndex((c) => c.id === overId);\n const newCards = [...col.cards];\n if (overIdx >= 0) {\n newCards.splice(overIdx, 0, card);\n } else {\n newCards.push(card);\n }\n return { ...col, cards: newCards };\n }\n return col;\n }),\n );\n };\n\n const handleDragEnd = (event: DragEndEvent) => {\n const { active, over } = event;\n setActiveCard(null);\n if (!over || active.id === over.id) return;\n\n const activeId = String(active.id);\n const overId = String(over.id);\n\n const col = findColumnByCardId(activeId);\n if (!col) return;\n\n const oldIdx = col.cards.findIndex((c) => c.id === activeId);\n const newIdx = col.cards.findIndex((c) => c.id === overId);\n\n if (oldIdx >= 0 && newIdx >= 0 && oldIdx !== newIdx) {\n setCols((prev) =>\n prev.map((c) => {\n if (c.id !== col.id) return c;\n const newCards = [...c.cards];\n const [moved] = newCards.splice(oldIdx, 1);\n newCards.splice(newIdx, 0, moved);\n return { ...c, cards: newCards };\n }),\n );\n }\n };\n\n return (\n <DndContext\n sensors={sensors}\n collisionDetection={closestCorners}\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDragEnd={handleDragEnd}\n >\n <div 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 <div\n key={col.id}\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 className=\"flex flex-col gap-ds-2.5 px-ds-3 pb-ds-3 min-h-[60px]\">\n {col.cards.map((card) => (\n <SortableCard\n key={card.id}\n card={card}\n renderCard={renderCard}\n onCardClick={onCardClick}\n />\n ))}\n </div>\n </SortableContext>\n </div>\n ))}\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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { Separator, Panel, Group } from 'react-resizable-panels';
|
|
3
|
-
import { ComponentProps } from 'react';
|
|
3
|
+
import { ComponentProps, ReactNode } from 'react';
|
|
4
4
|
|
|
5
5
|
type PanelGroupProps = ComponentProps<typeof Group>;
|
|
6
6
|
type Direction = "horizontal" | "vertical";
|
|
@@ -36,4 +36,50 @@ interface ResizableHandleProps extends Omit<PanelResizeHandleProps, "className">
|
|
|
36
36
|
}
|
|
37
37
|
declare function ResizableHandle({ withHandle, className, ...props }: ResizableHandleProps): react_jsx_runtime.JSX.Element;
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
type SplitViewFrame = "fill" | "page";
|
|
40
|
+
interface SplitViewProps {
|
|
41
|
+
/** The list (an inbox, a queue): it scrolls on its own. */
|
|
42
|
+
list: ReactNode;
|
|
43
|
+
/** The selected item (a thread, a record): it fills the height and scrolls on its own. */
|
|
44
|
+
detail: ReactNode;
|
|
45
|
+
/** 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`. */
|
|
46
|
+
aside?: ReactNode;
|
|
47
|
+
/** Names the aside's toggle and Drawer. */
|
|
48
|
+
asideTitle?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Below `collapseBelow` the list shows alone; with `detailOpen` the detail replaces it, with a Back button that calls
|
|
51
|
+
* `onDetailClose` (detailMode "stack"). The page owns the selection, so it owns this flag.
|
|
52
|
+
*/
|
|
53
|
+
detailOpen?: boolean;
|
|
54
|
+
onDetailClose?: () => void;
|
|
55
|
+
/** "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. */
|
|
56
|
+
detailMode?: "stack" | "route";
|
|
57
|
+
backLabel?: string;
|
|
58
|
+
/** Percent of the width the list takes; the divider is draggable. */
|
|
59
|
+
listWidth?: number;
|
|
60
|
+
listMinWidth?: number;
|
|
61
|
+
asideWidth?: number;
|
|
62
|
+
/** Below this width of the layout itself (px) the list and detail stop sitting side by side. */
|
|
63
|
+
collapseBelow?: number;
|
|
64
|
+
/** Below this width of the layout itself (px) the aside becomes a toggle. */
|
|
65
|
+
asideCollapseBelow?: number;
|
|
66
|
+
/** A bordered, rounded surface (inside a page with padding) instead of edge to edge (filling <main>). */
|
|
67
|
+
bordered?: boolean;
|
|
68
|
+
/** "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. */
|
|
69
|
+
frame?: SplitViewFrame;
|
|
70
|
+
"aria-label"?: string;
|
|
71
|
+
className?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The reading-pane composition (Sprint 25.2, R3): one surface with dividers —
|
|
75
|
+
* list, detail and an optional aside — that fills the height it is given (an
|
|
76
|
+
* AppShell's <main> already gives it) and never three cards with gaps. The
|
|
77
|
+
* panels compose ResizablePanelGroup, so the dividers drag. Below the collapse
|
|
78
|
+
* width, measured on the layout itself, the list shows alone and the detail
|
|
79
|
+
* stacks over it (or the app routes to it); the aside collapses to a toggle.
|
|
80
|
+
* The page owns the selection and assembles the contents; keyboard movement
|
|
81
|
+
* through the list is the list's job (StackedList selectedId).
|
|
82
|
+
*/
|
|
83
|
+
declare function SplitView({ list, detail, aside, asideTitle, detailOpen, onDetailClose, detailMode, backLabel, listWidth, listMinWidth, asideWidth, collapseBelow, asideCollapseBelow, bordered, frame, "aria-label": ariaLabel, className, }: SplitViewProps): react_jsx_runtime.JSX.Element;
|
|
84
|
+
|
|
85
|
+
export { ResizableHandle, ResizablePanel, ResizablePanelGroup, SplitView, type SplitViewFrame, type SplitViewProps };
|
package/dist/resizable.js
CHANGED
|
@@ -1,6 +1,153 @@
|
|
|
1
|
-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
1
|
+
import { useCompact, useAppShell, Button, Drawer } from './chunk-Z37HO5NU.js';
|
|
2
|
+
import './chunk-RLUK575N.js';
|
|
3
|
+
import { SplitPaneCtx } from './chunk-RG4KUCRS.js';
|
|
4
|
+
import { useBreakpoint } from './chunk-CRQ6KCRD.js';
|
|
5
|
+
import './chunk-CQADS7JZ.js';
|
|
6
|
+
import './chunk-PKLVP5ZB.js';
|
|
7
|
+
import './chunk-WH2FUFAC.js';
|
|
8
|
+
import { Icon } from './chunk-X4CNZFWC.js';
|
|
9
|
+
import { cn } from './chunk-4KVFH5KC.js';
|
|
10
|
+
import { Group, Panel, Separator } from 'react-resizable-panels';
|
|
11
|
+
import { createContext, useContext, useRef, useState } from 'react';
|
|
12
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
13
|
+
|
|
14
|
+
var DirectionCtx = createContext("horizontal");
|
|
15
|
+
var MobileCtx = createContext(false);
|
|
16
|
+
function ResizablePanelGroup({
|
|
17
|
+
className,
|
|
18
|
+
direction = "horizontal",
|
|
19
|
+
stackOnMobile = true,
|
|
20
|
+
...props
|
|
21
|
+
}) {
|
|
22
|
+
const isMobile = useBreakpoint("sm");
|
|
23
|
+
const shouldStack = stackOnMobile && isMobile && direction === "horizontal";
|
|
24
|
+
const effectiveDirection = shouldStack ? "vertical" : direction;
|
|
25
|
+
return /* @__PURE__ */ jsx(DirectionCtx.Provider, { value: effectiveDirection, children: /* @__PURE__ */ jsx(MobileCtx.Provider, { value: isMobile, children: /* @__PURE__ */ jsx(
|
|
26
|
+
Group,
|
|
27
|
+
{
|
|
28
|
+
className: cn(
|
|
29
|
+
"flex h-full w-full",
|
|
30
|
+
effectiveDirection === "vertical" && "flex-col",
|
|
31
|
+
className
|
|
32
|
+
),
|
|
33
|
+
orientation: effectiveDirection,
|
|
34
|
+
...props
|
|
35
|
+
}
|
|
36
|
+
) }) });
|
|
37
|
+
}
|
|
38
|
+
function ResizablePanel({ className, ...props }) {
|
|
39
|
+
return /* @__PURE__ */ jsx(Panel, { className: cn("", className), ...props });
|
|
40
|
+
}
|
|
41
|
+
function ResizableHandle({
|
|
42
|
+
withHandle,
|
|
43
|
+
className,
|
|
44
|
+
...props
|
|
45
|
+
}) {
|
|
46
|
+
const direction = useContext(DirectionCtx);
|
|
47
|
+
const isMobile = useContext(MobileCtx);
|
|
48
|
+
const isVertical = direction === "vertical";
|
|
49
|
+
return /* @__PURE__ */ jsx(
|
|
50
|
+
Separator,
|
|
51
|
+
{
|
|
52
|
+
className: cn(
|
|
53
|
+
"relative flex items-center justify-center bg-[var(--ds-border-default)]",
|
|
54
|
+
isVertical ? cn(
|
|
55
|
+
"h-[var(--ds-border-width)] w-full after:absolute after:left-0 after:right-0 after:content-['']",
|
|
56
|
+
isMobile ? "after:-top-3 after:-bottom-3" : "after:-top-1 after:-bottom-1"
|
|
57
|
+
) : cn(
|
|
58
|
+
"w-[var(--ds-border-width)] after:absolute after:inset-y-0 after:content-['']",
|
|
59
|
+
isMobile ? "after:-left-3 after:-right-3" : "after:-left-1 after:-right-1"
|
|
60
|
+
),
|
|
61
|
+
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
62
|
+
"[&[data-resize-handle-state=drag]]:bg-[var(--ds-accent-primary)]",
|
|
63
|
+
"[&[data-resize-handle-state=hover]]:bg-[var(--ds-accent-primary)]",
|
|
64
|
+
className
|
|
65
|
+
),
|
|
66
|
+
...props,
|
|
67
|
+
children: withHandle && /* @__PURE__ */ jsx(
|
|
68
|
+
"div",
|
|
69
|
+
{
|
|
70
|
+
className: cn(
|
|
71
|
+
"z-10 flex items-center justify-center rounded-[var(--ds-radius-sm)]",
|
|
72
|
+
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
73
|
+
"bg-[var(--ds-bg-surface)]",
|
|
74
|
+
isVertical ? isMobile ? "h-4 w-8" : "h-3 w-4" : isMobile ? "h-8 w-4" : "h-4 w-3"
|
|
75
|
+
),
|
|
76
|
+
children: /* @__PURE__ */ jsx(
|
|
77
|
+
Icon,
|
|
78
|
+
{
|
|
79
|
+
name: "grip-vertical",
|
|
80
|
+
size: isMobile ? 12 : 10,
|
|
81
|
+
className: cn(
|
|
82
|
+
"text-[var(--ds-text-muted)]",
|
|
83
|
+
isVertical && "rotate-90"
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
function SplitView({
|
|
93
|
+
list,
|
|
94
|
+
detail,
|
|
95
|
+
aside,
|
|
96
|
+
asideTitle = "Details",
|
|
97
|
+
detailOpen = false,
|
|
98
|
+
onDetailClose,
|
|
99
|
+
detailMode = "stack",
|
|
100
|
+
backLabel = "Back",
|
|
101
|
+
listWidth = 35,
|
|
102
|
+
listMinWidth = 25,
|
|
103
|
+
asideWidth = 25,
|
|
104
|
+
collapseBelow = 768,
|
|
105
|
+
asideCollapseBelow = 1024,
|
|
106
|
+
bordered = false,
|
|
107
|
+
frame = "page",
|
|
108
|
+
"aria-label": ariaLabel,
|
|
109
|
+
className
|
|
110
|
+
}) {
|
|
111
|
+
const rootRef = useRef(null);
|
|
112
|
+
const compact = useCompact(rootRef, collapseBelow);
|
|
113
|
+
const asideCollapsed = useCompact(rootRef, asideCollapseBelow);
|
|
114
|
+
const [asideWantsOpen, setAsideWantsOpen] = useState(false);
|
|
115
|
+
const asideOpen = asideCollapsed && asideWantsOpen;
|
|
116
|
+
const region = ariaLabel ? { role: "region", "aria-label": ariaLabel } : {};
|
|
117
|
+
const isFill = frame === "fill";
|
|
118
|
+
const shell = useAppShell();
|
|
119
|
+
const fillStyle = isFill && shell?.hasFooter ? { height: "var(--ds-main-height, 100%)" } : void 0;
|
|
120
|
+
const surface = cn(
|
|
121
|
+
"h-full min-h-0 w-full bg-[var(--ds-bg-surface)]",
|
|
122
|
+
isFill && "rounded-none border-0",
|
|
123
|
+
bordered && !isFill && "border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] rounded-[var(--ds-radius-md)] overflow-hidden",
|
|
124
|
+
className
|
|
125
|
+
);
|
|
126
|
+
if (compact) {
|
|
127
|
+
const showDetail = detailMode === "stack" && detailOpen;
|
|
128
|
+
return /* @__PURE__ */ jsx("div", { ref: rootRef, "data-split-view": showDetail ? "detail" : "list", "data-frame": frame, ...region, className: cn(surface, "flex flex-col"), style: fillStyle, children: showDetail ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
129
|
+
/* @__PURE__ */ jsx("div", { className: "shrink-0 px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", iconLeft: /* @__PURE__ */ jsx(Icon, { name: "arrow-left", size: 14 }), onClick: onDetailClose, children: backLabel }) }),
|
|
130
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: /* @__PURE__ */ jsx(SplitPaneCtx, { value: true, children: detail }) })
|
|
131
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: /* @__PURE__ */ jsx(SplitPaneCtx, { value: true, children: list }) }) });
|
|
132
|
+
}
|
|
133
|
+
const asideToggle = aside && asideCollapsed ? /* @__PURE__ */ jsx("div", { className: "shrink-0 flex justify-end px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", iconLeft: /* @__PURE__ */ jsx(Icon, { name: "info", size: 14 }), onClick: () => setAsideWantsOpen(true), "aria-expanded": asideOpen, children: asideTitle }) }) : null;
|
|
134
|
+
return /* @__PURE__ */ jsxs("div", { ref: rootRef, "data-split-view": "split", "data-frame": frame, ...region, className: surface, style: fillStyle, children: [
|
|
135
|
+
/* @__PURE__ */ jsxs(ResizablePanelGroup, { direction: "horizontal", stackOnMobile: false, className: "h-full", children: [
|
|
136
|
+
/* @__PURE__ */ jsx(ResizablePanel, { id: "list", defaultSize: `${listWidth}%`, minSize: `${listMinWidth}%`, children: /* @__PURE__ */ jsx("div", { "data-pane": "list", className: "h-full min-h-0 overflow-y-auto", children: /* @__PURE__ */ jsx(SplitPaneCtx, { value: true, children: list }) }) }),
|
|
137
|
+
/* @__PURE__ */ jsx(ResizableHandle, { withHandle: true }),
|
|
138
|
+
/* @__PURE__ */ jsx(ResizablePanel, { id: "detail", minSize: "30%", children: /* @__PURE__ */ jsxs("div", { "data-pane": "detail", className: "h-full min-h-0 flex flex-col", children: [
|
|
139
|
+
asideToggle,
|
|
140
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: /* @__PURE__ */ jsx(SplitPaneCtx, { value: true, children: detail }) })
|
|
141
|
+
] }) }),
|
|
142
|
+
aside && !asideCollapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
143
|
+
/* @__PURE__ */ jsx(ResizableHandle, { withHandle: true }),
|
|
144
|
+
/* @__PURE__ */ jsx(ResizablePanel, { id: "aside", defaultSize: `${asideWidth}%`, minSize: "15%", children: /* @__PURE__ */ jsx("div", { "data-pane": "aside", className: "h-full min-h-0 overflow-y-auto p-ds-4", children: /* @__PURE__ */ jsx(SplitPaneCtx, { value: true, children: aside }) }) })
|
|
145
|
+
] })
|
|
146
|
+
] }),
|
|
147
|
+
aside && asideCollapsed && /* @__PURE__ */ jsx(Drawer, { open: asideOpen, onClose: () => setAsideWantsOpen(false), title: asideTitle, position: "right", children: aside })
|
|
148
|
+
] });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export { ResizableHandle, ResizablePanel, ResizablePanelGroup, SplitView };
|
|
5
152
|
//# sourceMappingURL=resizable.js.map
|
|
6
153
|
//# sourceMappingURL=resizable.js.map
|
package/dist/resizable.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"resizable.js"}
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/components/ResizablePanels.tsx","../../../showcase/src/components/SplitView.tsx"],"names":["PanelGroup","PanelResizeHandle","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 { useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useCompact } 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\";\n\nexport type SplitViewFrame = \"fill\" | \"page\";\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 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 /** 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 backLabel = \"Back\",\n listWidth = 35,\n listMinWidth = 25,\n asideWidth = 25,\n collapseBelow = 768,\n asideCollapseBelow = 1024,\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);\n const asideCollapsed = useCompact(rootRef, asideCollapseBelow);\n const [asideWantsOpen, setAsideWantsOpen] = useState(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 const surface = cn(\n \"h-full min-h-0 w-full 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 if (compact) {\n const showDetail = detailMode === \"stack\" && detailOpen;\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 <>\n <div className=\"shrink-0 px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\">\n <Button variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"arrow-left\" size={14} />} onClick={onDetailClose}>{backLabel}</Button>\n </div>\n <div className=\"flex-1 min-h-0 overflow-y-auto\"><SplitPaneCtx value={true}>{detail}</SplitPaneCtx></div>\n </>\n ) : (\n <div className=\"flex-1 min-h-0 overflow-y-auto\"><SplitPaneCtx value={true}>{list}</SplitPaneCtx></div>\n )}\n </div>\n );\n }\n\n const asideToggle = aside && asideCollapsed ? (\n <div className=\"shrink-0 flex justify-end px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\">\n <Button variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"info\" size={14} />} onClick={() => setAsideWantsOpen(true)} aria-expanded={asideOpen}>{asideTitle}</Button>\n </div>\n ) : null;\n\n return (\n <div ref={rootRef} data-split-view=\"split\" data-frame={frame} {...region} className={surface} style={fillStyle}>\n <ResizablePanelGroup direction=\"horizontal\" stackOnMobile={false} className=\"h-full\">\n <ResizablePanel id=\"list\" defaultSize={`${listWidth}%`} minSize={`${listMinWidth}%`}>\n <div data-pane=\"list\" className=\"h-full min-h-0 overflow-y-auto\"><SplitPaneCtx value={true}>{list}</SplitPaneCtx></div>\n </ResizablePanel>\n <ResizableHandle withHandle />\n <ResizablePanel id=\"detail\" minSize=\"30%\">\n <div data-pane=\"detail\" className=\"h-full min-h-0 flex flex-col\">\n {asideToggle}\n <div className=\"flex-1 min-h-0 overflow-y-auto\"><SplitPaneCtx value={true}>{detail}</SplitPaneCtx></div>\n </div>\n </ResizablePanel>\n {aside && !asideCollapsed && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel id=\"aside\" defaultSize={`${asideWidth}%`} minSize=\"15%\">\n <div data-pane=\"aside\" className=\"h-full min-h-0 overflow-y-auto p-ds-4\"><SplitPaneCtx value={true}>{aside}</SplitPaneCtx></div>\n </ResizablePanel>\n </>\n )}\n </ResizablePanelGroup>\n {aside && asideCollapsed && (\n <Drawer open={asideOpen} onClose={() => setAsideWantsOpen(false)} title={asideTitle} position=\"right\">\n {aside}\n </Drawer>\n )}\n </div>\n );\n}\n"]}
|
package/package.json
CHANGED
package/dist/chunk-5B2ZFL2H.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { useBreakpoint } from './chunk-CRQ6KCRD.js';
|
|
2
|
-
import { Icon } from './chunk-X4CNZFWC.js';
|
|
3
|
-
import { cn } from './chunk-4KVFH5KC.js';
|
|
4
|
-
import { Group, Panel, Separator } from 'react-resizable-panels';
|
|
5
|
-
import { createContext, useContext } from 'react';
|
|
6
|
-
import { jsx } from 'react/jsx-runtime';
|
|
7
|
-
|
|
8
|
-
var DirectionCtx = createContext("horizontal");
|
|
9
|
-
var MobileCtx = createContext(false);
|
|
10
|
-
function ResizablePanelGroup({
|
|
11
|
-
className,
|
|
12
|
-
direction = "horizontal",
|
|
13
|
-
stackOnMobile = true,
|
|
14
|
-
...props
|
|
15
|
-
}) {
|
|
16
|
-
const isMobile = useBreakpoint("sm");
|
|
17
|
-
const shouldStack = stackOnMobile && isMobile && direction === "horizontal";
|
|
18
|
-
const effectiveDirection = shouldStack ? "vertical" : direction;
|
|
19
|
-
return /* @__PURE__ */ jsx(DirectionCtx.Provider, { value: effectiveDirection, children: /* @__PURE__ */ jsx(MobileCtx.Provider, { value: isMobile, children: /* @__PURE__ */ jsx(
|
|
20
|
-
Group,
|
|
21
|
-
{
|
|
22
|
-
className: cn(
|
|
23
|
-
"flex h-full w-full",
|
|
24
|
-
effectiveDirection === "vertical" && "flex-col",
|
|
25
|
-
className
|
|
26
|
-
),
|
|
27
|
-
orientation: effectiveDirection,
|
|
28
|
-
...props
|
|
29
|
-
}
|
|
30
|
-
) }) });
|
|
31
|
-
}
|
|
32
|
-
function ResizablePanel({ className, ...props }) {
|
|
33
|
-
return /* @__PURE__ */ jsx(Panel, { className: cn("", className), ...props });
|
|
34
|
-
}
|
|
35
|
-
function ResizableHandle({
|
|
36
|
-
withHandle,
|
|
37
|
-
className,
|
|
38
|
-
...props
|
|
39
|
-
}) {
|
|
40
|
-
const direction = useContext(DirectionCtx);
|
|
41
|
-
const isMobile = useContext(MobileCtx);
|
|
42
|
-
const isVertical = direction === "vertical";
|
|
43
|
-
return /* @__PURE__ */ jsx(
|
|
44
|
-
Separator,
|
|
45
|
-
{
|
|
46
|
-
className: cn(
|
|
47
|
-
"relative flex items-center justify-center bg-[var(--ds-border-default)]",
|
|
48
|
-
isVertical ? cn(
|
|
49
|
-
"h-[var(--ds-border-width)] w-full after:absolute after:left-0 after:right-0 after:content-['']",
|
|
50
|
-
isMobile ? "after:-top-3 after:-bottom-3" : "after:-top-1 after:-bottom-1"
|
|
51
|
-
) : cn(
|
|
52
|
-
"w-[var(--ds-border-width)] after:absolute after:inset-y-0 after:content-['']",
|
|
53
|
-
isMobile ? "after:-left-3 after:-right-3" : "after:-left-1 after:-right-1"
|
|
54
|
-
),
|
|
55
|
-
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
56
|
-
"[&[data-resize-handle-state=drag]]:bg-[var(--ds-accent-primary)]",
|
|
57
|
-
"[&[data-resize-handle-state=hover]]:bg-[var(--ds-accent-primary)]",
|
|
58
|
-
className
|
|
59
|
-
),
|
|
60
|
-
...props,
|
|
61
|
-
children: withHandle && /* @__PURE__ */ jsx(
|
|
62
|
-
"div",
|
|
63
|
-
{
|
|
64
|
-
className: cn(
|
|
65
|
-
"z-10 flex items-center justify-center rounded-[var(--ds-radius-sm)]",
|
|
66
|
-
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
67
|
-
"bg-[var(--ds-bg-surface)]",
|
|
68
|
-
isVertical ? isMobile ? "h-4 w-8" : "h-3 w-4" : isMobile ? "h-8 w-4" : "h-4 w-3"
|
|
69
|
-
),
|
|
70
|
-
children: /* @__PURE__ */ jsx(
|
|
71
|
-
Icon,
|
|
72
|
-
{
|
|
73
|
-
name: "grip-vertical",
|
|
74
|
-
size: isMobile ? 12 : 10,
|
|
75
|
-
className: cn(
|
|
76
|
-
"text-[var(--ds-text-muted)]",
|
|
77
|
-
isVertical && "rotate-90"
|
|
78
|
-
)
|
|
79
|
-
}
|
|
80
|
-
)
|
|
81
|
-
}
|
|
82
|
-
)
|
|
83
|
-
}
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export { ResizableHandle, ResizablePanel, ResizablePanelGroup };
|
|
88
|
-
//# sourceMappingURL=chunk-5B2ZFL2H.js.map
|
|
89
|
-
//# sourceMappingURL=chunk-5B2ZFL2H.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../showcase/src/components/ResizablePanels.tsx"],"names":["PanelGroup","PanelResizeHandle"],"mappings":";;;;;;;AAaA,IAAM,YAAA,GAAe,cAAyB,YAAY,CAAA;AAC1D,IAAM,SAAA,GAAY,cAAc,KAAK,CAAA;AAa9B,SAAS,mBAAA,CAAoB;AAAA,EAClC,SAAA;AAAA,EACA,SAAA,GAAY,YAAA;AAAA,EACZ,aAAA,GAAgB,IAAA;AAAA,EAChB,GAAG;AACL,CAAA,EAA6B;AAC3B,EAAA,MAAM,QAAA,GAAW,cAAc,IAAI,CAAA;AACnC,EAAA,MAAM,WAAA,GAAc,aAAA,IAAiB,QAAA,IAAY,SAAA,KAAc,YAAA;AAC/D,EAAA,MAAM,kBAAA,GAAqB,cAAc,UAAA,GAAa,SAAA;AAEtD,EAAA,uBACE,GAAA,CAAC,YAAA,CAAa,QAAA,EAAb,EAAsB,KAAA,EAAO,kBAAA,EAC5B,QAAA,kBAAA,GAAA,CAAC,SAAA,CAAU,QAAA,EAAV,EAAmB,KAAA,EAAO,QAAA,EACzB,QAAA,kBAAA,GAAA;AAAA,IAACA,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,oBAAA;AAAA,QACA,uBAAuB,UAAA,IAAc,UAAA;AAAA,QACrC;AAAA,OACF;AAAA,MACA,WAAA,EAAa,kBAAA;AAAA,MACZ,GAAG;AAAA;AAAA,KAER,CAAA,EACF,CAAA;AAEJ;AAcO,SAAS,cAAA,CAAe,EAAE,SAAA,EAAW,GAAG,OAAM,EAAwB;AAC3E,EAAA,uBAAO,GAAA,CAAC,SAAM,SAAA,EAAW,EAAA,CAAG,IAAI,SAAS,CAAA,EAAI,GAAG,KAAA,EAAO,CAAA;AACzD;AAUO,SAAS,eAAA,CAAgB;AAAA,EAC9B,UAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAyB;AACvB,EAAA,MAAM,SAAA,GAAY,WAAW,YAAY,CAAA;AACzC,EAAA,MAAM,QAAA,GAAW,WAAW,SAAS,CAAA;AACrC,EAAA,MAAM,aAAa,SAAA,KAAc,UAAA;AAEjC,EAAA,uBACE,GAAA;AAAA,IAACC,SAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,yEAAA;AAAA,QACA,UAAA,GACI,EAAA;AAAA,UACE,gGAAA;AAAA,UACA,WAAW,8BAAA,GAAiC;AAAA,SAC9C,GACA,EAAA;AAAA,UACE,8EAAA;AAAA,UACA,WAAW,8BAAA,GAAiC;AAAA,SAC9C;AAAA,QACJ,0EAAA;AAAA,QACA,kEAAA;AAAA,QACA,mEAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA,UAAA,oBACC,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAW,EAAA;AAAA,YACT,qEAAA;AAAA,YACA,0EAAA;AAAA,YACA,2BAAA;AAAA,YACA,UAAA,GACK,QAAA,GAAW,SAAA,GAAY,SAAA,GACvB,WAAW,SAAA,GAAY;AAAA,WAC9B;AAAA,UAEA,QAAA,kBAAA,GAAA;AAAA,YAAC,IAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,eAAA;AAAA,cACL,IAAA,EAAM,WAAW,EAAA,GAAK,EAAA;AAAA,cACtB,SAAA,EAAW,EAAA;AAAA,gBACT,6BAAA;AAAA,gBACA,UAAA,IAAc;AAAA;AAChB;AAAA;AACF;AAAA;AACF;AAAA,GAEJ;AAEJ","file":"chunk-5B2ZFL2H.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"]}
|
package/dist/chunk-PDZL4A6K.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// ../../showcase/src/lib/table-utils.ts
|
|
2
|
-
var DATE_ISO = /^\d{4}-\d{2}-\d{2}$/;
|
|
3
|
-
var DATE_US = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
|
|
4
|
-
var DATE_TEXT_MDY = /^[A-Z][a-z]{2}\s+\d{1,2},?\s+\d{4}$/;
|
|
5
|
-
var DATE_TEXT_DMY = /^\d{1,2}\s+[A-Z][a-z]{2}\s+\d{4}$/;
|
|
6
|
-
var NUMBER_RE = /^[$€£¥]?\s?[\d,]+\.?\d*%?$/;
|
|
7
|
-
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
8
|
-
function isDate(v) {
|
|
9
|
-
return DATE_ISO.test(v) || DATE_US.test(v) || DATE_TEXT_MDY.test(v) || DATE_TEXT_DMY.test(v);
|
|
10
|
-
}
|
|
11
|
-
function isJsx(v) {
|
|
12
|
-
return typeof v === "object" && v !== null;
|
|
13
|
-
}
|
|
14
|
-
function detectKind(values) {
|
|
15
|
-
const present = values.filter((v) => v != null);
|
|
16
|
-
if (present.length === 0) return void 0;
|
|
17
|
-
if (present.some(isJsx)) return void 0;
|
|
18
|
-
if (present.every((v) => typeof v === "string" && isDate(v))) return "date";
|
|
19
|
-
if (present.every((v) => typeof v === "number")) return "number";
|
|
20
|
-
if (present.every((v) => typeof v === "string" && NUMBER_RE.test(v))) return "number";
|
|
21
|
-
if (present.every((v) => typeof v === "string" && EMAIL_RE.test(v))) return "email";
|
|
22
|
-
if (present.every((v) => typeof v === "string" && v.length <= 20 && !/[\n\r]/.test(v))) return "label";
|
|
23
|
-
return "text";
|
|
24
|
-
}
|
|
25
|
-
function inferColumnKinds(data, columnKeys, maxSample = 50) {
|
|
26
|
-
const sample = data.length > maxSample ? data.slice(0, maxSample) : data;
|
|
27
|
-
const result = /* @__PURE__ */ new Map();
|
|
28
|
-
for (const key of columnKeys) {
|
|
29
|
-
const values = sample.map((row) => row[key]);
|
|
30
|
-
const kind = detectKind(values);
|
|
31
|
-
if (kind) result.set(key, kind);
|
|
32
|
-
}
|
|
33
|
-
return result;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export { inferColumnKinds };
|
|
37
|
-
//# sourceMappingURL=chunk-PDZL4A6K.js.map
|
|
38
|
-
//# sourceMappingURL=chunk-PDZL4A6K.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../showcase/src/lib/table-utils.ts"],"names":[],"mappings":";AAIA,IAAM,QAAA,GAAW,qBAAA;AACjB,IAAM,OAAA,GAAU,2BAAA;AAChB,IAAM,aAAA,GAAgB,qCAAA;AACtB,IAAM,aAAA,GAAgB,mCAAA;AACtB,IAAM,SAAA,GAAY,4BAAA;AAClB,IAAM,QAAA,GAAW,4BAAA;AAEjB,SAAS,OAAO,CAAA,EAAoB;AAClC,EAAA,OAAO,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,IAAK,QAAQ,IAAA,CAAK,CAAC,CAAA,IAAK,aAAA,CAAc,IAAA,CAAK,CAAC,CAAA,IAAK,aAAA,CAAc,KAAK,CAAC,CAAA;AAC7F;AAEA,SAAS,MAAM,CAAA,EAAqB;AAClC,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,KAAM,IAAA;AACxC;AAEA,SAAS,WAAW,MAAA,EAA2C;AAE7D,EAAA,MAAM,UAAU,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAM,KAAK,IAAI,CAAA;AAC9C,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAGjC,EAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG,OAAO,MAAA;AAGhC,EAAA,IAAI,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,KAAM,OAAO,CAAA,KAAM,QAAA,IAAY,MAAA,CAAO,CAAC,CAAC,CAAA,EAAG,OAAO,MAAA;AAGrE,EAAA,IAAI,OAAA,CAAQ,MAAM,CAAC,CAAA,KAAM,OAAO,CAAA,KAAM,QAAQ,GAAG,OAAO,QAAA;AACxD,EAAA,IAAI,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,KAAM,OAAO,CAAA,KAAM,QAAA,IAAY,SAAA,CAAU,IAAA,CAAK,CAAC,CAAC,CAAA,EAAG,OAAO,QAAA;AAG7E,EAAA,IAAI,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,KAAM,OAAO,CAAA,KAAM,QAAA,IAAY,QAAA,CAAS,IAAA,CAAK,CAAC,CAAC,CAAA,EAAG,OAAO,OAAA;AAG5E,EAAA,IAAI,QAAQ,KAAA,CAAM,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,IAAY,CAAA,CAAE,MAAA,IAAU,EAAA,IAAM,CAAC,QAAA,CAAS,IAAA,CAAK,CAAC,CAAC,GAAG,OAAO,OAAA;AAG/F,EAAA,OAAO,MAAA;AACT;AAOO,SAAS,gBAAA,CACd,IAAA,EACA,UAAA,EACA,SAAA,GAAY,EAAA,EACa;AACzB,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,GAAS,SAAA,GAAY,KAAK,KAAA,CAAM,CAAA,EAAG,SAAS,CAAA,GAAI,IAAA;AACpE,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAwB;AAE3C,EAAA,KAAA,MAAW,OAAO,UAAA,EAAY;AAC5B,IAAA,MAAM,SAAS,MAAA,CAAO,GAAA,CAAI,CAAC,GAAA,KAAQ,GAAA,CAAI,GAAG,CAAC,CAAA;AAC3C,IAAA,MAAM,IAAA,GAAO,WAAW,MAAM,CAAA;AAC9B,IAAA,IAAI,IAAA,EAAM,MAAA,CAAO,GAAA,CAAI,GAAA,EAAK,IAAI,CAAA;AAAA,EAChC;AAEA,EAAA,OAAO,MAAA;AACT","file":"chunk-PDZL4A6K.js","sourcesContent":["/** Shared column-kind inference for Table and DataGrid. */\n\nexport type ColumnKind = \"date\" | \"number\" | \"email\" | \"label\" | \"text\";\n\nconst DATE_ISO = /^\\d{4}-\\d{2}-\\d{2}$/;\nconst DATE_US = /^\\d{1,2}\\/\\d{1,2}\\/\\d{4}$/;\nconst DATE_TEXT_MDY = /^[A-Z][a-z]{2}\\s+\\d{1,2},?\\s+\\d{4}$/; // \"Jan 12, 2024\" or \"Jan 12 2024\"\nconst DATE_TEXT_DMY = /^\\d{1,2}\\s+[A-Z][a-z]{2}\\s+\\d{4}$/; // \"12 Jan 2024\"\nconst NUMBER_RE = /^[$€£¥]?\\s?[\\d,]+\\.?\\d*%?$/;\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nfunction isDate(v: string): boolean {\n return DATE_ISO.test(v) || DATE_US.test(v) || DATE_TEXT_MDY.test(v) || DATE_TEXT_DMY.test(v);\n}\n\nfunction isJsx(v: unknown): boolean {\n return typeof v === \"object\" && v !== null;\n}\n\nfunction detectKind(values: unknown[]): ColumnKind | undefined {\n // Filter out null/undefined\n const present = values.filter((v) => v != null);\n if (present.length === 0) return undefined;\n\n // Any JSX value means no kind\n if (present.some(isJsx)) return undefined;\n\n // Check date (strings only)\n if (present.every((v) => typeof v === \"string\" && isDate(v))) return \"date\";\n\n // Check number: all typeof number, or all strings matching the number pattern\n if (present.every((v) => typeof v === \"number\")) return \"number\";\n if (present.every((v) => typeof v === \"string\" && NUMBER_RE.test(v))) return \"number\";\n\n // Check email\n if (present.every((v) => typeof v === \"string\" && EMAIL_RE.test(v))) return \"email\";\n\n // Check label: strings <= 20 chars, no line breaks\n if (present.every((v) => typeof v === \"string\" && v.length <= 20 && !/[\\n\\r]/.test(v))) return \"label\";\n\n // Fallback\n return \"text\";\n}\n\n/**\n * Sample data rows and infer a ColumnKind for each key.\n * Returns a Map of key -> kind for columns that matched a pattern.\n * Columns with mixed types or JSX values get no entry.\n */\nexport function inferColumnKinds(\n data: Record<string, unknown>[],\n columnKeys: string[],\n maxSample = 50,\n): Map<string, ColumnKind> {\n const sample = data.length > maxSample ? data.slice(0, maxSample) : data;\n const result = new Map<string, ColumnKind>();\n\n for (const key of columnKeys) {\n const values = sample.map((row) => row[key]);\n const kind = detectKind(values);\n if (kind) result.set(key, kind);\n }\n\n return result;\n}\n"]}
|