@weasel-js/labkit 1.5.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -7
- package/dist/_dts/{CanvasStackContext-CJNMS6mz.d.ts → CanvasStackContext-DQgcH1ny.d.ts} +1 -1
- package/dist/_dts/LayerList.d-2c9yup5Y.d.ts +83 -0
- package/dist/_dts/{PrefsForm.d-DPy9I8It.d.ts → PrefsRow.d-DFpPIeIC.d.ts} +16 -1
- package/dist/_dts/{Select.d-Gwr8fLpK.d.ts → Select.d-BchGMC2Y.d.ts} +129 -12
- package/dist/_dts/{frac-B4okC2lX.d.ts → frac-DTRq7Xpb.d.ts} +31 -13
- package/dist/_dts/inDialog-D5ZKGjiD.d.ts +23 -0
- package/dist/_dts/{index-CSJoj4LC.d.ts → index-B0--8PEM.d.ts} +5 -4
- package/dist/_dts/index-DINmCuLA.d.ts +453 -0
- package/dist/_dts/number.d-OeQYQoUO.d.ts +28 -0
- package/dist/_dts/{types-DzoNY1pO.d.ts → types-B7y8hX1D.d.ts} +6 -6
- package/dist/_dts/{usePanZoom-Pzf9f2jh.d.ts → usePanZoom-Bq73pwFe.d.ts} +4 -47
- package/dist/_dts/{useTrialState-uLlmaccn.d.ts → useTrialState-CP4jfuKl.d.ts} +1 -1
- package/dist/canvas/index.d.ts +6 -5
- package/dist/canvas/index.js +1 -1
- package/dist/chrome/index.d.ts +5 -4
- package/dist/chrome/index.js +7 -7
- package/dist/chunk-2RVCB2PT.js +3 -0
- package/dist/chunk-2RVCB2PT.js.map +1 -0
- package/dist/{chunk-UN4U4P63.js → chunk-3FI7Y4R4.js} +9 -9
- package/dist/chunk-3FI7Y4R4.js.map +1 -0
- package/dist/{chunk-7PFH3CNM.js → chunk-AWH3SRPW.js} +31 -5
- package/dist/chunk-AWH3SRPW.js.map +1 -0
- package/dist/{chunk-ZDHY47EV.js → chunk-BVL7Y574.js} +25 -9
- package/dist/chunk-BVL7Y574.js.map +1 -0
- package/dist/{chunk-IHUVQ3TX.js → chunk-H5VIV7MQ.js} +31 -27
- package/dist/chunk-H5VIV7MQ.js.map +1 -0
- package/dist/chunk-HFRE4QQV.js +400 -0
- package/dist/chunk-HFRE4QQV.js.map +1 -0
- package/dist/{chunk-IXTQI7JX.js → chunk-MOLIUNVH.js} +4 -4
- package/dist/{chunk-IXTQI7JX.js.map → chunk-MOLIUNVH.js.map} +1 -1
- package/dist/{chunk-CEIUBPPW.js → chunk-TT5C5S6R.js} +3 -86
- package/dist/chunk-TT5C5S6R.js.map +1 -0
- package/dist/chunk-USO6TERP.js +90 -0
- package/dist/chunk-USO6TERP.js.map +1 -0
- package/dist/{chunk-PHK4W562.js → chunk-VQ47KWD5.js} +3 -3
- package/dist/{chunk-PHK4W562.js.map → chunk-VQ47KWD5.js.map} +1 -1
- package/dist/chunk-WUJXJC5O.js +14568 -0
- package/dist/chunk-WUJXJC5O.js.map +1 -0
- package/dist/{chunk-EHGVROVV.js → chunk-ZORVNOKX.js} +6 -25
- package/dist/chunk-ZORVNOKX.js.map +1 -0
- package/dist/config/index.d.ts +53 -11
- package/dist/config/index.js +5 -5
- package/dist/controls/index.d.ts +6 -3
- package/dist/controls/index.js +4 -4
- package/dist/dragdrop/index.d.ts +4 -3
- package/dist/index.d.ts +139 -114
- package/dist/index.js +470 -479
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +6 -35
- package/dist/layers/index.js +2 -3
- package/dist/loupe/index.d.ts +6 -5
- package/dist/passthrough/weasel-ui.d.ts +421 -215
- package/dist/passthrough/weasel-ui.js +1 -1
- package/dist/primitives/index.d.ts +2 -13
- package/dist/primitives/index.js +4 -4
- package/dist/state/index.d.ts +6 -5
- package/dist/state/index.js +5 -5
- package/dist/styles.css +410 -190
- package/dist/undo/index.d.ts +4 -3
- package/package.json +9 -13
- package/src/annotations/frac.test.ts +7 -0
- package/src/annotations/paint.test.ts +21 -0
- package/src/annotations/paint.ts +12 -0
- package/src/annotations/store.test.ts +31 -0
- package/src/annotations/types.ts +3 -2
- package/src/canvas/Stage.test.tsx +18 -0
- package/src/canvas/index.ts +0 -9
- package/src/chrome/labTypes.ts +1 -1
- package/src/chrome/regions/PaletteRegion.test.tsx +18 -0
- package/src/chrome/regions/PaletteRegion.tsx +5 -4
- package/src/chrome/regions/SidebarRegion.less +197 -0
- package/src/chrome/regions/SidebarRegion.test.tsx +20 -0
- package/src/chrome/regions/SidebarRegion.tsx +7 -2
- package/src/chrome/regions/TitleBarRegion.tsx +1 -1
- package/src/chrome/types.ts +13 -4
- package/src/config/autoConfig.ts +2 -2
- package/src/config/builder.ts +23 -5
- package/src/config/entry.test.ts +8 -0
- package/src/config/index.ts +2 -0
- package/src/config/rules.ts +2 -0
- package/src/config/sectionTree.test.ts +146 -0
- package/src/config/sectionTree.ts +124 -0
- package/src/config/types.ts +4 -4
- package/src/controls/AutoControls.stories.tsx +6 -6
- package/src/controls/ControlPanel.less +27 -0
- package/src/controls/ControlPanel.stories.tsx +95 -1
- package/src/controls/ControlPanel.test.tsx +82 -112
- package/src/controls/ControlPanel.tsx +159 -396
- package/src/controls/inDialog.test.tsx +82 -0
- package/src/controls/inDialog.tsx +46 -0
- package/src/controls/index.ts +1 -0
- package/src/index.test.ts +0 -2
- package/src/index.ts +14 -35
- package/src/instrument/types.ts +5 -2
- package/src/lab/Lab.nebula.test.tsx +31 -0
- package/src/lab/Lab.tsx +57 -18
- package/src/lab/LabBoundary.test.tsx +66 -0
- package/src/lab/LabBoundary.tsx +56 -0
- package/src/lab/LabHeader.tsx +4 -23
- package/src/lab/LabRoot.tsx +2 -3
- package/src/lab/LabShell.less +0 -1
- package/src/lab/LabShell.stories.tsx +15 -0
- package/src/lab/LabShell.test.tsx +18 -0
- package/src/lab/LabShell.tsx +14 -1
- package/src/lab/LabSwitcher.less +1 -1
- package/src/lab/LabSwitcher.test.tsx +41 -0
- package/src/lab/LabSwitcher.tsx +30 -8
- package/src/lab/index.ts +1 -0
- package/src/layers/AGENTS.md +18 -74
- package/src/layers/index.ts +4 -2
- package/src/passthrough/weasel-ui.ts +25 -10
- package/src/primitives/FpsMeter.less +6 -1
- package/src/primitives/FpsMeter.test.tsx +12 -4
- package/src/primitives/FpsMeter.tsx +6 -1
- package/src/primitives/JobProgress.stories.tsx +1 -1
- package/src/primitives/StatusBar.less +6 -0
- package/src/primitives/index.ts +0 -2
- package/src/specimen/Specimen.tsx +42 -56
- package/src/state/types.ts +8 -2
- package/src/state/view.test.ts +4 -4
- package/src/styles.less +4 -2
- package/src/theme/Interstellar.stories.tsx +8 -9
- package/src/theme/base.less +3 -20
- package/src/theme/interstellar.test.ts +6 -3
- package/src/theme/interstellar.theme.json +0 -56
- package/src/theme/interstellar.ts +2 -2
- package/src/trial/Trial.canvas.test.tsx +9 -5
- package/src/trial/Trial.config.test.tsx +1 -1
- package/src/trial/Trial.tsx +30 -8
- package/dist/_dts/index-BNdz-tNd.d.ts +0 -423
- package/dist/chunk-7PFH3CNM.js.map +0 -1
- package/dist/chunk-CEIUBPPW.js.map +0 -1
- package/dist/chunk-EH7UEQV7.js +0 -590
- package/dist/chunk-EH7UEQV7.js.map +0 -1
- package/dist/chunk-EHGVROVV.js.map +0 -1
- package/dist/chunk-IHUVQ3TX.js.map +0 -1
- package/dist/chunk-MDVTK5U3.js +0 -170
- package/dist/chunk-MDVTK5U3.js.map +0 -1
- package/dist/chunk-PJ7WEQBJ.js +0 -18
- package/dist/chunk-PJ7WEQBJ.js.map +0 -1
- package/dist/chunk-T3EC2DXD.js +0 -12628
- package/dist/chunk-T3EC2DXD.js.map +0 -1
- package/dist/chunk-UN4U4P63.js.map +0 -1
- package/dist/chunk-ZDHY47EV.js.map +0 -1
- package/dist/ui/layers/index.d.ts +0 -66
- package/dist/ui/layers/index.js +0 -3
- package/dist/ui/layers/index.js.map +0 -1
- package/src/canvas/useOrbit.test.ts +0 -167
- package/src/canvas/useOrbit.ts +0 -156
- package/src/lab/useSystemMode.ts +0 -30
- package/src/layers/LayerList.less +0 -93
- package/src/layers/LayerList.stories.tsx +0 -66
- package/src/layers/LayerList.test.tsx +0 -232
- package/src/layers/LayerList.tsx +0 -268
- package/src/primitives/Sidebar.less +0 -112
- package/src/primitives/Sidebar.stories.tsx +0 -38
- package/src/primitives/Sidebar.test.tsx +0 -74
- package/src/primitives/Sidebar.tsx +0 -35
- package/src/ui/layers/index.ts +0 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { newId, emptyUndoStack, deserializeTrials, openRecords, labPrefix, documentOfRecords, recordsOfDocument, trialRecord, trialValuesPrefix, saveRecord, LAYOUT_RECORD, UNDOCK_RECORD, META_RECORD, parseRecordName, compareTrialOrder, serializeTrials, labStorageKey } from './chunk-RWNDDKOH.js';
|
|
2
|
-
import { resolveConfigSchema, useResolvedConfig } from './chunk-
|
|
3
|
-
import { applyConfigWrite, fillConfigDefaults } from './chunk-
|
|
2
|
+
import { resolveConfigSchema, useResolvedConfig } from './chunk-BVL7Y574.js';
|
|
3
|
+
import { applyConfigWrite, fillConfigDefaults } from './chunk-AWH3SRPW.js';
|
|
4
4
|
import { LabStoreContext, TrialIdContext } from './chunk-2YILQ7Y5.js';
|
|
5
5
|
import { createStore } from 'zustand/vanilla';
|
|
6
6
|
import { useContext } from 'react';
|
|
@@ -733,5 +733,5 @@ function useTrialState() {
|
|
|
733
733
|
}
|
|
734
734
|
|
|
735
735
|
export { CURRENT_DOCUMENT_VERSION, createLabStore, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, unruledConfigSchema, useTrialState };
|
|
736
|
-
//# sourceMappingURL=chunk-
|
|
737
|
-
//# sourceMappingURL=chunk-
|
|
736
|
+
//# sourceMappingURL=chunk-MOLIUNVH.js.map
|
|
737
|
+
//# sourceMappingURL=chunk-MOLIUNVH.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/state/document.ts","../src/state/undock.ts","../src/instrument/serializers.ts","../src/state/store.ts","../src/state/openLabStore.ts","../src/state/useTrialState.ts"],"names":[],"mappings":"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","file":"chunk-IXTQI7JX.js","sourcesContent":["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 = 4;\n\n/** Where a version-3 lab kept its one document. Read once, to fold it into\n * records, then deleted. */\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\n/** The four keys a lab used before it was one document. */\nexport function legacyKeys(storageKey: string): string[] {\n return LEGACY_BUCKETS.map((bucket) => labStorageKey(storageKey, bucket));\n}\n\n/** A value some substrate returned for an old key: already parsed, or a JSON\n * string from a store that does not parse. `undefined` when it is neither. */\nexport function parseStored(value: unknown): unknown {\n if (typeof value !== 'string') return value;\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction bucketOr<T>(value: unknown, fallback: T, bucket: string, shape: 'array' | 'object'): T {\n if (value === undefined) return fallback;\n const parsed = parseStored(value);\n const fits = shape === 'array' ? Array.isArray(parsed) : !!parsed && typeof parsed === 'object';\n if (fits) return parsed as T;\n console.warn(`[labkit] unparseable legacy bucket \"${bucket}\", dropping it`);\n return fallback;\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 async function readLegacyDocument(\n read: (key: string) => Promise<unknown>,\n storageKey: string,\n fallbackMode: LabMode,\n): Promise<Record<string, unknown> | null> {\n const [workspaces, saves, layout, theme] = await Promise.all(\n LEGACY_BUCKETS.map((bucket) => read(labStorageKey(storageKey, bucket))),\n );\n if ([workspaces, saves, layout, theme].every((v) => v === undefined)) return null;\n\n const mode =\n theme === 'light' || theme === 'dark' || theme === 'auto' || theme === 'interstellar'\n ? theme\n : fallbackMode;\n\n return {\n version: 0,\n workspaces: bucketOr(workspaces, [], 'workspaces', 'array'),\n saves: bucketOr(saves, [], 'saves', 'array'),\n layout: bucketOr(layout, {}, 'layout', 'object'),\n mode,\n };\n}\n\n/** Whether two stored values hold the same data. Stored values are\n * structured-clone copies, so identity says nothing. */\nexport function sameStored(a: unknown, b: unknown): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n}\n\n/** Delete `keys` and read each back, so an adapter whose delete silently did\n * nothing is caught. `true` only once all of them are gone. */\nexport async function deleteConfirmed(storage: StorageAdapter, keys: string[]): Promise<boolean> {\n try {\n await Promise.all(keys.map((key) => storage.delete(key)));\n const left = await Promise.all(keys.map((key) => storage.get(key)));\n return left.every((v) => v === undefined);\n } catch {\n return false;\n }\n}\n\n/** Set `value` 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 async function quarantineDocument(\n storage: StorageAdapter,\n storageKey: string,\n value: unknown,\n): Promise<boolean> {\n try {\n await storage.set(quarantineKey(storageKey), value);\n return sameStored(await storage.get(quarantineKey(storageKey)), value);\n } catch {\n return false;\n }\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/** Version 3 to version 4: a lab is stored as records under one prefix\n * instead of one document. The joined shape does not change. */\nexport function migrateV3toV4(doc: Record<string, unknown>): Record<string, unknown> {\n return { ...doc, version: 4 };\n}\n\n/** Index `i` migrates a version-`i` document to version `i + 1`. */\nexport const MIGRATIONS: Migration[] = [migrateV0toV1, migrateV1toV2, migrateV2toV3, migrateV3toV4];\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 { resolveConfigSchema } from '../config/resolve';\nimport type { ResolvedConfig } from '../config/types';\nimport type { InstrumentSerializers } from '../state/types';\nimport type { Instrument, InstrumentList } from './types';\n\n/**\n * One instrument's config schema, resolved without the lab's rules — which\n * neither the store nor a trial composed outside a lab has access to. No rule\n * can reach `autoResolve`, `unpinned` or `manual`, so for reading those the\n * two resolutions agree; anything reading the rendered leaves wants\n * `useConfigSchema` instead. `undefined` for a legacy `configSchema()`\n * instrument, which declares no auto annotations at all.\n */\nexport function unruledConfigSchema(\n // biome-ignore lint/suspicious/noExplicitAny: instruments are stored contravariantly; see InstrumentList\n instrument: Instrument<any, any, any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n): ResolvedConfig | undefined {\n return instrument.config ? resolveConfigSchema(instrument.config, []) : undefined;\n}\n\n/** Each instrument's unruled config schema, keyed by name — what the store\n * reads a leaf's auto annotations off. */\nexport function configSchemasOf(instruments: InstrumentList): Record<string, ResolvedConfig> {\n const out: Record<string, ResolvedConfig> = {};\n for (const instrument of instruments) {\n const schema = unruledConfigSchema(instrument);\n if (schema) out[instrument.name] = schema;\n }\n return out;\n}\n\n/**\n * Each instrument's default config, keyed by name — what `createLabStore`\n * fills a stored config's gaps from, so one saved before its schema grew a\n * branch still loads.\n */\nexport function configDefaultsOf(instruments: InstrumentList): Record<string, () => unknown> {\n const out: Record<string, () => unknown> = {};\n for (const instrument of instruments) out[instrument.name] = () => instrument.defaultConfig();\n return out;\n}\n\n/** Each instrument's `migrateConfig`, keyed by name, for those that declare one. */\nexport function configMigrationsOf(\n instruments: InstrumentList,\n): Record<string, (stored: unknown) => unknown> {\n const out: Record<string, (stored: unknown) => unknown> = {};\n for (const { name, migrateConfig } of instruments) {\n if (migrateConfig) out[name] = (stored) => migrateConfig(stored);\n }\n return out;\n}\n\n/**\n * The `serialize` / `deserialize` an instrument list declares, keyed by\n * instrument name — what `createLabStore` needs to rebuild a trial's state\n * from storage.\n *\n * An instrument declaring neither gets no entry, which is what leaves a\n * JSON-safe state to pass through untouched.\n */\nexport function serializersOf(instruments: InstrumentList): InstrumentSerializers {\n const out: InstrumentSerializers = {};\n for (const instrument of instruments) {\n const { name, serialize, deserialize } = instrument;\n if (!serialize && !deserialize) continue;\n out[name] = {\n ...(serialize ? { serialize: (state: unknown) => serialize(state) } : {}),\n ...(deserialize\n ? { deserialize: (data: unknown, config: unknown) => deserialize(data, config) }\n : {}),\n };\n }\n return out;\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla';\nimport { applyConfigWrite } from '../config/autoConfig';\nimport { fillConfigDefaults } from '../config/path';\nimport {\n configDefaultsOf,\n configMigrationsOf,\n configSchemasOf,\n serializersOf,\n} from '../instrument/serializers';\nimport type { InstrumentList } from '../instrument/types';\nimport { emptyDocument } from './document';\nimport { deserializeTrials, emptyUndoStack, newId } from './helpers';\nimport type {\n CreateLabStoreOptions,\n InstrumentHooks,\n InstrumentSerializers,\n LabMode,\n LabStoreState,\n SavedSnapshot,\n SerializedTrial,\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 /** Replace the lab's instruments. Trials and saves of an instrument that is\n * new or a different object are brought up to date against it in the same\n * write; every other trial keeps its object. */\n setInstruments: (instruments: InstrumentList) => void;\n /** The per-instrument hooks in force now. Read them at use; never keep them. */\n instrumentHooks: () => InstrumentHooks;\n}\n\n/** A lab's store: its state and its actions. How each instrument's state is\n * serialized comes in through `CreateLabStoreOptions.instruments`. */\nexport type LabStore = StoreApi<LabStoreState & LabStoreActions>;\n\n/** Build a lab store holding `initial`, or an empty lab. It knows nothing\n * about storage; `openLabStore` reads a stored lab and binds one of these to\n * it. */\nexport function createLabStore(options: CreateLabStoreOptions = {}): LabStore {\n let hooks: InstrumentHooks = options.instruments\n ? hooksOf(options.instruments)\n : {\n serializers: options.serializers ?? {},\n configDefaults: options.configDefaults ?? {},\n configMigrations: options.configMigrations ?? {},\n configSchemas: options.configSchemas ?? {},\n };\n const initial = options.initial ?? emptyDocument(options.initialMode ?? 'auto');\n\n const store = createStore<LabStoreState & LabStoreActions>()((set, get) => ({\n trials: hydrateTrials(initial.trials, hooks.serializers, hooks),\n savedSnapshots: hydrateSnapshots(initial.saves, hooks),\n mode: initial.mode,\n layout: initial.layout,\n undockedPanels: initial.undockedPanels,\n activeToolId: null,\n instruments: options.instruments ?? null,\n\n addTrial: (record) => {\n set((s) => ({\n trials: [...s.trials, { ...record, undoStack: emptyUndoStack() }],\n }));\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 },\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 },\n\n updateTrialConfig: (id, path, value) => {\n set((s) => ({\n trials: s.trials.map((w) => {\n if (w.id !== id) return w;\n const was = w.auto ?? [];\n // The sentinel is never stored: it becomes membership in `auto`, and\n // the pinned value at the path is left exactly where it is.\n const next = applyConfigWrite(w.config, was, path, value);\n if (next.config === w.config && next.autoPaths === was) return w;\n const { auto: _was, ...kept } = w;\n const record: TrialRecord = { ...kept, config: next.config };\n if (next.autoPaths.length > 0) record.auto = next.autoPaths;\n return record;\n }),\n }));\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 },\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 },\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 },\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 },\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 },\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 },\n\n saveSnapshot: (trialId, name) => {\n const trial = get().trials.find((w) => w.id === trialId);\n if (!trial) return;\n const reg = hooks.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 auto: [...(trial.auto ?? [])],\n savedAt,\n };\n set((s) => ({ savedSnapshots: [...s.savedSnapshots, snapshot] }));\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 = hooks.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 if (w.id !== trialId) return w;\n const loaded: TrialRecord = { ...w, state: restoredState, config: snapshot.config };\n if (snapshot.auto === undefined) return loaded;\n delete loaded.auto;\n if (snapshot.auto.length > 0) loaded.auto = [...snapshot.auto];\n return loaded;\n }),\n }));\n },\n\n deleteSnapshot: (snapshotId) => {\n set((s) => ({\n savedSnapshots: s.savedSnapshots.filter((sn) => sn.id !== snapshotId),\n }));\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 },\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 },\n\n dockPanel: (trialId, sectionId) => {\n set((s) => ({ undockedPanels: dockPanelIn(s.undockedPanels, trialId, sectionId) }));\n },\n\n setLayout: (layout) => {\n set({ layout });\n },\n\n setInstruments: (instruments) => {\n const before = get().instruments;\n if (before === instruments) return;\n const next = mergedHooks(hooks, instruments);\n const previous = new Map((before ?? []).map((i) => [i.name, i]));\n const changed = new Set(\n instruments.filter((i) => previous.get(i.name) !== i).map((i) => i.name),\n );\n if (changed.size === 0) {\n hooks = next;\n set({ instruments });\n return;\n }\n const s = get();\n const trials = s.trials.map((w) =>\n changed.has(w.instrumentName)\n ? { ...w, config: hydratedConfig(next, w.instrumentName, w.config) }\n : w,\n );\n const savedSnapshots = s.savedSnapshots.map((sn) =>\n changed.has(sn.instrumentName)\n ? { ...sn, config: hydratedConfig(next, sn.instrumentName, sn.config) }\n : sn,\n );\n hooks = next;\n set({ instruments, trials, savedSnapshots });\n },\n\n instrumentHooks: () => hooks,\n }));\n\n return store;\n}\n\nfunction hooksOf(instruments: InstrumentList): InstrumentHooks {\n return {\n serializers: serializersOf(instruments),\n configDefaults: configDefaultsOf(instruments),\n configSchemas: configSchemasOf(instruments),\n configMigrations: configMigrationsOf(instruments),\n };\n}\n\n/** Hooks for `instruments`, keeping those of any instrument no longer listed:\n * its trials stay open, and their state still has to round-trip. A listed\n * name takes its hooks wholly from the new list. */\nfunction mergedHooks(old: InstrumentHooks, instruments: InstrumentList): InstrumentHooks {\n const listed = new Set(instruments.map((i) => i.name));\n const fresh = hooksOf(instruments);\n const unlisted = <T>(entries: Record<string, T>): Record<string, T> =>\n Object.fromEntries(Object.entries(entries).filter(([name]) => !listed.has(name)));\n return {\n serializers: { ...unlisted(old.serializers), ...fresh.serializers },\n configDefaults: { ...unlisted(old.configDefaults), ...fresh.configDefaults },\n configSchemas: { ...unlisted(old.configSchemas), ...fresh.configSchemas },\n configMigrations: { ...unlisted(old.configMigrations), ...fresh.configMigrations },\n };\n}\n\n/** How a stored config is brought up to date on the way in. */\nexport type ConfigHydration = Pick<CreateLabStoreOptions, 'configDefaults' | 'configMigrations'>;\n\nfunction hydratedConfig(\n hydration: ConfigHydration,\n instrumentName: string,\n config: unknown,\n): unknown {\n const migrate = hydration.configMigrations?.[instrumentName];\n const moved = migrate ? migrate(config) : config;\n const defaults = hydration.configDefaults?.[instrumentName];\n return defaults ? fillConfigDefaults(moved, defaults()) : moved;\n}\n\n/** Rebuild stored trials: migrate each config, fill its gaps from its\n * instrument's defaults, then run the deserializer against the result. */\nexport function hydrateTrials(\n trials: SerializedTrial[],\n serializers: InstrumentSerializers,\n hydration: ConfigHydration = {},\n): TrialRecord[] {\n return deserializeTrials(\n trials.map((t) => ({ ...t, config: hydratedConfig(hydration, t.instrumentName, t.config) })),\n serializers,\n );\n}\n\n/** Bring each stored snapshot's config up to date the way `hydrateTrials` does a trial's. */\nexport function hydrateSnapshots(\n saves: SavedSnapshot[],\n hydration: ConfigHydration = {},\n): SavedSnapshot[] {\n return saves.map((sn) => ({\n ...sn,\n config: hydratedConfig(hydration, sn.instrumentName, sn.config),\n }));\n}\n","import {\n CURRENT_DOCUMENT_VERSION,\n deleteConfirmed,\n emptyDocument,\n labDocumentKey,\n legacyKeys,\n MIGRATIONS,\n normalizeDocument,\n parseStored,\n quarantineDocument,\n readLegacyDocument,\n runMigrations,\n sameStored,\n} from './document';\nimport { serializeTrials } from './helpers';\nimport {\n compareTrialOrder,\n documentOfRecords,\n LAYOUT_RECORD,\n type LabMeta,\n labPrefix,\n META_RECORD,\n parseRecordName,\n recordsOfDocument,\n saveRecord,\n trialRecord,\n trialValuesPrefix,\n UNDOCK_RECORD,\n} from './labRecords';\nimport { type OwnedRecordCache, openRecords, type RecordCache } from './records';\nimport { createLabStore, hydrateSnapshots, hydrateTrials, type LabStore } from './store';\nimport type {\n CreateLabStoreOptions,\n LabDocument,\n LabMode,\n SavedSnapshot,\n SerializedTrial,\n StorageAdapter,\n TrialRecord,\n} from './types';\n\n/** Options for `openLabStore`. `storageKey` names the lab, so two labs on one\n * origin keep separate records. */\nexport interface OpenLabStoreOptions extends Omit<CreateLabStoreOptions, 'initial'> {\n storageKey: string;\n storage: StorageAdapter;\n}\n\n/** A lab store bound to its records. */\nexport interface OpenedLabStore {\n store: LabStore;\n /** Every record of the lab, `usePersistedState` values included. */\n records: RecordCache;\n /** Send queued writes and stop hearing other writers. */\n close(): Promise<void>;\n}\n\n/**\n * Read a stored lab and return a store bound to it: every change to the store\n * is written as the records it touched, and another writer's records are\n * applied back into the store. A lab stored before records existed is folded\n * forward on the way in.\n */\nexport async function openLabStore(options: OpenLabStoreOptions): Promise<OpenedLabStore> {\n const records = await openRecords({\n storage: options.storage,\n prefix: labPrefix(options.storageKey),\n });\n const { doc, orders } = await readLab(options, records);\n const store = createLabStore({ ...options, initial: doc });\n const unbind = bindLabStore(store, records, { orders });\n return {\n store,\n records,\n close: async () => {\n unbind();\n await records.close();\n },\n };\n}\n\ninterface ReadLab {\n doc: LabDocument;\n orders: Map<string, number>;\n}\n\nfunction emptyLab(mode: LabMode): ReadLab {\n return { doc: emptyDocument(mode), orders: new Map() };\n}\n\nfunction ordersOf(doc: LabDocument): Map<string, number> {\n return new Map(doc.trials.map((t, i) => [t.id, i]));\n}\n\nasync function readLab(options: OpenLabStoreOptions, records: OwnedRecordCache): Promise<ReadLab> {\n const mode = options.initialMode ?? 'auto';\n if (!records.writable) return emptyLab(mode);\n\n const joined = documentOfRecords(records.entries());\n if (!joined) return foldOldStorage(options, records);\n\n const outcome = runMigrations(joined.doc, MIGRATIONS, CURRENT_DOCUMENT_VERSION);\n if (outcome.ok) {\n return { doc: normalizeDocument(outcome.doc, mode), orders: joined.orders };\n }\n const why =\n outcome.reason === 'future' ? 'are from a newer version of labkit' : 'failed to migrate';\n console.warn(`[labkit] lab records ${why}; starting empty and leaving them alone`, outcome.error);\n records.stopWriting();\n return emptyLab(mode);\n}\n\n/** Fold a version-3 document, or the four keys before it, into records. The\n * old keys are deleted only once every record has been read back. */\nasync function foldOldStorage(\n options: OpenLabStoreOptions,\n records: OwnedRecordCache,\n): Promise<ReadLab> {\n const { storage, storageKey } = options;\n const mode = options.initialMode ?? 'auto';\n\n let raw: unknown;\n let oldKeys: string[];\n try {\n const stored = await storage.get(labDocumentKey(storageKey));\n if (stored !== undefined) {\n raw = stored;\n oldKeys = [labDocumentKey(storageKey)];\n } else {\n raw = await readLegacyDocument((key) => storage.get(key), storageKey, mode);\n oldKeys = legacyKeys(storageKey);\n if (raw === null) return emptyLab(mode);\n }\n } catch (error) {\n console.warn(\n `[labkit] could not read the old storage for \"${storageKey}\"; not persisting`,\n error,\n );\n records.stopWriting();\n return emptyLab(mode);\n }\n\n const setAside = async (value: unknown, why: string, error?: unknown): Promise<ReadLab> => {\n if (await quarantineDocument(storage, storageKey, value)) {\n console.warn(`[labkit] ${why}; quarantined it and starting empty`, error);\n await deleteConfirmed(storage, oldKeys);\n records.set(META_RECORD, { version: CURRENT_DOCUMENT_VERSION, mode } satisfies LabMeta);\n } else {\n console.warn(\n `[labkit] ${why} and could not be quarantined; leaving it in place and not persisting`,\n error,\n );\n records.stopWriting();\n }\n return emptyLab(mode);\n };\n\n const parsed = parseStored(raw);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return setAside(raw, 'lab document is unparseable');\n }\n const outcome = runMigrations(\n parsed as Record<string, unknown>,\n MIGRATIONS,\n 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 records.stopWriting();\n return emptyLab(mode);\n }\n return setAside(parsed, 'lab document failed to migrate', outcome.error);\n }\n\n const doc = normalizeDocument(outcome.doc, mode);\n const entries = recordsOfDocument(doc);\n records.seed(entries);\n if (await writeConfirmed(storage, records.prefix, entries)) {\n await deleteConfirmed(storage, oldKeys);\n } else {\n console.warn(\n `[labkit] keeping the old storage for \"${storageKey}\": could not confirm its records were written`,\n );\n }\n return { doc, orders: ordersOf(doc) };\n}\n\n/** Write `entries` in order and read every one back. */\nasync function writeConfirmed(\n storage: StorageAdapter,\n prefix: string,\n entries: [string, unknown][],\n): Promise<boolean> {\n try {\n for (const [name, value] of entries) await storage.set(prefix + name, value);\n const back = new Map(await storage.list(prefix));\n return entries.every(([name, value]) => sameStored(back.get(prefix + name), value));\n } catch {\n return false;\n }\n}\n\ninterface BindOptions {\n orders: Map<string, number>;\n}\n\nfunction persistedFieldsDiffer(a: TrialRecord, b: TrialRecord): boolean {\n if (a === b) return false;\n const left = a as unknown as Record<string, unknown>;\n const right = b as unknown as Record<string, unknown>;\n for (const key of new Set([...Object.keys(left), ...Object.keys(right)])) {\n if (key !== 'undoStack' && !Object.is(left[key], right[key])) return true;\n }\n return false;\n}\n\n/** Keep `store` and `records` in step, both ways. Returns the unbinding. */\nfunction bindLabStore(store: LabStore, records: RecordCache, options: BindOptions): () => void {\n const orderOf = new Map(options.orders);\n let applyingRemote = false;\n\n const nextOrder = (): number => {\n let max = -1;\n for (const order of orderOf.values()) max = Math.max(max, order);\n return max + 1;\n };\n\n const writeTrial = (trial: TrialRecord): void => {\n const [serialized] = serializeTrials([trial], store.getState().instrumentHooks().serializers);\n records.set(trialRecord(trial.id), { ...serialized, order: orderOf.get(trial.id) });\n };\n\n const inStoredOrder = (trials: TrialRecord[]): boolean => {\n for (let i = 1; i < trials.length; i++) {\n const a = trials[i - 1] as TrialRecord;\n const b = trials[i] as TrialRecord;\n const at = { trial: a, order: orderOf.get(a.id) ?? 0 };\n const bt = { trial: b, order: orderOf.get(b.id) ?? 0 };\n if (compareTrialOrder(at, bt) >= 0) return false;\n }\n return true;\n };\n\n const offStore = store.subscribe((state, prev) => {\n if (applyingRemote) return;\n let wrote = false;\n\n if (state.trials !== prev.trials) {\n const before = new Map(prev.trials.map((t) => [t.id, t]));\n const now = new Set(state.trials.map((t) => t.id));\n for (const t of prev.trials) {\n if (now.has(t.id)) continue;\n records.delete(trialRecord(t.id));\n for (const [name] of records.entries(trialValuesPrefix(t.id))) records.delete(name);\n orderOf.delete(t.id);\n wrote = true;\n }\n const added = state.trials.filter((t) => !before.has(t.id));\n for (const t of added) orderOf.set(t.id, nextOrder());\n if (inStoredOrder(state.trials)) {\n for (const t of state.trials) {\n const old = before.get(t.id);\n if (old && !persistedFieldsDiffer(old, t)) continue;\n writeTrial(t);\n wrote = true;\n }\n } else {\n // A reorder, or a trial inserted mid-list: renumber them all.\n for (const [i, t] of state.trials.entries()) orderOf.set(t.id, i);\n for (const t of state.trials) writeTrial(t);\n wrote = true;\n }\n }\n\n if (state.savedSnapshots !== prev.savedSnapshots) {\n const before = new Map(prev.savedSnapshots.map((s) => [s.id, s]));\n const now = new Set(state.savedSnapshots.map((s) => s.id));\n for (const s of state.savedSnapshots) {\n if (before.get(s.id) === s) continue;\n records.set(saveRecord(s.id), s);\n wrote = true;\n }\n for (const s of prev.savedSnapshots) {\n if (now.has(s.id)) continue;\n records.delete(saveRecord(s.id));\n wrote = true;\n }\n }\n\n if (state.layout !== prev.layout) {\n records.set(LAYOUT_RECORD, state.layout);\n wrote = true;\n }\n if (state.undockedPanels !== prev.undockedPanels) {\n records.set(UNDOCK_RECORD, state.undockedPanels);\n wrote = true;\n }\n if (state.mode !== prev.mode || (wrote && !records.has(META_RECORD))) {\n records.set(META_RECORD, {\n version: CURRENT_DOCUMENT_VERSION,\n mode: state.mode,\n } satisfies LabMeta);\n }\n });\n\n const offRecords = records.subscribe((changes) => {\n const remote = changes.filter((c) => c.origin === 'remote');\n if (remote.length === 0) return;\n\n const current = store.getState();\n let trials = current.trials;\n let saves = current.savedSnapshots;\n const patch: Partial<Pick<typeof current, 'layout' | 'undockedPanels' | 'mode'>> = {};\n\n for (const { name, value } of remote) {\n const parsed = parseRecordName(name);\n if (!parsed) continue;\n switch (parsed.kind) {\n case 'trial': {\n const id = parsed.id;\n if (value === undefined || !value || typeof value !== 'object') {\n trials = trials.filter((t) => t.id !== id);\n orderOf.delete(id);\n break;\n }\n const { order, ...rest } = value as SerializedTrial & { order?: unknown };\n orderOf.set(\n id,\n typeof order === 'number' && Number.isFinite(order) ? order : nextOrder(),\n );\n // Hydrating starts an empty undo history: the old one describes a\n // state that no longer exists.\n const hooks = store.getState().instrumentHooks();\n const [replacement] = hydrateTrials([{ ...rest, id }], hooks.serializers, hooks);\n if (!replacement) break;\n trials = trials.some((t) => t.id === id)\n ? trials.map((t) => (t.id === id ? replacement : t))\n : [...trials, replacement];\n break;\n }\n case 'save': {\n const id = parsed.id;\n if (value === undefined || !value || typeof value !== 'object') {\n saves = saves.filter((s) => s.id !== id);\n break;\n }\n const [snapshot] = hydrateSnapshots(\n [{ ...(value as SavedSnapshot), id }],\n store.getState().instrumentHooks(),\n );\n if (!snapshot) break;\n saves = saves.some((s) => s.id === id)\n ? saves.map((s) => (s.id === id ? snapshot : s))\n : [...saves, snapshot];\n break;\n }\n case 'layout':\n patch.layout = (value as Record<string, unknown> | undefined) ?? {};\n break;\n case 'undock':\n patch.undockedPanels = (value as typeof current.undockedPanels | undefined) ?? {};\n break;\n case 'meta': {\n const meta = value as Partial<LabMeta> | undefined;\n if (typeof meta?.version === 'number' && meta.version > CURRENT_DOCUMENT_VERSION) {\n console.warn(\n '[labkit] another tab wrote this lab with a newer labkit; no longer persisting',\n );\n if ('stopWriting' in records) (records as OwnedRecordCache).stopWriting();\n break;\n }\n if (meta?.mode === 'light' || meta?.mode === 'dark' || meta?.mode === 'auto') {\n patch.mode = meta.mode;\n }\n break;\n }\n }\n }\n\n if (trials !== current.trials) {\n trials = [...trials].sort((a, b) =>\n compareTrialOrder(\n { trial: a, order: orderOf.get(a.id) ?? 0 },\n { trial: b, order: orderOf.get(b.id) ?? 0 },\n ),\n );\n }\n applyingRemote = true;\n try {\n store.setState({ ...patch, trials, savedSnapshots: saves });\n } finally {\n applyingRemote = false;\n }\n });\n\n return () => {\n offStore();\n offRecords();\n };\n}\n","import { useContext } from 'react';\nimport { useStore } from 'zustand/react';\nimport { useResolvedConfig } from '../config/useResolvedConfig';\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 // The store's own copy, not `useConfigSchema`: that reads `LabContext`, and\n // this hook only has the store's.\n const instrumentHooks = useStore(ctx.store, (s) => s.instrumentHooks);\n const schema = instrumentHooks().configSchemas[record.instrumentName];\n const { config, auto } = useResolvedConfig<TC>(schema, record.config as TC, record.auto);\n\n return {\n state: record.state as TS,\n config,\n raw: record.config as TC,\n auto,\n setState: (next) => updateTrialState(trialId, next as Parameters<typeof updateTrialState>[1]),\n setConfig: (path, value) => updateTrialConfig(trialId, path, value),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/state/document.ts","../src/state/undock.ts","../src/instrument/serializers.ts","../src/state/store.ts","../src/state/openLabStore.ts","../src/state/useTrialState.ts"],"names":[],"mappings":"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","file":"chunk-MOLIUNVH.js","sourcesContent":["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 = 4;\n\n/** Where a version-3 lab kept its one document. Read once, to fold it into\n * records, then deleted. */\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\n/** The four keys a lab used before it was one document. */\nexport function legacyKeys(storageKey: string): string[] {\n return LEGACY_BUCKETS.map((bucket) => labStorageKey(storageKey, bucket));\n}\n\n/** A value some substrate returned for an old key: already parsed, or a JSON\n * string from a store that does not parse. `undefined` when it is neither. */\nexport function parseStored(value: unknown): unknown {\n if (typeof value !== 'string') return value;\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction bucketOr<T>(value: unknown, fallback: T, bucket: string, shape: 'array' | 'object'): T {\n if (value === undefined) return fallback;\n const parsed = parseStored(value);\n const fits = shape === 'array' ? Array.isArray(parsed) : !!parsed && typeof parsed === 'object';\n if (fits) return parsed as T;\n console.warn(`[labkit] unparseable legacy bucket \"${bucket}\", dropping it`);\n return fallback;\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 async function readLegacyDocument(\n read: (key: string) => Promise<unknown>,\n storageKey: string,\n fallbackMode: LabMode,\n): Promise<Record<string, unknown> | null> {\n const [workspaces, saves, layout, theme] = await Promise.all(\n LEGACY_BUCKETS.map((bucket) => read(labStorageKey(storageKey, bucket))),\n );\n if ([workspaces, saves, layout, theme].every((v) => v === undefined)) return null;\n\n const mode =\n theme === 'light' || theme === 'dark' || theme === 'auto' || theme === 'interstellar'\n ? theme\n : fallbackMode;\n\n return {\n version: 0,\n workspaces: bucketOr(workspaces, [], 'workspaces', 'array'),\n saves: bucketOr(saves, [], 'saves', 'array'),\n layout: bucketOr(layout, {}, 'layout', 'object'),\n mode,\n };\n}\n\n/** Whether two stored values hold the same data. Stored values are\n * structured-clone copies, so identity says nothing. */\nexport function sameStored(a: unknown, b: unknown): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n}\n\n/** Delete `keys` and read each back, so an adapter whose delete silently did\n * nothing is caught. `true` only once all of them are gone. */\nexport async function deleteConfirmed(storage: StorageAdapter, keys: string[]): Promise<boolean> {\n try {\n await Promise.all(keys.map((key) => storage.delete(key)));\n const left = await Promise.all(keys.map((key) => storage.get(key)));\n return left.every((v) => v === undefined);\n } catch {\n return false;\n }\n}\n\n/** Set `value` 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 async function quarantineDocument(\n storage: StorageAdapter,\n storageKey: string,\n value: unknown,\n): Promise<boolean> {\n try {\n await storage.set(quarantineKey(storageKey), value);\n return sameStored(await storage.get(quarantineKey(storageKey)), value);\n } catch {\n return false;\n }\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/** Version 3 to version 4: a lab is stored as records under one prefix\n * instead of one document. The joined shape does not change. */\nexport function migrateV3toV4(doc: Record<string, unknown>): Record<string, unknown> {\n return { ...doc, version: 4 };\n}\n\n/** Index `i` migrates a version-`i` document to version `i + 1`. */\nexport const MIGRATIONS: Migration[] = [migrateV0toV1, migrateV1toV2, migrateV2toV3, migrateV3toV4];\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 { resolveConfigSchema } from '../config/resolve';\nimport type { ResolvedConfig } from '../config/types';\nimport type { InstrumentSerializers } from '../state/types';\nimport type { Instrument, InstrumentList } from './types';\n\n/**\n * One instrument's config schema, resolved without the lab's rules — which\n * neither the store nor a trial composed outside a lab has access to. No rule\n * can reach `autoResolve`, `unpinned` or `manual`, so for reading those the\n * two resolutions agree; anything reading the rendered leaves wants\n * `useConfigSchema` instead. `undefined` for a legacy `configSchema()`\n * instrument, which declares no auto annotations at all.\n */\nexport function unruledConfigSchema(\n // biome-ignore lint/suspicious/noExplicitAny: instruments are stored contravariantly; see InstrumentList\n instrument: Instrument<any, any, any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n): ResolvedConfig | undefined {\n return instrument.config ? resolveConfigSchema(instrument.config, []) : undefined;\n}\n\n/** Each instrument's unruled config schema, keyed by name — what the store\n * reads a leaf's auto annotations off. */\nexport function configSchemasOf(instruments: InstrumentList): Record<string, ResolvedConfig> {\n const out: Record<string, ResolvedConfig> = {};\n for (const instrument of instruments) {\n const schema = unruledConfigSchema(instrument);\n if (schema) out[instrument.name] = schema;\n }\n return out;\n}\n\n/**\n * Each instrument's default config, keyed by name — what `createLabStore`\n * fills a stored config's gaps from, so one saved before its schema grew a\n * branch still loads.\n */\nexport function configDefaultsOf(instruments: InstrumentList): Record<string, () => unknown> {\n const out: Record<string, () => unknown> = {};\n for (const instrument of instruments) out[instrument.name] = () => instrument.defaultConfig();\n return out;\n}\n\n/** Each instrument's `migrateConfig`, keyed by name, for those that declare one. */\nexport function configMigrationsOf(\n instruments: InstrumentList,\n): Record<string, (stored: unknown) => unknown> {\n const out: Record<string, (stored: unknown) => unknown> = {};\n for (const { name, migrateConfig } of instruments) {\n if (migrateConfig) out[name] = (stored) => migrateConfig(stored);\n }\n return out;\n}\n\n/**\n * The `serialize` / `deserialize` an instrument list declares, keyed by\n * instrument name — what `createLabStore` needs to rebuild a trial's state\n * from storage.\n *\n * An instrument declaring neither gets no entry, which is what leaves a\n * JSON-safe state to pass through untouched.\n */\nexport function serializersOf(instruments: InstrumentList): InstrumentSerializers {\n const out: InstrumentSerializers = {};\n for (const instrument of instruments) {\n const { name, serialize, deserialize } = instrument;\n if (!serialize && !deserialize) continue;\n out[name] = {\n ...(serialize ? { serialize: (state: unknown) => serialize(state) } : {}),\n ...(deserialize\n ? { deserialize: (data: unknown, config: unknown) => deserialize(data, config) }\n : {}),\n };\n }\n return out;\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla';\nimport { applyConfigWrite } from '../config/autoConfig';\nimport { fillConfigDefaults } from '../config/path';\nimport {\n configDefaultsOf,\n configMigrationsOf,\n configSchemasOf,\n serializersOf,\n} from '../instrument/serializers';\nimport type { InstrumentList } from '../instrument/types';\nimport { emptyDocument } from './document';\nimport { deserializeTrials, emptyUndoStack, newId } from './helpers';\nimport type {\n CreateLabStoreOptions,\n InstrumentHooks,\n InstrumentSerializers,\n LabMode,\n LabStoreState,\n SavedSnapshot,\n SerializedTrial,\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 /** Replace the lab's instruments. Trials and saves of an instrument that is\n * new or a different object are brought up to date against it in the same\n * write; every other trial keeps its object. */\n setInstruments: (instruments: InstrumentList) => void;\n /** The per-instrument hooks in force now. Read them at use; never keep them. */\n instrumentHooks: () => InstrumentHooks;\n}\n\n/** A lab's store: its state and its actions. How each instrument's state is\n * serialized comes in through `CreateLabStoreOptions.instruments`. */\nexport type LabStore = StoreApi<LabStoreState & LabStoreActions>;\n\n/** Build a lab store holding `initial`, or an empty lab. It knows nothing\n * about storage; `openLabStore` reads a stored lab and binds one of these to\n * it. */\nexport function createLabStore(options: CreateLabStoreOptions = {}): LabStore {\n let hooks: InstrumentHooks = options.instruments\n ? hooksOf(options.instruments)\n : {\n serializers: options.serializers ?? {},\n configDefaults: options.configDefaults ?? {},\n configMigrations: options.configMigrations ?? {},\n configSchemas: options.configSchemas ?? {},\n };\n const initial = options.initial ?? emptyDocument(options.initialMode ?? 'auto');\n\n const store = createStore<LabStoreState & LabStoreActions>()((set, get) => ({\n trials: hydrateTrials(initial.trials, hooks.serializers, hooks),\n savedSnapshots: hydrateSnapshots(initial.saves, hooks),\n mode: initial.mode,\n layout: initial.layout,\n undockedPanels: initial.undockedPanels,\n activeToolId: null,\n instruments: options.instruments ?? null,\n\n addTrial: (record) => {\n set((s) => ({\n trials: [...s.trials, { ...record, undoStack: emptyUndoStack() }],\n }));\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 },\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 },\n\n updateTrialConfig: (id, path, value) => {\n set((s) => ({\n trials: s.trials.map((w) => {\n if (w.id !== id) return w;\n const was = w.auto ?? [];\n // The sentinel is never stored: it becomes membership in `auto`, and\n // the pinned value at the path is left exactly where it is.\n const next = applyConfigWrite(w.config, was, path, value);\n if (next.config === w.config && next.autoPaths === was) return w;\n const { auto: _was, ...kept } = w;\n const record: TrialRecord = { ...kept, config: next.config };\n if (next.autoPaths.length > 0) record.auto = next.autoPaths;\n return record;\n }),\n }));\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 },\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 },\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 },\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 },\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 },\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 },\n\n saveSnapshot: (trialId, name) => {\n const trial = get().trials.find((w) => w.id === trialId);\n if (!trial) return;\n const reg = hooks.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 auto: [...(trial.auto ?? [])],\n savedAt,\n };\n set((s) => ({ savedSnapshots: [...s.savedSnapshots, snapshot] }));\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 = hooks.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 if (w.id !== trialId) return w;\n const loaded: TrialRecord = { ...w, state: restoredState, config: snapshot.config };\n if (snapshot.auto === undefined) return loaded;\n delete loaded.auto;\n if (snapshot.auto.length > 0) loaded.auto = [...snapshot.auto];\n return loaded;\n }),\n }));\n },\n\n deleteSnapshot: (snapshotId) => {\n set((s) => ({\n savedSnapshots: s.savedSnapshots.filter((sn) => sn.id !== snapshotId),\n }));\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 },\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 },\n\n dockPanel: (trialId, sectionId) => {\n set((s) => ({ undockedPanels: dockPanelIn(s.undockedPanels, trialId, sectionId) }));\n },\n\n setLayout: (layout) => {\n set({ layout });\n },\n\n setInstruments: (instruments) => {\n const before = get().instruments;\n if (before === instruments) return;\n const next = mergedHooks(hooks, instruments);\n const previous = new Map((before ?? []).map((i) => [i.name, i]));\n const changed = new Set(\n instruments.filter((i) => previous.get(i.name) !== i).map((i) => i.name),\n );\n if (changed.size === 0) {\n hooks = next;\n set({ instruments });\n return;\n }\n const s = get();\n const trials = s.trials.map((w) =>\n changed.has(w.instrumentName)\n ? { ...w, config: hydratedConfig(next, w.instrumentName, w.config) }\n : w,\n );\n const savedSnapshots = s.savedSnapshots.map((sn) =>\n changed.has(sn.instrumentName)\n ? { ...sn, config: hydratedConfig(next, sn.instrumentName, sn.config) }\n : sn,\n );\n hooks = next;\n set({ instruments, trials, savedSnapshots });\n },\n\n instrumentHooks: () => hooks,\n }));\n\n return store;\n}\n\nfunction hooksOf(instruments: InstrumentList): InstrumentHooks {\n return {\n serializers: serializersOf(instruments),\n configDefaults: configDefaultsOf(instruments),\n configSchemas: configSchemasOf(instruments),\n configMigrations: configMigrationsOf(instruments),\n };\n}\n\n/** Hooks for `instruments`, keeping those of any instrument no longer listed:\n * its trials stay open, and their state still has to round-trip. A listed\n * name takes its hooks wholly from the new list. */\nfunction mergedHooks(old: InstrumentHooks, instruments: InstrumentList): InstrumentHooks {\n const listed = new Set(instruments.map((i) => i.name));\n const fresh = hooksOf(instruments);\n const unlisted = <T>(entries: Record<string, T>): Record<string, T> =>\n Object.fromEntries(Object.entries(entries).filter(([name]) => !listed.has(name)));\n return {\n serializers: { ...unlisted(old.serializers), ...fresh.serializers },\n configDefaults: { ...unlisted(old.configDefaults), ...fresh.configDefaults },\n configSchemas: { ...unlisted(old.configSchemas), ...fresh.configSchemas },\n configMigrations: { ...unlisted(old.configMigrations), ...fresh.configMigrations },\n };\n}\n\n/** How a stored config is brought up to date on the way in. */\nexport type ConfigHydration = Pick<CreateLabStoreOptions, 'configDefaults' | 'configMigrations'>;\n\nfunction hydratedConfig(\n hydration: ConfigHydration,\n instrumentName: string,\n config: unknown,\n): unknown {\n const migrate = hydration.configMigrations?.[instrumentName];\n const moved = migrate ? migrate(config) : config;\n const defaults = hydration.configDefaults?.[instrumentName];\n return defaults ? fillConfigDefaults(moved, defaults()) : moved;\n}\n\n/** Rebuild stored trials: migrate each config, fill its gaps from its\n * instrument's defaults, then run the deserializer against the result. */\nexport function hydrateTrials(\n trials: SerializedTrial[],\n serializers: InstrumentSerializers,\n hydration: ConfigHydration = {},\n): TrialRecord[] {\n return deserializeTrials(\n trials.map((t) => ({ ...t, config: hydratedConfig(hydration, t.instrumentName, t.config) })),\n serializers,\n );\n}\n\n/** Bring each stored snapshot's config up to date the way `hydrateTrials` does a trial's. */\nexport function hydrateSnapshots(\n saves: SavedSnapshot[],\n hydration: ConfigHydration = {},\n): SavedSnapshot[] {\n return saves.map((sn) => ({\n ...sn,\n config: hydratedConfig(hydration, sn.instrumentName, sn.config),\n }));\n}\n","import {\n CURRENT_DOCUMENT_VERSION,\n deleteConfirmed,\n emptyDocument,\n labDocumentKey,\n legacyKeys,\n MIGRATIONS,\n normalizeDocument,\n parseStored,\n quarantineDocument,\n readLegacyDocument,\n runMigrations,\n sameStored,\n} from './document';\nimport { serializeTrials } from './helpers';\nimport {\n compareTrialOrder,\n documentOfRecords,\n LAYOUT_RECORD,\n type LabMeta,\n labPrefix,\n META_RECORD,\n parseRecordName,\n recordsOfDocument,\n saveRecord,\n trialRecord,\n trialValuesPrefix,\n UNDOCK_RECORD,\n} from './labRecords';\nimport { type OwnedRecordCache, openRecords, type RecordCache } from './records';\nimport { createLabStore, hydrateSnapshots, hydrateTrials, type LabStore } from './store';\nimport type {\n CreateLabStoreOptions,\n LabDocument,\n LabMode,\n SavedSnapshot,\n SerializedTrial,\n StorageAdapter,\n TrialRecord,\n} from './types';\n\n/** Options for `openLabStore`. `storageKey` names the lab, so two labs on one\n * origin keep separate records. */\nexport interface OpenLabStoreOptions extends Omit<CreateLabStoreOptions, 'initial'> {\n storageKey: string;\n storage: StorageAdapter;\n}\n\n/** A lab store bound to its records. */\nexport interface OpenedLabStore {\n store: LabStore;\n /** Every record of the lab, `usePersistedState` values included. */\n records: RecordCache;\n /** Send queued writes and stop hearing other writers. */\n close(): Promise<void>;\n}\n\n/**\n * Read a stored lab and return a store bound to it: every change to the store\n * is written as the records it touched, and another writer's records are\n * applied back into the store. A lab stored before records existed is folded\n * forward on the way in.\n */\nexport async function openLabStore(options: OpenLabStoreOptions): Promise<OpenedLabStore> {\n const records = await openRecords({\n storage: options.storage,\n prefix: labPrefix(options.storageKey),\n });\n const { doc, orders } = await readLab(options, records);\n const store = createLabStore({ ...options, initial: doc });\n const unbind = bindLabStore(store, records, { orders });\n return {\n store,\n records,\n close: async () => {\n unbind();\n await records.close();\n },\n };\n}\n\ninterface ReadLab {\n doc: LabDocument;\n orders: Map<string, number>;\n}\n\nfunction emptyLab(mode: LabMode): ReadLab {\n return { doc: emptyDocument(mode), orders: new Map() };\n}\n\nfunction ordersOf(doc: LabDocument): Map<string, number> {\n return new Map(doc.trials.map((t, i) => [t.id, i]));\n}\n\nasync function readLab(options: OpenLabStoreOptions, records: OwnedRecordCache): Promise<ReadLab> {\n const mode = options.initialMode ?? 'auto';\n if (!records.writable) return emptyLab(mode);\n\n const joined = documentOfRecords(records.entries());\n if (!joined) return foldOldStorage(options, records);\n\n const outcome = runMigrations(joined.doc, MIGRATIONS, CURRENT_DOCUMENT_VERSION);\n if (outcome.ok) {\n return { doc: normalizeDocument(outcome.doc, mode), orders: joined.orders };\n }\n const why =\n outcome.reason === 'future' ? 'are from a newer version of labkit' : 'failed to migrate';\n console.warn(`[labkit] lab records ${why}; starting empty and leaving them alone`, outcome.error);\n records.stopWriting();\n return emptyLab(mode);\n}\n\n/** Fold a version-3 document, or the four keys before it, into records. The\n * old keys are deleted only once every record has been read back. */\nasync function foldOldStorage(\n options: OpenLabStoreOptions,\n records: OwnedRecordCache,\n): Promise<ReadLab> {\n const { storage, storageKey } = options;\n const mode = options.initialMode ?? 'auto';\n\n let raw: unknown;\n let oldKeys: string[];\n try {\n const stored = await storage.get(labDocumentKey(storageKey));\n if (stored !== undefined) {\n raw = stored;\n oldKeys = [labDocumentKey(storageKey)];\n } else {\n raw = await readLegacyDocument((key) => storage.get(key), storageKey, mode);\n oldKeys = legacyKeys(storageKey);\n if (raw === null) return emptyLab(mode);\n }\n } catch (error) {\n console.warn(\n `[labkit] could not read the old storage for \"${storageKey}\"; not persisting`,\n error,\n );\n records.stopWriting();\n return emptyLab(mode);\n }\n\n const setAside = async (value: unknown, why: string, error?: unknown): Promise<ReadLab> => {\n if (await quarantineDocument(storage, storageKey, value)) {\n console.warn(`[labkit] ${why}; quarantined it and starting empty`, error);\n await deleteConfirmed(storage, oldKeys);\n records.set(META_RECORD, { version: CURRENT_DOCUMENT_VERSION, mode } satisfies LabMeta);\n } else {\n console.warn(\n `[labkit] ${why} and could not be quarantined; leaving it in place and not persisting`,\n error,\n );\n records.stopWriting();\n }\n return emptyLab(mode);\n };\n\n const parsed = parseStored(raw);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return setAside(raw, 'lab document is unparseable');\n }\n const outcome = runMigrations(\n parsed as Record<string, unknown>,\n MIGRATIONS,\n 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 records.stopWriting();\n return emptyLab(mode);\n }\n return setAside(parsed, 'lab document failed to migrate', outcome.error);\n }\n\n const doc = normalizeDocument(outcome.doc, mode);\n const entries = recordsOfDocument(doc);\n records.seed(entries);\n if (await writeConfirmed(storage, records.prefix, entries)) {\n await deleteConfirmed(storage, oldKeys);\n } else {\n console.warn(\n `[labkit] keeping the old storage for \"${storageKey}\": could not confirm its records were written`,\n );\n }\n return { doc, orders: ordersOf(doc) };\n}\n\n/** Write `entries` in order and read every one back. */\nasync function writeConfirmed(\n storage: StorageAdapter,\n prefix: string,\n entries: [string, unknown][],\n): Promise<boolean> {\n try {\n for (const [name, value] of entries) await storage.set(prefix + name, value);\n const back = new Map(await storage.list(prefix));\n return entries.every(([name, value]) => sameStored(back.get(prefix + name), value));\n } catch {\n return false;\n }\n}\n\ninterface BindOptions {\n orders: Map<string, number>;\n}\n\nfunction persistedFieldsDiffer(a: TrialRecord, b: TrialRecord): boolean {\n if (a === b) return false;\n const left = a as unknown as Record<string, unknown>;\n const right = b as unknown as Record<string, unknown>;\n for (const key of new Set([...Object.keys(left), ...Object.keys(right)])) {\n if (key !== 'undoStack' && !Object.is(left[key], right[key])) return true;\n }\n return false;\n}\n\n/** Keep `store` and `records` in step, both ways. Returns the unbinding. */\nfunction bindLabStore(store: LabStore, records: RecordCache, options: BindOptions): () => void {\n const orderOf = new Map(options.orders);\n let applyingRemote = false;\n\n const nextOrder = (): number => {\n let max = -1;\n for (const order of orderOf.values()) max = Math.max(max, order);\n return max + 1;\n };\n\n const writeTrial = (trial: TrialRecord): void => {\n const [serialized] = serializeTrials([trial], store.getState().instrumentHooks().serializers);\n records.set(trialRecord(trial.id), { ...serialized, order: orderOf.get(trial.id) });\n };\n\n const inStoredOrder = (trials: TrialRecord[]): boolean => {\n for (let i = 1; i < trials.length; i++) {\n const a = trials[i - 1] as TrialRecord;\n const b = trials[i] as TrialRecord;\n const at = { trial: a, order: orderOf.get(a.id) ?? 0 };\n const bt = { trial: b, order: orderOf.get(b.id) ?? 0 };\n if (compareTrialOrder(at, bt) >= 0) return false;\n }\n return true;\n };\n\n const offStore = store.subscribe((state, prev) => {\n if (applyingRemote) return;\n let wrote = false;\n\n if (state.trials !== prev.trials) {\n const before = new Map(prev.trials.map((t) => [t.id, t]));\n const now = new Set(state.trials.map((t) => t.id));\n for (const t of prev.trials) {\n if (now.has(t.id)) continue;\n records.delete(trialRecord(t.id));\n for (const [name] of records.entries(trialValuesPrefix(t.id))) records.delete(name);\n orderOf.delete(t.id);\n wrote = true;\n }\n const added = state.trials.filter((t) => !before.has(t.id));\n for (const t of added) orderOf.set(t.id, nextOrder());\n if (inStoredOrder(state.trials)) {\n for (const t of state.trials) {\n const old = before.get(t.id);\n if (old && !persistedFieldsDiffer(old, t)) continue;\n writeTrial(t);\n wrote = true;\n }\n } else {\n // A reorder, or a trial inserted mid-list: renumber them all.\n for (const [i, t] of state.trials.entries()) orderOf.set(t.id, i);\n for (const t of state.trials) writeTrial(t);\n wrote = true;\n }\n }\n\n if (state.savedSnapshots !== prev.savedSnapshots) {\n const before = new Map(prev.savedSnapshots.map((s) => [s.id, s]));\n const now = new Set(state.savedSnapshots.map((s) => s.id));\n for (const s of state.savedSnapshots) {\n if (before.get(s.id) === s) continue;\n records.set(saveRecord(s.id), s);\n wrote = true;\n }\n for (const s of prev.savedSnapshots) {\n if (now.has(s.id)) continue;\n records.delete(saveRecord(s.id));\n wrote = true;\n }\n }\n\n if (state.layout !== prev.layout) {\n records.set(LAYOUT_RECORD, state.layout);\n wrote = true;\n }\n if (state.undockedPanels !== prev.undockedPanels) {\n records.set(UNDOCK_RECORD, state.undockedPanels);\n wrote = true;\n }\n if (state.mode !== prev.mode || (wrote && !records.has(META_RECORD))) {\n records.set(META_RECORD, {\n version: CURRENT_DOCUMENT_VERSION,\n mode: state.mode,\n } satisfies LabMeta);\n }\n });\n\n const offRecords = records.subscribe((changes) => {\n const remote = changes.filter((c) => c.origin === 'remote');\n if (remote.length === 0) return;\n\n const current = store.getState();\n let trials = current.trials;\n let saves = current.savedSnapshots;\n const patch: Partial<Pick<typeof current, 'layout' | 'undockedPanels' | 'mode'>> = {};\n\n for (const { name, value } of remote) {\n const parsed = parseRecordName(name);\n if (!parsed) continue;\n switch (parsed.kind) {\n case 'trial': {\n const id = parsed.id;\n if (value === undefined || !value || typeof value !== 'object') {\n trials = trials.filter((t) => t.id !== id);\n orderOf.delete(id);\n break;\n }\n const { order, ...rest } = value as SerializedTrial & { order?: unknown };\n orderOf.set(\n id,\n typeof order === 'number' && Number.isFinite(order) ? order : nextOrder(),\n );\n // Hydrating starts an empty undo history: the old one describes a\n // state that no longer exists.\n const hooks = store.getState().instrumentHooks();\n const [replacement] = hydrateTrials([{ ...rest, id }], hooks.serializers, hooks);\n if (!replacement) break;\n trials = trials.some((t) => t.id === id)\n ? trials.map((t) => (t.id === id ? replacement : t))\n : [...trials, replacement];\n break;\n }\n case 'save': {\n const id = parsed.id;\n if (value === undefined || !value || typeof value !== 'object') {\n saves = saves.filter((s) => s.id !== id);\n break;\n }\n const [snapshot] = hydrateSnapshots(\n [{ ...(value as SavedSnapshot), id }],\n store.getState().instrumentHooks(),\n );\n if (!snapshot) break;\n saves = saves.some((s) => s.id === id)\n ? saves.map((s) => (s.id === id ? snapshot : s))\n : [...saves, snapshot];\n break;\n }\n case 'layout':\n patch.layout = (value as Record<string, unknown> | undefined) ?? {};\n break;\n case 'undock':\n patch.undockedPanels = (value as typeof current.undockedPanels | undefined) ?? {};\n break;\n case 'meta': {\n const meta = value as Partial<LabMeta> | undefined;\n if (typeof meta?.version === 'number' && meta.version > CURRENT_DOCUMENT_VERSION) {\n console.warn(\n '[labkit] another tab wrote this lab with a newer labkit; no longer persisting',\n );\n if ('stopWriting' in records) (records as OwnedRecordCache).stopWriting();\n break;\n }\n if (meta?.mode === 'light' || meta?.mode === 'dark' || meta?.mode === 'auto') {\n patch.mode = meta.mode;\n }\n break;\n }\n }\n }\n\n if (trials !== current.trials) {\n trials = [...trials].sort((a, b) =>\n compareTrialOrder(\n { trial: a, order: orderOf.get(a.id) ?? 0 },\n { trial: b, order: orderOf.get(b.id) ?? 0 },\n ),\n );\n }\n applyingRemote = true;\n try {\n store.setState({ ...patch, trials, savedSnapshots: saves });\n } finally {\n applyingRemote = false;\n }\n });\n\n return () => {\n offStore();\n offRecords();\n };\n}\n","import { useContext } from 'react';\nimport { useStore } from 'zustand/react';\nimport { useResolvedConfig } from '../config/useResolvedConfig';\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 // The store's own copy, not `useConfigSchema`: that reads `LabContext`, and\n // this hook only has the store's.\n const instrumentHooks = useStore(ctx.store, (s) => s.instrumentHooks);\n const schema = instrumentHooks().configSchemas[record.instrumentName];\n const { config, auto } = useResolvedConfig<TC>(schema, record.config as TC, record.auto);\n\n return {\n state: record.state as TS,\n config,\n raw: record.config as TC,\n auto,\n setState: (next) => updateTrialState(trialId, next as Parameters<typeof updateTrialState>[1]),\n setConfig: (path, value) => updateTrialConfig(trialId, path, value),\n };\n}\n"]}
|
|
@@ -362,90 +362,7 @@ function Stage({
|
|
|
362
362
|
}
|
|
363
363
|
);
|
|
364
364
|
}
|
|
365
|
-
var PITCH_LIMIT = Math.PI / 2 - 0.01;
|
|
366
|
-
var YAW_PER_PX = 8e-3;
|
|
367
|
-
var PITCH_PER_PX = 8e-3;
|
|
368
|
-
var DISTANCE_PER_NOTCH = 15e-4;
|
|
369
|
-
var DRAG_THRESHOLD2 = 3;
|
|
370
|
-
function clampPitch(pitch) {
|
|
371
|
-
return Math.min(PITCH_LIMIT, Math.max(-PITCH_LIMIT, pitch));
|
|
372
|
-
}
|
|
373
|
-
function wrapYaw(yaw) {
|
|
374
|
-
const wrapped = ((yaw + Math.PI) % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI) - Math.PI;
|
|
375
|
-
return wrapped === -Math.PI ? Math.PI : wrapped;
|
|
376
|
-
}
|
|
377
|
-
function orbitAfterDrag(start, dx, dy) {
|
|
378
|
-
return {
|
|
379
|
-
...start,
|
|
380
|
-
yaw: wrapYaw(start.yaw + dx * YAW_PER_PX),
|
|
381
|
-
pitch: clampPitch(start.pitch + dy * PITCH_PER_PX)
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
function orbitAfterWheel(view, deltaY, minDistance, maxDistance) {
|
|
385
|
-
const factor = Math.exp(deltaY * DISTANCE_PER_NOTCH);
|
|
386
|
-
return {
|
|
387
|
-
...view,
|
|
388
|
-
distance: Math.min(maxDistance, Math.max(minDistance, view.distance * factor))
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
function useOrbit({
|
|
392
|
-
view,
|
|
393
|
-
onViewChange,
|
|
394
|
-
home,
|
|
395
|
-
minDistance = 0.1,
|
|
396
|
-
maxDistance = 1e3
|
|
397
|
-
}) {
|
|
398
|
-
const dragRef = useRef(null);
|
|
399
|
-
const sessionRef = useRef(null);
|
|
400
|
-
const viewRef = useRef(view);
|
|
401
|
-
viewRef.current = view;
|
|
402
|
-
const onViewChangeRef = useRef(onViewChange);
|
|
403
|
-
onViewChangeRef.current = onViewChange;
|
|
404
|
-
const homeRef = useRef(home ?? view);
|
|
405
|
-
if (home) homeRef.current = home;
|
|
406
|
-
const onWheel = useCallback(
|
|
407
|
-
(e) => {
|
|
408
|
-
e.preventDefault();
|
|
409
|
-
onViewChange(orbitAfterWheel(viewRef.current, e.deltaY, minDistance, maxDistance));
|
|
410
|
-
},
|
|
411
|
-
[onViewChange, minDistance, maxDistance]
|
|
412
|
-
);
|
|
413
|
-
const clearDrag = useCallback(() => {
|
|
414
|
-
dragRef.current = null;
|
|
415
|
-
sessionRef.current = null;
|
|
416
|
-
}, []);
|
|
417
|
-
const onPointerDown = useCallback(
|
|
418
|
-
(e) => {
|
|
419
|
-
if (e.button !== 0) return;
|
|
420
|
-
const drag = {
|
|
421
|
-
startX: e.clientX,
|
|
422
|
-
startY: e.clientY,
|
|
423
|
-
startView: viewRef.current,
|
|
424
|
-
moved: false
|
|
425
|
-
};
|
|
426
|
-
dragRef.current = drag;
|
|
427
|
-
sessionRef.current = openPointerSession(e.currentTarget, e, {
|
|
428
|
-
onMove: (ev) => {
|
|
429
|
-
const dx = ev.clientX - drag.startX;
|
|
430
|
-
const dy = ev.clientY - drag.startY;
|
|
431
|
-
if (!drag.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD2) return;
|
|
432
|
-
drag.moved = true;
|
|
433
|
-
onViewChangeRef.current(orbitAfterDrag(drag.startView, dx, dy));
|
|
434
|
-
},
|
|
435
|
-
onEnd: clearDrag,
|
|
436
|
-
// A cancelled turn keeps where it got to: every move was committed as
|
|
437
|
-
// it arrived, so there is nothing left to undo.
|
|
438
|
-
onCancel: clearDrag
|
|
439
|
-
});
|
|
440
|
-
},
|
|
441
|
-
[clearDrag]
|
|
442
|
-
);
|
|
443
|
-
useEffect(() => () => sessionRef.current?.cancel(), []);
|
|
444
|
-
const onDoubleClick = useCallback(() => onViewChange(homeRef.current), [onViewChange]);
|
|
445
|
-
const isDragging = useCallback(() => dragRef.current?.moved === true, []);
|
|
446
|
-
return { onWheel, onPointerDown, onDoubleClick, isDragging };
|
|
447
|
-
}
|
|
448
365
|
|
|
449
|
-
export { CameraWheelContext, CanvasStack, DEFAULT_VIEW,
|
|
450
|
-
//# sourceMappingURL=chunk-
|
|
451
|
-
//# sourceMappingURL=chunk-
|
|
366
|
+
export { CameraWheelContext, CanvasStack, DEFAULT_VIEW, Stage, as2DView, fitStage, usePanZoom, withZoom };
|
|
367
|
+
//# sourceMappingURL=chunk-TT5C5S6R.js.map
|
|
368
|
+
//# sourceMappingURL=chunk-TT5C5S6R.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/canvas/CameraWheelContext.ts","../src/state/view.ts","../src/canvas/useLayerScheduler.ts","../src/canvas/usePanZoom.ts","../src/canvas/CanvasStack.tsx","../src/canvas/Stage.tsx"],"names":["useRef","useEffect","useContext","jsxs","jsx"],"mappings":"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","file":"chunk-TT5C5S6R.js","sourcesContent":["import { createContext } from 'react';\n\n/** Where a trial's camera takes a wheel event from outside its own element. */\nexport type CameraWheelSlot = { current: ((e: WheelEvent) => void) | null };\n\n/**\n * The trial's camera, for input that lands outside it. An annotation target's\n * input box is portalled into the surface container, so a wheel over a mark\n * never bubbles through the stage or canvas stack it sits on; the box hands\n * the event here instead.\n */\nexport const CameraWheelContext = createContext<CameraWheelSlot | null>(null);\n","import { normalizeZoom } from '@weasel-js/core';\nimport type { ViewTransform } from '../instrument/types';\n\n/** The 2D view labkit has always shipped, and what a trial gets when it names no\n * other. Re-exported under its own name so a consumer can say which it means. */\nexport type ViewTransform2D = ViewTransform;\n\nexport const DEFAULT_VIEW: ViewTransform2D = { zoom: 1, pan: { x: 0, y: 0 } };\n\n/** A trial's view is opaque to labkit, so anything that needs the 2D shape — the\n * zoom chrome, `CanvasStack` — asks for it and handles not getting it. */\nexport function as2DView(view: unknown): ViewTransform2D | null {\n if (typeof view !== 'object' || view === null) return null;\n const v = view as Partial<ViewTransform2D>;\n if (typeof v.zoom !== 'number') return null;\n if (typeof v.pan !== 'object' || v.pan === null) return null;\n if (typeof v.pan.x !== 'number' || typeof v.pan.y !== 'number') return null;\n return normalize2DView({ zoom: v.zoom, pan: { x: v.pan.x, y: v.pan.y } });\n}\n\n/** `view` inside the invariant every view holds: a zoom that is not a finite\n * number of at least `ZOOM_FLOOR` becomes the floor, and a non-finite pan\n * becomes 0. Returns `view` itself when it already holds. */\nexport function normalize2DView(view: ViewTransform2D): ViewTransform2D {\n const zoom = normalizeZoom(view.zoom);\n const x = Number.isFinite(view.pan.x) ? view.pan.x : 0;\n const y = Number.isFinite(view.pan.y) ? view.pan.y : 0;\n if (zoom === view.zoom && x === view.pan.x && y === view.pan.y) return view;\n return { zoom, pan: { x, y } };\n}\n\n/** `view` at a new zoom, through the same rule. */\nexport function withZoom(view: ViewTransform2D, zoom: number): ViewTransform2D {\n return normalize2DView({ zoom, pan: view.pan });\n}\n","import { useVisibleRaf } from '@weasel-js/core';\nimport { type RefObject, useEffect, useRef } from 'react';\nimport type { ViewTransform } from '../instrument/types';\nimport { DEFAULT_FRAME, type WorldFrame } from './worldSpec';\n\n/** One layer of a canvas stack: its id, whether it is currently shown, and how\n * it paints itself. */\nexport interface CanvasLayerDescriptor {\n id: string;\n visible: boolean;\n render: (ctx: CanvasRenderingContext2D, view: ViewTransform, frame: WorldFrame) => void;\n}\n\ninterface SchedulerOptions {\n layers: CanvasLayerDescriptor[];\n view: ViewTransform;\n /** The instrument's coordinate system, resolved against `size`. */\n frame?: WorldFrame;\n canvasRefs: RefObject<Map<string, HTMLCanvasElement>>;\n size: { width: number; height: number; dpr: number };\n /** The element the stack occupies. Given one, the scheduler also stops while\n * the stack sits outside the viewport. */\n host?: RefObject<Element | null>;\n}\n\nexport function useLayerScheduler({\n layers,\n view,\n frame = DEFAULT_FRAME,\n canvasRefs,\n size,\n host,\n}: SchedulerOptions): void {\n const dirty = useRef<Set<string>>(new Set());\n const lastRenderRef = useRef<Map<string, CanvasLayerDescriptor['render']>>(new Map());\n\n useEffect(() => {\n for (const layer of layers) {\n const prev = lastRenderRef.current.get(layer.id);\n if (prev !== layer.render) dirty.current.add(layer.id);\n lastRenderRef.current.set(layer.id, layer.render);\n }\n for (const id of [...lastRenderRef.current.keys()]) {\n if (!layers.find((l) => l.id === id)) lastRenderRef.current.delete(id);\n }\n }, [layers]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: re-mark dirty when view or size changes\n useEffect(() => {\n for (const layer of layers) dirty.current.add(layer.id);\n }, [view, frame, size, layers]);\n\n // Painting only what is dirty is not the same as doing nothing: a hidden tab\n // still commits React updates, and the effect above marks every layer dirty\n // on any view or size change. The gate is what actually stops the work.\n const frameLoop = useVisibleRaf(\n () => {\n if (dirty.current.size === 0) return;\n const map = canvasRefs.current;\n if (!map) {\n dirty.current.clear();\n return;\n }\n for (const layer of layers) {\n if (!dirty.current.has(layer.id)) continue;\n if (!layer.visible) continue;\n const canvas = map.get(layer.id);\n if (!canvas) continue;\n const ctx = canvas.getContext('2d');\n if (!ctx) continue;\n ctx.save();\n ctx.setTransform(size.dpr, 0, 0, size.dpr, 0, 0);\n ctx.clearRect(0, 0, size.width, size.height);\n layer.render(ctx, view, frame);\n ctx.restore();\n }\n dirty.current.clear();\n },\n { target: host },\n );\n\n useEffect(() => {\n if (dirty.current.size > 0) frameLoop.request();\n });\n}\n","import { openPointerSession, type PointerSession } from '@weasel-js/core';\nimport {\n type PointerEvent as ReactPointerEvent,\n useCallback,\n useEffect,\n useRef,\n type WheelEvent,\n} from 'react';\nimport type { ViewTransform } from '../instrument/types';\nimport { normalize2DView } from '../state/view';\nimport { zoomAt } from './camera';\nimport { DEFAULT_FRAME, type WorldFrame } from './worldSpec';\n\nexport interface UsePanZoomOptions {\n view: ViewTransform;\n onViewChange: (v: ViewTransform) => void;\n /** The opening `view.zoom` always stays reachable, widening these past\n * whatever is passed here if it would otherwise exclude it. */\n minZoom?: number;\n maxZoom?: number;\n /** The instrument's coordinate system, resolved against the viewport. The\n * wheel anchors in this frame; omitting it anchors at the element's\n * top-left, which is what labkit did before a frame could be declared. */\n frame?: WorldFrame;\n /** A primary-button press released without ever crossing the drag\n * threshold. The pointer session owns the release, so the gesture's end is\n * reported here rather than left for a consumer's own `onPointerUp`. */\n onTap?: (e: PointerEvent) => void;\n}\n\nexport interface PanZoomHandlers {\n /** Zoom about the pointer. `anchor` is the element the pointer position is\n * measured against, for an event whose `currentTarget` is some other box. */\n onWheel: (e: WheelEvent<HTMLElement> | globalThis.WheelEvent, anchor?: Element) => void;\n onPointerDown: (e: ReactPointerEvent<HTMLElement>) => void;\n isDragging: () => boolean;\n}\n\ninterface DragState {\n startScreenX: number;\n startScreenY: number;\n startPan: { x: number; y: number };\n moved: boolean;\n}\n\nconst DRAG_THRESHOLD = 3;\n\nfunction isPositiveFinite(n: number): boolean {\n return Number.isFinite(n) && n > 0;\n}\n\nexport function usePanZoom({\n view,\n onViewChange,\n minZoom = 0.1,\n maxZoom = 32,\n frame = DEFAULT_FRAME,\n onTap,\n}: UsePanZoomOptions): PanZoomHandlers {\n const dragRef = useRef<DragState | null>(null);\n const sessionRef = useRef<PointerSession | null>(null);\n const viewRef = useRef(normalize2DView(view));\n viewRef.current = normalize2DView(view);\n const onViewChangeRef = useRef(onViewChange);\n onViewChangeRef.current = onViewChange;\n const onTapRef = useRef(onTap);\n onTapRef.current = onTap;\n // Captured once, from the view the canvas opened at — not the current view,\n // which would let a prior zoom-out shrink the range and trap the opening\n // view unreachable behind it.\n const initialZoomRef = useRef(isPositiveFinite(view.zoom) ? view.zoom : null);\n\n // Written ahead of the render so a second event inside one commit steps\n // from this one; the render-time assignment above still lets the prop win.\n const commit = useCallback((next: ViewTransform) => {\n viewRef.current = normalize2DView(next);\n onViewChangeRef.current(next);\n }, []);\n\n const onWheel = useCallback(\n (e: WheelEvent<HTMLElement> | globalThis.WheelEvent, anchor?: Element) => {\n const el = anchor ?? (e.currentTarget as Element | null);\n if (!el) return;\n e.preventDefault();\n const rect = el.getBoundingClientRect();\n const initialZoom = initialZoomRef.current;\n commit(\n zoomAt(\n viewRef.current,\n Math.exp(-e.deltaY * 0.001),\n { x: e.clientX - rect.left, y: e.clientY - rect.top },\n {\n frame,\n min: initialZoom == null ? minZoom : Math.min(minZoom, initialZoom),\n max: initialZoom == null ? maxZoom : Math.max(maxZoom, initialZoom),\n },\n ),\n );\n },\n [commit, minZoom, maxZoom, frame],\n );\n\n const clearDrag = useCallback(() => {\n dragRef.current = null;\n sessionRef.current = null;\n }, []);\n\n const onPointerDown = useCallback(\n (e: ReactPointerEvent<HTMLElement>) => {\n if (e.button !== 0) return;\n const drag: DragState = {\n startScreenX: e.clientX,\n startScreenY: e.clientY,\n startPan: { ...viewRef.current.pan },\n moved: false,\n };\n dragRef.current = drag;\n sessionRef.current = openPointerSession(e.currentTarget, e, {\n onMove: (ev) => {\n const dx = ev.clientX - drag.startScreenX;\n const dy = ev.clientY - drag.startScreenY;\n if (!drag.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;\n drag.moved = true;\n commit({\n zoom: viewRef.current.zoom,\n pan: { x: drag.startPan.x + dx, y: drag.startPan.y + dy },\n });\n },\n onEnd: (ev) => {\n const tapped = !drag.moved;\n clearDrag();\n if (tapped) onTapRef.current?.(ev);\n },\n // A cancelled pan keeps whatever it had already applied: every move\n // was committed as it arrived, so there is nothing left to undo.\n onCancel: clearDrag,\n });\n },\n [clearDrag, commit],\n );\n\n useEffect(() => () => sessionRef.current?.cancel(), []);\n\n const isDragging = useCallback(() => dragRef.current?.moved === true, []);\n\n return { onWheel, onPointerDown, isDragging };\n}\n","import {\n type CSSProperties,\n type ReactNode,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { Point, ViewTransform } from '../instrument/types';\nimport { normalize2DView } from '../state/view';\nimport { CameraWheelContext } from './CameraWheelContext';\nimport { CanvasStackContext } from './CanvasStackContext';\nimport { screenToWorld } from './canvasCoords';\nimport { type CanvasLayerDescriptor, useLayerScheduler } from './useLayerScheduler';\nimport { usePanZoom } from './usePanZoom';\nimport { resolveFrame, type ViewportSize, type WorldSpec } from './worldSpec';\n\n/** Props for `<CanvasStack>`. */\nexport interface CanvasStackProps {\n layers: CanvasLayerDescriptor[];\n view: ViewTransform;\n onViewChange: (v: ViewTransform) => void;\n /** The instrument's coordinate system. Omitted, world (0,0) sits at the\n * element's top-left with y running down. */\n worldSpec?: WorldSpec;\n minZoom?: number;\n maxZoom?: number;\n width?: number | string;\n height?: number | string;\n className?: string;\n /** Fired whenever the stack is measured, so a consumer can place a view that\n * only makes sense in terms of the viewport. */\n onResize?: (size: ViewportSize) => void;\n onHitTest?: (worldPos: Point) => void;\n children?: ReactNode;\n}\n\n/** Stacks one `<canvas>` per layer and drives them from a shared view, so a\n * layer that changes rarely is not redrawn with one that changes every frame.\n * Handles sizing, device pixel ratio, and pan/zoom. */\nexport function CanvasStack({\n layers,\n view: viewProp,\n onViewChange,\n worldSpec,\n minZoom,\n maxZoom,\n width = '100%',\n height = '100%',\n className,\n onResize,\n onHitTest,\n children,\n}: CanvasStackProps) {\n const view = normalize2DView(viewProp);\n const containerRef = useRef<HTMLDivElement | null>(null);\n const canvasMap = useRef<Map<string, HTMLCanvasElement>>(new Map());\n const [size, setSize] = useState({ width: 0, height: 0, dpr: 1 });\n\n const setCanvasRef = (id: string, el: HTMLCanvasElement | null): void => {\n if (el) canvasMap.current.set(id, el);\n else canvasMap.current.delete(id);\n };\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const update = () => {\n const rect = el.getBoundingClientRect();\n const dpr = window.devicePixelRatio ?? 1;\n setSize((prev) => {\n if (prev.width === rect.width && prev.height === rect.height && prev.dpr === dpr) {\n return prev;\n }\n return { width: rect.width, height: rect.height, dpr };\n });\n };\n update();\n if (typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(update);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n const onResizeRef = useRef(onResize);\n onResizeRef.current = onResize;\n useEffect(() => {\n if (size.width === 0 && size.height === 0) return;\n onResizeRef.current?.({ width: size.width, height: size.height });\n }, [size.width, size.height]);\n\n const frame = useMemo(() => resolveFrame(worldSpec, size), [worldSpec, size]);\n\n const onTap = (e: PointerEvent) => {\n const el = containerRef.current;\n if (!onHitTest || !el) return;\n const rect = el.getBoundingClientRect();\n onHitTest(screenToWorld({ x: e.clientX - rect.left, y: e.clientY - rect.top }, view, frame));\n };\n\n const handlers = usePanZoom({ view: viewProp, onViewChange, minZoom, maxZoom, frame, onTap });\n const onWheelRef = useRef(handlers.onWheel);\n onWheelRef.current = handlers.onWheel;\n const wheelSlot = useContext(CameraWheelContext);\n\n // Bound by hand because React registers wheel listeners passive, where\n // `preventDefault` is refused and the page scrolls under the zoom.\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const wheel = (e: WheelEvent): void => onWheelRef.current(e, el);\n el.addEventListener('wheel', wheel, { passive: false });\n if (wheelSlot) wheelSlot.current = wheel;\n return () => {\n el.removeEventListener('wheel', wheel);\n if (wheelSlot?.current === wheel) wheelSlot.current = null;\n };\n }, [wheelSlot]);\n useLayerScheduler({ layers, view, frame, canvasRefs: canvasMap, size, host: containerRef });\n\n const ctxValue = useMemo(\n () => ({\n view,\n frame,\n surface: { element: containerRef, size, canvases: canvasMap, layers },\n }),\n [view, frame, size, layers],\n );\n\n const containerStyle: CSSProperties = { width, height };\n const canvasPx = {\n width: Math.max(0, Math.round(size.width * size.dpr)),\n height: Math.max(0, Math.round(size.height * size.dpr)),\n };\n const canvasCss: CSSProperties = {\n width: size.width,\n height: size.height,\n };\n\n return (\n <CanvasStackContext.Provider value={ctxValue}>\n <div\n ref={containerRef}\n className={className ? `lk-canvas-stack ${className}` : 'lk-canvas-stack'}\n style={containerStyle}\n onPointerDown={handlers.onPointerDown}\n >\n {layers.map((layer) => (\n <canvas\n key={layer.id}\n ref={(el) => setCanvasRef(layer.id, el)}\n className=\"lk-canvas-stack__canvas\"\n width={canvasPx.width}\n height={canvasPx.height}\n style={{ ...canvasCss, display: layer.visible ? 'block' : 'none' }}\n />\n ))}\n <div className=\"lk-canvas-stack__overlay\">{children}</div>\n </div>\n </CanvasStackContext.Provider>\n );\n}\n","import { type CSSProperties, type ReactNode, useContext, useEffect, useRef } from 'react';\nimport type { ViewTransform } from '../instrument/types';\nimport { normalize2DView } from '../state/view';\nimport { useSurfaceOptional } from '../surface/useSurfaceTile';\nimport { CameraWheelContext } from './CameraWheelContext';\nimport { usePanZoom } from './usePanZoom';\nimport type { ViewportSize } from './worldSpec';\n\n/** Props for `<Stage>`. */\nexport interface StageProps {\n /** The content's own size in CSS pixels, at zoom 1. */\n size: ViewportSize;\n view: ViewTransform;\n onViewChange: (v: ViewTransform) => void;\n minZoom?: number;\n maxZoom?: number;\n /** Fired whenever the stage's viewport is measured at a non-zero size. */\n onResize?: (viewport: ViewportSize) => void;\n /** Handed the viewport element, for a consumer tracking the pointer over it. */\n hostRef?: { current: HTMLDivElement | null };\n /** Drawn over the content in viewport pixels, outside the camera. */\n overlay?: ReactNode;\n children?: ReactNode;\n}\n\n/**\n * The camera a stage opens at: the content centered in its viewport, shrunk to\n * fit if it has to be and never enlarged past its own size.\n */\nexport function fitStage(size: ViewportSize, viewport: ViewportSize): ViewTransform {\n if (!(size.width > 0 && size.height > 0 && viewport.width > 0 && viewport.height > 0)) {\n return { zoom: 1, pan: { x: 0, y: 0 } };\n }\n const zoom = Math.min(1, viewport.width / size.width, viewport.height / size.height);\n return {\n zoom,\n pan: {\n x: (viewport.width - size.width * zoom) / 2,\n y: (viewport.height - size.height * zoom) / 2,\n },\n };\n}\n\n/**\n * DOM content of a fixed size, panned and zoomed by a camera — what\n * `<CanvasStack>` is for layers drawn to a canvas. The content is laid out at\n * its own size and transformed, so everything inside keeps its layout and a\n * measurement of any element in it reports where it is actually drawn.\n */\nexport function Stage({\n size,\n view: viewProp,\n onViewChange,\n minZoom,\n maxZoom,\n onResize,\n hostRef,\n overlay,\n children,\n}: StageProps) {\n const view = normalize2DView(viewProp);\n const host = useRef<HTMLDivElement | null>(null);\n const surface = useSurfaceOptional();\n const handlers = usePanZoom({ view: viewProp, onViewChange, minZoom, maxZoom });\n const onWheelRef = useRef(handlers.onWheel);\n onWheelRef.current = handlers.onWheel;\n const wheelSlot = useContext(CameraWheelContext);\n\n // Bound by hand because React registers wheel listeners passive, where\n // `preventDefault` is refused and the page scrolls under the zoom.\n useEffect(() => {\n const el = host.current;\n if (!el) return;\n const wheel = (e: WheelEvent): void => onWheelRef.current(e, el);\n el.addEventListener('wheel', wheel, { passive: false });\n if (wheelSlot) wheelSlot.current = wheel;\n return () => {\n el.removeEventListener('wheel', wheel);\n if (wheelSlot?.current === wheel) wheelSlot.current = null;\n };\n }, [wheelSlot]);\n\n const onResizeRef = useRef(onResize);\n onResizeRef.current = onResize;\n useEffect(() => {\n const el = host.current;\n if (!el) return;\n const measure = () => {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) {\n onResizeRef.current?.({ width: rect.width, height: rect.height });\n }\n };\n measure();\n if (typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n // A transform moves every tile inside the content without resizing anything,\n // and a ResizeObserver reports only resizes.\n // biome-ignore lint/correctness/useExhaustiveDependencies: the camera is the trigger, not an input — the effect re-measures whenever it moves.\n useEffect(() => {\n surface?.invalidateRects();\n }, [surface, view.zoom, view.pan.x, view.pan.y]);\n\n // The camera changes every frame of a pan, and a transform has nowhere to\n // live but the element's own style: set as custom properties the stylesheet\n // reads.\n const camera = {\n ['--lk-stage-x' as string]: `${view.pan.x}px`,\n ['--lk-stage-y' as string]: `${view.pan.y}px`,\n ['--lk-stage-zoom' as string]: String(view.zoom),\n ['--lk-stage-w' as string]: `${size.width}px`,\n ['--lk-stage-h' as string]: `${size.height}px`,\n } as CSSProperties;\n\n return (\n <div\n ref={(el) => {\n host.current = el;\n if (hostRef) hostRef.current = el;\n }}\n className=\"lk-stage\"\n onPointerDown={handlers.onPointerDown}\n >\n <div className=\"lk-stage__content\" style={camera}>\n {children}\n </div>\n {overlay}\n </div>\n );\n}\n"]}
|