@weasel-js/labkit 1.4.2 → 1.4.4

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.
Files changed (117) hide show
  1. package/README.md +20 -2
  2. package/dist/_dts/{CanvasStackContext-kjILVnPj.d.ts → CanvasStackContext-kTEZvEgE.d.ts} +1 -1
  3. package/dist/_dts/{PrefsForm.d-CgxUequc.d.ts → PrefsForm.d-DDHFANkc.d.ts} +1 -1
  4. package/dist/_dts/{frac-A4R6v4ld.d.ts → frac-z7ker2Vx.d.ts} +11 -7
  5. package/dist/_dts/{index-CsU9WhjM.d.ts → index-Blv9uQzu.d.ts} +42 -9
  6. package/dist/_dts/types-B9_zrHmb.d.ts +166 -0
  7. package/dist/_dts/{types-BbXpvQa8.d.ts → types-BP2OCcpg.d.ts} +21 -3
  8. package/dist/_dts/types-x92Kfeme.d.ts +62 -0
  9. package/dist/_dts/{useTrialState-DKjqpv20.d.ts → useTrialState-D6Vb3T-g.d.ts} +7 -7
  10. package/dist/canvas/index.d.ts +9 -8
  11. package/dist/canvas/index.js +1 -2
  12. package/dist/chrome/index.d.ts +7 -6
  13. package/dist/chrome/index.js +5 -5
  14. package/dist/{chunk-ULDW42CR.js → chunk-2P6PP5N4.js} +33 -23
  15. package/dist/chunk-2P6PP5N4.js.map +1 -0
  16. package/dist/{chunk-W2FJR5FF.js → chunk-64ZCN3DA.js} +74 -76
  17. package/dist/chunk-64ZCN3DA.js.map +1 -0
  18. package/dist/{chunk-NSOVI3AZ.js → chunk-BKFVHKJH.js} +6 -6
  19. package/dist/{chunk-NSOVI3AZ.js.map → chunk-BKFVHKJH.js.map} +1 -1
  20. package/dist/chunk-E44SU6XS.js +50 -0
  21. package/dist/chunk-E44SU6XS.js.map +1 -0
  22. package/dist/{chunk-WS6ZRV75.js → chunk-FQMJUVHJ.js} +3 -3
  23. package/dist/{chunk-WS6ZRV75.js.map → chunk-FQMJUVHJ.js.map} +1 -1
  24. package/dist/{chunk-FJG4PHTL.js → chunk-I6JCVE24.js} +3 -3
  25. package/dist/chunk-I6JCVE24.js.map +1 -0
  26. package/dist/{chunk-UDXOYZEC.js → chunk-MOM3GOVY.js} +4 -4
  27. package/dist/{chunk-UDXOYZEC.js.map → chunk-MOM3GOVY.js.map} +1 -1
  28. package/dist/{chunk-TN7YSJVU.js → chunk-RS3HRQWU.js} +3 -3
  29. package/dist/{chunk-TN7YSJVU.js.map → chunk-RS3HRQWU.js.map} +1 -1
  30. package/dist/{chunk-UTOEDPNU.js → chunk-SMHP6XZ4.js} +7 -6
  31. package/dist/chunk-SMHP6XZ4.js.map +1 -0
  32. package/dist/{chunk-D5KQ5OY6.js → chunk-TJ7QY3OC.js} +3 -3
  33. package/dist/{chunk-D5KQ5OY6.js.map → chunk-TJ7QY3OC.js.map} +1 -1
  34. package/dist/{chunk-XKENZTNE.js → chunk-U3IYHIAE.js} +71 -55
  35. package/dist/chunk-U3IYHIAE.js.map +1 -0
  36. package/dist/chunk-W3ECWC2K.js +7335 -0
  37. package/dist/chunk-W3ECWC2K.js.map +1 -0
  38. package/dist/controls/index.d.ts +5 -4
  39. package/dist/controls/index.js +3 -3
  40. package/dist/dragdrop/index.d.ts +6 -5
  41. package/dist/dragdrop/index.js +1 -2
  42. package/dist/index.d.ts +139 -26
  43. package/dist/index.js +309 -144
  44. package/dist/index.js.map +1 -1
  45. package/dist/layers/index.d.ts +7 -6
  46. package/dist/layers/index.js +2 -3
  47. package/dist/loupe/index.d.ts +8 -7
  48. package/dist/loupe/index.js +1 -2
  49. package/dist/passthrough/weasel-canvas.d.ts +1 -3
  50. package/dist/passthrough/weasel-canvas.js +1 -1
  51. package/dist/passthrough/weasel-canvas.js.map +1 -1
  52. package/dist/passthrough/weasel-ui.d.ts +98 -20
  53. package/dist/passthrough/weasel-ui.js +1 -2
  54. package/dist/primitives/index.js +3 -4
  55. package/dist/state/index.d.ts +6 -3
  56. package/dist/state/index.js +3 -2
  57. package/dist/state/index.js.map +1 -1
  58. package/dist/styles.css +82 -15
  59. package/dist/surface/index.js +1 -2
  60. package/dist/ui/layers/index.js +1 -2
  61. package/dist/undo/index.d.ts +6 -6
  62. package/package.json +7 -7
  63. package/src/annotations/ExportMenu.test.tsx +16 -0
  64. package/src/annotations/ExportMenu.tsx +0 -5
  65. package/src/annotations/frac.test.ts +4 -4
  66. package/src/annotations/frac.ts +3 -2
  67. package/src/annotations/index.ts +1 -1
  68. package/src/annotations/store.ts +2 -2
  69. package/src/annotations/svgNodes.ts +1 -2
  70. package/src/config/builder.test.ts +56 -2
  71. package/src/config/builder.ts +73 -13
  72. package/src/config/index.ts +16 -1
  73. package/src/config/path.test.ts +109 -0
  74. package/src/config/path.ts +76 -0
  75. package/src/config/resolve.test.ts +93 -2
  76. package/src/config/resolve.ts +72 -29
  77. package/src/config/types.ts +99 -9
  78. package/src/config/visible.ts +6 -4
  79. package/src/controls/ControlPanel.stories.tsx +38 -4
  80. package/src/controls/ControlPanel.test.tsx +114 -0
  81. package/src/controls/ControlPanel.tsx +99 -50
  82. package/src/index.ts +17 -2
  83. package/src/instrument/serializers.ts +36 -0
  84. package/src/instrument/types.ts +4 -2
  85. package/src/lab/Lab.test.tsx +29 -1
  86. package/src/lab/Lab.tsx +10 -1
  87. package/src/lab/LabShell.test.tsx +8 -0
  88. package/src/lab/LabShell.tsx +17 -3
  89. package/src/lab/LabSwitcher.less +85 -0
  90. package/src/lab/LabSwitcher.test.tsx +96 -0
  91. package/src/lab/LabSwitcher.tsx +112 -0
  92. package/src/lab/index.ts +2 -0
  93. package/src/primitives/ZoomControl.less +6 -2
  94. package/src/primitives/ZoomControl.tsx +1 -0
  95. package/src/state/helpers.test.ts +20 -0
  96. package/src/state/helpers.ts +17 -1
  97. package/src/state/store.test.ts +155 -1
  98. package/src/state/store.ts +32 -26
  99. package/src/state/types.ts +24 -3
  100. package/src/state/useTrialState.ts +1 -1
  101. package/src/styles.less +1 -0
  102. package/src/theme/base.less +4 -4
  103. package/src/trial/Trial.config.test.tsx +44 -0
  104. package/src/trial/Trial.tsx +3 -3
  105. package/src/trial/TrialChrome.tsx +10 -5
  106. package/src/trial/trialOps.ts +7 -10
  107. package/dist/_dts/types-lg4TSCb2.d.ts +0 -164
  108. package/dist/_dts/weasel-canvas-FJTFi3ZZ.d.ts +0 -5041
  109. package/dist/chunk-54ZWZ5FQ.js +0 -29997
  110. package/dist/chunk-54ZWZ5FQ.js.map +0 -1
  111. package/dist/chunk-FJG4PHTL.js.map +0 -1
  112. package/dist/chunk-ISSVF5PT.js +0 -7263
  113. package/dist/chunk-ISSVF5PT.js.map +0 -1
  114. package/dist/chunk-ULDW42CR.js.map +0 -1
  115. package/dist/chunk-UTOEDPNU.js.map +0 -1
  116. package/dist/chunk-W2FJR5FF.js.map +0 -1
  117. package/dist/chunk-XKENZTNE.js.map +0 -1
