state-surgeon 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1192 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var React2 = require('react');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var React2__default = /*#__PURE__*/_interopDefault(React2);
9
+
10
+ // src/dashboard/components/MutationInspector.tsx
11
+ function MutationInspector({
12
+ mutation,
13
+ className = ""
14
+ }) {
15
+ if (!mutation) {
16
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `mutation-inspector mutation-inspector--empty ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Select a mutation to inspect" }) });
17
+ }
18
+ const formatDuration = (ms) => {
19
+ if (ms === void 0) return "N/A";
20
+ if (ms < 1) return `${(ms * 1e3).toFixed(2)}\u03BCs`;
21
+ if (ms < 1e3) return `${ms.toFixed(2)}ms`;
22
+ return `${(ms / 1e3).toFixed(2)}s`;
23
+ };
24
+ const formatTimestamp = (ts) => {
25
+ const date = new Date(ts);
26
+ return date.toLocaleString();
27
+ };
28
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `mutation-inspector ${className}`, children: [
29
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mutation-inspector__header", children: [
30
+ /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "mutation-inspector__title", children: [
31
+ /* @__PURE__ */ jsxRuntime.jsx(
32
+ "span",
33
+ {
34
+ className: "mutation-inspector__source-badge",
35
+ "data-source": mutation.source,
36
+ children: mutation.source
37
+ }
38
+ ),
39
+ mutation.actionType
40
+ ] }),
41
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mutation-inspector__id", children: mutation.id })
42
+ ] }),
43
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mutation-inspector__grid", children: [
44
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mutation-inspector__section", children: [
45
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { children: "Location" }),
46
+ /* @__PURE__ */ jsxRuntime.jsxs("dl", { className: "mutation-inspector__details", children: [
47
+ mutation.component && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
48
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Component" }),
49
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: mutation.component })
50
+ ] }),
51
+ mutation.function && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
52
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Function" }),
53
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: mutation.function }) })
54
+ ] }),
55
+ mutation.file && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
56
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "File" }),
57
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: /* @__PURE__ */ jsxRuntime.jsxs("code", { children: [
58
+ mutation.file,
59
+ mutation.line && `:${mutation.line}`,
60
+ mutation.column && `:${mutation.column}`
61
+ ] }) })
62
+ ] })
63
+ ] })
64
+ ] }),
65
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mutation-inspector__section", children: [
66
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { children: "Timing" }),
67
+ /* @__PURE__ */ jsxRuntime.jsxs("dl", { className: "mutation-inspector__details", children: [
68
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Timestamp" }),
69
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: formatTimestamp(mutation.timestamp) }),
70
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Logical Clock" }),
71
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: mutation.logicalClock }),
72
+ mutation.duration !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
73
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Duration" }),
74
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: formatDuration(mutation.duration) })
75
+ ] })
76
+ ] })
77
+ ] })
78
+ ] }),
79
+ mutation.actionPayload && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mutation-inspector__section", children: [
80
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { children: "Action Payload" }),
81
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "mutation-inspector__code", children: JSON.stringify(mutation.actionPayload, null, 2) })
82
+ ] }),
83
+ mutation.diff && mutation.diff.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mutation-inspector__section", children: [
84
+ /* @__PURE__ */ jsxRuntime.jsxs("h4", { children: [
85
+ "State Changes (",
86
+ mutation.diff.length,
87
+ ")"
88
+ ] }),
89
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mutation-inspector__changes", children: mutation.diff.map((change, index) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: `mutation-inspector__change mutation-inspector__change--${change.operation.toLowerCase()}`, children: [
90
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: change.path }),
91
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mutation-inspector__op", children: change.operation })
92
+ ] }, index)) })
93
+ ] }),
94
+ mutation.callStack && mutation.callStack.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mutation-inspector__section", children: [
95
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { children: "Call Stack" }),
96
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mutation-inspector__stack", children: mutation.callStack.map((frame, index) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "mutation-inspector__frame", children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: frame }) }, index)) })
97
+ ] }),
98
+ mutation.causes && mutation.causes.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mutation-inspector__section", children: [
99
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { children: "Caused By" }),
100
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mutation-inspector__causes", children: mutation.causes.map((causeId, index) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: causeId }) }, index)) })
101
+ ] }),
102
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
103
+ .mutation-inspector {
104
+ padding: 1rem;
105
+ background: #1a1a2e;
106
+ border-radius: 8px;
107
+ color: #e0e0e0;
108
+ font-size: 0.875rem;
109
+ }
110
+
111
+ .mutation-inspector--empty {
112
+ text-align: center;
113
+ color: #666;
114
+ padding: 2rem;
115
+ }
116
+
117
+ .mutation-inspector__header {
118
+ display: flex;
119
+ justify-content: space-between;
120
+ align-items: center;
121
+ margin-bottom: 1rem;
122
+ padding-bottom: 0.5rem;
123
+ border-bottom: 1px solid #333;
124
+ }
125
+
126
+ .mutation-inspector__title {
127
+ display: flex;
128
+ align-items: center;
129
+ gap: 0.5rem;
130
+ margin: 0;
131
+ font-size: 1rem;
132
+ color: #fff;
133
+ }
134
+
135
+ .mutation-inspector__source-badge {
136
+ padding: 0.125rem 0.5rem;
137
+ border-radius: 4px;
138
+ font-size: 0.75rem;
139
+ font-weight: 600;
140
+ text-transform: uppercase;
141
+ }
142
+
143
+ .mutation-inspector__source-badge[data-source="react"] {
144
+ background: #61dafb;
145
+ color: #000;
146
+ }
147
+
148
+ .mutation-inspector__source-badge[data-source="redux"] {
149
+ background: #764abc;
150
+ color: #fff;
151
+ }
152
+
153
+ .mutation-inspector__source-badge[data-source="zustand"] {
154
+ background: #f59e0b;
155
+ color: #000;
156
+ }
157
+
158
+ .mutation-inspector__source-badge[data-source="api"] {
159
+ background: #3b82f6;
160
+ color: #fff;
161
+ }
162
+
163
+ .mutation-inspector__id {
164
+ color: #666;
165
+ font-family: monospace;
166
+ font-size: 0.75rem;
167
+ }
168
+
169
+ .mutation-inspector__grid {
170
+ display: grid;
171
+ grid-template-columns: 1fr 1fr;
172
+ gap: 1rem;
173
+ margin-bottom: 1rem;
174
+ }
175
+
176
+ .mutation-inspector__section {
177
+ margin-bottom: 1rem;
178
+ }
179
+
180
+ .mutation-inspector__section h4 {
181
+ margin: 0 0 0.5rem 0;
182
+ color: #00d9ff;
183
+ font-size: 0.875rem;
184
+ }
185
+
186
+ .mutation-inspector__details {
187
+ margin: 0;
188
+ display: grid;
189
+ grid-template-columns: auto 1fr;
190
+ gap: 0.25rem 0.5rem;
191
+ }
192
+
193
+ .mutation-inspector__details dt {
194
+ color: #888;
195
+ }
196
+
197
+ .mutation-inspector__details dd {
198
+ margin: 0;
199
+ color: #e0e0e0;
200
+ }
201
+
202
+ .mutation-inspector__code {
203
+ margin: 0;
204
+ padding: 0.75rem;
205
+ background: #0f0f23;
206
+ border-radius: 4px;
207
+ overflow: auto;
208
+ max-height: 200px;
209
+ font-size: 0.8rem;
210
+ }
211
+
212
+ .mutation-inspector__changes,
213
+ .mutation-inspector__stack,
214
+ .mutation-inspector__causes {
215
+ list-style: none;
216
+ margin: 0;
217
+ padding: 0;
218
+ }
219
+
220
+ .mutation-inspector__change {
221
+ display: flex;
222
+ align-items: center;
223
+ gap: 0.5rem;
224
+ padding: 0.25rem 0.5rem;
225
+ border-radius: 4px;
226
+ margin-bottom: 0.25rem;
227
+ }
228
+
229
+ .mutation-inspector__change--add {
230
+ background: rgba(34, 197, 94, 0.1);
231
+ }
232
+
233
+ .mutation-inspector__change--update {
234
+ background: rgba(251, 191, 36, 0.1);
235
+ }
236
+
237
+ .mutation-inspector__change--remove {
238
+ background: rgba(239, 68, 68, 0.1);
239
+ }
240
+
241
+ .mutation-inspector__op {
242
+ font-size: 0.7rem;
243
+ padding: 0.125rem 0.375rem;
244
+ border-radius: 3px;
245
+ background: #333;
246
+ color: #888;
247
+ }
248
+
249
+ .mutation-inspector__frame {
250
+ padding: 0.25rem 0;
251
+ border-bottom: 1px solid #222;
252
+ }
253
+
254
+ .mutation-inspector__frame:last-child {
255
+ border-bottom: none;
256
+ }
257
+
258
+ code {
259
+ font-family: 'Fira Code', 'Monaco', monospace;
260
+ }
261
+ ` })
262
+ ] });
263
+ }
264
+
265
+ // src/core/diff.ts
266
+ function calculateDiff(before, after, path = "") {
267
+ const diffs = [];
268
+ if (before === after) {
269
+ return diffs;
270
+ }
271
+ if (before === null || before === void 0 || typeof before !== "object") {
272
+ if (after === null || after === void 0 || typeof after !== "object") {
273
+ if (before !== after) {
274
+ if (before === void 0) {
275
+ diffs.push({ path: path || "root", operation: "ADD", newValue: after });
276
+ } else if (after === void 0) {
277
+ diffs.push({ path: path || "root", operation: "REMOVE", oldValue: before });
278
+ } else {
279
+ diffs.push({ path: path || "root", operation: "UPDATE", oldValue: before, newValue: after });
280
+ }
281
+ }
282
+ return diffs;
283
+ }
284
+ diffs.push({ path: path || "root", operation: "UPDATE", oldValue: before, newValue: after });
285
+ return diffs;
286
+ }
287
+ if (after === null || after === void 0 || typeof after !== "object") {
288
+ diffs.push({ path: path || "root", operation: "UPDATE", oldValue: before, newValue: after });
289
+ return diffs;
290
+ }
291
+ if (Array.isArray(before) || Array.isArray(after)) {
292
+ if (!Array.isArray(before) || !Array.isArray(after)) {
293
+ diffs.push({ path: path || "root", operation: "UPDATE", oldValue: before, newValue: after });
294
+ return diffs;
295
+ }
296
+ const maxLength = Math.max(before.length, after.length);
297
+ for (let i = 0; i < maxLength; i++) {
298
+ const itemPath = path ? `${path}[${i}]` : `[${i}]`;
299
+ if (i >= before.length) {
300
+ diffs.push({ path: itemPath, operation: "ADD", newValue: after[i] });
301
+ } else if (i >= after.length) {
302
+ diffs.push({ path: itemPath, operation: "REMOVE", oldValue: before[i] });
303
+ } else {
304
+ diffs.push(...calculateDiff(before[i], after[i], itemPath));
305
+ }
306
+ }
307
+ return diffs;
308
+ }
309
+ const beforeObj = before;
310
+ const afterObj = after;
311
+ const allKeys = /* @__PURE__ */ new Set([...Object.keys(beforeObj), ...Object.keys(afterObj)]);
312
+ for (const key of allKeys) {
313
+ const keyPath = path ? `${path}.${key}` : key;
314
+ const beforeValue = beforeObj[key];
315
+ const afterValue = afterObj[key];
316
+ if (!(key in beforeObj)) {
317
+ diffs.push({ path: keyPath, operation: "ADD", newValue: afterValue });
318
+ } else if (!(key in afterObj)) {
319
+ diffs.push({ path: keyPath, operation: "REMOVE", oldValue: beforeValue });
320
+ } else {
321
+ diffs.push(...calculateDiff(beforeValue, afterValue, keyPath));
322
+ }
323
+ }
324
+ return diffs;
325
+ }
326
+ function StateDiffViewer({
327
+ previousState,
328
+ nextState,
329
+ diff: preDiff,
330
+ defaultExpandDepth = 3,
331
+ className = ""
332
+ }) {
333
+ const diff = React2.useMemo(
334
+ () => preDiff || calculateDiff(previousState, nextState),
335
+ [previousState, nextState, preDiff]
336
+ );
337
+ const changedPaths = React2.useMemo(
338
+ () => new Set(diff.map((d) => d.path)),
339
+ [diff]
340
+ );
341
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `state-diff-viewer ${className}`, children: [
342
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "state-diff-viewer__panels", children: [
343
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "state-diff-viewer__panel", children: [
344
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "state-diff-viewer__title", children: "Before" }),
345
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "state-diff-viewer__content", children: /* @__PURE__ */ jsxRuntime.jsx(
346
+ StateTree,
347
+ {
348
+ value: previousState,
349
+ path: "",
350
+ changedPaths,
351
+ defaultExpandDepth,
352
+ changeType: "before"
353
+ }
354
+ ) })
355
+ ] }),
356
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "state-diff-viewer__panel", children: [
357
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "state-diff-viewer__title", children: "After" }),
358
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "state-diff-viewer__content", children: /* @__PURE__ */ jsxRuntime.jsx(
359
+ StateTree,
360
+ {
361
+ value: nextState,
362
+ path: "",
363
+ changedPaths,
364
+ defaultExpandDepth,
365
+ changeType: "after"
366
+ }
367
+ ) })
368
+ ] })
369
+ ] }),
370
+ diff.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "state-diff-viewer__summary", children: [
371
+ /* @__PURE__ */ jsxRuntime.jsxs("h4", { children: [
372
+ "Changes (",
373
+ diff.length,
374
+ ")"
375
+ ] }),
376
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "state-diff-viewer__changes", children: diff.map((change, index) => /* @__PURE__ */ jsxRuntime.jsxs(
377
+ "li",
378
+ {
379
+ className: `state-diff-viewer__change state-diff-viewer__change--${change.operation.toLowerCase()}`,
380
+ children: [
381
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: change.path }),
382
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "state-diff-viewer__change-type", children: change.operation }),
383
+ change.operation === "UPDATE" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
384
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "state-diff-viewer__value state-diff-viewer__value--old", children: formatValue(change.oldValue) }),
385
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "state-diff-viewer__arrow", children: "\u2192" }),
386
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "state-diff-viewer__value state-diff-viewer__value--new", children: formatValue(change.newValue) })
387
+ ] }),
388
+ change.operation === "ADD" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "state-diff-viewer__value state-diff-viewer__value--new", children: formatValue(change.newValue) }),
389
+ change.operation === "REMOVE" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "state-diff-viewer__value state-diff-viewer__value--old", children: formatValue(change.oldValue) })
390
+ ]
391
+ },
392
+ index
393
+ )) })
394
+ ] }),
395
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
396
+ .state-diff-viewer {
397
+ font-family: monospace;
398
+ font-size: 0.875rem;
399
+ color: #e0e0e0;
400
+ }
401
+
402
+ .state-diff-viewer__panels {
403
+ display: grid;
404
+ grid-template-columns: 1fr 1fr;
405
+ gap: 1rem;
406
+ }
407
+
408
+ .state-diff-viewer__panel {
409
+ background: #16213e;
410
+ border-radius: 8px;
411
+ overflow: hidden;
412
+ }
413
+
414
+ .state-diff-viewer__title {
415
+ margin: 0;
416
+ padding: 0.75rem 1rem;
417
+ background: #1a1a2e;
418
+ font-size: 0.875rem;
419
+ font-weight: 600;
420
+ color: #00d9ff;
421
+ }
422
+
423
+ .state-diff-viewer__content {
424
+ padding: 1rem;
425
+ max-height: 400px;
426
+ overflow: auto;
427
+ }
428
+
429
+ .state-diff-viewer__summary {
430
+ margin-top: 1rem;
431
+ padding: 1rem;
432
+ background: #16213e;
433
+ border-radius: 8px;
434
+ }
435
+
436
+ .state-diff-viewer__summary h4 {
437
+ margin: 0 0 0.5rem 0;
438
+ color: #00d9ff;
439
+ }
440
+
441
+ .state-diff-viewer__changes {
442
+ list-style: none;
443
+ margin: 0;
444
+ padding: 0;
445
+ }
446
+
447
+ .state-diff-viewer__change {
448
+ display: flex;
449
+ flex-wrap: wrap;
450
+ align-items: center;
451
+ gap: 0.5rem;
452
+ padding: 0.5rem;
453
+ border-radius: 4px;
454
+ margin-bottom: 0.25rem;
455
+ }
456
+
457
+ .state-diff-viewer__change--add {
458
+ background: rgba(34, 197, 94, 0.1);
459
+ border-left: 3px solid #22c55e;
460
+ }
461
+
462
+ .state-diff-viewer__change--update {
463
+ background: rgba(251, 191, 36, 0.1);
464
+ border-left: 3px solid #fbbf24;
465
+ }
466
+
467
+ .state-diff-viewer__change--remove {
468
+ background: rgba(239, 68, 68, 0.1);
469
+ border-left: 3px solid #ef4444;
470
+ }
471
+
472
+ .state-diff-viewer__change-type {
473
+ font-size: 0.7rem;
474
+ padding: 0.125rem 0.375rem;
475
+ border-radius: 3px;
476
+ background: #333;
477
+ color: #888;
478
+ }
479
+
480
+ .state-diff-viewer__value {
481
+ padding: 0.125rem 0.375rem;
482
+ border-radius: 3px;
483
+ }
484
+
485
+ .state-diff-viewer__value--old {
486
+ background: rgba(239, 68, 68, 0.2);
487
+ color: #fca5a5;
488
+ text-decoration: line-through;
489
+ }
490
+
491
+ .state-diff-viewer__value--new {
492
+ background: rgba(34, 197, 94, 0.2);
493
+ color: #86efac;
494
+ }
495
+
496
+ .state-diff-viewer__arrow {
497
+ color: #666;
498
+ }
499
+ ` })
500
+ ] });
501
+ }
502
+ function StateTree({
503
+ value,
504
+ path,
505
+ changedPaths,
506
+ defaultExpandDepth,
507
+ depth = 0,
508
+ changeType
509
+ }) {
510
+ const [isExpanded, setIsExpanded] = React2.useState(depth < defaultExpandDepth);
511
+ const isChanged = path ? changedPaths.has(path) : false;
512
+ const toggle = React2.useCallback(() => setIsExpanded((e) => !e), []);
513
+ if (value === null) {
514
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "state-tree__null", children: "null" });
515
+ }
516
+ if (value === void 0) {
517
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "state-tree__undefined", children: "undefined" });
518
+ }
519
+ if (typeof value === "boolean") {
520
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "state-tree__boolean", children: String(value) });
521
+ }
522
+ if (typeof value === "number") {
523
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `state-tree__number ${isChanged ? "state-tree--changed" : ""}`, children: String(value) });
524
+ }
525
+ if (typeof value === "string") {
526
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `state-tree__string ${isChanged ? "state-tree--changed" : ""}`, children: [
527
+ '"',
528
+ value,
529
+ '"'
530
+ ] });
531
+ }
532
+ if (Array.isArray(value)) {
533
+ if (value.length === 0) {
534
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "state-tree__empty", children: "[]" });
535
+ }
536
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "state-tree__array", children: [
537
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "state-tree__toggle", onClick: toggle, children: [
538
+ isExpanded ? "\u25BC" : "\u25B6",
539
+ " Array(",
540
+ value.length,
541
+ ")"
542
+ ] }),
543
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "state-tree__children", children: value.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "state-tree__item", children: [
544
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "state-tree__key", children: [
545
+ index,
546
+ ":"
547
+ ] }),
548
+ /* @__PURE__ */ jsxRuntime.jsx(
549
+ StateTree,
550
+ {
551
+ value: item,
552
+ path: path ? `${path}[${index}]` : `[${index}]`,
553
+ changedPaths,
554
+ defaultExpandDepth,
555
+ depth: depth + 1,
556
+ changeType
557
+ }
558
+ )
559
+ ] }, index)) })
560
+ ] });
561
+ }
562
+ if (typeof value === "object") {
563
+ const entries = Object.entries(value);
564
+ if (entries.length === 0) {
565
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "state-tree__empty", children: "{}" });
566
+ }
567
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "state-tree__object", children: [
568
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "state-tree__toggle", onClick: toggle, children: [
569
+ isExpanded ? "\u25BC" : "\u25B6",
570
+ " Object(",
571
+ entries.length,
572
+ ")"
573
+ ] }),
574
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "state-tree__children", children: entries.map(([key, val]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "state-tree__item", children: [
575
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "state-tree__key", children: [
576
+ key,
577
+ ":"
578
+ ] }),
579
+ /* @__PURE__ */ jsxRuntime.jsx(
580
+ StateTree,
581
+ {
582
+ value: val,
583
+ path: path ? `${path}.${key}` : key,
584
+ changedPaths,
585
+ defaultExpandDepth,
586
+ depth: depth + 1,
587
+ changeType
588
+ }
589
+ )
590
+ ] }, key)) })
591
+ ] });
592
+ }
593
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: String(value) });
594
+ }
595
+ function formatValue(value) {
596
+ if (value === void 0) return "undefined";
597
+ if (value === null) return "null";
598
+ if (typeof value === "object") {
599
+ try {
600
+ const str = JSON.stringify(value);
601
+ return str.length > 50 ? str.slice(0, 50) + "..." : str;
602
+ } catch {
603
+ return "[Object]";
604
+ }
605
+ }
606
+ return String(value);
607
+ }
608
+ var sourceColors = {
609
+ react: "#61dafb",
610
+ redux: "#764abc",
611
+ zustand: "#f59e0b",
612
+ express: "#68a063",
613
+ websocket: "#8b5cf6",
614
+ api: "#3b82f6",
615
+ custom: "#6b7280"
616
+ };
617
+ function TimelineScrubber({
618
+ mutations,
619
+ selectedIndex,
620
+ onSelect,
621
+ isPlaying = false,
622
+ onPlay,
623
+ onPause,
624
+ onStepForward,
625
+ onStepBackward,
626
+ className = ""
627
+ }) {
628
+ const handleSliderChange = React2.useCallback(
629
+ (e) => {
630
+ const index = parseInt(e.target.value, 10);
631
+ if (mutations[index]) {
632
+ onSelect(index, mutations[index]);
633
+ }
634
+ },
635
+ [mutations, onSelect]
636
+ );
637
+ const handleMarkerClick = React2.useCallback(
638
+ (index) => {
639
+ if (mutations[index]) {
640
+ onSelect(index, mutations[index]);
641
+ }
642
+ },
643
+ [mutations, onSelect]
644
+ );
645
+ const formatTime = (timestamp) => {
646
+ const date = new Date(timestamp);
647
+ return date.toLocaleTimeString("en-US", {
648
+ hour12: false,
649
+ hour: "2-digit",
650
+ minute: "2-digit",
651
+ second: "2-digit",
652
+ fractionalSecondDigits: 3
653
+ });
654
+ };
655
+ if (mutations.length === 0) {
656
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `timeline-scrubber timeline-scrubber--empty ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "No mutations recorded yet" }) });
657
+ }
658
+ const selectedMutation = mutations[selectedIndex];
659
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `timeline-scrubber ${className}`, children: [
660
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "timeline-scrubber__header", children: [
661
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "timeline-scrubber__count", children: [
662
+ selectedIndex + 1,
663
+ " / ",
664
+ mutations.length,
665
+ " mutations"
666
+ ] }),
667
+ selectedMutation && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "timeline-scrubber__time", children: formatTime(selectedMutation.timestamp) })
668
+ ] }),
669
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "timeline-scrubber__track", children: [
670
+ mutations.map((mutation, index) => /* @__PURE__ */ jsxRuntime.jsx(
671
+ "div",
672
+ {
673
+ className: `timeline-scrubber__marker ${index === selectedIndex ? "timeline-scrubber__marker--selected" : ""}`,
674
+ style: {
675
+ left: `${index / (mutations.length - 1 || 1) * 100}%`,
676
+ backgroundColor: sourceColors[mutation.source] || sourceColors.custom
677
+ },
678
+ onClick: () => handleMarkerClick(index),
679
+ title: `${mutation.source}: ${mutation.actionType}${mutation.component ? ` @ ${mutation.component}` : ""}`
680
+ },
681
+ mutation.id
682
+ )),
683
+ /* @__PURE__ */ jsxRuntime.jsx(
684
+ "div",
685
+ {
686
+ className: "timeline-scrubber__position",
687
+ style: {
688
+ left: `${selectedIndex / (mutations.length - 1 || 1) * 100}%`
689
+ }
690
+ }
691
+ )
692
+ ] }),
693
+ /* @__PURE__ */ jsxRuntime.jsx(
694
+ "input",
695
+ {
696
+ type: "range",
697
+ min: 0,
698
+ max: mutations.length - 1,
699
+ value: selectedIndex,
700
+ onChange: handleSliderChange,
701
+ className: "timeline-scrubber__slider"
702
+ }
703
+ ),
704
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "timeline-scrubber__controls", children: [
705
+ /* @__PURE__ */ jsxRuntime.jsx(
706
+ "button",
707
+ {
708
+ onClick: onStepBackward,
709
+ disabled: selectedIndex === 0,
710
+ className: "timeline-scrubber__button",
711
+ title: "Step Backward",
712
+ children: "\u23EE"
713
+ }
714
+ ),
715
+ isPlaying ? /* @__PURE__ */ jsxRuntime.jsx(
716
+ "button",
717
+ {
718
+ onClick: onPause,
719
+ className: "timeline-scrubber__button timeline-scrubber__button--primary",
720
+ title: "Pause",
721
+ children: "\u23F8"
722
+ }
723
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
724
+ "button",
725
+ {
726
+ onClick: onPlay,
727
+ disabled: selectedIndex === mutations.length - 1,
728
+ className: "timeline-scrubber__button timeline-scrubber__button--primary",
729
+ title: "Play",
730
+ children: "\u25B6"
731
+ }
732
+ ),
733
+ /* @__PURE__ */ jsxRuntime.jsx(
734
+ "button",
735
+ {
736
+ onClick: onStepForward,
737
+ disabled: selectedIndex === mutations.length - 1,
738
+ className: "timeline-scrubber__button",
739
+ title: "Step Forward",
740
+ children: "\u23ED"
741
+ }
742
+ )
743
+ ] }),
744
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "timeline-scrubber__legend", children: Object.entries(sourceColors).map(([source, color]) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "timeline-scrubber__legend-item", children: [
745
+ /* @__PURE__ */ jsxRuntime.jsx(
746
+ "span",
747
+ {
748
+ className: "timeline-scrubber__legend-dot",
749
+ style: { backgroundColor: color }
750
+ }
751
+ ),
752
+ source
753
+ ] }, source)) }),
754
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
755
+ .timeline-scrubber {
756
+ padding: 1rem;
757
+ background: #1a1a2e;
758
+ border-radius: 8px;
759
+ color: #fff;
760
+ }
761
+
762
+ .timeline-scrubber--empty {
763
+ text-align: center;
764
+ color: #888;
765
+ }
766
+
767
+ .timeline-scrubber__header {
768
+ display: flex;
769
+ justify-content: space-between;
770
+ margin-bottom: 0.5rem;
771
+ font-size: 0.875rem;
772
+ }
773
+
774
+ .timeline-scrubber__count {
775
+ color: #00d9ff;
776
+ font-weight: 600;
777
+ }
778
+
779
+ .timeline-scrubber__time {
780
+ color: #888;
781
+ font-family: monospace;
782
+ }
783
+
784
+ .timeline-scrubber__track {
785
+ position: relative;
786
+ height: 24px;
787
+ background: #16213e;
788
+ border-radius: 4px;
789
+ margin-bottom: 0.5rem;
790
+ }
791
+
792
+ .timeline-scrubber__marker {
793
+ position: absolute;
794
+ width: 4px;
795
+ height: 16px;
796
+ top: 4px;
797
+ border-radius: 2px;
798
+ cursor: pointer;
799
+ transition: transform 0.1s, opacity 0.1s;
800
+ opacity: 0.7;
801
+ }
802
+
803
+ .timeline-scrubber__marker:hover {
804
+ transform: scaleY(1.2);
805
+ opacity: 1;
806
+ }
807
+
808
+ .timeline-scrubber__marker--selected {
809
+ opacity: 1;
810
+ box-shadow: 0 0 8px currentColor;
811
+ }
812
+
813
+ .timeline-scrubber__position {
814
+ position: absolute;
815
+ width: 2px;
816
+ height: 24px;
817
+ top: 0;
818
+ background: #fff;
819
+ border-radius: 1px;
820
+ pointer-events: none;
821
+ }
822
+
823
+ .timeline-scrubber__slider {
824
+ width: 100%;
825
+ margin: 0.5rem 0;
826
+ cursor: pointer;
827
+ }
828
+
829
+ .timeline-scrubber__controls {
830
+ display: flex;
831
+ justify-content: center;
832
+ gap: 0.5rem;
833
+ margin: 0.5rem 0;
834
+ }
835
+
836
+ .timeline-scrubber__button {
837
+ padding: 0.5rem 1rem;
838
+ border: none;
839
+ border-radius: 4px;
840
+ background: #16213e;
841
+ color: #fff;
842
+ cursor: pointer;
843
+ font-size: 1rem;
844
+ transition: background 0.2s;
845
+ }
846
+
847
+ .timeline-scrubber__button:hover:not(:disabled) {
848
+ background: #1f2b4d;
849
+ }
850
+
851
+ .timeline-scrubber__button:disabled {
852
+ opacity: 0.5;
853
+ cursor: not-allowed;
854
+ }
855
+
856
+ .timeline-scrubber__button--primary {
857
+ background: #00d9ff;
858
+ color: #000;
859
+ }
860
+
861
+ .timeline-scrubber__button--primary:hover:not(:disabled) {
862
+ background: #00b8e6;
863
+ }
864
+
865
+ .timeline-scrubber__legend {
866
+ display: flex;
867
+ flex-wrap: wrap;
868
+ gap: 1rem;
869
+ margin-top: 0.5rem;
870
+ font-size: 0.75rem;
871
+ }
872
+
873
+ .timeline-scrubber__legend-item {
874
+ display: flex;
875
+ align-items: center;
876
+ gap: 0.25rem;
877
+ color: #888;
878
+ }
879
+
880
+ .timeline-scrubber__legend-dot {
881
+ width: 8px;
882
+ height: 8px;
883
+ border-radius: 50%;
884
+ }
885
+ ` })
886
+ ] });
887
+ }
888
+ var DashboardContext = React2__default.default.createContext(null);
889
+ function DashboardProvider({
890
+ serverUrl = "http://localhost:8080",
891
+ children
892
+ }) {
893
+ const [state, setState] = React2.useState({
894
+ serverUrl,
895
+ sessions: [],
896
+ currentSession: null,
897
+ timeline: [],
898
+ selectedMutation: null,
899
+ isLoading: false,
900
+ error: null
901
+ });
902
+ const loadSessions = async () => {
903
+ setState((s) => ({ ...s, isLoading: true, error: null }));
904
+ try {
905
+ const res = await fetch(`${serverUrl}/api/sessions`);
906
+ const data = await res.json();
907
+ setState((s) => ({ ...s, sessions: data.sessions, isLoading: false }));
908
+ } catch (error) {
909
+ setState((s) => ({ ...s, error: String(error), isLoading: false }));
910
+ }
911
+ };
912
+ const selectSession = async (sessionId) => {
913
+ const session = state.sessions.find((s) => s.id === sessionId);
914
+ if (!session) return;
915
+ setState((s) => ({ ...s, currentSession: session, isLoading: true }));
916
+ try {
917
+ const res = await fetch(`${serverUrl}/api/sessions/${sessionId}/timeline`);
918
+ const data = await res.json();
919
+ setState((s) => ({
920
+ ...s,
921
+ timeline: data.timeline,
922
+ selectedMutation: data.timeline[0] || null,
923
+ isLoading: false
924
+ }));
925
+ } catch (error) {
926
+ setState((s) => ({ ...s, error: String(error), isLoading: false }));
927
+ }
928
+ };
929
+ const selectMutation = (mutation) => {
930
+ setState((s) => ({ ...s, selectedMutation: mutation }));
931
+ };
932
+ const refreshTimeline = async () => {
933
+ if (!state.currentSession) return;
934
+ await selectSession(state.currentSession.id);
935
+ };
936
+ React2.useEffect(() => {
937
+ loadSessions();
938
+ }, [serverUrl]);
939
+ const value = {
940
+ ...state,
941
+ loadSessions,
942
+ selectSession,
943
+ selectMutation,
944
+ refreshTimeline
945
+ };
946
+ return /* @__PURE__ */ jsxRuntime.jsx(DashboardContext.Provider, { value, children });
947
+ }
948
+ function useDashboard() {
949
+ const context = React2__default.default.useContext(DashboardContext);
950
+ if (!context) {
951
+ throw new Error("useDashboard must be used within a DashboardProvider");
952
+ }
953
+ return context;
954
+ }
955
+ function usePlayback(timeline) {
956
+ const [currentIndex, setCurrentIndex] = React2.useState(0);
957
+ const [isPlaying, setIsPlaying] = React2.useState(false);
958
+ const [playbackSpeed, setPlaybackSpeed] = React2.useState(1);
959
+ React2.useEffect(() => {
960
+ if (!isPlaying || timeline.length === 0) return;
961
+ const interval = setInterval(() => {
962
+ setCurrentIndex((i) => {
963
+ if (i >= timeline.length - 1) {
964
+ setIsPlaying(false);
965
+ return i;
966
+ }
967
+ return i + 1;
968
+ });
969
+ }, 500 / playbackSpeed);
970
+ return () => clearInterval(interval);
971
+ }, [isPlaying, timeline.length, playbackSpeed]);
972
+ return {
973
+ currentIndex,
974
+ currentMutation: timeline[currentIndex] || null,
975
+ isPlaying,
976
+ play: () => setIsPlaying(true),
977
+ pause: () => setIsPlaying(false),
978
+ stepForward: () => setCurrentIndex((i) => Math.min(i + 1, timeline.length - 1)),
979
+ stepBackward: () => setCurrentIndex((i) => Math.max(i - 1, 0)),
980
+ goTo: (index) => setCurrentIndex(Math.max(0, Math.min(index, timeline.length - 1))),
981
+ setSpeed: setPlaybackSpeed,
982
+ playbackSpeed
983
+ };
984
+ }
985
+ function StateSurgeonDashboard({ serverUrl = "http://localhost:8080" }) {
986
+ return /* @__PURE__ */ jsxRuntime.jsx(DashboardProvider, { serverUrl, children: /* @__PURE__ */ jsxRuntime.jsx(DashboardContent, {}) });
987
+ }
988
+ function DashboardContent() {
989
+ const {
990
+ sessions,
991
+ currentSession,
992
+ timeline,
993
+ selectedMutation,
994
+ isLoading,
995
+ error,
996
+ selectSession,
997
+ selectMutation,
998
+ loadSessions
999
+ } = useDashboard();
1000
+ const playback = usePlayback(timeline);
1001
+ React2__default.default.useEffect(() => {
1002
+ if (playback.currentMutation) {
1003
+ selectMutation(playback.currentMutation);
1004
+ }
1005
+ }, [playback.currentMutation, selectMutation]);
1006
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surgeon-dashboard", children: [
1007
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "surgeon-dashboard__header", children: [
1008
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "surgeon-dashboard__logo", children: "\u{1F52C} State Surgeon" }),
1009
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surgeon-dashboard__session-select", children: [
1010
+ /* @__PURE__ */ jsxRuntime.jsxs(
1011
+ "select",
1012
+ {
1013
+ value: currentSession?.id || "",
1014
+ onChange: (e) => selectSession(e.target.value),
1015
+ disabled: isLoading,
1016
+ children: [
1017
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select a session..." }),
1018
+ sessions.map((session) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: session.id, children: [
1019
+ session.appId,
1020
+ " - ",
1021
+ session.id.slice(0, 16),
1022
+ "... (",
1023
+ session.mutationCount,
1024
+ " mutations)"
1025
+ ] }, session.id))
1026
+ ]
1027
+ }
1028
+ ),
1029
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: loadSessions, disabled: isLoading, children: "\u{1F504}" })
1030
+ ] })
1031
+ ] }),
1032
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "surgeon-dashboard__error", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
1033
+ "Error: ",
1034
+ error
1035
+ ] }) }),
1036
+ isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "surgeon-dashboard__loading", children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Loading..." }) }),
1037
+ currentSession && !isLoading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surgeon-dashboard__main", children: [
1038
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "surgeon-dashboard__timeline", children: /* @__PURE__ */ jsxRuntime.jsx(
1039
+ TimelineScrubber,
1040
+ {
1041
+ mutations: timeline,
1042
+ selectedIndex: playback.currentIndex,
1043
+ onSelect: (index, mutation) => {
1044
+ playback.goTo(index);
1045
+ selectMutation(mutation);
1046
+ },
1047
+ isPlaying: playback.isPlaying,
1048
+ onPlay: playback.play,
1049
+ onPause: playback.pause,
1050
+ onStepForward: playback.stepForward,
1051
+ onStepBackward: playback.stepBackward
1052
+ }
1053
+ ) }),
1054
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surgeon-dashboard__content", children: [
1055
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "surgeon-dashboard__diff", children: selectedMutation && /* @__PURE__ */ jsxRuntime.jsx(
1056
+ StateDiffViewer,
1057
+ {
1058
+ previousState: selectedMutation.previousState,
1059
+ nextState: selectedMutation.nextState,
1060
+ diff: selectedMutation.diff
1061
+ }
1062
+ ) }),
1063
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "surgeon-dashboard__inspector", children: /* @__PURE__ */ jsxRuntime.jsx(MutationInspector, { mutation: selectedMutation }) })
1064
+ ] })
1065
+ ] }),
1066
+ !currentSession && !isLoading && sessions.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "surgeon-dashboard__empty", children: [
1067
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "No Sessions Yet" }),
1068
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Connect your application to start capturing mutations." }),
1069
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { children: `import { StateSurgeonClient, instrumentReact } from 'state-surgeon/instrument';
1070
+
1071
+ // Initialize the client
1072
+ const client = new StateSurgeonClient({
1073
+ serverUrl: 'ws://localhost:8081',
1074
+ appId: 'my-app',
1075
+ });
1076
+
1077
+ // Instrument React
1078
+ instrumentReact(React);` })
1079
+ ] }),
1080
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
1081
+ .surgeon-dashboard {
1082
+ min-height: 100vh;
1083
+ background: #0f0f23;
1084
+ color: #e0e0e0;
1085
+ font-family: system-ui, -apple-system, sans-serif;
1086
+ }
1087
+
1088
+ .surgeon-dashboard__header {
1089
+ display: flex;
1090
+ justify-content: space-between;
1091
+ align-items: center;
1092
+ padding: 1rem 2rem;
1093
+ background: #1a1a2e;
1094
+ border-bottom: 1px solid #333;
1095
+ }
1096
+
1097
+ .surgeon-dashboard__logo {
1098
+ margin: 0;
1099
+ font-size: 1.5rem;
1100
+ color: #00d9ff;
1101
+ }
1102
+
1103
+ .surgeon-dashboard__session-select {
1104
+ display: flex;
1105
+ gap: 0.5rem;
1106
+ }
1107
+
1108
+ .surgeon-dashboard__session-select select {
1109
+ padding: 0.5rem 1rem;
1110
+ border: 1px solid #333;
1111
+ border-radius: 4px;
1112
+ background: #16213e;
1113
+ color: #e0e0e0;
1114
+ min-width: 300px;
1115
+ }
1116
+
1117
+ .surgeon-dashboard__session-select button {
1118
+ padding: 0.5rem 1rem;
1119
+ border: 1px solid #333;
1120
+ border-radius: 4px;
1121
+ background: #16213e;
1122
+ color: #e0e0e0;
1123
+ cursor: pointer;
1124
+ }
1125
+
1126
+ .surgeon-dashboard__session-select button:hover {
1127
+ background: #1f2b4d;
1128
+ }
1129
+
1130
+ .surgeon-dashboard__error {
1131
+ padding: 1rem 2rem;
1132
+ background: rgba(239, 68, 68, 0.1);
1133
+ border-bottom: 1px solid #ef4444;
1134
+ color: #fca5a5;
1135
+ }
1136
+
1137
+ .surgeon-dashboard__loading {
1138
+ padding: 2rem;
1139
+ text-align: center;
1140
+ color: #888;
1141
+ }
1142
+
1143
+ .surgeon-dashboard__main {
1144
+ padding: 1rem 2rem;
1145
+ }
1146
+
1147
+ .surgeon-dashboard__timeline {
1148
+ margin-bottom: 1rem;
1149
+ }
1150
+
1151
+ .surgeon-dashboard__content {
1152
+ display: grid;
1153
+ grid-template-columns: 2fr 1fr;
1154
+ gap: 1rem;
1155
+ }
1156
+
1157
+ .surgeon-dashboard__empty {
1158
+ padding: 4rem 2rem;
1159
+ text-align: center;
1160
+ }
1161
+
1162
+ .surgeon-dashboard__empty h2 {
1163
+ color: #888;
1164
+ margin-bottom: 1rem;
1165
+ }
1166
+
1167
+ .surgeon-dashboard__empty pre {
1168
+ display: inline-block;
1169
+ text-align: left;
1170
+ padding: 1.5rem;
1171
+ background: #16213e;
1172
+ border-radius: 8px;
1173
+ font-size: 0.875rem;
1174
+ }
1175
+
1176
+ @media (max-width: 1024px) {
1177
+ .surgeon-dashboard__content {
1178
+ grid-template-columns: 1fr;
1179
+ }
1180
+ }
1181
+ ` })
1182
+ ] });
1183
+ }
1184
+
1185
+ exports.DashboardProvider = DashboardProvider;
1186
+ exports.MutationInspector = MutationInspector;
1187
+ exports.StateDiffViewer = StateDiffViewer;
1188
+ exports.StateSurgeonDashboard = StateSurgeonDashboard;
1189
+ exports.TimelineScrubber = TimelineScrubber;
1190
+ exports.useDashboard = useDashboard;
1191
+ //# sourceMappingURL=index.js.map
1192
+ //# sourceMappingURL=index.js.map