@objectifthunes/whiteboard 0.2.0 → 0.2.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/index.cjs DELETED
@@ -1,1648 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- Alert: () => Alert,
24
- AssetCardSkeleton: () => AssetCardSkeleton,
25
- AssetTitle: () => AssetTitle,
26
- AvatarSkeleton: () => AvatarSkeleton,
27
- Button: () => Button,
28
- ButtonRow: () => ButtonRow,
29
- ButtonSkeleton: () => ButtonSkeleton,
30
- CanvasSkeleton: () => CanvasSkeleton,
31
- Chip: () => Chip,
32
- ChipSkeleton: () => ChipSkeleton,
33
- ChoiceCard: () => ChoiceCard,
34
- ChoiceGroup: () => ChoiceGroup,
35
- ChoiceGroupSkeleton: () => ChoiceGroupSkeleton,
36
- ConfirmDialog: () => ConfirmDialog,
37
- CoordGrid: () => CoordGrid,
38
- CoordInput: () => CoordInput,
39
- EmptyState: () => EmptyState,
40
- Field: () => Field,
41
- FloatingPanel: () => FloatingPanel,
42
- GeneratingOverlay: () => GeneratingOverlay,
43
- IconButtonSkeleton: () => IconButtonSkeleton,
44
- IconText: () => IconText,
45
- ImageThumb: () => ImageThumb,
46
- Inline: () => Inline,
47
- Input: () => Input,
48
- InputSkeleton: () => InputSkeleton,
49
- ItemCard: () => ItemCard,
50
- ItemList: () => ItemList,
51
- Label: () => Label,
52
- LineSkeleton: () => LineSkeleton,
53
- List: () => List,
54
- LoadingState: () => LoadingState,
55
- Minimap: () => Minimap,
56
- MutedText: () => MutedText,
57
- PageCard: () => PageCard,
58
- PageShell: () => PageShell,
59
- PageTitle: () => PageTitle,
60
- PanelCloseButton: () => PanelCloseButton,
61
- PanelErrorBoundary: () => PanelErrorBoundary,
62
- PanelFormSkeleton: () => PanelFormSkeleton,
63
- PanelSection: () => PanelSection,
64
- PanelTitle: () => PanelTitle,
65
- PickerCard: () => PickerCard,
66
- PickerGrid: () => PickerGrid,
67
- PickerGridSkeleton: () => PickerGridSkeleton,
68
- Pill: () => Pill,
69
- SectionDescription: () => SectionDescription,
70
- SectionTitle: () => SectionTitle,
71
- Select: () => Select,
72
- SelectSkeleton: () => SelectSkeleton,
73
- Skeleton: () => Skeleton,
74
- SplitLayout: () => SplitLayout,
75
- Stack: () => Stack,
76
- StoryCardSkeleton: () => StoryCardSkeleton,
77
- StoryTitle: () => StoryTitle,
78
- TagRow: () => TagRow,
79
- Textarea: () => Textarea,
80
- TextareaSkeleton: () => TextareaSkeleton,
81
- ThemeToggle: () => ThemeToggle,
82
- ThumbSkeleton: () => ThumbSkeleton,
83
- TitleRow: () => TitleRow,
84
- TitleSkeleton: () => TitleSkeleton,
85
- UserCardSkeleton: () => UserCardSkeleton,
86
- UserListSkeleton: () => UserListSkeleton,
87
- WHITEBOARD_GRID: () => WHITEBOARD_GRID,
88
- WhiteboardShell: () => WhiteboardShell,
89
- ZoomBar: () => ZoomBar,
90
- belowPanel: () => belowPanel,
91
- cn: () => cn,
92
- computeWhiteboardFit: () => computeWhiteboardFit,
93
- computeWhiteboardRectFocus: () => computeWhiteboardRectFocus,
94
- snapToWhiteboardGrid: () => snapToWhiteboardGrid,
95
- usePanelRect: () => usePanelRect,
96
- useWhiteboardLayout: () => useWhiteboardLayout,
97
- useWhiteboardStore: () => useWhiteboardStore
98
- });
99
- module.exports = __toCommonJS(index_exports);
100
-
101
- // src/WhiteboardShell.tsx
102
- var import_react3 = require("react");
103
-
104
- // src/ZoomBar.tsx
105
- var import_react = require("react");
106
-
107
- // src/icons.tsx
108
- var import_jsx_runtime = require("react/jsx-runtime");
109
- var defaults = (size = 14) => ({
110
- xmlns: "http://www.w3.org/2000/svg",
111
- width: size,
112
- height: size,
113
- viewBox: "0 0 24 24",
114
- fill: "none",
115
- stroke: "currentColor",
116
- strokeWidth: 2,
117
- strokeLinecap: "round",
118
- strokeLinejoin: "round"
119
- });
120
- function Minus({ size, ...props }) {
121
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...defaults(size), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 12h14" }) });
122
- }
123
- function Plus({ size, ...props }) {
124
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...defaults(size), ...props, children: [
125
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 12h14" }),
126
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 5v14" })
127
- ] });
128
- }
129
- function ScanSearch({ size, ...props }) {
130
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...defaults(size), ...props, children: [
131
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425z", fill: "none", stroke: "none" }),
132
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }),
133
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }),
134
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }),
135
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" }),
136
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "3" }),
137
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m16 16-1.9-1.9" })
138
- ] });
139
- }
140
- function RotateCcw({ size, ...props }) {
141
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...defaults(size), ...props, children: [
142
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
143
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 3v5h5" })
144
- ] });
145
- }
146
- function Grid3x3({ size, ...props }) {
147
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...defaults(size), ...props, children: [
148
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }),
149
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 9h18" }),
150
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 15h18" }),
151
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 3v18" }),
152
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15 3v18" })
153
- ] });
154
- }
155
- function Maximize2({ size, ...props }) {
156
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...defaults(size), ...props, children: [
157
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "15 3 21 3 21 9" }),
158
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "9 21 3 21 3 15" }),
159
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "21", x2: "14", y1: "3", y2: "10" }),
160
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "3", x2: "10", y1: "21", y2: "14" })
161
- ] });
162
- }
163
- function Loader2({ size, ...props }) {
164
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...defaults(size), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
165
- }
166
- function AlertTriangle({ size, ...props }) {
167
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...defaults(size), ...props, children: [
168
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }),
169
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 9v4" }),
170
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 17h.01" })
171
- ] });
172
- }
173
- function Check({ size, ...props }) {
174
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...defaults(size), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 6 9 17l-5-5" }) });
175
- }
176
- function X({ size, ...props }) {
177
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...defaults(size), ...props, children: [
178
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18 6 6 18" }),
179
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m6 6 12 12" })
180
- ] });
181
- }
182
- function Moon({ size, ...props }) {
183
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...defaults(size), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" }) });
184
- }
185
- function Sun({ size, ...props }) {
186
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...defaults(size), ...props, children: [
187
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "4" }),
188
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 2v2" }),
189
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 20v2" }),
190
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m4.93 4.93 1.41 1.41" }),
191
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m17.66 17.66 1.41 1.41" }),
192
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2 12h2" }),
193
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 12h2" }),
194
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m6.34 17.66-1.41 1.41" }),
195
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m19.07 4.93-1.41 1.41" })
196
- ] });
197
- }
198
-
199
- // src/store.ts
200
- var import_zustand = require("zustand");
201
-
202
- // src/grid.ts
203
- var WHITEBOARD_GRID = 20;
204
- function snapToWhiteboardGrid(value) {
205
- return Math.round(value / WHITEBOARD_GRID) * WHITEBOARD_GRID;
206
- }
207
-
208
- // src/store.ts
209
- function computeWhiteboardFit(panels, viewportSize, padding = 60) {
210
- if (panels.size === 0) return null;
211
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
212
- for (const r of panels.values()) {
213
- minX = Math.min(minX, r.x);
214
- minY = Math.min(minY, r.y);
215
- maxX = Math.max(maxX, r.x + r.width);
216
- maxY = Math.max(maxY, r.y + r.height);
217
- }
218
- const contentW = maxX - minX + padding * 2;
219
- const contentH = maxY - minY + padding * 2;
220
- const vpW = viewportSize.width || window.innerWidth;
221
- const vpH = viewportSize.height || window.innerHeight;
222
- const fitScale = Math.min(vpW / contentW, vpH / contentH, 1.5);
223
- const centerX = (minX + maxX) / 2;
224
- const centerY = (minY + maxY) / 2;
225
- return {
226
- scale: Math.min(3, Math.max(0.2, fitScale)),
227
- offset: {
228
- x: vpW / 2 - centerX * fitScale,
229
- y: vpH / 2 - centerY * fitScale
230
- }
231
- };
232
- }
233
- function computeWhiteboardRectFocus(rect, viewportSize, padding = 40, maxScale = 1.5) {
234
- const vpW = viewportSize.width || window.innerWidth;
235
- const vpH = viewportSize.height || window.innerHeight;
236
- const safeWidth = Math.max(1, rect.width);
237
- const safeHeight = Math.max(1, rect.height);
238
- const fitScale = Math.min(
239
- (vpW - padding * 2) / safeWidth,
240
- (vpH - padding * 2) / safeHeight,
241
- maxScale
242
- );
243
- const nextScale = Math.min(3, Math.max(0.2, fitScale));
244
- return {
245
- scale: nextScale,
246
- offset: {
247
- x: vpW / 2 - (rect.x + safeWidth / 2) * nextScale,
248
- y: vpH / 2 - (rect.y + safeHeight / 2) * nextScale
249
- }
250
- };
251
- }
252
- var useWhiteboardStore = (0, import_zustand.create)((set, get) => ({
253
- offset: { x: 0, y: 0 },
254
- scale: 1,
255
- viewportSize: { width: 0, height: 0 },
256
- snapToGrid: false,
257
- snapGridSize: WHITEBOARD_GRID,
258
- panels: /* @__PURE__ */ new Map(),
259
- resetFns: /* @__PURE__ */ new Map(),
260
- registryVersion: 0,
261
- setOffset: (v) => set((s) => ({ offset: typeof v === "function" ? v(s.offset) : v })),
262
- setScale: (v) => set((s) => ({ scale: typeof v === "function" ? v(s.scale) : v })),
263
- setViewportSize: (v) => set({ viewportSize: v }),
264
- setSnapToGrid: (v) => set((s) => ({ snapToGrid: typeof v === "function" ? v(s.snapToGrid) : v })),
265
- register: (id, rect) => {
266
- get().panels.set(id, rect);
267
- set((s) => ({ registryVersion: s.registryVersion + 1 }));
268
- },
269
- unregister: (id) => {
270
- get().panels.delete(id);
271
- set((s) => ({ registryVersion: s.registryVersion + 1 }));
272
- },
273
- registerReset: (id, fn) => {
274
- get().resetFns.set(id, fn);
275
- },
276
- unregisterReset: (id) => {
277
- get().resetFns.delete(id);
278
- },
279
- fitToContent: () => {
280
- const { panels, viewportSize } = get();
281
- const fit = computeWhiteboardFit(panels, viewportSize);
282
- if (fit) set({ scale: fit.scale, offset: fit.offset });
283
- },
284
- focusPanel: (rect, options) => {
285
- const { viewportSize } = get();
286
- const fit = computeWhiteboardRectFocus(
287
- rect,
288
- viewportSize,
289
- options?.padding ?? 40,
290
- options?.maxScale ?? 1.5
291
- );
292
- set({ scale: fit.scale, offset: fit.offset });
293
- },
294
- resetWidgets: () => {
295
- for (const fn of get().resetFns.values()) fn();
296
- const attempt = (tries = 0) => {
297
- const { panels, viewportSize } = get();
298
- const fit = computeWhiteboardFit(panels, viewportSize);
299
- if (fit) {
300
- set({ scale: fit.scale, offset: fit.offset });
301
- return;
302
- }
303
- if (tries < 6) requestAnimationFrame(() => attempt(tries + 1));
304
- };
305
- requestAnimationFrame(() => requestAnimationFrame(() => attempt()));
306
- },
307
- resetSession: () => set({
308
- offset: { x: 0, y: 0 },
309
- scale: 1,
310
- viewportSize: { width: 0, height: 0 },
311
- snapToGrid: false,
312
- registryVersion: 0,
313
- panels: /* @__PURE__ */ new Map(),
314
- resetFns: /* @__PURE__ */ new Map()
315
- })
316
- }));
317
-
318
- // src/ZoomBar.tsx
319
- var import_jsx_runtime2 = require("react/jsx-runtime");
320
- function ZoomBar({ extraActions }) {
321
- const scale = useWhiteboardStore((s) => s.scale);
322
- const viewportSize = useWhiteboardStore((s) => s.viewportSize);
323
- const snapToGrid = useWhiteboardStore((s) => s.snapToGrid);
324
- const setScale = useWhiteboardStore((s) => s.setScale);
325
- const setOffset = useWhiteboardStore((s) => s.setOffset);
326
- const setSnapToGrid = useWhiteboardStore((s) => s.setSnapToGrid);
327
- const fitToContent = useWhiteboardStore((s) => s.fitToContent);
328
- const resetWidgets = useWhiteboardStore((s) => s.resetWidgets);
329
- (0, import_react.useEffect)(() => {
330
- if (!snapToGrid) return;
331
- window.dispatchEvent(new Event("whiteboard-snap-now"));
332
- }, [snapToGrid]);
333
- const zoomTo = (nextScale) => {
334
- const clamped = Math.min(3, Math.max(0.2, nextScale));
335
- const ratio = clamped / scale;
336
- const cx = (viewportSize.width || window.innerWidth) / 2;
337
- const cy = (viewportSize.height || window.innerHeight) / 2;
338
- setOffset((prev) => ({
339
- x: cx - (cx - prev.x) * ratio,
340
- y: cy - (cy - prev.y) * ratio
341
- }));
342
- setScale(clamped);
343
- };
344
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
345
- "div",
346
- {
347
- className: "zoom-bar",
348
- onPointerDown: (e) => e.stopPropagation(),
349
- onWheel: (e) => e.stopPropagation(),
350
- children: [
351
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "wb-btn wb-btn--secondary wb-btn--icon-only zoom-bar__icon", onClick: () => zoomTo(scale * 0.8), title: "Zoom out", "aria-label": "Zoom out", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Minus, { size: 14 }) }),
352
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "zoom-bar__value", children: [
353
- Math.round(scale * 100),
354
- "%"
355
- ] }),
356
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "wb-btn wb-btn--secondary wb-btn--icon-only zoom-bar__icon", onClick: () => zoomTo(scale * 1.2), title: "Zoom in", "aria-label": "Zoom in", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Plus, { size: 14 }) }),
357
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "wb-btn wb-btn--secondary wb-btn--icon-only zoom-bar__action", onClick: fitToContent, title: "Fit camera to all panels", "aria-label": "Fit camera to all panels", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ScanSearch, { size: 14 }) }),
358
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "wb-btn wb-btn--secondary wb-btn--icon-only zoom-bar__action", onClick: resetWidgets, title: "Reset panel positions", "aria-label": "Reset panel positions", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RotateCcw, { size: 14 }) }),
359
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
360
- "button",
361
- {
362
- type: "button",
363
- className: `wb-btn wb-btn--secondary wb-btn--icon-only zoom-bar__action${snapToGrid ? " is-active" : ""}`,
364
- onClick: () => setSnapToGrid((prev) => !prev),
365
- title: snapToGrid ? "Disable snap to grid" : "Enable snap to grid",
366
- "aria-label": snapToGrid ? "Disable snap to grid" : "Enable snap to grid",
367
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Grid3x3, { size: 14 })
368
- }
369
- ),
370
- extraActions
371
- ]
372
- }
373
- );
374
- }
375
-
376
- // src/Minimap.tsx
377
- var import_react2 = require("react");
378
- var import_jsx_runtime3 = require("react/jsx-runtime");
379
- var MAP_W = 200;
380
- var MAP_H = 150;
381
- var PADDING = 40;
382
- var MIN_WORLD_SIZE = 1;
383
- function Minimap({ loading = false }) {
384
- useWhiteboardStore((s) => s.registryVersion);
385
- const offset = useWhiteboardStore((s) => s.offset);
386
- const scale = useWhiteboardStore((s) => s.scale);
387
- const viewportSize = useWhiteboardStore((s) => s.viewportSize);
388
- const panels = useWhiteboardStore((s) => s.panels);
389
- const setOffset = useWhiteboardStore((s) => s.setOffset);
390
- const setScale = useWhiteboardStore((s) => s.setScale);
391
- const focusPanel = useWhiteboardStore((s) => s.focusPanel);
392
- const containerRef = (0, import_react2.useRef)(null);
393
- const dragging = (0, import_react2.useRef)(false);
394
- const lastPanelTapRef = (0, import_react2.useRef)(null);
395
- const rectEntries = Array.from(panels.entries());
396
- const visibleRectEntries = rectEntries.filter(([, rect]) => Number.isFinite(rect.width) && Number.isFinite(rect.height));
397
- const rects = visibleRectEntries.map(([, rect]) => rect);
398
- if (loading || rects.length === 0) {
399
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "minimap minimap--loading", style: { width: MAP_W, height: MAP_H }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "minimap__loading", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Loader2, { size: 14, className: "icon-spin" }) }) });
400
- }
401
- const viewportWidth = viewportSize.width || window.innerWidth;
402
- const viewportHeight = viewportSize.height || window.innerHeight;
403
- const vpW = viewportWidth / scale;
404
- const vpH = viewportHeight / scale;
405
- const vpX = -offset.x / scale;
406
- const vpY = -offset.y / scale;
407
- let minX = Infinity;
408
- let minY = Infinity;
409
- let maxX = -Infinity;
410
- let maxY = -Infinity;
411
- for (const r of rects) {
412
- minX = Math.min(minX, r.x);
413
- minY = Math.min(minY, r.y);
414
- maxX = Math.max(maxX, r.x + r.width);
415
- maxY = Math.max(maxY, r.y + r.height);
416
- }
417
- minX -= PADDING;
418
- minY -= PADDING;
419
- maxX += PADDING;
420
- maxY += PADDING;
421
- const worldW = Math.max(MIN_WORLD_SIZE, maxX - minX);
422
- const worldH = Math.max(MIN_WORLD_SIZE, maxY - minY);
423
- const mapScale = Math.min(MAP_W / worldW, MAP_H / worldH);
424
- const contentW = worldW * mapScale;
425
- const contentH = worldH * mapScale;
426
- const mapOffsetX = (MAP_W - contentW) / 2;
427
- const mapOffsetY = (MAP_H - contentH) / 2;
428
- const toMapX = (wx) => mapOffsetX + (wx - minX) * mapScale;
429
- const toMapY = (wy) => mapOffsetY + (wy - minY) * mapScale;
430
- const clientToWorld = (clientX, clientY) => {
431
- if (!containerRef.current) return;
432
- const mapRect = containerRef.current.getBoundingClientRect();
433
- const localX = Math.min(MAP_W, Math.max(0, clientX - mapRect.left));
434
- const localY = Math.min(MAP_H, Math.max(0, clientY - mapRect.top));
435
- const boundedX = Math.min(contentW + mapOffsetX, Math.max(mapOffsetX, localX));
436
- const boundedY = Math.min(contentH + mapOffsetY, Math.max(mapOffsetY, localY));
437
- const worldX = (boundedX - mapOffsetX) / mapScale + minX;
438
- const worldY = (boundedY - mapOffsetY) / mapScale + minY;
439
- return { worldX, worldY };
440
- };
441
- const centerToWorld = (worldX, worldY, targetScale) => {
442
- const clampedScale = Math.min(3, Math.max(0.2, targetScale));
443
- setScale(clampedScale);
444
- setOffset({
445
- x: viewportWidth / 2 - worldX * clampedScale,
446
- y: viewportHeight / 2 - worldY * clampedScale
447
- });
448
- };
449
- const panTo = (clientX, clientY) => {
450
- const world = clientToWorld(clientX, clientY);
451
- if (!world) return;
452
- centerToWorld(world.worldX, world.worldY, scale);
453
- };
454
- const onDown = (e) => {
455
- e.stopPropagation();
456
- e.preventDefault();
457
- dragging.current = true;
458
- e.currentTarget.setPointerCapture(e.pointerId);
459
- panTo(e.clientX, e.clientY);
460
- };
461
- const onMove = (e) => {
462
- if (!dragging.current) return;
463
- panTo(e.clientX, e.clientY);
464
- };
465
- const onUp = () => {
466
- dragging.current = false;
467
- };
468
- const onWheel = (e) => {
469
- e.preventDefault();
470
- e.stopPropagation();
471
- const world = clientToWorld(e.clientX, e.clientY);
472
- if (!world) return;
473
- const factor = e.deltaY > 0 ? 0.9 : 1.1;
474
- centerToWorld(world.worldX, world.worldY, scale * factor);
475
- };
476
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
477
- "div",
478
- {
479
- ref: containerRef,
480
- onPointerDown: onDown,
481
- onPointerMove: onMove,
482
- onPointerUp: onUp,
483
- onPointerCancel: onUp,
484
- onWheel,
485
- className: "minimap",
486
- style: {
487
- width: MAP_W,
488
- height: MAP_H
489
- },
490
- children: [
491
- visibleRectEntries.map(([id, r]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
492
- "div",
493
- {
494
- className: "minimap__panel",
495
- onPointerDown: (event) => {
496
- event.stopPropagation();
497
- },
498
- onPointerUp: (event) => {
499
- event.stopPropagation();
500
- const now = Date.now();
501
- const last = lastPanelTapRef.current;
502
- if (last && last.id === id && now - last.time < 300) {
503
- event.preventDefault();
504
- focusPanel(r, { padding: r.focusPadding, maxScale: r.focusMaxScale });
505
- lastPanelTapRef.current = null;
506
- return;
507
- }
508
- lastPanelTapRef.current = { id, time: now };
509
- },
510
- onDoubleClick: (event) => {
511
- event.preventDefault();
512
- event.stopPropagation();
513
- focusPanel(r, { padding: r.focusPadding, maxScale: r.focusMaxScale });
514
- },
515
- style: {
516
- left: toMapX(r.x),
517
- top: toMapY(r.y),
518
- width: Math.max(1, r.width * mapScale),
519
- height: Math.max(1, r.height * mapScale)
520
- }
521
- },
522
- id
523
- )),
524
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
525
- "div",
526
- {
527
- className: "minimap__viewport",
528
- style: {
529
- left: toMapX(vpX),
530
- top: toMapY(vpY),
531
- width: vpW * mapScale,
532
- height: vpH * mapScale
533
- }
534
- }
535
- )
536
- ]
537
- }
538
- );
539
- }
540
-
541
- // src/WhiteboardShell.tsx
542
- var import_jsx_runtime4 = require("react/jsx-runtime");
543
- function WhiteboardShell({ children, showMinimap = true, minimapLoading = false, extraActions }) {
544
- const offset = useWhiteboardStore((s) => s.offset);
545
- const scale = useWhiteboardStore((s) => s.scale);
546
- const registryVersion = useWhiteboardStore((s) => s.registryVersion);
547
- const viewportSize = useWhiteboardStore((s) => s.viewportSize);
548
- const setOffset = useWhiteboardStore((s) => s.setOffset);
549
- const setScale = useWhiteboardStore((s) => s.setScale);
550
- const setViewportSize = useWhiteboardStore((s) => s.setViewportSize);
551
- const shellRef = (0, import_react3.useRef)(null);
552
- const panning = (0, import_react3.useRef)(false);
553
- const last = (0, import_react3.useRef)({ x: 0, y: 0 });
554
- const activePointerId = (0, import_react3.useRef)(null);
555
- const scaleRef = (0, import_react3.useRef)(scale);
556
- const hasFitted = (0, import_react3.useRef)(false);
557
- (0, import_react3.useEffect)(() => {
558
- return () => {
559
- useWhiteboardStore.getState().resetSession();
560
- };
561
- }, []);
562
- (0, import_react3.useEffect)(() => {
563
- scaleRef.current = scale;
564
- }, [scale]);
565
- (0, import_react3.useEffect)(() => {
566
- const shell = shellRef.current;
567
- if (!shell) return;
568
- const updateViewport = () => {
569
- const rect = shell.getBoundingClientRect();
570
- setViewportSize({
571
- width: Math.max(0, rect.width),
572
- height: Math.max(0, rect.height)
573
- });
574
- };
575
- updateViewport();
576
- if (typeof ResizeObserver === "undefined") return;
577
- const observer = new ResizeObserver(updateViewport);
578
- observer.observe(shell);
579
- return () => observer.disconnect();
580
- }, [setViewportSize]);
581
- (0, import_react3.useEffect)(() => {
582
- if (hasFitted.current) return;
583
- const { panels } = useWhiteboardStore.getState();
584
- if (panels.size === 0 || viewportSize.width <= 0 || viewportSize.height <= 0) return;
585
- hasFitted.current = true;
586
- requestAnimationFrame(() => {
587
- useWhiteboardStore.getState().fitToContent();
588
- });
589
- }, [registryVersion, viewportSize]);
590
- const onDown = (0, import_react3.useCallback)((e) => {
591
- if (e.target !== e.currentTarget) return;
592
- if (e.button === 0 || e.button === 1) {
593
- panning.current = true;
594
- activePointerId.current = e.pointerId;
595
- last.current = { x: e.clientX, y: e.clientY };
596
- e.currentTarget.setPointerCapture(e.pointerId);
597
- e.preventDefault();
598
- }
599
- }, []);
600
- const onMove = (0, import_react3.useCallback)((e) => {
601
- if (!panning.current || activePointerId.current !== e.pointerId) return;
602
- const dx = e.movementX ?? e.clientX - last.current.x;
603
- const dy = e.movementY ?? e.clientY - last.current.y;
604
- setOffset((p) => ({ x: p.x + dx, y: p.y + dy }));
605
- last.current = { x: e.clientX, y: e.clientY };
606
- }, [setOffset]);
607
- const stopPan = (0, import_react3.useCallback)((e) => {
608
- if (activePointerId.current !== null) {
609
- try {
610
- e.currentTarget.releasePointerCapture(activePointerId.current);
611
- } catch {
612
- }
613
- }
614
- panning.current = false;
615
- activePointerId.current = null;
616
- }, []);
617
- const onWheel = (0, import_react3.useCallback)((e) => {
618
- const s = scaleRef.current;
619
- const rect = e.currentTarget.getBoundingClientRect();
620
- const anchor = { x: e.clientX - rect.left, y: e.clientY - rect.top };
621
- const nextScale = Math.min(3, Math.max(0.2, s * (e.deltaY > 0 ? 0.9 : 1.1)));
622
- const ratio = nextScale / s;
623
- setOffset((prev) => ({
624
- x: anchor.x - (anchor.x - prev.x) * ratio,
625
- y: anchor.y - (anchor.y - prev.y) * ratio
626
- }));
627
- setScale(nextScale);
628
- }, [setOffset, setScale]);
629
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
630
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
631
- "div",
632
- {
633
- ref: shellRef,
634
- onPointerDown: onDown,
635
- onPointerMove: onMove,
636
- onPointerUp: stopPan,
637
- onPointerCancel: stopPan,
638
- onWheel,
639
- onContextMenu: (e) => e.preventDefault(),
640
- className: "whiteboard-shell",
641
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
642
- "div",
643
- {
644
- className: "whiteboard-canvas",
645
- style: { transform: `translate(${offset.x}px, ${offset.y}px) scale(${scale})` },
646
- children: [
647
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "whiteboard-grid", "aria-hidden": true }),
648
- children
649
- ]
650
- }
651
- )
652
- }
653
- ),
654
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ZoomBar, { extraActions }),
655
- showMinimap ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Minimap, { loading: minimapLoading }) : null
656
- ] });
657
- }
658
-
659
- // src/FloatingPanel.tsx
660
- var import_react4 = require("react");
661
- var import_jsx_runtime5 = require("react/jsx-runtime");
662
- var FloatingPanel = (0, import_react4.memo)(function FloatingPanel2({
663
- title,
664
- defaultPosition,
665
- width = 300,
666
- className,
667
- trackRect: trackRectRef,
668
- focusable,
669
- focusPadding = 40,
670
- focusMaxScale = 1.5,
671
- headerActions,
672
- children
673
- }) {
674
- const panelId = (0, import_react4.useId)();
675
- const [pos, setPos] = (0, import_react4.useState)(defaultPosition);
676
- const dragging = (0, import_react4.useRef)(false);
677
- const posRef = (0, import_react4.useRef)(pos);
678
- const elRef = (0, import_react4.useRef)(null);
679
- const lastRegisteredRectRef = (0, import_react4.useRef)(null);
680
- const scale = useWhiteboardStore((s) => s.scale);
681
- const snapToGrid = useWhiteboardStore((s) => s.snapToGrid);
682
- const snapGridSize = useWhiteboardStore((s) => s.snapGridSize);
683
- const register = useWhiteboardStore((s) => s.register);
684
- const unregister = useWhiteboardStore((s) => s.unregister);
685
- const registerReset = useWhiteboardStore((s) => s.registerReset);
686
- const unregisterReset = useWhiteboardStore((s) => s.unregisterReset);
687
- const focusPanel = useWhiteboardStore((s) => s.focusPanel);
688
- const scaleRef = (0, import_react4.useRef)(scale);
689
- const snapToGridRef = (0, import_react4.useRef)(false);
690
- const snapGridSizeRef = (0, import_react4.useRef)(20);
691
- const defaultPosRef = (0, import_react4.useRef)(defaultPosition);
692
- const cleanupRef = (0, import_react4.useRef)(null);
693
- const lastTapRef = (0, import_react4.useRef)(null);
694
- (0, import_react4.useEffect)(() => {
695
- scaleRef.current = scale;
696
- }, [scale]);
697
- (0, import_react4.useEffect)(() => {
698
- snapToGridRef.current = snapToGrid;
699
- snapGridSizeRef.current = snapGridSize;
700
- }, [snapToGrid, snapGridSize]);
701
- (0, import_react4.useEffect)(() => {
702
- const onSnapNow = () => {
703
- const snapSize = snapGridSizeRef.current;
704
- setPos((current) => {
705
- const next = {
706
- x: Math.round(current.x / snapSize) * snapSize,
707
- y: Math.round(current.y / snapSize) * snapSize
708
- };
709
- return next.x === current.x && next.y === current.y ? current : next;
710
- });
711
- };
712
- window.addEventListener("whiteboard-snap-now", onSnapNow);
713
- return () => window.removeEventListener("whiteboard-snap-now", onSnapNow);
714
- }, []);
715
- (0, import_react4.useEffect)(() => {
716
- posRef.current = pos;
717
- }, [pos]);
718
- const registerRect = (0, import_react4.useCallback)(() => {
719
- const el = elRef.current;
720
- if (!el) return;
721
- const nextRect = {
722
- x: posRef.current.x,
723
- y: posRef.current.y,
724
- width: el.offsetWidth,
725
- height: el.offsetHeight,
726
- focusPadding,
727
- focusMaxScale
728
- };
729
- const prev = lastRegisteredRectRef.current;
730
- if (prev && prev.x === nextRect.x && prev.y === nextRect.y && prev.width === nextRect.width && prev.height === nextRect.height && prev.focusPadding === nextRect.focusPadding && prev.focusMaxScale === nextRect.focusMaxScale) {
731
- return;
732
- }
733
- lastRegisteredRectRef.current = nextRect;
734
- register(panelId, nextRect);
735
- if (trackRectRef) {
736
- trackRectRef.current = nextRect;
737
- }
738
- }, [focusMaxScale, focusPadding, panelId, register, trackRectRef]);
739
- const getCurrentRect = (0, import_react4.useCallback)(() => {
740
- const el = elRef.current;
741
- if (!el) return null;
742
- return {
743
- x: posRef.current.x,
744
- y: posRef.current.y,
745
- width: el.offsetWidth,
746
- height: el.offsetHeight,
747
- focusPadding,
748
- focusMaxScale
749
- };
750
- }, [focusMaxScale, focusPadding]);
751
- const handleFocus = (0, import_react4.useCallback)(() => {
752
- const rect = getCurrentRect();
753
- if (!rect) return;
754
- focusPanel(rect, { padding: focusPadding, maxScale: focusMaxScale });
755
- }, [focusPanel, focusPadding, focusMaxScale, getCurrentRect]);
756
- (0, import_react4.useEffect)(() => {
757
- registerReset(panelId, () => setPos(defaultPosRef.current));
758
- return () => {
759
- cleanupRef.current?.();
760
- unregister(panelId);
761
- unregisterReset(panelId);
762
- lastRegisteredRectRef.current = null;
763
- };
764
- }, [panelId, registerReset, unregister, unregisterReset]);
765
- (0, import_react4.useLayoutEffect)(() => {
766
- registerRect();
767
- }, [pos.x, pos.y, width, registerRect]);
768
- (0, import_react4.useEffect)(() => {
769
- const el = elRef.current;
770
- if (!el) return;
771
- if (typeof ResizeObserver === "undefined") return;
772
- const obs = new ResizeObserver(() => {
773
- registerRect();
774
- });
775
- obs.observe(el);
776
- return () => obs.disconnect();
777
- }, [registerRect]);
778
- const onDown = (0, import_react4.useCallback)((e) => {
779
- if (e.button !== 0) return;
780
- dragging.current = true;
781
- const startX = e.clientX;
782
- const startY = e.clientY;
783
- const startPosX = posRef.current.x;
784
- const startPosY = posRef.current.y;
785
- const startScale = scaleRef.current;
786
- e.preventDefault();
787
- e.stopPropagation();
788
- e.target.setPointerCapture(e.pointerId);
789
- const move = (ev) => {
790
- if (!dragging.current) return;
791
- const rawX = startPosX + (ev.clientX - startX) / startScale;
792
- const rawY = startPosY + (ev.clientY - startY) / startScale;
793
- const snapSize = snapGridSizeRef.current;
794
- const nextX = snapToGridRef.current ? Math.round(rawX / snapSize) * snapSize : rawX;
795
- const nextY = snapToGridRef.current ? Math.round(rawY / snapSize) * snapSize : rawY;
796
- setPos({
797
- x: nextX,
798
- y: nextY
799
- });
800
- };
801
- const up = () => {
802
- dragging.current = false;
803
- window.removeEventListener("pointermove", move);
804
- window.removeEventListener("pointerup", up);
805
- cleanupRef.current = null;
806
- };
807
- cleanupRef.current?.();
808
- window.addEventListener("pointermove", move);
809
- window.addEventListener("pointerup", up);
810
- cleanupRef.current = up;
811
- }, []);
812
- const panelClassName = className ? `floating-panel ${className}` : "floating-panel";
813
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
814
- "div",
815
- {
816
- ref: elRef,
817
- className: panelClassName,
818
- style: { left: pos.x, top: pos.y, width },
819
- onPointerDown: (e) => e.stopPropagation(),
820
- onPointerUp: (e) => {
821
- if (dragging.current) return;
822
- const now = Date.now();
823
- const last = lastTapRef.current;
824
- if (last && now - last.time < 300) {
825
- const dx = e.clientX - last.x;
826
- const dy = e.clientY - last.y;
827
- if (dx * dx + dy * dy < 100) {
828
- e.stopPropagation();
829
- handleFocus();
830
- lastTapRef.current = null;
831
- return;
832
- }
833
- }
834
- lastTapRef.current = { time: now, x: e.clientX, y: e.clientY };
835
- },
836
- onWheel: (e) => e.stopPropagation(),
837
- onDoubleClick: (e) => {
838
- e.stopPropagation();
839
- handleFocus();
840
- },
841
- children: [
842
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { onPointerDown: onDown, className: "floating-panel__header", children: [
843
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { className: "floating-panel__title", children: title }),
844
- headerActions,
845
- focusable && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
846
- "button",
847
- {
848
- type: "button",
849
- className: "wb-btn wb-btn--secondary wb-btn--icon-only floating-panel__focus",
850
- onClick: handleFocus,
851
- onPointerDown: (e) => e.stopPropagation(),
852
- title: "Focus on this panel",
853
- "aria-label": "Focus on this panel",
854
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Maximize2, { size: 14 })
855
- }
856
- )
857
- ] }),
858
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "floating-panel__body", children })
859
- ]
860
- }
861
- );
862
- });
863
- function usePanelRect(initial) {
864
- const ref = (0, import_react4.useRef)({ ...initial, width: 0, height: 0 });
865
- return ref;
866
- }
867
- function belowPanel(rect, gap = WHITEBOARD_GRID) {
868
- return { x: rect.x, y: rect.y + rect.height + gap };
869
- }
870
-
871
- // src/ConfirmDialog.tsx
872
- var import_react5 = require("react");
873
- var import_react_dom = require("react-dom");
874
- var import_jsx_runtime6 = require("react/jsx-runtime");
875
- function ConfirmDialog({
876
- open,
877
- title,
878
- message,
879
- onConfirm,
880
- onCancel,
881
- confirmLabel = "Confirm",
882
- loading,
883
- error
884
- }) {
885
- (0, import_react5.useEffect)(() => {
886
- if (!open) return;
887
- const onKey = (e) => {
888
- if (e.key === "Escape") onCancel();
889
- };
890
- window.addEventListener("keydown", onKey);
891
- return () => window.removeEventListener("keydown", onKey);
892
- }, [open, onCancel]);
893
- if (!open || typeof document === "undefined") return null;
894
- return (0, import_react_dom.createPortal)(
895
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "confirm-modal-overlay", onMouseDown: onCancel, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
896
- "div",
897
- {
898
- className: "confirm-modal",
899
- role: "dialog",
900
- "aria-modal": "true",
901
- "aria-label": title,
902
- onMouseDown: (e) => e.stopPropagation(),
903
- children: [
904
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "confirm-modal__header", children: [
905
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "confirm-modal__title", children: [
906
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AlertTriangle, { size: 16 }),
907
- title
908
- ] }),
909
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "wb-btn wb-btn--secondary wb-btn--icon-only", onClick: onCancel, "aria-label": "Close dialog", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(X, { size: 14 }) })
910
- ] }),
911
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "confirm-modal__message", children: message }),
912
- error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "wb-alert wb-alert--error", children: error }),
913
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "wb-btn-row", children: [
914
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "wb-btn wb-btn--secondary", onClick: onCancel, children: "Cancel" }),
915
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "wb-btn wb-btn--danger", onClick: onConfirm, disabled: loading, children: loading ? "Deleting..." : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
916
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Check, { size: 14 }),
917
- confirmLabel
918
- ] }) })
919
- ] })
920
- ]
921
- }
922
- ) }),
923
- document.body
924
- );
925
- }
926
-
927
- // src/PanelErrorBoundary.tsx
928
- var import_react6 = require("react");
929
- var import_jsx_runtime7 = require("react/jsx-runtime");
930
- var PanelErrorBoundary = class extends import_react6.Component {
931
- constructor() {
932
- super(...arguments);
933
- this.state = { error: null };
934
- }
935
- static getDerivedStateFromError(error) {
936
- return { error };
937
- }
938
- render() {
939
- if (this.state.error) {
940
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "wb-stack wb-stack--sm", children: [
941
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "wb-alert wb-alert--error", children: this.props.fallbackMessage ?? "This panel crashed." }),
942
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
943
- "button",
944
- {
945
- type: "button",
946
- className: "wb-btn wb-btn--secondary",
947
- onClick: () => this.setState({ error: null }),
948
- children: "Retry"
949
- }
950
- )
951
- ] });
952
- }
953
- return this.props.children;
954
- }
955
- };
956
-
957
- // src/useWhiteboardLayout.ts
958
- var import_react7 = require("react");
959
- function useWhiteboardLayout({
960
- widths,
961
- startX = 20,
962
- y = 40,
963
- gap = 20
964
- }) {
965
- const panelWidth = (0, import_react7.useMemo)(() => {
966
- const normalized = {};
967
- for (const [key, value] of Object.entries(widths)) {
968
- normalized[key] = snapToWhiteboardGrid(value);
969
- }
970
- return normalized;
971
- }, [widths]);
972
- const layout = (0, import_react7.useMemo)(
973
- () => ({
974
- startX: snapToWhiteboardGrid(startX),
975
- y: snapToWhiteboardGrid(y),
976
- gap: snapToWhiteboardGrid(gap)
977
- }),
978
- [startX, y, gap]
979
- );
980
- const positions = (0, import_react7.useMemo)(() => {
981
- const next = {};
982
- let x = layout.startX;
983
- for (const [key, width] of Object.entries(panelWidth)) {
984
- ;
985
- next[key] = { x, y: layout.y };
986
- x += width + layout.gap;
987
- }
988
- return next;
989
- }, [layout.gap, layout.startX, layout.y, panelWidth]);
990
- return { layout, panelWidth, positions };
991
- }
992
-
993
- // src/cn.ts
994
- function cn(...args) {
995
- return args.filter(Boolean).join(" ");
996
- }
997
-
998
- // src/Alert.tsx
999
- var import_jsx_runtime8 = require("react/jsx-runtime");
1000
- var toneClasses = {
1001
- error: "status-error",
1002
- muted: "text-sm text-muted",
1003
- info: "ui-alert ui-alert--info",
1004
- success: "ui-alert ui-alert--success"
1005
- };
1006
- function Alert({ tone = "info", className, ...props }) {
1007
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: cn(toneClasses[tone], className), ...props });
1008
- }
1009
-
1010
- // src/Button.tsx
1011
- var import_react8 = require("react");
1012
- var import_jsx_runtime9 = require("react/jsx-runtime");
1013
- var variantClasses = {
1014
- primary: "",
1015
- secondary: "secondary-btn",
1016
- danger: "danger-btn"
1017
- };
1018
- var Button = (0, import_react8.forwardRef)(function Button2({
1019
- variant = "primary",
1020
- fullWidth = false,
1021
- iconOnly = false,
1022
- loading = false,
1023
- disabled,
1024
- className,
1025
- children,
1026
- loadingText,
1027
- ...props
1028
- }, ref) {
1029
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1030
- "button",
1031
- {
1032
- ref,
1033
- className: cn(variantClasses[variant], fullWidth && "full-width-btn", iconOnly && "icon-only-btn", className),
1034
- disabled: disabled || loading,
1035
- ...props,
1036
- children: loading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1037
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Loader2, { size: 14, className: "icon-spin" }),
1038
- loadingText || children
1039
- ] }) : children
1040
- }
1041
- );
1042
- });
1043
-
1044
- // src/ButtonRow.tsx
1045
- var import_react9 = require("react");
1046
- function ButtonRow({ as = "div", className, ...props }) {
1047
- return (0, import_react9.createElement)(as, {
1048
- className: cn("button-row", className),
1049
- ...props
1050
- });
1051
- }
1052
-
1053
- // src/Chip.tsx
1054
- var import_jsx_runtime10 = require("react/jsx-runtime");
1055
- function Chip({ className, ...props }) {
1056
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: cn("chip", className), ...props });
1057
- }
1058
-
1059
- // src/ChoiceCard.tsx
1060
- var import_jsx_runtime11 = require("react/jsx-runtime");
1061
- function ChoiceCard({ active = false, className, ...props }) {
1062
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1063
- "button",
1064
- {
1065
- type: "button",
1066
- className: cn("choice-card", className),
1067
- "data-active": active,
1068
- ...props
1069
- }
1070
- );
1071
- }
1072
-
1073
- // src/List.tsx
1074
- var import_react10 = require("react");
1075
- function List({ as = "ul", reset = true, className, ...props }) {
1076
- return (0, import_react10.createElement)(as, {
1077
- className: cn(reset && "list-reset", className),
1078
- ...props
1079
- });
1080
- }
1081
-
1082
- // src/Skeleton.tsx
1083
- var import_react11 = require("react");
1084
- var import_jsx_runtime12 = require("react/jsx-runtime");
1085
- var radiusClasses = {
1086
- sm: "",
1087
- md: "skeleton--md",
1088
- pill: "skeleton--pill"
1089
- };
1090
- function Skeleton({ as = "div", radius = "sm", className, ...props }) {
1091
- return (0, import_react11.createElement)(as, {
1092
- className: cn("skeleton", radiusClasses[radius], className),
1093
- "aria-hidden": true,
1094
- ...props
1095
- });
1096
- }
1097
- function InputSkeleton(props) {
1098
- const { className, ...rest } = props;
1099
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Skeleton, { className: cn("skeleton-input", className), ...rest });
1100
- }
1101
- function ButtonSkeleton(props) {
1102
- const { className, ...rest } = props;
1103
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Skeleton, { className: cn("skeleton-btn", className), ...rest });
1104
- }
1105
- function IconButtonSkeleton(props) {
1106
- const { className, ...rest } = props;
1107
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Skeleton, { className: cn("skeleton-icon-btn", className), ...rest });
1108
- }
1109
- function SelectSkeleton(props) {
1110
- const { className, ...rest } = props;
1111
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Skeleton, { className: cn("skeleton-select", className), ...rest });
1112
- }
1113
- function TextareaSkeleton(props) {
1114
- const { className, ...rest } = props;
1115
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Skeleton, { className: cn("skeleton-textarea", className), ...rest });
1116
- }
1117
- function ThumbSkeleton(props) {
1118
- const { className, ...rest } = props;
1119
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Skeleton, { className: cn("skeleton-thumb", className), ...rest });
1120
- }
1121
- function ChipSkeleton(props) {
1122
- const { className, ...rest } = props;
1123
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Skeleton, { radius: "pill", className: cn("skeleton-chip", className), ...rest });
1124
- }
1125
- function TitleSkeleton(props) {
1126
- const { className, ...rest } = props;
1127
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Skeleton, { className: cn("skeleton-title", className), ...rest });
1128
- }
1129
- function LineSkeleton({ short = false, className, ...props }) {
1130
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Skeleton, { className: cn("skeleton-line", short && "skeleton-line--short", className), ...props });
1131
- }
1132
- function AvatarSkeleton(props) {
1133
- const { className, ...rest } = props;
1134
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Skeleton, { radius: "pill", className: cn("skeleton-avatar", className), ...rest });
1135
- }
1136
- function CanvasSkeleton(props) {
1137
- const { className, ...rest } = props;
1138
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Skeleton, { className: cn("skeleton-canvas", className), ...rest });
1139
- }
1140
-
1141
- // src/ChoiceGroup.tsx
1142
- var import_jsx_runtime13 = require("react/jsx-runtime");
1143
- function ChoiceGroup({
1144
- options,
1145
- value,
1146
- onChange,
1147
- className
1148
- }) {
1149
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(List, { className: cn("choice-list", className), children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1150
- ChoiceCard,
1151
- {
1152
- active: value === option.value,
1153
- onClick: () => onChange(option.value),
1154
- disabled: option.disabled,
1155
- "data-has-description": option.description ? "true" : "false",
1156
- children: option.description ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "choice-card__row", children: [
1157
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "choice-card__label", children: option.label }),
1158
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "choice-card__description", children: option.description })
1159
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "choice-card__label", children: option.label })
1160
- }
1161
- ) }, option.value)) });
1162
- }
1163
- function ChoiceGroupSkeleton({ count = 4, className, withDescription = false }) {
1164
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(List, { className: cn("choice-list", className), "aria-hidden": true, children: Array.from({ length: count }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "choice-card", children: [
1165
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TitleSkeleton, { className: cn("skeleton-title--sm", !withDescription && "skeleton-choice-label") }),
1166
- withDescription ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(LineSkeleton, { short: true }) : null
1167
- ] }) }, `choice-skeleton-${i}`)) });
1168
- }
1169
-
1170
- // src/CoordGrid.tsx
1171
- var import_jsx_runtime14 = require("react/jsx-runtime");
1172
- function CoordGrid({ className, ...props }) {
1173
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: cn("coord-grid", className), ...props });
1174
- }
1175
- function CoordInput({ axis, className, ...props }) {
1176
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: cn("coord-input", className), children: [
1177
- axis,
1178
- " ",
1179
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("input", { type: "number", step: "0.01", ...props })
1180
- ] });
1181
- }
1182
-
1183
- // src/Stack.tsx
1184
- var import_react12 = require("react");
1185
- function Stack({
1186
- as,
1187
- size = "md",
1188
- className,
1189
- ...props
1190
- }) {
1191
- return (0, import_react12.createElement)(as ?? "div", {
1192
- className: cn(size === "sm" ? "panel-stack-sm" : "panel-stack", className),
1193
- ...props
1194
- });
1195
- }
1196
-
1197
- // src/Typography.tsx
1198
- var import_react13 = require("react");
1199
- var mutedSizeClasses = {
1200
- xs: "text-xs",
1201
- sm: "text-sm",
1202
- md: ""
1203
- };
1204
- function AssetTitle({ as = "p", clamp = false, className, ...props }) {
1205
- return (0, import_react13.createElement)(as, {
1206
- className: cn("asset-title", clamp && "asset-title--clamp", className),
1207
- ...props
1208
- });
1209
- }
1210
- function StoryTitle({ as = "h3", className, ...props }) {
1211
- return (0, import_react13.createElement)(as, {
1212
- className: cn("story-title", className),
1213
- ...props
1214
- });
1215
- }
1216
- function MutedText({ as = "p", size = "sm", className, ...props }) {
1217
- return (0, import_react13.createElement)(as, {
1218
- className: cn(mutedSizeClasses[size], "text-muted", className),
1219
- ...props
1220
- });
1221
- }
1222
- function PageTitle({ as = "h1", className, ...props }) {
1223
- return (0, import_react13.createElement)(as, {
1224
- className: cn("page-title", className),
1225
- ...props
1226
- });
1227
- }
1228
- function SectionTitle({ as = "span", className, ...props }) {
1229
- return (0, import_react13.createElement)(as, {
1230
- className: cn("widget-section__title", className),
1231
- ...props
1232
- });
1233
- }
1234
- function SectionDescription({ as = "p", className, ...props }) {
1235
- return (0, import_react13.createElement)(as, {
1236
- className: cn("widget-section__description", className),
1237
- ...props
1238
- });
1239
- }
1240
-
1241
- // src/EmptyState.tsx
1242
- var import_jsx_runtime15 = require("react/jsx-runtime");
1243
- function EmptyState({ title, description, action }) {
1244
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Stack, { size: "sm", children: [
1245
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AssetTitle, { children: title }),
1246
- description ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MutedText, { children: description }) : null,
1247
- action
1248
- ] });
1249
- }
1250
-
1251
- // src/Field.tsx
1252
- var import_react14 = require("react");
1253
-
1254
- // src/Label.tsx
1255
- var import_jsx_runtime16 = require("react/jsx-runtime");
1256
- function Label({ className, ...props }) {
1257
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("label", { className: cn("widget-label", className), ...props });
1258
- }
1259
-
1260
- // src/Field.tsx
1261
- var import_jsx_runtime17 = require("react/jsx-runtime");
1262
- function Field({
1263
- as,
1264
- label,
1265
- htmlFor,
1266
- hint,
1267
- error,
1268
- layout = "stack",
1269
- className,
1270
- children,
1271
- ...props
1272
- }) {
1273
- return (0, import_react14.createElement)(
1274
- as ?? "div",
1275
- {
1276
- className: cn(layout === "control" ? "widget-control" : "panel-stack-sm", className),
1277
- ...props
1278
- },
1279
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1280
- label ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Label, { htmlFor, children: label }) : null,
1281
- children,
1282
- hint ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MutedText, { size: "xs", children: hint }) : null,
1283
- error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "field-error", children: error }) : null
1284
- ] })
1285
- );
1286
- }
1287
-
1288
- // src/GeneratingOverlay.tsx
1289
- var import_jsx_runtime18 = require("react/jsx-runtime");
1290
- function GeneratingOverlay({ isGenerating, children, message }) {
1291
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "generating-overlay-wrap", children: [
1292
- children,
1293
- isGenerating && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "generating-overlay", "aria-live": "polite", children: [
1294
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Loader2, { size: 20, className: "icon-spin" }),
1295
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: message ?? "Generating, please wait\u2026" })
1296
- ] })
1297
- ] });
1298
- }
1299
-
1300
- // src/IconText.tsx
1301
- var import_react15 = require("react");
1302
- var import_jsx_runtime19 = require("react/jsx-runtime");
1303
- function IconText({ as = "span", icon, className, children, ...props }) {
1304
- return (0, import_react15.createElement)(
1305
- as,
1306
- {
1307
- className: cn("inline-row", className),
1308
- ...props
1309
- },
1310
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
1311
- icon,
1312
- children
1313
- ] })
1314
- );
1315
- }
1316
-
1317
- // src/ImageThumb.tsx
1318
- var import_react16 = require("react");
1319
- var import_jsx_runtime20 = require("react/jsx-runtime");
1320
- function ImageThumb({
1321
- src,
1322
- alt,
1323
- placeholder = "No image",
1324
- size = "md",
1325
- fit = "contain",
1326
- onImageError,
1327
- className,
1328
- ...props
1329
- }) {
1330
- const [failedSrc, setFailedSrc] = (0, import_react16.useState)(null);
1331
- const failed = Boolean(src && failedSrc === src);
1332
- const classes = cn("image-thumb", `image-thumb--${size}`, `image-thumb--fit-${fit}`, className);
1333
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: classes, ...props, children: src && !failed ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1334
- "img",
1335
- {
1336
- src,
1337
- alt,
1338
- className: "image-thumb__img",
1339
- style: { objectFit: fit, objectPosition: "center" },
1340
- onError: () => {
1341
- setFailedSrc(src);
1342
- onImageError?.();
1343
- }
1344
- }
1345
- ) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "image-thumb__placeholder", children: placeholder }) });
1346
- }
1347
-
1348
- // src/Inline.tsx
1349
- var import_react17 = require("react");
1350
- function Inline({
1351
- as,
1352
- justify = "start",
1353
- className,
1354
- ...props
1355
- }) {
1356
- return (0, import_react17.createElement)(as ?? "div", {
1357
- className: cn(justify === "between" ? "space-between" : "inline-row", className),
1358
- ...props
1359
- });
1360
- }
1361
-
1362
- // src/Input.tsx
1363
- var import_react18 = require("react");
1364
- var import_jsx_runtime21 = require("react/jsx-runtime");
1365
- var Input = (0, import_react18.forwardRef)(function Input2({ className, ...props }, ref) {
1366
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { ref, className: cn(className), ...props });
1367
- });
1368
-
1369
- // src/ItemCard.tsx
1370
- var import_react19 = require("react");
1371
- function ItemCard({ as = "div", className, ...props }) {
1372
- return (0, import_react19.createElement)(as, {
1373
- className: cn("item-card", className),
1374
- ...props
1375
- });
1376
- }
1377
-
1378
- // src/ItemList.tsx
1379
- var import_react20 = require("react");
1380
- function ItemList({ as = "div", className, ...props }) {
1381
- return (0, import_react20.createElement)(as, {
1382
- className: cn("item-list", className),
1383
- ...props
1384
- });
1385
- }
1386
-
1387
- // src/LoadingState.tsx
1388
- var import_jsx_runtime22 = require("react/jsx-runtime");
1389
- function LoadingState({ label = "Loading...", className }) {
1390
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: cn("status-inline", className), children: [
1391
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Loader2, { size: 14, className: "icon-spin" }),
1392
- label
1393
- ] });
1394
- }
1395
-
1396
- // src/PageLayout.tsx
1397
- var import_jsx_runtime23 = require("react/jsx-runtime");
1398
- function PageShell({ children }) {
1399
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("main", { className: "page-shell", children });
1400
- }
1401
- function PageCard({ children }) {
1402
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "page-card", children });
1403
- }
1404
-
1405
- // src/PanelCloseButton.tsx
1406
- var import_jsx_runtime24 = require("react/jsx-runtime");
1407
- function PanelCloseButton({ onClick, label = "Close" }) {
1408
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(Button, { variant: "secondary", className: "panel-close-btn", onClick, children: [
1409
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(X, { size: 14 }),
1410
- label
1411
- ] });
1412
- }
1413
-
1414
- // src/PanelSection.tsx
1415
- var import_jsx_runtime25 = require("react/jsx-runtime");
1416
- function PanelSection({ heading, description, actions, className, children, ...props }) {
1417
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("section", { className: cn("widget-section", className), ...props, children: [
1418
- heading || actions ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("header", { className: actions ? "title-row" : void 0, children: [
1419
- heading ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SectionTitle, { children: heading }) : null,
1420
- actions
1421
- ] }) : null,
1422
- description ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SectionDescription, { children: description }) : null,
1423
- children
1424
- ] });
1425
- }
1426
-
1427
- // src/PanelTitle.tsx
1428
- var import_jsx_runtime26 = require("react/jsx-runtime");
1429
- function PanelTitle({ icon: Icon, label }) {
1430
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "panel-title-with-icon", children: [
1431
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Icon, { size: 13, className: "panel-title-icon" }),
1432
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: label })
1433
- ] });
1434
- }
1435
-
1436
- // src/PickerCard.tsx
1437
- var import_react21 = require("react");
1438
- function PickerCard({ as = "button", className, ...props }) {
1439
- return (0, import_react21.createElement)(as, {
1440
- className: cn("picker-card", className),
1441
- ...props
1442
- });
1443
- }
1444
-
1445
- // src/PickerGrid.tsx
1446
- var import_jsx_runtime27 = require("react/jsx-runtime");
1447
- var variantClasses2 = {
1448
- elements: "picker-grid--elements",
1449
- characters: "picker-grid--characters",
1450
- library: "picker-grid--library"
1451
- };
1452
- function PickerGrid({ variant, className, ...props }) {
1453
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(List, { className: cn("picker-grid", variantClasses2[variant], className), ...props });
1454
- }
1455
-
1456
- // src/Pill.tsx
1457
- var import_jsx_runtime28 = require("react/jsx-runtime");
1458
- var toneClasses2 = {
1459
- default: "",
1460
- success: "success",
1461
- warning: "warning",
1462
- danger: "danger"
1463
- };
1464
- function Pill({ tone = "default", className, ...props }) {
1465
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: cn("pill", toneClasses2[tone], className), ...props });
1466
- }
1467
-
1468
- // src/Select.tsx
1469
- var import_react22 = require("react");
1470
- var import_jsx_runtime29 = require("react/jsx-runtime");
1471
- var Select = (0, import_react22.forwardRef)(function Select2({ className, ...props }, ref) {
1472
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("select", { ref, className: cn(className), ...props });
1473
- });
1474
-
1475
- // src/SplitLayout.tsx
1476
- var import_jsx_runtime30 = require("react/jsx-runtime");
1477
- var variantClasses3 = {
1478
- element: "split-layout--element",
1479
- character: "split-layout--character",
1480
- user: "split-layout--user"
1481
- };
1482
- function SplitLayout({ variant, className, ...props }) {
1483
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: cn("split-layout", variantClasses3[variant], className), ...props });
1484
- }
1485
-
1486
- // src/TagRow.tsx
1487
- var import_jsx_runtime31 = require("react/jsx-runtime");
1488
- function TagRow({ className, ...props }) {
1489
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: cn("tag-row", className), ...props });
1490
- }
1491
-
1492
- // src/Textarea.tsx
1493
- var import_react23 = require("react");
1494
- var import_jsx_runtime32 = require("react/jsx-runtime");
1495
- var Textarea = (0, import_react23.forwardRef)(function Textarea2({ className, ...props }, ref) {
1496
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("textarea", { ref, className: cn(className), ...props });
1497
- });
1498
-
1499
- // src/ThemeToggle.tsx
1500
- var import_jsx_runtime33 = require("react/jsx-runtime");
1501
- function ThemeToggle({ className, theme = "light", onToggle, lightIcon, darkIcon }) {
1502
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { className, onClick: onToggle, title: `Switch to ${theme === "light" ? "dark" : "light"} mode`, "aria-label": "Toggle theme", children: theme === "light" ? darkIcon ?? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Moon, {}) : lightIcon ?? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Sun, {}) });
1503
- }
1504
-
1505
- // src/TitleRow.tsx
1506
- var import_jsx_runtime34 = require("react/jsx-runtime");
1507
- function TitleRow({ className, ...props }) {
1508
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: cn("title-row", className), ...props });
1509
- }
1510
-
1511
- // src/WidgetSkeletons.tsx
1512
- var import_jsx_runtime35 = require("react/jsx-runtime");
1513
- function PanelFormSkeleton({ inputs = 1, showButton = true, className, ...props }) {
1514
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Stack, { className, ...props, children: [
1515
- Array.from({ length: inputs }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(InputSkeleton, {}, `panel-form-input-${i}`)),
1516
- showButton && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ButtonSkeleton, {})
1517
- ] });
1518
- }
1519
- function StoryCardSkeleton() {
1520
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("article", { className: "story-card", children: [
1521
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "story-cover", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "story-cover__placeholder story-cover__placeholder--skeleton" }) }),
1522
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "story-card__overlay story-card__overlay--skeleton", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "story-card__overlay-text", children: [
1523
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Inline, { as: "header", children: [
1524
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ChipSkeleton, {}),
1525
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ChipSkeleton, {})
1526
- ] }),
1527
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TitleSkeleton, {}),
1528
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(LineSkeleton, { short: true })
1529
- ] }) })
1530
- ] });
1531
- }
1532
- function UserCardSkeleton() {
1533
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ItemCard, { as: "li", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(SplitLayout, { variant: "user", children: [
1534
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(AvatarSkeleton, {}),
1535
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Stack, { size: "sm", children: [
1536
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TitleSkeleton, {}),
1537
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(LineSkeleton, { short: true })
1538
- ] }),
1539
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Stack, { size: "sm", children: [
1540
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ChipSkeleton, {}),
1541
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(SelectSkeleton, {})
1542
- ] })
1543
- ] }) });
1544
- }
1545
- function UserListSkeleton({ count = 3 }) {
1546
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ItemList, { as: "ul", children: Array.from({ length: count }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(UserCardSkeleton, {}, `user-skeleton-${i}`)) });
1547
- }
1548
- function AssetCardSkeleton() {
1549
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(ItemCard, { as: "li", children: [
1550
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Stack, { size: "sm", children: [
1551
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ThumbSkeleton, { className: "asset-thumb" }),
1552
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TitleSkeleton, {}),
1553
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(TagRow, { children: [
1554
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ChipSkeleton, {}),
1555
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ChipSkeleton, {})
1556
- ] })
1557
- ] }),
1558
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(ButtonRow, { children: [
1559
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ButtonSkeleton, {}),
1560
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ButtonSkeleton, {})
1561
- ] })
1562
- ] });
1563
- }
1564
- function PickerGridSkeleton({ count = 8, gridClass }) {
1565
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(List, { className: cn("picker-grid", gridClass), children: Array.from({ length: count }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(PickerCard, { as: "div", className: "picker-card--skeleton", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Stack, { size: "sm", children: [
1566
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ThumbSkeleton, { className: "asset-thumb" }),
1567
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(LineSkeleton, { short: true })
1568
- ] }) }) }, `picker-skeleton-${i}`)) });
1569
- }
1570
- // Annotate the CommonJS export names for ESM import in node:
1571
- 0 && (module.exports = {
1572
- Alert,
1573
- AssetCardSkeleton,
1574
- AssetTitle,
1575
- AvatarSkeleton,
1576
- Button,
1577
- ButtonRow,
1578
- ButtonSkeleton,
1579
- CanvasSkeleton,
1580
- Chip,
1581
- ChipSkeleton,
1582
- ChoiceCard,
1583
- ChoiceGroup,
1584
- ChoiceGroupSkeleton,
1585
- ConfirmDialog,
1586
- CoordGrid,
1587
- CoordInput,
1588
- EmptyState,
1589
- Field,
1590
- FloatingPanel,
1591
- GeneratingOverlay,
1592
- IconButtonSkeleton,
1593
- IconText,
1594
- ImageThumb,
1595
- Inline,
1596
- Input,
1597
- InputSkeleton,
1598
- ItemCard,
1599
- ItemList,
1600
- Label,
1601
- LineSkeleton,
1602
- List,
1603
- LoadingState,
1604
- Minimap,
1605
- MutedText,
1606
- PageCard,
1607
- PageShell,
1608
- PageTitle,
1609
- PanelCloseButton,
1610
- PanelErrorBoundary,
1611
- PanelFormSkeleton,
1612
- PanelSection,
1613
- PanelTitle,
1614
- PickerCard,
1615
- PickerGrid,
1616
- PickerGridSkeleton,
1617
- Pill,
1618
- SectionDescription,
1619
- SectionTitle,
1620
- Select,
1621
- SelectSkeleton,
1622
- Skeleton,
1623
- SplitLayout,
1624
- Stack,
1625
- StoryCardSkeleton,
1626
- StoryTitle,
1627
- TagRow,
1628
- Textarea,
1629
- TextareaSkeleton,
1630
- ThemeToggle,
1631
- ThumbSkeleton,
1632
- TitleRow,
1633
- TitleSkeleton,
1634
- UserCardSkeleton,
1635
- UserListSkeleton,
1636
- WHITEBOARD_GRID,
1637
- WhiteboardShell,
1638
- ZoomBar,
1639
- belowPanel,
1640
- cn,
1641
- computeWhiteboardFit,
1642
- computeWhiteboardRectFocus,
1643
- snapToWhiteboardGrid,
1644
- usePanelRect,
1645
- useWhiteboardLayout,
1646
- useWhiteboardStore
1647
- });
1648
- //# sourceMappingURL=index.cjs.map