@@ -1,4 +1,5 @@
1
1
  import { LabStoreContext, TrialIdContext } from './chunk-2YILQ7Y5.js';
2
+ import { withValueAtPath, fillConfigDefaults } from './chunk-E44SU6XS.js';
2
3
  import { createStore } from 'zustand/vanilla';
3
4
  import { useContext } from 'react';
4
5
  import { useStore } from 'zustand/react';
@@ -18,6 +19,12 @@ function decodeUrlHash(hash) {
18
19
  return null;
19
20
  }
20
21
  }
22
+ var idCounter = 0;
23
+ function newId() {
24
+ const c = globalThis.crypto;
25
+ if (c && typeof c.randomUUID === "function") return c.randomUUID();
26
+ return `lk-${Date.now().toString(36)}-${idCounter++}`;
27
+ }
21
28
  function emptyUndoStack() {
22
29
  return { past: [], future: [] };
23
30
  }
@@ -36,7 +43,7 @@ function deserializeTrials(records, deserializers) {
36
43
  const d = deserializers[r.instrumentName];
37
44
  return {
38
45
  ...r,
39
- state: d?.deserialize ? d.deserialize(r.state) : r.state,
46
+ state: d?.deserialize ? d.deserialize(r.state, r.config) : r.state,
40
47
  undoStack: emptyUndoStack()
41
48
  };
42
49
  });
@@ -262,14 +269,25 @@ function dockPanel(panels, trialId, sectionId) {
262
269
  return out;
263
270
  }
264
271
  function createLabStore(options) {
265
- let serializers = {};
272
+ const serializers = options.serializers ?? {};
266
273
  let flushTimer = null;
267
274
  const hydration = hydrateDocument(options);
268
275
  const hydrated = hydration.document;
269
276
  const persistDisabled = hydration.persistDisabled;
270
277
  let foldedFromLegacy = hydration.foldedFromLegacy;
271
- const hydratedTrials = deserializeTrials(hydrated.trials, serializers);
272
- const hydratedSnapshots = hydrated.saves;
278
+ const configDefaults = options.configDefaults ?? {};
279
+ const filled = (instrumentName, config) => {
280
+ const defaults = configDefaults[instrumentName];
281
+ return defaults ? fillConfigDefaults(config, defaults()) : config;
282
+ };
283
+ const hydratedTrials = deserializeTrials(
284
+ hydrated.trials.map((t) => ({ ...t, config: filled(t.instrumentName, t.config) })),
285
+ serializers
286
+ );
287
+ const hydratedSnapshots = hydrated.saves.map((sn) => ({
288
+ ...sn,
289
+ config: filled(sn.instrumentName, sn.config)
290
+ }));
273
291
  const hydratedLayout = hydrated.layout;
274
292
  const hydratedMode = hydrated.mode;
275
293
  const store = createStore()((set, get) => ({
@@ -303,15 +321,11 @@ function createLabStore(options) {
303
321
  }));
304
322
  scheduleFlush();
305
323
  },
306
- updateTrialConfig: (id, key, value) => {
324
+ updateTrialConfig: (id, path, value) => {
307
325
  set((s) => ({
308
- trials: s.trials.map((w) => {
309
- if (w.id !== id) return w;
310
- return {
311
- ...w,
312
- config: { ...w.config, [key]: value }
313
- };
314
- })
326
+ trials: s.trials.map(
327
+ (w) => w.id === id ? { ...w, config: withValueAtPath(w.config, path, value) } : w
328
+ )
315
329
  }));
316
330
  scheduleFlush();
317
331
  },
@@ -382,7 +396,7 @@ function createLabStore(options) {
382
396
  const lastAt = get().savedSnapshots.reduce((m, sn) => sn.savedAt > m ? sn.savedAt : m, 0);
383
397
  const savedAt = Math.max(Date.now(), lastAt + 1);
384
398
  const snapshot = {
385
- id: crypto.randomUUID(),
399
+ id: newId(),
386
400
  name,
387
401
  trialId,
388
402
  instrumentName: trial.instrumentName,
@@ -405,7 +419,7 @@ function createLabStore(options) {
405
419
  return;
406
420
  }
407
421
  const reg = serializers[snapshot.instrumentName];
408
- const restoredState = reg?.deserialize ? reg.deserialize(snapshot.state) : snapshot.state;
422
+ const restoredState = reg?.deserialize ? reg.deserialize(snapshot.state, snapshot.config) : snapshot.state;
409
423
  set((s) => ({
410
424
  trials: s.trials.map(
411
425
  (w) => w.id === trialId ? { ...w, state: restoredState, config: snapshot.config } : w
@@ -467,11 +481,7 @@ function createLabStore(options) {
467
481
  }, 300);
468
482
  }
469
483
  if (foldedFromLegacy) scheduleFlush();
470
- return Object.assign(store, {
471
- registerSerializers(s) {
472
- serializers = s;
473
- }
474
- });
484
+ return store;
475
485
  }
476
486
  function setAside(options, raw, why, error) {
477
487
  const quarantined = quarantineDocument(options.storage, options.storageKey, raw);
@@ -534,10 +544,10 @@ function useTrialState() {
534
544
  state: record.state,
535
545
  config: record.config,
536
546
  setState: (next) => updateTrialState(trialId, next),
537
- setConfig: (key, value) => updateTrialConfig(trialId, key, value)
547
+ setConfig: (path, value) => updateTrialConfig(trialId, path, value)
538
548
  };
539
549
  }
540
550
 
541
- export { CURRENT_DOCUMENT_VERSION, createLabStore, createMemoryAdapter, decodeUrlHash, deserializeTrials, dockPanel, emptyUndoStack, encodeUrlHash, labDocumentKey, labStorageKey, localStorageAdapter, noneAdapter, panelKey, quarantineKey, serializeTrials, sessionStorageAdapter, undockPanel, urlHashAdapter, useTrialState };
542
- //# sourceMappingURL=chunk-ULDW42CR.js.map
543
- //# sourceMappingURL=chunk-ULDW42CR.js.map
551
+ export { CURRENT_DOCUMENT_VERSION, createLabStore, createMemoryAdapter, decodeUrlHash, deserializeTrials, dockPanel, emptyUndoStack, encodeUrlHash, labDocumentKey, labStorageKey, localStorageAdapter, newId, noneAdapter, panelKey, quarantineKey, serializeTrials, sessionStorageAdapter, undockPanel, urlHashAdapter, useTrialState };
552
+ //# sourceMappingURL=chunk-2P6PP5N4.js.map
553
+ //# sourceMappingURL=chunk-2P6PP5N4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/state/helpers.ts","../src/state/adapters.ts","../src/state/document.ts","../src/state/undock.ts","../src/state/store.ts","../src/state/useTrialState.ts"],"names":[],"mappings":"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","file":"chunk-2P6PP5N4.js","sourcesContent":["import type { InstrumentSerializers, SerializedTrial, TrialRecord, UndoStack } from './types';\n\n/** The storage key a lab writes one of its buckets under. Namespaced by\n * `storageKey` so two labs sharing an origin do not collide. */\nexport function labStorageKey(\n storageKey: string,\n bucket: 'workspaces' | 'saves' | 'theme' | 'layout',\n): string {\n return `lk:${storageKey}:${bucket}`;\n}\n\n/** Encode a string for the URL fragment. */\nexport function encodeUrlHash(value: string): string {\n return btoa(encodeURIComponent(value));\n}\n\n/** Decode a URL fragment written by `encodeUrlHash`, or `null` if it is\n * malformed. */\nexport function decodeUrlHash(hash: string): string | null {\n if (!hash) return null;\n try {\n return decodeURIComponent(atob(hash));\n } catch {\n return null;\n }\n}\n\n/**\n * An id for a trial or a snapshot.\n *\n * `crypto.randomUUID` exists only in a secure context, and a LAN address is\n * not one — so a lab opened on a phone or a tablet by IP throws on its first\n * render and shows a blank page with nothing in reach to say why. The counter\n * is per page load, which is all these ids have to survive: they name records\n * inside one session's store, and a saved snapshot carries its own name.\n */\nlet idCounter = 0;\nexport function newId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c && typeof c.randomUUID === 'function') return c.randomUUID();\n return `lk-${Date.now().toString(36)}-${idCounter++}`;\n}\n\n/** A fresh, empty undo history. */\nexport function emptyUndoStack(): UndoStack {\n return { past: [], future: [] };\n}\n\n/** Serialize trials for storage, running each instrument's own serializer\n * over its state. Undo history is deliberately dropped — it does not survive\n * a reload. */\nexport function serializeTrials(\n trials: TrialRecord[],\n serializers: InstrumentSerializers,\n): SerializedTrial[] {\n return trials.map(({ undoStack: _undo, ...w }) => {\n const s = serializers[w.instrumentName];\n return { ...w, state: s?.serialize ? s.serialize(w.state) : w.state };\n });\n}\n\n/** Rebuild trials from storage, running each instrument's deserializer\n * over its state and starting each with an empty undo history. Returns an\n * empty list rather than throwing on malformed input. */\nexport function deserializeTrials(\n records: SerializedTrial[],\n deserializers: InstrumentSerializers,\n): TrialRecord[] {\n if (!Array.isArray(records)) {\n console.warn('[labkit] deserializeTrials: not an array, returning empty list');\n return [];\n }\n return records.map((r) => {\n const d = deserializers[r.instrumentName];\n return {\n ...r,\n state: d?.deserialize ? d.deserialize(r.state, r.config) : r.state,\n undoStack: emptyUndoStack(),\n };\n });\n}\n","import { decodeUrlHash, encodeUrlHash } from './helpers';\nimport type { StorageAdapter } from './types';\n\n/** Persist to `localStorage` — state survives a reload and a new tab. Falls\n * back to no-ops when storage is unavailable. */\nexport const localStorageAdapter: StorageAdapter = {\n read: (key) => {\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n },\n write: (key, value) => {\n try {\n localStorage.setItem(key, value);\n } catch (e) {\n console.warn('[labkit] localStorage write failed:', e);\n }\n },\n delete: (key) => {\n try {\n localStorage.removeItem(key);\n } catch {\n /* ignore */\n }\n },\n};\n\n/** Persist to `sessionStorage` — state survives a reload but not a new tab. */\nexport const sessionStorageAdapter: StorageAdapter = {\n read: (key) => {\n try {\n return sessionStorage.getItem(key);\n } catch {\n return null;\n }\n },\n write: (key, value) => {\n try {\n sessionStorage.setItem(key, value);\n } catch (e) {\n console.warn('[labkit] sessionStorage write failed:', e);\n }\n },\n delete: (key) => {\n try {\n sessionStorage.removeItem(key);\n } catch {\n /* ignore */\n }\n },\n};\n\nconst URL_HASH_GUARD = typeof window !== 'undefined';\n\nfunction readHashMap(): Record<string, string> {\n if (!URL_HASH_GUARD) return {};\n const raw = decodeUrlHash(window.location.hash.replace(/^#/, ''));\n if (!raw) return {};\n try {\n return JSON.parse(raw) as Record<string, string>;\n } catch {\n return {};\n }\n}\n\nfunction writeHashMap(map: Record<string, string>): void {\n if (!URL_HASH_GUARD) return;\n const encoded = encodeUrlHash(JSON.stringify(map));\n window.history.replaceState(null, '', `#${encoded}`);\n}\n\n/** Persist into the URL fragment, so the page's link carries its state and\n * can be shared or bookmarked. */\nexport const urlHashAdapter: StorageAdapter = {\n read: (key) => readHashMap()[key] ?? null,\n write: (key, value) => {\n const map = readHashMap();\n map[key] = value;\n writeHashMap(map);\n },\n delete: (key) => {\n const map = readHashMap();\n delete map[key];\n writeHashMap(map);\n },\n};\n\n/** An in-memory store, discarded on reload. For tests, and for labs that\n * should start fresh every time. */\nexport function createMemoryAdapter(): StorageAdapter {\n const store = new Map<string, string>();\n return {\n read: (key) => store.get(key) ?? null,\n write: (key, value) => {\n store.set(key, value);\n },\n delete: (key) => {\n store.delete(key);\n },\n };\n}\n\n/** Persists nothing and reads back nothing. */\nexport const noneAdapter: StorageAdapter = {\n read: () => null,\n write: () => {},\n delete: () => {},\n};\n","import { labStorageKey } from './helpers';\nimport type {\n LabDocument,\n LabMode,\n Migration,\n SavedSnapshot,\n SerializedTrial,\n StorageAdapter,\n} from './types';\nimport type { UndockedPanels } from './undock';\n\n/** Bumped whenever the persisted shape changes; every bump needs a migration. */\nexport const CURRENT_DOCUMENT_VERSION = 3;\n\n/** The one key a lab persists under. The `:doc` suffix keeps it out of the\n * legacy bucket namespace, where a lab named `a:saves` would otherwise write\n * its document over lab `a`'s saves bucket. */\nexport function labDocumentKey(storageKey: string): string {\n return `lk:${storageKey}:doc`;\n}\n\n/** Where a document that failed to migrate is set aside, so a bad migration\n * loses state loudly rather than silently. */\nexport function quarantineKey(storageKey: string): string {\n return `lk:${storageKey}:quarantine`;\n}\n\n/** A fresh document at the current version. */\nexport function emptyDocument(mode: LabMode): LabDocument {\n return {\n version: CURRENT_DOCUMENT_VERSION,\n undockedPanels: {},\n trials: [],\n saves: [],\n layout: {},\n mode,\n };\n}\n\n/** What a migration run produced: the migrated document, or why it refused. */\nexport type MigrationOutcome =\n | { ok: true; doc: Record<string, unknown>; migrated: boolean }\n | { ok: false; reason: 'future' | 'failed'; error?: unknown };\n\n/** Walk a document forward to `target`, one migration at a time. A version\n * above `target` is refused rather than parsed under a shape it may not\n * have. */\nexport function runMigrations(\n raw: Record<string, unknown>,\n migrations: Migration[],\n target: number,\n): MigrationOutcome {\n const from = typeof raw.version === 'number' ? raw.version : 0;\n if (from > target) return { ok: false, reason: 'future' };\n if (from === target) return { ok: true, doc: raw, migrated: false };\n\n let doc = raw;\n try {\n for (let v = from; v < target; v++) {\n const migration = migrations[v];\n if (!migration) throw new Error(`[labkit] no migration from version ${v}`);\n doc = migration(doc);\n }\n } catch (error) {\n return { ok: false, reason: 'failed', error };\n }\n return { ok: true, doc, migrated: true };\n}\n\nconst LEGACY_BUCKETS = ['workspaces', 'saves', 'layout', 'theme'] as const;\n\nfunction parseOr<T>(raw: string | null, fallback: T, bucket: string): T {\n if (raw === null) return fallback;\n try {\n return JSON.parse(raw) as T;\n } catch {\n console.warn(`[labkit] unparseable legacy bucket \"${bucket}\", dropping it`);\n return fallback;\n }\n}\n\n/** Assemble a version-0 document out of the four pre-document keys, or null\n * if none of them is present. `fallbackMode` is used when the theme key is\n * absent or holds something unrecognized; `interstellar` passes through\n * untouched for `migrateV0toV1` to coerce. */\nexport function readLegacyDocument(\n storage: StorageAdapter,\n storageKey: string,\n fallbackMode: LabMode,\n): Record<string, unknown> | null {\n const present = LEGACY_BUCKETS.some((b) => storage.read(labStorageKey(storageKey, b)) !== null);\n if (!present) return null;\n\n const rawMode = storage.read(labStorageKey(storageKey, 'theme'));\n const mode =\n rawMode === 'light' || rawMode === 'dark' || rawMode === 'auto' || rawMode === 'interstellar'\n ? rawMode\n : fallbackMode;\n\n return {\n version: 0,\n workspaces: parseOr(storage.read(labStorageKey(storageKey, 'workspaces')), [], 'workspaces'),\n saves: parseOr(storage.read(labStorageKey(storageKey, 'saves')), [], 'saves'),\n layout: parseOr(storage.read(labStorageKey(storageKey, 'layout')), {}, 'layout'),\n mode,\n };\n}\n\n/** Delete the four pre-document keys, but only once `expectedDocument` is\n * confirmed to be exactly what is stored under the document key — a\n * read-back, not a trust of the write that produced it. On any mismatch\n * (write failed, landed partially, or never happened) it deletes nothing,\n * warns, and returns `false` so the legacy buckets stay as a recoverable\n * copy. Deletion itself is read back too — `StorageAdapter.delete` is\n * optional, so an adapter without it leaves the keys in place — and `true`\n * is returned only once all four are actually gone. */\nexport function deleteLegacyKeys(\n storage: StorageAdapter,\n storageKey: string,\n expectedDocument: string,\n): boolean {\n const actual = storage.read(labDocumentKey(storageKey));\n if (actual !== expectedDocument) {\n console.warn(\n `[labkit] keeping legacy keys for \"${storageKey}\": could not confirm the migrated document was written`,\n );\n return false;\n }\n let allGone = true;\n for (const bucket of LEGACY_BUCKETS) {\n const key = labStorageKey(storageKey, bucket);\n storage.delete?.(key);\n if (storage.read(key) !== null) allGone = false;\n }\n return allGone;\n}\n\n/** Set `raw` aside under the quarantine key, reading it back to confirm it\n * landed. Returns `false` when it did not — a full disk is exactly when a\n * document goes unreadable — so the caller can leave the original alone\n * rather than overwrite the only copy of it. */\nexport function quarantineDocument(\n storage: StorageAdapter,\n storageKey: string,\n raw: string,\n): boolean {\n storage.write(quarantineKey(storageKey), raw);\n return storage.read(quarantineKey(storageKey)) === raw;\n}\n\n/** Fill in whatever a document is missing or holds the wrong shape of, so a\n * hydrated store never sees `undefined` where a section should be. Applied to\n * every document, migrated or already current. */\nexport function normalizeDocument(\n doc: Record<string, unknown>,\n fallbackMode: LabMode,\n): LabDocument {\n const mode =\n doc.mode === 'light' || doc.mode === 'dark' || doc.mode === 'auto' ? doc.mode : fallbackMode;\n return {\n version: CURRENT_DOCUMENT_VERSION,\n trials: Array.isArray(doc.trials) ? (doc.trials as SerializedTrial[]) : [],\n saves: Array.isArray(doc.saves) ? (doc.saves as SavedSnapshot[]) : [],\n layout:\n doc.layout && typeof doc.layout === 'object' ? (doc.layout as Record<string, unknown>) : {},\n undockedPanels:\n doc.undockedPanels && typeof doc.undockedPanels === 'object'\n ? (doc.undockedPanels as UndockedPanels)\n : {},\n mode,\n };\n}\n\n/** Version 0 (four loose keys) to version 1 (one document). Normalizes the\n * mode, including `interstellar` — the dark mode's name back when it was a\n * theme. Coerces against version 1's own field names rather than reusing\n * `normalizeDocument`, which produces the current shape and would drop\n * `workspaces` from a document it labels version 1. */\nexport function migrateV0toV1(doc: Record<string, unknown>): Record<string, unknown> {\n const raw = doc.mode === 'interstellar' ? 'dark' : doc.mode;\n const mode = raw === 'light' || raw === 'dark' || raw === 'auto' ? raw : 'auto';\n return {\n version: 1,\n workspaces: Array.isArray(doc.workspaces) ? doc.workspaces : [],\n saves: Array.isArray(doc.saves) ? doc.saves : [],\n layout: doc.layout && typeof doc.layout === 'object' ? doc.layout : {},\n mode,\n };\n}\n\n/** Version 1 to version 2: the vocabulary refresh renamed a tile from\n * workspace to trial. Only the records field moves; a record's own fields are\n * unchanged. */\nexport function migrateV1toV2(doc: Record<string, unknown>): Record<string, unknown> {\n const { workspaces, ...rest } = doc;\n return { ...rest, trials: Array.isArray(workspaces) ? workspaces : [], version: 2 };\n}\n\n/** Version 2 to version 3: undocked sidebar panels became persisted state.\n * Nothing existing moves; the field simply starts empty. */\nexport function migrateV2toV3(doc: Record<string, unknown>): Record<string, unknown> {\n return { ...doc, undockedPanels: {}, version: 3 };\n}\n\n/** Index `i` migrates a version-`i` document to version `i + 1`. */\nexport const MIGRATIONS: Migration[] = [migrateV0toV1, migrateV1toV2, migrateV2toV3];\n","/** A sidebar section torn out of its trial, and where it went. */\nexport interface UndockedPanel {\n trialId: string;\n sectionId: string;\n as: 'tile' | 'floating';\n}\n\n/** Undocked panels, keyed by {@link panelKey}. */\nexport type UndockedPanels = Record<string, UndockedPanel>;\n\nexport function panelKey(trialId: string, sectionId: string): string {\n return `${trialId}::${sectionId}`;\n}\n\nexport function undockPanel(\n panels: UndockedPanels,\n trialId: string,\n sectionId: string,\n as: UndockedPanel['as'] = 'tile',\n): UndockedPanels {\n return { ...panels, [panelKey(trialId, sectionId)]: { trialId, sectionId, as } };\n}\n\n/** Dock one section back, or — with no `sectionId` — every panel the trial\n * owns, which is what closing a trial wants. */\nexport function dockPanel(\n panels: UndockedPanels,\n trialId: string,\n sectionId?: string,\n): UndockedPanels {\n const out: UndockedPanels = {};\n for (const [key, panel] of Object.entries(panels)) {\n if (panel.trialId === trialId && (sectionId === undefined || panel.sectionId === sectionId)) {\n continue;\n }\n out[key] = panel;\n }\n return out;\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla';\nimport { fillConfigDefaults, withValueAtPath } from '../config/path';\nimport {\n CURRENT_DOCUMENT_VERSION,\n deleteLegacyKeys,\n emptyDocument,\n labDocumentKey,\n MIGRATIONS,\n normalizeDocument,\n quarantineDocument,\n readLegacyDocument,\n runMigrations,\n} from './document';\nimport { deserializeTrials, emptyUndoStack, newId, serializeTrials } from './helpers';\nimport type {\n CreateLabStoreOptions,\n LabDocument,\n LabMode,\n LabStoreState,\n SavedSnapshot,\n TrialRecord,\n} from './types';\nimport {\n dockPanel as dockPanelIn,\n type UndockedPanel,\n undockPanel as undockPanelIn,\n} from './undock';\n\n/** Every mutation a lab store supports: managing trials, saving and\n * restoring snapshots, and setting the color mode. */\nexport interface LabStoreActions {\n addTrial: (record: Omit<TrialRecord, 'undoStack'>) => void;\n removeTrial: (id: string) => void;\n updateTrialState: <TS>(id: string, next: TS | ((prev: TS) => TS)) => void;\n /** Write one config value. `path` is dotted for a value nested under an\n * `f.group`, and the bare key for one at the root. */\n updateTrialConfig: (id: string, path: string, value: unknown) => void;\n updateTrialView: (id: string, view: unknown) => void;\n updateTrialSidebarWidth: (id: string, width: number) => void;\n /** Retitle a trial. `null` returns it to its instrument's name. */\n setTrialTitle: (id: string, title: string | null) => void;\n /** Fold or unfold one of a trial's sections. */\n setTrialSectionCollapsed: (id: string, key: string, collapsed: boolean) => void;\n updateTrialAnnotations: (id: string, doc: unknown) => void;\n updateTrialUndoStack: (\n id: string,\n next: TrialRecord['undoStack'] | ((prev: TrialRecord['undoStack']) => TrialRecord['undoStack']),\n ) => void;\n setTrialInstrument: (id: string, instrumentName: string) => void;\n saveSnapshot: (trialId: string, name: string) => void;\n loadSnapshot: (snapshotId: string, trialId: string) => void;\n deleteSnapshot: (snapshotId: string) => void;\n listSnapshots: (trialId?: string) => SavedSnapshot[];\n setMode: (mode: LabMode) => void;\n setLabTool: (id: string | null) => void;\n setTrialTool: (trialId: string, id: string | null) => void;\n setLayout: (layout: Record<string, unknown>) => void;\n /** Tear a sidebar section out of its trial. Default target is a workspace tile. */\n undockPanel: (trialId: string, sectionId: string, as?: UndockedPanel['as']) => void;\n /** Put one section back, or — with no `sectionId` — every panel the trial owns. */\n dockPanel: (trialId: string, sectionId?: string) => void;\n}\n\n/** A lab's store: its state and its actions. How each instrument's state is\n * serialized comes in through `CreateLabStoreOptions.serializers`. */\nexport type LabStore = StoreApi<LabStoreState & LabStoreActions>;\n\n/** Build a lab store, hydrating from storage if anything was saved under the\n * same key. Writes back are debounced. */\nexport function createLabStore(options: CreateLabStoreOptions): LabStore {\n const serializers = options.serializers ?? {};\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n const hydration = hydrateDocument(options);\n const hydrated = hydration.document;\n const persistDisabled = hydration.persistDisabled;\n // Cleared once the legacy keys are actually gone; see the flush.\n let foldedFromLegacy = hydration.foldedFromLegacy;\n\n const configDefaults = options.configDefaults ?? {};\n const filled = (instrumentName: string, config: unknown): unknown => {\n const defaults = configDefaults[instrumentName];\n return defaults ? fillConfigDefaults(config, defaults()) : config;\n };\n\n const hydratedTrials = deserializeTrials(\n hydrated.trials.map((t) => ({ ...t, config: filled(t.instrumentName, t.config) })),\n serializers,\n );\n const hydratedSnapshots = hydrated.saves.map((sn) => ({\n ...sn,\n config: filled(sn.instrumentName, sn.config),\n }));\n const hydratedLayout = hydrated.layout;\n const hydratedMode = hydrated.mode;\n\n const store = createStore<LabStoreState & LabStoreActions>()((set, get) => ({\n trials: hydratedTrials,\n savedSnapshots: hydratedSnapshots,\n mode: hydratedMode,\n layout: hydratedLayout,\n undockedPanels: hydrated.undockedPanels,\n activeToolId: null,\n\n addTrial: (record) => {\n set((s) => ({\n trials: [...s.trials, { ...record, undoStack: emptyUndoStack() }],\n }));\n scheduleFlush();\n },\n\n removeTrial: (id) => {\n set((s) => ({\n trials: s.trials.filter((w) => w.id !== id),\n undockedPanels: dockPanelIn(s.undockedPanels, id),\n }));\n scheduleFlush();\n },\n\n updateTrialState: (id, next) => {\n set((s) => ({\n trials: s.trials.map((w) => {\n if (w.id !== id) return w;\n const nextState =\n typeof next === 'function' ? (next as (prev: unknown) => unknown)(w.state) : next;\n // An updater that returns its input means \"nothing changed\", and must not\n // cost a new record: the trial re-renders on record identity, so\n // allocating here turns the standard React bail-out into a render loop.\n if (Object.is(nextState, w.state)) return w;\n return { ...w, state: nextState };\n }),\n }));\n scheduleFlush();\n },\n\n updateTrialConfig: (id, path, value) => {\n set((s) => ({\n trials: s.trials.map((w) =>\n w.id === id ? { ...w, config: withValueAtPath(w.config, path, value) } : w,\n ),\n }));\n scheduleFlush();\n },\n\n updateTrialView: (id, view) => {\n set((s) => ({\n trials: s.trials.map((w) => (w.id === id && !Object.is(view, w.view) ? { ...w, view } : w)),\n }));\n scheduleFlush();\n },\n\n updateTrialSidebarWidth: (id, width) => {\n set((s) => ({\n trials: s.trials.map((w) =>\n w.id === id && w.sidebarWidth !== width ? { ...w, sidebarWidth: width } : w,\n ),\n }));\n scheduleFlush();\n },\n\n setTrialTitle: (id, title) => {\n set((s) => ({\n trials: s.trials.map((w) => {\n if (w.id !== id) return w;\n const next = title === null ? undefined : title;\n if ((w.title ?? undefined) === next) return w;\n return { ...w, title: next };\n }),\n }));\n scheduleFlush();\n },\n\n setTrialSectionCollapsed: (id, key, collapsed) => {\n set((s) => ({\n trials: s.trials.map((w) => {\n if (w.id !== id) return w;\n if (w.collapsedSections?.[key] === collapsed) return w;\n return { ...w, collapsedSections: { ...w.collapsedSections, [key]: collapsed } };\n }),\n }));\n scheduleFlush();\n },\n\n updateTrialAnnotations: (id, doc) => {\n set((s) => ({\n trials: s.trials.map((w) =>\n w.id === id && !Object.is(doc, w.annotations) ? { ...w, annotations: doc } : w,\n ),\n }));\n scheduleFlush();\n },\n\n updateTrialUndoStack: (id, next) => {\n set((s) => ({\n trials: s.trials.map((w) => {\n if (w.id !== id) return w;\n const undoStack =\n typeof next === 'function'\n ? (next as (prev: TrialRecord['undoStack']) => TrialRecord['undoStack'])(w.undoStack)\n : next;\n return { ...w, undoStack };\n }),\n }));\n },\n\n setTrialInstrument: (id, instrumentName) => {\n set((s) => ({\n trials: s.trials.map((w) => (w.id === id ? { ...w, instrumentName } : w)),\n }));\n scheduleFlush();\n },\n\n saveSnapshot: (trialId, name) => {\n const trial = get().trials.find((w) => w.id === trialId);\n if (!trial) return;\n const reg = serializers[trial.instrumentName];\n const serializedState = reg?.serialize\n ? reg.serialize(trial.state)\n : structuredClone(trial.state);\n const clonedConfig = structuredClone(trial.config);\n const lastAt = get().savedSnapshots.reduce((m, sn) => (sn.savedAt > m ? sn.savedAt : m), 0);\n const savedAt = Math.max(Date.now(), lastAt + 1);\n const snapshot: SavedSnapshot = {\n id: newId(),\n name,\n trialId,\n instrumentName: trial.instrumentName,\n config: clonedConfig,\n state: serializedState,\n savedAt,\n };\n set((s) => ({ savedSnapshots: [...s.savedSnapshots, snapshot] }));\n scheduleFlush();\n },\n\n loadSnapshot: (snapshotId, trialId) => {\n const snapshot = get().savedSnapshots.find((sn) => sn.id === snapshotId);\n if (!snapshot) return;\n const trial = get().trials.find((w) => w.id === trialId);\n if (!trial) return;\n if (snapshot.instrumentName !== trial.instrumentName) {\n console.warn(\n `[labkit] loadSnapshot: instrument mismatch (snapshot=${snapshot.instrumentName}, trial=${trial.instrumentName}); refusing to load`,\n );\n return;\n }\n const reg = serializers[snapshot.instrumentName];\n const restoredState = reg?.deserialize\n ? reg.deserialize(snapshot.state, snapshot.config)\n : snapshot.state;\n set((s) => ({\n trials: s.trials.map((w) =>\n w.id === trialId ? { ...w, state: restoredState, config: snapshot.config } : w,\n ),\n }));\n scheduleFlush();\n },\n\n deleteSnapshot: (snapshotId) => {\n set((s) => ({\n savedSnapshots: s.savedSnapshots.filter((sn) => sn.id !== snapshotId),\n }));\n scheduleFlush();\n },\n\n listSnapshots: (trialId) => {\n const all = get().savedSnapshots;\n const filtered = trialId ? all.filter((sn) => sn.trialId === trialId) : all;\n return [...filtered].sort((a, b) => b.savedAt - a.savedAt);\n },\n\n setMode: (mode) => {\n set({ mode });\n scheduleFlush();\n },\n\n setLabTool: (id) => set({ activeToolId: id }),\n\n setTrialTool: (trialId, id) =>\n set((s) => ({\n trials: s.trials.map((t) => (t.id === trialId ? { ...t, activeToolId: id } : t)),\n })),\n\n undockPanel: (trialId, sectionId, as) => {\n set((s) => ({ undockedPanels: undockPanelIn(s.undockedPanels, trialId, sectionId, as) }));\n scheduleFlush();\n },\n\n dockPanel: (trialId, sectionId) => {\n set((s) => ({ undockedPanels: dockPanelIn(s.undockedPanels, trialId, sectionId) }));\n scheduleFlush();\n },\n\n setLayout: (layout) => {\n set({ layout });\n scheduleFlush();\n },\n }));\n\n function scheduleFlush(): void {\n if (persistDisabled) return;\n if (flushTimer) clearTimeout(flushTimer);\n flushTimer = setTimeout(() => {\n const s = store.getState();\n const document: LabDocument = {\n version: CURRENT_DOCUMENT_VERSION,\n trials: serializeTrials(s.trials, serializers),\n saves: s.savedSnapshots,\n layout: s.layout,\n undockedPanels: s.undockedPanels,\n mode: s.mode,\n };\n const serialized = JSON.stringify(document);\n options.storage.write(labDocumentKey(options.storageKey), serialized);\n if (foldedFromLegacy && deleteLegacyKeys(options.storage, options.storageKey, serialized)) {\n foldedFromLegacy = false;\n }\n flushTimer = null;\n }, 300);\n }\n\n // A lab opened and closed without a single mutation still completes its\n // fold; the flush is what removes the legacy keys.\n if (foldedFromLegacy) scheduleFlush();\n\n return store;\n}\n\ninterface HydrateResult {\n document: LabDocument;\n /** True when flushing would destroy the only copy of something: a document\n * newer than this code understands, or an unusable one whose quarantine\n * copy did not land. */\n persistDisabled: boolean;\n foldedFromLegacy: boolean;\n}\n\n/** Copy an unusable document aside, and report whether the store may go on\n * persisting. A failed quarantine write means the copy in storage is the only\n * one there is, so the store must not overwrite it. */\nfunction setAside(\n options: CreateLabStoreOptions,\n raw: string,\n why: string,\n error?: unknown,\n): boolean {\n const quarantined = quarantineDocument(options.storage, options.storageKey, raw);\n const message = quarantined\n ? `[labkit] ${why}; quarantined it and starting empty`\n : `[labkit] ${why} and could not be quarantined; leaving it in place and not persisting`;\n if (error === undefined) console.warn(message);\n else console.warn(message, error);\n return quarantined;\n}\n\nfunction hydrateDocument(options: CreateLabStoreOptions): HydrateResult {\n const fallback = emptyDocument(options.initialMode ?? 'auto');\n const raw = options.storage.read(labDocumentKey(options.storageKey));\n\n let parsed: Record<string, unknown> | null = null;\n if (raw !== null) {\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n const persistDisabled = !setAside(options, raw, 'lab document is unparseable');\n return { document: fallback, persistDisabled, foldedFromLegacy: false };\n }\n } else {\n parsed = readLegacyDocument(options.storage, options.storageKey, options.initialMode ?? 'auto');\n }\n\n if (parsed === null) {\n return { document: fallback, persistDisabled: false, foldedFromLegacy: false };\n }\n\n const foldedFromLegacy = raw === null;\n const outcome = runMigrations(parsed, MIGRATIONS, CURRENT_DOCUMENT_VERSION);\n\n if (!outcome.ok) {\n if (outcome.reason === 'future') {\n console.warn(\n '[labkit] lab document is from a newer version of labkit; starting empty and leaving it alone',\n );\n return { document: fallback, persistDisabled: true, foldedFromLegacy: false };\n }\n const stored = JSON.stringify(parsed);\n const persistDisabled = !setAside(\n options,\n stored,\n 'lab document failed to migrate',\n outcome.error,\n );\n return { document: fallback, persistDisabled, foldedFromLegacy: false };\n }\n\n return {\n document: normalizeDocument(outcome.doc, options.initialMode ?? 'auto'),\n persistDisabled: false,\n foldedFromLegacy,\n };\n}\n","import { useContext } from 'react';\nimport { useStore } from 'zustand/react';\nimport { LabStoreContext, TrialIdContext } from './context';\nimport type { TrialStateHandle } from './types';\n\n/** An instrument's own state and config, plus setters. Reads the surrounding\n * trial id, so an instrument never has to know which trial it is\n * running in. Throws outside a lab store and trial. */\nexport function useTrialState<TS = unknown, TC = unknown>(): TrialStateHandle<TS, TC> {\n const ctx = useContext(LabStoreContext);\n if (!ctx) throw new Error('[labkit] useTrialState must be used inside <LabStoreProvider>');\n\n const trialId = useContext(TrialIdContext);\n if (!trialId) throw new Error('[labkit] useTrialState must be used inside <TrialIdProvider>');\n\n const record = useStore(ctx.store, (s) => s.trials.find((w) => w.id === trialId));\n\n if (!record) throw new Error(`[labkit] No trial found with id \"${trialId}\"`);\n\n const updateTrialState = useStore(ctx.store, (s) => s.updateTrialState);\n const updateTrialConfig = useStore(ctx.store, (s) => s.updateTrialConfig);\n\n return {\n state: record.state as TS,\n config: record.config as TC,\n setState: (next) => updateTrialState(trialId, next as Parameters<typeof updateTrialState>[1]),\n setConfig: (path, value) => updateTrialConfig(trialId, path, value),\n };\n}\n"]}
@@ -1,7 +1,6 @@
1
- import { Toolbar, ZoomControl, ScaleIndicator, FpsMeter, useRovingTabIndex, StatusBar } from './chunk-UTOEDPNU.js';
2
- import { ControlPanel } from './chunk-XKENZTNE.js';
3
- import { b, h2, u, A, j, U, M, x, N, h, _, v, P, y, n4, o3 } from './chunk-ISSVF5PT.js';
4
- import { SelectIcon, PencilIcon, LineIcon, ArrowIcon, RectIcon, EllipseIcon, TextIcon } from './chunk-54ZWZ5FQ.js';
1
+ import { Toolbar, ZoomControl, ScaleIndicator, FpsMeter, useRovingTabIndex, StatusBar } from './chunk-SMHP6XZ4.js';
2
+ import { ControlPanel } from './chunk-U3IYHIAE.js';
3
+ import { p, u, c, n, f, r2, h, b, g3, u2, A, j, U, M, x, N, g, _, v, P, y, n6, o3 } from './chunk-W3ECWC2K.js';
5
4
  import { createContext, useContext, useState, useId, useRef, useSyncExternalStore, useCallback } from 'react';
6
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
6
 
@@ -98,14 +97,13 @@ function ExportMenu() {
98
97
  }
99
98
  ),
100
99
  /* @__PURE__ */ jsx(
101
- h2,
100
+ g3,
102
101
  {
103
102
  triggerRef: { current: anchor },
104
103
  isOpen: open,
105
104
  onOpenChange: setOpen,
106
105
  onDismiss: () => setOpen(false),
107
106
  placement: "bottom end",
108
- UNSTABLE_portalContainer: anchor?.closest(".lk-root") ?? void 0,
109
107
  "aria-labelledby": titleId,
110
108
  children: /* @__PURE__ */ jsxs("div", { className: "lk-export__panel", children: [
111
109
  /* @__PURE__ */ jsx("span", { className: "lk-export__title", id: titleId, children: "Export" }),
@@ -123,18 +121,18 @@ function ExportMenu() {
123
121
  ] }),
124
122
  /* @__PURE__ */ jsxs("div", { className: "lk-export__row", children: [
125
123
  /* @__PURE__ */ jsx("span", { children: "Format" }),
126
- /* @__PURE__ */ jsx("span", { className: "lk-export__choices", role: "radiogroup", "aria-label": "Format", children: FORMATS.map((f) => /* @__PURE__ */ jsxs("label", { children: [
124
+ /* @__PURE__ */ jsx("span", { className: "lk-export__choices", role: "radiogroup", "aria-label": "Format", children: FORMATS.map((f2) => /* @__PURE__ */ jsxs("label", { children: [
127
125
  /* @__PURE__ */ jsx(
128
126
  "input",
129
127
  {
130
128
  type: "radio",
131
129
  name: "lk-export-format",
132
- checked: format === f.id,
133
- onChange: () => setFormat(f.id)
130
+ checked: format === f2.id,
131
+ onChange: () => setFormat(f2.id)
134
132
  }
135
133
  ),
136
- f.label
137
- ] }, f.id)) })
134
+ f2.label
135
+ ] }, f2.id)) })
138
136
  ] }),
139
137
  /* @__PURE__ */ jsxs("div", { className: "lk-export__row", children: [
140
138
  /* @__PURE__ */ jsx("span", { children: "Scale" }),
@@ -188,7 +186,7 @@ function MarkList({ meaning, config }) {
188
186
  )
189
187
  ] }),
190
188
  /* @__PURE__ */ jsx(
191
- u,
189
+ u2,
192
190
  {
193
191
  className: "lk-mark-list__title",
194
192
  "aria-label": `Title of ${a.kind} on ${a.target}`,
@@ -229,13 +227,13 @@ var TOOLS = {
229
227
  text: { weaselTool: "text", kind: "text" }
230
228
  };
231
229
  var ANNOTATION_TOOLS = [
232
- { id: "select", label: "Select", icon: SelectIcon, group: "annotate" },
233
- { id: "stroke", label: "Freehand", icon: PencilIcon, group: "annotate" },
234
- { id: "line", label: "Line", icon: LineIcon, group: "annotate" },
235
- { id: "arrow", label: "Arrow", icon: ArrowIcon, group: "annotate" },
236
- { id: "rect", label: "Rectangle", icon: RectIcon, group: "annotate" },
237
- { id: "ellipse", label: "Ellipse", icon: EllipseIcon, group: "annotate" },
238
- { id: "text", label: "Text", icon: TextIcon, group: "annotate" }
230
+ { id: "select", label: "Select", icon: p, group: "annotate" },
231
+ { id: "stroke", label: "Freehand", icon: u, group: "annotate" },
232
+ { id: "line", label: "Line", icon: c, group: "annotate" },
233
+ { id: "arrow", label: "Arrow", icon: n, group: "annotate" },
234
+ { id: "rect", label: "Rectangle", icon: f, group: "annotate" },
235
+ { id: "ellipse", label: "Ellipse", icon: r2, group: "annotate" },
236
+ { id: "text", label: "Text", icon: h, group: "annotate" }
239
237
  ];
240
238
  function annotationToolInfo(id) {
241
239
  return id === null ? void 0 : TOOLS[id];
@@ -337,7 +335,7 @@ function builtinContributions(instrument, ctx, controls) {
337
335
  id: "zoom-control",
338
336
  region: "viewport",
339
337
  group: "zoom",
340
- render: (c) => /* @__PURE__ */ jsx(ZoomControl, { zoom: c.zoom ?? 1, onZoomChange: c.setZoom })
338
+ render: (c2) => /* @__PURE__ */ jsx(ZoomControl, { zoom: c2.zoom ?? 1, onZoomChange: c2.setZoom })
341
339
  });
342
340
  out.push({
343
341
  id: "scale",
@@ -396,16 +394,16 @@ function builtinContributions(instrument, ctx, controls) {
396
394
  region: "toolbar",
397
395
  group: "trial",
398
396
  end: true,
399
- render: (c) => /* @__PURE__ */ jsx(
400
- h,
397
+ render: (c2) => /* @__PURE__ */ jsx(
398
+ g,
401
399
  {
402
400
  className: "lk-toolbar__load-select",
403
401
  "aria-label": "Load snapshot",
404
402
  placeholder: "Load\u2026",
405
403
  selectedKey: null,
406
- options: c.savedSnapshots.map((sn) => ({ value: sn.id, label: sn.name })),
404
+ options: c2.savedSnapshots.map((sn) => ({ value: sn.id, label: sn.name })),
407
405
  onSelectionChange: (id) => {
408
- if (id != null) c.loadSnapshot(String(id));
406
+ if (id != null) c2.loadSnapshot(String(id));
409
407
  }
410
408
  }
411
409
  )
@@ -467,7 +465,7 @@ function mergeContributions(...bundles) {
467
465
  return out;
468
466
  }
469
467
  function suppressContributions(bundle, ids) {
470
- const present = new Set(bundle.map((c) => c.id));
468
+ const present = new Set(bundle.map((c2) => c2.id));
471
469
  for (const id of ids) {
472
470
  if (!present.has(id)) {
473
471
  throw new Error(
@@ -476,7 +474,7 @@ function suppressContributions(bundle, ids) {
476
474
  }
477
475
  }
478
476
  const drop = new Set(ids);
479
- return bundle.filter((c) => !drop.has(c.id));
477
+ return bundle.filter((c2) => !drop.has(c2.id));
480
478
  }
481
479
  function PaletteRegion({ contributions, ctx }) {
482
480
  const { ref, onKeyDown } = useRovingTabIndex("vertical");
@@ -490,21 +488,21 @@ function PaletteRegion({ contributions, ctx }) {
490
488
  "aria-label": "Tools",
491
489
  "aria-orientation": "vertical",
492
490
  onKeyDown,
493
- children: /* @__PURE__ */ jsx(n4, { orientation: "vertical", children: contributions.map((c) => {
494
- if (c.render) return /* @__PURE__ */ jsx("span", { children: c.render(ctx) }, c.id);
495
- if (c.region !== "palette" || !c.item) return null;
496
- const { icon: Icon, label, shortcut, disabled } = c.item;
491
+ children: /* @__PURE__ */ jsx(n6, { orientation: "vertical", children: contributions.map((c2) => {
492
+ if (c2.render) return /* @__PURE__ */ jsx("span", { children: c2.render(ctx) }, c2.id);
493
+ if (c2.region !== "palette" || !c2.item) return null;
494
+ const { icon: Icon, label, shortcut, disabled } = c2.item;
497
495
  return /* @__PURE__ */ jsx(
498
496
  o3,
499
497
  {
500
498
  icon: /* @__PURE__ */ jsx(Icon, { size: 16 }),
501
499
  label,
502
500
  shortcut,
503
- active: ctx.activeToolId === c.id,
501
+ active: ctx.activeToolId === c2.id,
504
502
  disabled,
505
- onClick: () => ctx.setActiveTool(c.id)
503
+ onClick: () => ctx.setActiveTool(c2.id)
506
504
  },
507
- c.id
505
+ c2.id
508
506
  );
509
507
  }) })
510
508
  }
@@ -546,37 +544,37 @@ function Section({
546
544
  }
547
545
  function SidebarRegion({ contributions, ctx }) {
548
546
  if (contributions.length === 0) return null;
549
- return /* @__PURE__ */ jsx(Fragment, { children: contributions.map((c) => {
550
- if (c.render) return /* @__PURE__ */ jsx("div", { children: c.render(ctx) }, c.id);
551
- if (c.region !== "sidebar" || !c.item) return null;
552
- if (ctx.undockedPanels.includes(c.id)) return null;
553
- const item = c.item;
547
+ return /* @__PURE__ */ jsx(Fragment, { children: contributions.map((c2) => {
548
+ if (c2.render) return /* @__PURE__ */ jsx("div", { children: c2.render(ctx) }, c2.id);
549
+ if (c2.region !== "sidebar" || !c2.item) return null;
550
+ if (ctx.undockedPanels.includes(c2.id)) return null;
551
+ const item = c2.item;
554
552
  return /* @__PURE__ */ jsx(
555
553
  Section,
556
554
  {
557
555
  title: item.title,
558
- collapsed: ctx.collapsedSections[c.id] ?? item.defaultCollapsed ?? false,
559
- onCollapsedChange: (next) => ctx.setSectionCollapsed(c.id, next),
560
- onUndock: item.undockable === false ? void 0 : () => ctx.undockPanel(c.id, item.undockAs ?? "tile"),
556
+ collapsed: ctx.collapsedSections[c2.id] ?? item.defaultCollapsed ?? false,
557
+ onCollapsedChange: (next) => ctx.setSectionCollapsed(c2.id, next),
558
+ onUndock: item.undockable === false ? void 0 : () => ctx.undockPanel(c2.id, item.undockAs ?? "tile"),
561
559
  children: item.body
562
560
  },
563
- c.id
561
+ c2.id
564
562
  );
565
563
  }) });
566
564
  }
567
565
  function StatusRegion({ contributions, ctx }) {
568
566
  if (contributions.length === 0) return null;
569
- return /* @__PURE__ */ jsx(StatusBar, { children: contributions.map((c) => {
570
- if (c.render)
571
- return /* @__PURE__ */ jsx(StatusBar.Section, { end: c.end, children: c.render(ctx) }, c.id);
572
- if (c.region !== "status" || !c.item) return null;
573
- return /* @__PURE__ */ jsx(StatusBar.Section, { end: c.end, children: /* @__PURE__ */ jsx("span", { title: c.item.title, children: c.item.text }) }, c.id);
567
+ return /* @__PURE__ */ jsx(StatusBar, { children: contributions.map((c2) => {
568
+ if (c2.render)
569
+ return /* @__PURE__ */ jsx(StatusBar.Section, { end: c2.end, children: c2.render(ctx) }, c2.id);
570
+ if (c2.region !== "status" || !c2.item) return null;
571
+ return /* @__PURE__ */ jsx(StatusBar.Section, { end: c2.end, children: /* @__PURE__ */ jsx("span", { title: c2.item.title, children: c2.item.text }) }, c2.id);
574
572
  }) });
575
573
  }
576
- function renderEntry(c, ctx) {
577
- if (c.render) return /* @__PURE__ */ jsx("span", { children: c.render(ctx) }, c.id);
578
- if (c.region !== "titlebar" || !c.item) return null;
579
- const { icon: Icon, label, shortcut, disabled, danger, onActivate } = c.item;
574
+ function renderEntry(c2, ctx) {
575
+ if (c2.render) return /* @__PURE__ */ jsx("span", { children: c2.render(ctx) }, c2.id);
576
+ if (c2.region !== "titlebar" || !c2.item) return null;
577
+ const { icon: Icon, label, shortcut, disabled, danger, onActivate } = c2.item;
580
578
  return /* @__PURE__ */ jsx(
581
579
  "button",
582
580
  {
@@ -590,37 +588,37 @@ function renderEntry(c, ctx) {
590
588
  onMouseDown: (e) => e.stopPropagation(),
591
589
  children: /* @__PURE__ */ jsx(Icon, { size: 14 })
592
590
  },
593
- c.id
591
+ c2.id
594
592
  );
595
593
  }
596
594
  function TitleBarRegion({ contributions, ctx, placement = "actions" }) {
597
595
  const wanted = placement === "actions";
598
- const mine = contributions.filter((c) => (c.end ?? false) === wanted);
596
+ const mine = contributions.filter((c2) => (c2.end ?? false) === wanted);
599
597
  if (mine.length === 0) return null;
600
- return /* @__PURE__ */ jsx("span", { className: wanted ? "lk-trial__titlebar-actions" : "lk-trial__titlebar-lead", children: mine.map((c) => renderEntry(c, ctx)) });
598
+ return /* @__PURE__ */ jsx("span", { className: wanted ? "lk-trial__titlebar-actions" : "lk-trial__titlebar-lead", children: mine.map((c2) => renderEntry(c2, ctx)) });
601
599
  }
602
600
  function groupsOf(contributions) {
603
601
  const groups = [];
604
602
  const byKey = /* @__PURE__ */ new Map();
605
- for (const c of contributions) {
606
- if (c.group == null) {
607
- groups.push({ key: c.id, end: c.end ?? false, entries: [c] });
603
+ for (const c2 of contributions) {
604
+ if (c2.group == null) {
605
+ groups.push({ key: c2.id, end: c2.end ?? false, entries: [c2] });
608
606
  continue;
609
607
  }
610
- let g = byKey.get(c.group);
611
- if (!g) {
612
- g = { key: c.group, end: c.end ?? false, entries: [] };
613
- byKey.set(c.group, g);
614
- groups.push(g);
608
+ let g3 = byKey.get(c2.group);
609
+ if (!g3) {
610
+ g3 = { key: c2.group, end: c2.end ?? false, entries: [] };
611
+ byKey.set(c2.group, g3);
612
+ groups.push(g3);
615
613
  }
616
- g.entries.push(c);
614
+ g3.entries.push(c2);
617
615
  }
618
616
  return groups;
619
617
  }
620
- function renderEntry2(c, ctx) {
621
- if (c.render) return /* @__PURE__ */ jsx("span", { children: c.render(ctx) }, c.id);
622
- if (c.region !== "toolbar" || !c.item) return null;
623
- const { icon: Icon, label, shortcut, disabled, danger, showLabel, pressed, onActivate } = c.item;
618
+ function renderEntry2(c2, ctx) {
619
+ if (c2.render) return /* @__PURE__ */ jsx("span", { children: c2.render(ctx) }, c2.id);
620
+ if (c2.region !== "toolbar" || !c2.item) return null;
621
+ const { icon: Icon, label, shortcut, disabled, danger, showLabel, pressed, onActivate } = c2.item;
624
622
  return /* @__PURE__ */ jsxs(
625
623
  Toolbar.Button,
626
624
  {
@@ -636,13 +634,13 @@ function renderEntry2(c, ctx) {
636
634
  showLabel ? /* @__PURE__ */ jsx("span", { children: label }) : null
637
635
  ]
638
636
  },
639
- c.id
637
+ c2.id
640
638
  );
641
639
  }
642
640
  function ToolbarRegion({ contributions, ctx }) {
643
641
  if (contributions.length === 0) return null;
644
642
  const groups = groupsOf(contributions);
645
- return /* @__PURE__ */ jsx(Toolbar, { "aria-label": "Trial actions", children: groups.map((g) => /* @__PURE__ */ jsx(Toolbar.Group, { end: g.end, "aria-label": g.key, children: g.entries.map((c) => renderEntry2(c, ctx)) }, g.key)) });
643
+ return /* @__PURE__ */ jsx(Toolbar, { "aria-label": "Trial actions", children: groups.map((g3) => /* @__PURE__ */ jsx(Toolbar.Group, { end: g3.end, "aria-label": g3.key, children: g3.entries.map((c2) => renderEntry2(c2, ctx)) }, g3.key)) });
646
644
  }
647
645
  function ViewportRegion({ contributions, ctx }) {
648
646
  const { ref, onKeyDown } = useRovingTabIndex();
@@ -655,10 +653,10 @@ function ViewportRegion({ contributions, ctx }) {
655
653
  role: "toolbar",
656
654
  "aria-label": "View",
657
655
  onKeyDown,
658
- children: contributions.map((c) => {
659
- if (c.render) return /* @__PURE__ */ jsx("span", { children: c.render(ctx) }, c.id);
660
- if (c.region !== "viewport" || !c.item) return null;
661
- const { icon: Icon, label, disabled, onActivate } = c.item;
656
+ children: contributions.map((c2) => {
657
+ if (c2.render) return /* @__PURE__ */ jsx("span", { children: c2.render(ctx) }, c2.id);
658
+ if (c2.region !== "viewport" || !c2.item) return null;
659
+ const { icon: Icon, label, disabled, onActivate } = c2.item;
662
660
  return /* @__PURE__ */ jsx(
663
661
  "button",
664
662
  {
@@ -670,7 +668,7 @@ function ViewportRegion({ contributions, ctx }) {
670
668
  onClick: () => onActivate(ctx),
671
669
  children: /* @__PURE__ */ jsx(Icon, { size: 16 })
672
670
  },
673
- c.id
671
+ c2.id
674
672
  );
675
673
  })
676
674
  }
@@ -678,5 +676,5 @@ function ViewportRegion({ contributions, ctx }) {
678
676
  }
679
677
 
680
678
  export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, AnnotationsContext, ExportMenu, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, annotationToolInfo, builtinContributions, mergeContributions, suppressContributions, useAnnotations, useAnnotationsOptional };
681
- //# sourceMappingURL=chunk-W2FJR5FF.js.map
682
- //# sourceMappingURL=chunk-W2FJR5FF.js.map
679
+ //# sourceMappingURL=chunk-64ZCN3DA.js.map
680
+ //# sourceMappingURL=chunk-64ZCN3DA.js.map