@weasel-js/labkit 1.5.2 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -7
- package/dist/_dts/{CanvasStackContext-CMMo180l.d.ts → CanvasStackContext-Wo6OwIVM.d.ts} +1 -1
- package/dist/_dts/FloatingPanel-7j0IcXwz.d.ts +30 -0
- package/dist/_dts/LayerList.d-BoELAMsM.d.ts +83 -0
- package/dist/_dts/{PrefsForm.d-DPy9I8It.d.ts → PrefsRow.d-DFpPIeIC.d.ts} +16 -1
- package/dist/_dts/PropertyField.d-D0ndfIIt.d.ts +404 -0
- package/dist/_dts/{Select.d-ZTiwzYyT.d.ts → Select.d-Cr8-zoup.d.ts} +105 -15
- package/dist/_dts/{usePanZoom-SSTZe410.d.ts → Stage-DWBBi8IU.d.ts} +80 -35
- package/dist/_dts/{index-DlKolEIZ.d.ts → index-CKyX0ME_.d.ts} +12 -13
- package/dist/_dts/{frac-B4hFJMiN.d.ts → types-B7yBTTF9.d.ts} +709 -651
- package/dist/_dts/{types-Db-3NNk1.d.ts → types-DTuViBvc.d.ts} +21 -2
- package/dist/_dts/{useTrialState-pnAE-UBD.d.ts → useTrialState-CMaV6UD4.d.ts} +2 -3
- package/dist/canvas/index.d.ts +41 -8
- package/dist/canvas/index.js +5 -3
- package/dist/chrome/index.d.ts +6 -6
- package/dist/chrome/index.js +9 -7
- package/dist/chunk-24W5VEJW.js +18 -0
- package/dist/chunk-24W5VEJW.js.map +1 -0
- package/dist/chunk-2RVCB2PT.js +3 -0
- package/dist/chunk-2RVCB2PT.js.map +1 -0
- package/dist/chunk-3RY6WL5T.js +38 -0
- package/dist/chunk-3RY6WL5T.js.map +1 -0
- package/dist/{chunk-CKUKF72R.js → chunk-4TT3PNPR.js} +68 -55
- package/dist/chunk-4TT3PNPR.js.map +1 -0
- package/dist/{chunk-KJCUERQF.js → chunk-6FLXL3I7.js} +9 -164
- package/dist/chunk-6FLXL3I7.js.map +1 -0
- package/dist/chunk-ASOK76ZH.js +431 -0
- package/dist/chunk-ASOK76ZH.js.map +1 -0
- package/dist/chunk-AWQG7FCC.js +19 -0
- package/dist/chunk-AWQG7FCC.js.map +1 -0
- package/dist/chunk-CGHF6RZV.js +300 -0
- package/dist/chunk-CGHF6RZV.js.map +1 -0
- package/dist/chunk-DWMSB4CA.js +228 -0
- package/dist/chunk-DWMSB4CA.js.map +1 -0
- package/dist/chunk-GHGO52SO.js +92 -0
- package/dist/chunk-GHGO52SO.js.map +1 -0
- package/dist/{chunk-LRI3MBGR.js → chunk-HKV7LRHY.js} +4 -4
- package/dist/{chunk-LRI3MBGR.js.map → chunk-HKV7LRHY.js.map} +1 -1
- package/dist/{chunk-EMXAIRUJ.js → chunk-IRTGUQ5O.js} +5 -4
- package/dist/chunk-IRTGUQ5O.js.map +1 -0
- package/dist/{chunk-H6ZAOWNE.js → chunk-JVBYV6TL.js} +3 -3
- package/dist/{chunk-H6ZAOWNE.js.map → chunk-JVBYV6TL.js.map} +1 -1
- package/dist/chunk-KHK5FGER.js +145 -0
- package/dist/chunk-KHK5FGER.js.map +1 -0
- package/dist/chunk-NEXR37YJ.js +144 -0
- package/dist/chunk-NEXR37YJ.js.map +1 -0
- package/dist/{chunk-A2ACAGW6.js → chunk-O6FFFOHS.js} +32 -7
- package/dist/chunk-O6FFFOHS.js.map +1 -0
- package/dist/chunk-QGMOA2YE.js +731 -0
- package/dist/chunk-QGMOA2YE.js.map +1 -0
- package/dist/{chunk-ERFMC6WU.js → chunk-S4NCI32V.js} +19 -10
- package/dist/chunk-S4NCI32V.js.map +1 -0
- package/dist/{chunk-753Y6HE6.js → chunk-SLAQPUI4.js} +4 -4
- package/dist/chunk-SLAQPUI4.js.map +1 -0
- package/dist/{chunk-REOBGYMC.js → chunk-TJ77A4A3.js} +3 -5
- package/dist/chunk-TJ77A4A3.js.map +1 -0
- package/dist/chunk-TYN6MLXX.js +13864 -0
- package/dist/chunk-TYN6MLXX.js.map +1 -0
- package/dist/{chunk-RS3HRQWU.js → chunk-WPLAANH4.js} +4 -3
- package/dist/chunk-WPLAANH4.js.map +1 -0
- package/dist/config/index.d.ts +51 -7
- package/dist/config/index.js +4 -5
- package/dist/controls/index.d.ts +92 -5
- package/dist/controls/index.js +5 -4
- package/dist/dragdrop/index.d.ts +9 -6
- package/dist/dragdrop/index.js +3 -2
- package/dist/index.d.ts +108 -154
- package/dist/index.js +456 -600
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +5 -35
- package/dist/layers/index.js +3 -3
- package/dist/loupe/index.d.ts +21 -17
- package/dist/loupe/index.js +5 -3
- package/dist/overview/index.d.ts +56 -0
- package/dist/overview/index.js +288 -0
- package/dist/overview/index.js.map +1 -0
- package/dist/passthrough/weasel-ui.d.ts +434 -231
- package/dist/passthrough/weasel-ui.js +2 -1
- package/dist/primitives/index.d.ts +19 -54
- package/dist/primitives/index.js +6 -4
- package/dist/state/index.d.ts +8 -7
- package/dist/state/index.js +4 -5
- package/dist/state/index.js.map +1 -1
- package/dist/styles.css +360 -174
- package/dist/undo/index.d.ts +5 -4
- package/package.json +13 -13
- package/src/annotations/frac.test.ts +7 -0
- package/src/annotations/index.ts +1 -0
- package/src/annotations/paint.test.ts +21 -0
- package/src/annotations/paint.ts +12 -0
- package/src/annotations/store.test.ts +57 -0
- package/src/annotations/store.ts +25 -6
- package/src/annotations/toolMap.test.ts +37 -2
- package/src/annotations/toolMap.ts +13 -0
- package/src/annotations/types.ts +30 -2
- package/src/canvas/AGENTS.md +8 -10
- package/src/canvas/CameraInput.test.tsx +136 -0
- package/src/canvas/CameraInput.tsx +311 -0
- package/src/canvas/CanvasStack.tsx +42 -58
- package/src/canvas/LinkedCursor.less +16 -0
- package/src/canvas/LinkedCursor.tsx +54 -0
- package/src/canvas/Stage.test.tsx +18 -0
- package/src/canvas/Stage.tsx +42 -37
- package/src/canvas/cameraView.test.ts +60 -0
- package/src/canvas/cameraView.ts +61 -0
- package/src/canvas/index.ts +11 -2
- package/src/chrome/regions/SidebarRegion.less +197 -0
- package/src/chrome/regions/SidebarRegion.test.tsx +27 -0
- package/src/chrome/regions/SidebarRegion.tsx +7 -2
- package/src/chrome/types.ts +5 -2
- package/src/config/autoConfig.ts +2 -2
- package/src/config/builder.ts +21 -2
- package/src/config/entry.test.ts +10 -0
- package/src/config/fromConfigField.ts +1 -0
- package/src/config/index.ts +5 -0
- package/src/config/resolve.ts +11 -1
- package/src/config/rules.ts +2 -0
- package/src/config/sectionTree.test.ts +152 -0
- package/src/config/sectionTree.ts +134 -0
- package/src/config/types.ts +21 -0
- package/src/controls/ControlPanel.less +4 -0
- package/src/controls/ControlPanel.stories.tsx +55 -2
- package/src/controls/ControlPanel.test.tsx +40 -3
- package/src/controls/ControlPanel.tsx +134 -336
- package/src/controls/inDialog.test.tsx +100 -0
- package/src/controls/inDialog.tsx +38 -0
- package/src/controls/index.ts +1 -0
- package/src/index.test.ts +1 -1
- package/src/index.ts +18 -29
- package/src/instrument/SineWave.smoke.test.tsx +2 -0
- package/src/instrument/types.ts +15 -3
- package/src/lab/Lab.nebula.test.tsx +40 -0
- package/src/lab/Lab.test.tsx +3 -1
- package/src/lab/Lab.tsx +42 -19
- 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/loupe/AGENTS.md +7 -6
- package/src/loupe/LoupeGestures.tsx +14 -9
- package/src/loupe/TrialLoupe.tsx +5 -5
- package/src/loupe/index.ts +1 -0
- package/src/loupe/loupeActions.ts +6 -2
- package/src/overview/AGENTS.md +38 -0
- package/src/overview/OverviewMarks.test.tsx +100 -0
- package/src/overview/OverviewMarks.tsx +93 -0
- package/src/overview/TrialOverview.less +53 -0
- package/src/overview/TrialOverview.stories.tsx +50 -0
- package/src/overview/TrialOverview.test.tsx +116 -0
- package/src/overview/TrialOverview.tsx +374 -0
- package/src/overview/index.ts +2 -0
- package/src/passthrough/weasel-ui.ts +32 -10
- package/src/primitives/index.ts +0 -2
- package/src/specimen/Specimen.tsx +59 -56
- package/src/state/labRecords.test.ts +4 -1
- package/src/state/store.test.ts +4 -4
- package/src/state/types.ts +2 -1
- package/src/state/useTrialState.test.tsx +1 -1
- package/src/styles.less +6 -2
- package/src/theme/Interstellar.stories.tsx +8 -13
- 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/tools/labTool.ts +6 -2
- package/src/trial/Trial.annotations.test.tsx +16 -0
- package/src/trial/Trial.canvas.test.tsx +1 -1
- package/src/trial/Trial.loupe.test.tsx +73 -1
- package/src/trial/Trial.stories.tsx +2 -0
- package/src/trial/Trial.tsx +47 -9
- package/src/trial/trialOps.test.ts +4 -4
- package/dist/_dts/index-8LiKe3A-.d.ts +0 -410
- package/dist/chunk-2AYGEN57.js +0 -32
- package/dist/chunk-2AYGEN57.js.map +0 -1
- package/dist/chunk-6BUQ77ZV.js +0 -18
- package/dist/chunk-6BUQ77ZV.js.map +0 -1
- package/dist/chunk-753Y6HE6.js.map +0 -1
- package/dist/chunk-A2ACAGW6.js.map +0 -1
- package/dist/chunk-CKUKF72R.js.map +0 -1
- package/dist/chunk-D35PFTS7.js +0 -170
- package/dist/chunk-D35PFTS7.js.map +0 -1
- package/dist/chunk-EMXAIRUJ.js.map +0 -1
- package/dist/chunk-ERFMC6WU.js.map +0 -1
- package/dist/chunk-FKLT3ITC.js +0 -590
- package/dist/chunk-FKLT3ITC.js.map +0 -1
- package/dist/chunk-KJCUERQF.js.map +0 -1
- package/dist/chunk-LASCBWW7.js +0 -13456
- package/dist/chunk-LASCBWW7.js.map +0 -1
- package/dist/chunk-REOBGYMC.js.map +0 -1
- package/dist/chunk-RS3HRQWU.js.map +0 -1
- package/dist/chunk-TT5C5S6R.js +0 -368
- package/dist/chunk-TT5C5S6R.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/usePanZoom.test.ts +0 -244
- package/src/canvas/usePanZoom.ts +0 -147
- 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 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config/auto.ts","../src/config/path.ts","../src/config/autoConfig.ts"],"names":["n"],"mappings":"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","file":"chunk-REOBGYMC.js","sourcesContent":["/**\n * Written at a config path to mean \"do not pin this — let the instrument\n * decide\". Accepted by `setConfig`, by a trial's `configSeed`, and by\n * `.initial()` in a schema. It is normalized into the trial's set of unpinned\n * paths on the way into the store and is never itself stored, so a serialized\n * trial contains no sentinel and the last pinned value survives.\n */\nexport const auto: unique symbol = Symbol('weasel.auto');\n\n/** The type of the `auto` sentinel, for widening a value parameter. */\nexport type Auto = typeof auto;\n\nexport function isAuto(value: unknown): value is Auto {\n return value === auto;\n}\n","import type { PrefGroup, PrefLeaf } from '@weasel-js/ui';\n\n/**\n * Reading and writing a config tree by dotted path. A schema's leaves address\n * their values this way, so a leaf nested under `f.group` and a flat one are\n * reached by exactly the same call.\n */\n\n/** A plain object a config tree can be walked into. An array, a `Date`, a\n * `Map` or a class instance is a leaf value: a walk that descended into one\n * would rebuild it as a bare `{}`. */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\n/** The value at a dotted path. `undefined` when a segment is missing or the\n * walk hits something that is not a record. */\nexport function valueAtPath(config: unknown, path: string): unknown {\n let cur = config;\n for (const segment of path.split('.')) {\n if (!isRecord(cur)) return undefined;\n cur = cur[segment];\n }\n return cur;\n}\n\n/** Whether a dotted path is actually present, which a `undefined` value is\n * not enough to tell you. */\nexport function hasConfigPath(config: unknown, path: string): boolean {\n let cur = config;\n for (const segment of path.split('.')) {\n if (!isRecord(cur) || !(segment in cur)) return false;\n cur = cur[segment];\n }\n return true;\n}\n\nfunction writeIn(node: unknown, segments: readonly string[], value: unknown): unknown {\n const [head, ...rest] = segments;\n if (head === undefined) return value;\n const base = isRecord(node) ? node : {};\n return { ...base, [head]: rest.length === 0 ? value : writeIn(base[head], rest, value) };\n}\n\n/** A copy of `config` with `value` written at a dotted path. Every record on\n * the way down is copied and the input is left alone; a missing — or\n * non-record — intermediate is replaced with the branch the path implies. */\nexport function withValueAtPath<T>(config: T, path: string, value: unknown): T {\n return writeIn(config, path.split('.'), value) as T;\n}\n\n/**\n * `stored` with every gap filled from `defaults`, down the whole tree.\n *\n * This is how a config written before its schema grew a branch still loads:\n * the branch arrives at its defaults instead of `undefined`, and a key the\n * defaults no longer mention is kept rather than dropped, so nothing is lost\n * to a schema change the author has not finished making.\n */\nexport function fillConfigDefaults<T>(stored: unknown, defaults: T): T {\n if (!isRecord(defaults)) return (stored === undefined ? defaults : stored) as T;\n const base = isRecord(stored) ? stored : {};\n const out: Record<string, unknown> = { ...base };\n for (const [key, value] of Object.entries(defaults)) {\n out[key] = fillConfigDefaults(base[key], value);\n }\n return out as T;\n}\n\n/** A node in a resolved schema tree, by dotted path. Structural rather than\n * `isPrefLeaf` so this stays free of a runtime import. */\nexport function schemaNodeAtPath(group: PrefGroup, path: string): PrefLeaf | PrefGroup | undefined {\n let node: PrefLeaf | PrefGroup | undefined = group;\n for (const segment of path.split('.')) {\n if (node === undefined || !('children' in node)) return undefined;\n node = node.children[segment];\n }\n return node;\n}\n","import { isPrefLeaf, type PrefGroup, type PrefLeaf } from '@weasel-js/ui';\nimport { isAuto } from './auto';\nimport { isRecord, withValueAtPath } from './path';\nimport type { ResolvedConfig } from './types';\n\ntype Resolver = (config: Record<string, unknown>) => unknown;\n\n/** Reads a labkit-only extra off a resolved leaf. `PrefLeaf` has no field for\n * these; they ride as extra keys and survive the resolve walk. */\nfunction extra<T>(leaf: PrefLeaf, key: string): T | undefined {\n return (leaf as unknown as Record<string, T | undefined>)[key];\n}\n\n/** Every leaf in a resolved schema, in schema order, with its dotted path. */\nfunction* leaves(group: PrefGroup, at = ''): Generator<[string, PrefLeaf]> {\n for (const [key, child] of Object.entries(group.children)) {\n const path = at === '' ? key : `${at}.${key}`;\n if (isPrefLeaf(child)) yield [path, child];\n else yield* leaves(child, path);\n }\n}\n\n/** The dotted paths a schema declares as starting auto — every leaf that said\n * `.initial(auto)`. This is what seeds a new trial's unpinned set. */\nexport function autoPathsOf(resolved: ResolvedConfig): string[] {\n const out: string[] = [];\n for (const [path, leaf] of leaves(resolved.group)) {\n if (extra<boolean>(leaf, 'unpinned')) out.push(path);\n }\n return out;\n}\n\n/**\n * The config an instrument reads: the stored one, with every unpinned path\n * either computed by its resolver or removed.\n *\n * Resolution is demand-driven — a resolver reading another unpinned path\n * forces that one first, whatever order the schema declared them in — so a\n * cycle is a real cycle and not an ordering accident.\n */\nexport function resolveAutoConfig<TC>(\n resolved: ResolvedConfig,\n config: TC,\n autoPaths: ReadonlySet<string>,\n): TC {\n if (autoPaths.size === 0) return config;\n\n const resolvers = new Map<string, Resolver | undefined>();\n for (const [path, leaf] of leaves(resolved.group)) {\n if (autoPaths.has(path)) resolvers.set(path, extra<Resolver>(leaf, 'autoResolve'));\n }\n if (resolvers.size === 0) return config;\n\n // Drop first, so a resolver reading a still-unresolved auto path sees\n // `undefined` rather than a stale pinned value it would silently believe.\n let out = config as unknown as Record<string, unknown>;\n for (const path of resolvers.keys()) out = dropAtPath(out, path);\n\n const inFlight = new Set<string>();\n const done = new Set<string>();\n\n const need = (path: string): void => {\n if (done.has(path)) return;\n if (inFlight.has(path)) {\n throw new Error(`[labkit] auto resolver cycle at \"${path}\"`);\n }\n const resolve = resolvers.get(path);\n if (!resolve) {\n done.add(path);\n return;\n }\n inFlight.add(path);\n try {\n // Read `out` only after the resolver has run: it forces its own\n // dependencies, and each of those replaced `out`.\n const value = resolve(demand(() => out, resolvers, need));\n out = withValueAtPath(out, path, value);\n } finally {\n inFlight.delete(path);\n }\n done.add(path);\n };\n\n for (const path of resolvers.keys()) need(path);\n return out as unknown as TC;\n}\n\n/**\n * The config a resolver reads. A top-level key that is itself unpinned is\n * forced before it is handed back, which is what makes declaration order\n * irrelevant and turns a genuine loop into a named error.\n *\n * Only top-level keys are trapped: a resolver reaching `c.grid.size` gets the\n * already-dropped branch, and a nested auto path it depends on resolves by\n * schema order alone.\n */\nfunction demand(\n read: () => Record<string, unknown>,\n resolvers: ReadonlyMap<string, Resolver | undefined>,\n need: (path: string) => void,\n): Record<string, unknown> {\n return new Proxy(read(), {\n get(_target, key) {\n if (typeof key === 'string' && resolvers.has(key)) need(key);\n return Reflect.get(read(), key);\n },\n has(_target, key) {\n return Reflect.has(read(), key);\n },\n ownKeys() {\n return Reflect.ownKeys(read());\n },\n getOwnPropertyDescriptor(_target, key) {\n return Reflect.getOwnPropertyDescriptor(read(), key);\n },\n });\n}\n\n/** A copy of `config` with the dotted path removed, copying every record on\n * the way down. A path that is not there comes back unchanged. */\nfunction dropAtPath(config: Record<string, unknown>, path: string): Record<string, unknown> {\n const [head, ...rest] = path.split('.');\n if (head === undefined || !(head in config)) return config;\n if (rest.length === 0) {\n const { [head]: _dropped, ...kept } = config;\n return kept;\n }\n const child = config[head];\n if (!isRecord(child)) return config;\n return { ...config, [head]: dropAtPath(child, rest.join('.')) };\n}\n\n/**\n * What writing `value` at `path` makes of a trial's raw config and its set of\n * unpinned paths. `auto` pins nothing and joins the set; any other value is\n * written and leaves it. Both the store and the chrome go through this, so\n * they cannot disagree about what a write meant.\n */\nexport function applyConfigWrite<TC>(\n config: TC,\n autoPaths: readonly string[],\n path: string,\n value: unknown,\n): { config: TC; autoPaths: readonly string[] } {\n if (isAuto(value)) {\n if (autoPaths.includes(path)) return { config, autoPaths };\n return { config, autoPaths: [...autoPaths, path] };\n }\n return {\n config: withValueAtPath(config, path, value),\n autoPaths: autoPaths.includes(path) ? autoPaths.filter((p) => p !== path) : autoPaths,\n };\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dragdrop/DragGhost.tsx","../src/dragdrop/DragDropRuntime.tsx","../src/dragdrop/Palette.tsx"],"names":["useState","useEffect","jsx"],"mappings":"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","file":"chunk-RS3HRQWU.js","sourcesContent":["import { type ReactPortal, useEffect, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { PaletteItem, Point } from '../instrument/types';\n\nexport interface DragGhostProps {\n item: PaletteItem;\n screenPos: Point;\n}\n\nexport function DragGhost({ item, screenPos }: DragGhostProps): ReactPortal | null {\n const [mounted, setMounted] = useState(false);\n useEffect(() => setMounted(true), []);\n if (!mounted || typeof document === 'undefined') return null;\n const style = {\n left: `${screenPos.x + 12}px`,\n top: `${screenPos.y + 12}px`,\n };\n return createPortal(\n <div className=\"lk-drag-ghost\" style={style}>\n <span className=\"lk-drag-ghost__label\">{item.label}</span>\n </div>,\n document.body,\n );\n}\n","import { openPointerSession, type PointerSession, useVisibleRaf } from '@weasel-js/core';\nimport {\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { screenToWorld } from '../canvas/canvasCoords';\nimport { resolveFrame, type WorldSpec } from '../canvas/worldSpec';\nimport type {\n DragDropCapability,\n DragFeedback,\n PaletteItem,\n Point,\n ViewTransform,\n} from '../instrument/types';\nimport { DragGhost } from './DragGhost';\n\nexport interface DragState {\n item: PaletteItem;\n screenPos: Point;\n feedback: DragFeedback | null;\n}\n\nexport interface UseDragDropArgs<TS, TC> {\n capability: DragDropCapability<TS, TC>;\n canvasContainerRef: RefObject<HTMLElement | null>;\n view: ViewTransform;\n /** The instrument's coordinate system, resolved against the container each\n * time a screen point is converted — the container is what knows its size. */\n worldSpec?: WorldSpec;\n state: TS;\n config: TC;\n setState: (next: TS | ((prev: TS) => TS)) => void;\n emit: (event: string) => void;\n}\n\nexport interface UseDragDropResult {\n drag: DragState | null;\n startDrag: (item: PaletteItem, e: ReactPointerEvent) => void;\n}\n\nexport function useDragDrop<TS, TC>({\n capability,\n canvasContainerRef,\n view,\n state,\n config,\n setState,\n emit,\n worldSpec,\n}: UseDragDropArgs<TS, TC>): UseDragDropResult {\n const [drag, setDrag] = useState<DragState | null>(null);\n const dragRef = useRef<DragState | null>(null);\n dragRef.current = drag;\n /** The move the next frame will resolve. Doubles as the throttle's flag:\n * non-null means a frame is already queued. */\n const pendingPos = useRef<Point | null>(null);\n const sessionRef = useRef<PointerSession | null>(null);\n\n /** A session keeps the closure it was opened with, so everything the drop\n * reads has to come from here rather than from that closure. */\n const liveRef = useRef({ capability, state, config, setState, emit, view, worldSpec });\n liveRef.current = { capability, state, config, setState, emit, view, worldSpec };\n\n const isOverCanvas = useCallback(\n (screenPos: Point): boolean => {\n const el = canvasContainerRef.current;\n if (!el) return false;\n const r = el.getBoundingClientRect();\n return (\n screenPos.x >= r.left &&\n screenPos.x <= r.right &&\n screenPos.y >= r.top &&\n screenPos.y <= r.bottom\n );\n },\n [canvasContainerRef],\n );\n\n const screenToWorldFromContainer = useCallback(\n (screenPos: Point): Point | null => {\n const el = canvasContainerRef.current;\n if (!el) return null;\n const r = el.getBoundingClientRect();\n const frame = resolveFrame(liveRef.current.worldSpec, { width: r.width, height: r.height });\n return screenToWorld(\n { x: screenPos.x - r.left, y: screenPos.y - r.top },\n liveRef.current.view,\n frame,\n );\n },\n [canvasContainerRef],\n );\n\n const frameLoop = useVisibleRaf(() => {\n const screenPos = pendingPos.current;\n pendingPos.current = null;\n const active = dragRef.current;\n if (!active || !screenPos) return;\n const live = liveRef.current;\n let feedback: DragFeedback | null = null;\n if (live.capability.onDragOver && isOverCanvas(screenPos)) {\n const world = screenToWorldFromContainer(screenPos);\n if (world) feedback = live.capability.onDragOver(world, active.item, live.state, live.config);\n }\n setDrag({ ...active, screenPos, feedback });\n });\n\n const clearDrag = useCallback(() => {\n pendingPos.current = null;\n frameLoop.cancel();\n sessionRef.current = null;\n dragRef.current = null;\n setDrag(null);\n }, [frameLoop]);\n\n const startDrag = useCallback(\n (item: PaletteItem, e: ReactPointerEvent) => {\n if (sessionRef.current) return;\n const next: DragState = { item, screenPos: { x: e.clientX, y: e.clientY }, feedback: null };\n dragRef.current = next;\n setDrag(next);\n sessionRef.current = openPointerSession(e.currentTarget, e, {\n onMove: (ev) => {\n const screenPos = { x: ev.clientX, y: ev.clientY };\n const current = dragRef.current;\n if (!current) return;\n if (pendingPos.current !== null) {\n // A frame is already queued: keep the ghost under the cursor and\n // let that frame probe the drop target from the newest position.\n pendingPos.current = screenPos;\n dragRef.current = { ...current, screenPos };\n setDrag(dragRef.current);\n return;\n }\n pendingPos.current = screenPos;\n frameLoop.request();\n },\n onEnd: (ev) => {\n const screenPos = { x: ev.clientX, y: ev.clientY };\n const active = dragRef.current;\n clearDrag();\n if (!active || !isOverCanvas(screenPos)) return;\n const world = screenToWorldFromContainer(screenPos);\n if (!world) return;\n const live = liveRef.current;\n live.setState(live.capability.onDrop(world, active.item, live.state, live.config));\n live.emit('canvas.itemAdded');\n },\n // An interrupted gesture never named a destination, so it drops nothing.\n onCancel: clearDrag,\n });\n },\n [clearDrag, frameLoop, isOverCanvas, screenToWorldFromContainer],\n );\n\n useEffect(() => () => sessionRef.current?.cancel(), []);\n\n return { drag, startDrag };\n}\n\nexport interface DragOverlayProps {\n drag: DragState | null;\n}\n\nexport function DragOverlay({ drag }: DragOverlayProps) {\n if (!drag) return null;\n return <DragGhost item={drag.item} screenPos={drag.screenPos} />;\n}\n","import type { PointerEvent as ReactPointerEvent } from 'react';\nimport type { PaletteItem } from '../instrument/types';\n\nexport interface PaletteProps {\n items: PaletteItem[];\n onDragStart: (item: PaletteItem, e: ReactPointerEvent) => void;\n className?: string;\n}\n\nexport function Palette({ items, onDragStart, className }: PaletteProps) {\n return (\n <div className={className ? `lk-palette ${className}` : 'lk-palette'}>\n {items.map((item) => (\n <button\n type=\"button\"\n key={item.id}\n className=\"lk-palette__item\"\n onPointerDown={(e) => {\n e.preventDefault();\n onDragStart(item, e);\n }}\n >\n <span className=\"lk-palette__label\">{item.label}</span>\n </button>\n ))}\n </div>\n );\n}\n"]}
|
package/dist/chunk-TT5C5S6R.js
DELETED
|
@@ -1,368 +0,0 @@
|
|
|
1
|
-
import { zoomAt } from './chunk-H6ZAOWNE.js';
|
|
2
|
-
import { DEFAULT_FRAME, resolveFrame, screenToWorld } from './chunk-2AYGEN57.js';
|
|
3
|
-
import { useSurfaceOptional } from './chunk-WIG6XHJ7.js';
|
|
4
|
-
import { CanvasStackContext } from './chunk-CQLQPQ4P.js';
|
|
5
|
-
import { createContext, useRef, useCallback, useEffect, useState, useMemo, useContext } from 'react';
|
|
6
|
-
import { normalizeZoom, openPointerSession, useVisibleRaf } from '@weasel-js/core';
|
|
7
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
8
|
-
|
|
9
|
-
var CameraWheelContext = createContext(null);
|
|
10
|
-
var DEFAULT_VIEW = { zoom: 1, pan: { x: 0, y: 0 } };
|
|
11
|
-
function as2DView(view) {
|
|
12
|
-
if (typeof view !== "object" || view === null) return null;
|
|
13
|
-
const v = view;
|
|
14
|
-
if (typeof v.zoom !== "number") return null;
|
|
15
|
-
if (typeof v.pan !== "object" || v.pan === null) return null;
|
|
16
|
-
if (typeof v.pan.x !== "number" || typeof v.pan.y !== "number") return null;
|
|
17
|
-
return normalize2DView({ zoom: v.zoom, pan: { x: v.pan.x, y: v.pan.y } });
|
|
18
|
-
}
|
|
19
|
-
function normalize2DView(view) {
|
|
20
|
-
const zoom = normalizeZoom(view.zoom);
|
|
21
|
-
const x = Number.isFinite(view.pan.x) ? view.pan.x : 0;
|
|
22
|
-
const y = Number.isFinite(view.pan.y) ? view.pan.y : 0;
|
|
23
|
-
if (zoom === view.zoom && x === view.pan.x && y === view.pan.y) return view;
|
|
24
|
-
return { zoom, pan: { x, y } };
|
|
25
|
-
}
|
|
26
|
-
function withZoom(view, zoom) {
|
|
27
|
-
return normalize2DView({ zoom, pan: view.pan });
|
|
28
|
-
}
|
|
29
|
-
function useLayerScheduler({
|
|
30
|
-
layers,
|
|
31
|
-
view,
|
|
32
|
-
frame = DEFAULT_FRAME,
|
|
33
|
-
canvasRefs,
|
|
34
|
-
size,
|
|
35
|
-
host
|
|
36
|
-
}) {
|
|
37
|
-
const dirty = useRef(/* @__PURE__ */ new Set());
|
|
38
|
-
const lastRenderRef = useRef(/* @__PURE__ */ new Map());
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
for (const layer of layers) {
|
|
41
|
-
const prev = lastRenderRef.current.get(layer.id);
|
|
42
|
-
if (prev !== layer.render) dirty.current.add(layer.id);
|
|
43
|
-
lastRenderRef.current.set(layer.id, layer.render);
|
|
44
|
-
}
|
|
45
|
-
for (const id of [...lastRenderRef.current.keys()]) {
|
|
46
|
-
if (!layers.find((l) => l.id === id)) lastRenderRef.current.delete(id);
|
|
47
|
-
}
|
|
48
|
-
}, [layers]);
|
|
49
|
-
useEffect(() => {
|
|
50
|
-
for (const layer of layers) dirty.current.add(layer.id);
|
|
51
|
-
}, [view, frame, size, layers]);
|
|
52
|
-
const frameLoop = useVisibleRaf(
|
|
53
|
-
() => {
|
|
54
|
-
if (dirty.current.size === 0) return;
|
|
55
|
-
const map = canvasRefs.current;
|
|
56
|
-
if (!map) {
|
|
57
|
-
dirty.current.clear();
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
for (const layer of layers) {
|
|
61
|
-
if (!dirty.current.has(layer.id)) continue;
|
|
62
|
-
if (!layer.visible) continue;
|
|
63
|
-
const canvas = map.get(layer.id);
|
|
64
|
-
if (!canvas) continue;
|
|
65
|
-
const ctx = canvas.getContext("2d");
|
|
66
|
-
if (!ctx) continue;
|
|
67
|
-
ctx.save();
|
|
68
|
-
ctx.setTransform(size.dpr, 0, 0, size.dpr, 0, 0);
|
|
69
|
-
ctx.clearRect(0, 0, size.width, size.height);
|
|
70
|
-
layer.render(ctx, view, frame);
|
|
71
|
-
ctx.restore();
|
|
72
|
-
}
|
|
73
|
-
dirty.current.clear();
|
|
74
|
-
},
|
|
75
|
-
{ target: host }
|
|
76
|
-
);
|
|
77
|
-
useEffect(() => {
|
|
78
|
-
if (dirty.current.size > 0) frameLoop.request();
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
var DRAG_THRESHOLD = 3;
|
|
82
|
-
function isPositiveFinite(n) {
|
|
83
|
-
return Number.isFinite(n) && n > 0;
|
|
84
|
-
}
|
|
85
|
-
function usePanZoom({
|
|
86
|
-
view,
|
|
87
|
-
onViewChange,
|
|
88
|
-
minZoom = 0.1,
|
|
89
|
-
maxZoom = 32,
|
|
90
|
-
frame = DEFAULT_FRAME,
|
|
91
|
-
onTap
|
|
92
|
-
}) {
|
|
93
|
-
const dragRef = useRef(null);
|
|
94
|
-
const sessionRef = useRef(null);
|
|
95
|
-
const viewRef = useRef(normalize2DView(view));
|
|
96
|
-
viewRef.current = normalize2DView(view);
|
|
97
|
-
const onViewChangeRef = useRef(onViewChange);
|
|
98
|
-
onViewChangeRef.current = onViewChange;
|
|
99
|
-
const onTapRef = useRef(onTap);
|
|
100
|
-
onTapRef.current = onTap;
|
|
101
|
-
const initialZoomRef = useRef(isPositiveFinite(view.zoom) ? view.zoom : null);
|
|
102
|
-
const commit = useCallback((next) => {
|
|
103
|
-
viewRef.current = normalize2DView(next);
|
|
104
|
-
onViewChangeRef.current(next);
|
|
105
|
-
}, []);
|
|
106
|
-
const onWheel = useCallback(
|
|
107
|
-
(e, anchor) => {
|
|
108
|
-
const el = anchor ?? e.currentTarget;
|
|
109
|
-
if (!el) return;
|
|
110
|
-
e.preventDefault();
|
|
111
|
-
const rect = el.getBoundingClientRect();
|
|
112
|
-
const initialZoom = initialZoomRef.current;
|
|
113
|
-
commit(
|
|
114
|
-
zoomAt(
|
|
115
|
-
viewRef.current,
|
|
116
|
-
Math.exp(-e.deltaY * 1e-3),
|
|
117
|
-
{ x: e.clientX - rect.left, y: e.clientY - rect.top },
|
|
118
|
-
{
|
|
119
|
-
frame,
|
|
120
|
-
min: initialZoom == null ? minZoom : Math.min(minZoom, initialZoom),
|
|
121
|
-
max: initialZoom == null ? maxZoom : Math.max(maxZoom, initialZoom)
|
|
122
|
-
}
|
|
123
|
-
)
|
|
124
|
-
);
|
|
125
|
-
},
|
|
126
|
-
[commit, minZoom, maxZoom, frame]
|
|
127
|
-
);
|
|
128
|
-
const clearDrag = useCallback(() => {
|
|
129
|
-
dragRef.current = null;
|
|
130
|
-
sessionRef.current = null;
|
|
131
|
-
}, []);
|
|
132
|
-
const onPointerDown = useCallback(
|
|
133
|
-
(e) => {
|
|
134
|
-
if (e.button !== 0) return;
|
|
135
|
-
const drag = {
|
|
136
|
-
startScreenX: e.clientX,
|
|
137
|
-
startScreenY: e.clientY,
|
|
138
|
-
startPan: { ...viewRef.current.pan },
|
|
139
|
-
moved: false
|
|
140
|
-
};
|
|
141
|
-
dragRef.current = drag;
|
|
142
|
-
sessionRef.current = openPointerSession(e.currentTarget, e, {
|
|
143
|
-
onMove: (ev) => {
|
|
144
|
-
const dx = ev.clientX - drag.startScreenX;
|
|
145
|
-
const dy = ev.clientY - drag.startScreenY;
|
|
146
|
-
if (!drag.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;
|
|
147
|
-
drag.moved = true;
|
|
148
|
-
commit({
|
|
149
|
-
zoom: viewRef.current.zoom,
|
|
150
|
-
pan: { x: drag.startPan.x + dx, y: drag.startPan.y + dy }
|
|
151
|
-
});
|
|
152
|
-
},
|
|
153
|
-
onEnd: (ev) => {
|
|
154
|
-
const tapped = !drag.moved;
|
|
155
|
-
clearDrag();
|
|
156
|
-
if (tapped) onTapRef.current?.(ev);
|
|
157
|
-
},
|
|
158
|
-
// A cancelled pan keeps whatever it had already applied: every move
|
|
159
|
-
// was committed as it arrived, so there is nothing left to undo.
|
|
160
|
-
onCancel: clearDrag
|
|
161
|
-
});
|
|
162
|
-
},
|
|
163
|
-
[clearDrag, commit]
|
|
164
|
-
);
|
|
165
|
-
useEffect(() => () => sessionRef.current?.cancel(), []);
|
|
166
|
-
const isDragging = useCallback(() => dragRef.current?.moved === true, []);
|
|
167
|
-
return { onWheel, onPointerDown, isDragging };
|
|
168
|
-
}
|
|
169
|
-
function CanvasStack({
|
|
170
|
-
layers,
|
|
171
|
-
view: viewProp,
|
|
172
|
-
onViewChange,
|
|
173
|
-
worldSpec,
|
|
174
|
-
minZoom,
|
|
175
|
-
maxZoom,
|
|
176
|
-
width = "100%",
|
|
177
|
-
height = "100%",
|
|
178
|
-
className,
|
|
179
|
-
onResize,
|
|
180
|
-
onHitTest,
|
|
181
|
-
children
|
|
182
|
-
}) {
|
|
183
|
-
const view = normalize2DView(viewProp);
|
|
184
|
-
const containerRef = useRef(null);
|
|
185
|
-
const canvasMap = useRef(/* @__PURE__ */ new Map());
|
|
186
|
-
const [size, setSize] = useState({ width: 0, height: 0, dpr: 1 });
|
|
187
|
-
const setCanvasRef = (id, el) => {
|
|
188
|
-
if (el) canvasMap.current.set(id, el);
|
|
189
|
-
else canvasMap.current.delete(id);
|
|
190
|
-
};
|
|
191
|
-
useEffect(() => {
|
|
192
|
-
const el = containerRef.current;
|
|
193
|
-
if (!el) return;
|
|
194
|
-
const update = () => {
|
|
195
|
-
const rect = el.getBoundingClientRect();
|
|
196
|
-
const dpr = window.devicePixelRatio ?? 1;
|
|
197
|
-
setSize((prev) => {
|
|
198
|
-
if (prev.width === rect.width && prev.height === rect.height && prev.dpr === dpr) {
|
|
199
|
-
return prev;
|
|
200
|
-
}
|
|
201
|
-
return { width: rect.width, height: rect.height, dpr };
|
|
202
|
-
});
|
|
203
|
-
};
|
|
204
|
-
update();
|
|
205
|
-
if (typeof ResizeObserver === "undefined") return;
|
|
206
|
-
const ro = new ResizeObserver(update);
|
|
207
|
-
ro.observe(el);
|
|
208
|
-
return () => ro.disconnect();
|
|
209
|
-
}, []);
|
|
210
|
-
const onResizeRef = useRef(onResize);
|
|
211
|
-
onResizeRef.current = onResize;
|
|
212
|
-
useEffect(() => {
|
|
213
|
-
if (size.width === 0 && size.height === 0) return;
|
|
214
|
-
onResizeRef.current?.({ width: size.width, height: size.height });
|
|
215
|
-
}, [size.width, size.height]);
|
|
216
|
-
const frame = useMemo(() => resolveFrame(worldSpec, size), [worldSpec, size]);
|
|
217
|
-
const onTap = (e) => {
|
|
218
|
-
const el = containerRef.current;
|
|
219
|
-
if (!onHitTest || !el) return;
|
|
220
|
-
const rect = el.getBoundingClientRect();
|
|
221
|
-
onHitTest(screenToWorld({ x: e.clientX - rect.left, y: e.clientY - rect.top }, view, frame));
|
|
222
|
-
};
|
|
223
|
-
const handlers = usePanZoom({ view: viewProp, onViewChange, minZoom, maxZoom, frame, onTap });
|
|
224
|
-
const onWheelRef = useRef(handlers.onWheel);
|
|
225
|
-
onWheelRef.current = handlers.onWheel;
|
|
226
|
-
const wheelSlot = useContext(CameraWheelContext);
|
|
227
|
-
useEffect(() => {
|
|
228
|
-
const el = containerRef.current;
|
|
229
|
-
if (!el) return;
|
|
230
|
-
const wheel = (e) => onWheelRef.current(e, el);
|
|
231
|
-
el.addEventListener("wheel", wheel, { passive: false });
|
|
232
|
-
if (wheelSlot) wheelSlot.current = wheel;
|
|
233
|
-
return () => {
|
|
234
|
-
el.removeEventListener("wheel", wheel);
|
|
235
|
-
if (wheelSlot?.current === wheel) wheelSlot.current = null;
|
|
236
|
-
};
|
|
237
|
-
}, [wheelSlot]);
|
|
238
|
-
useLayerScheduler({ layers, view, frame, canvasRefs: canvasMap, size, host: containerRef });
|
|
239
|
-
const ctxValue = useMemo(
|
|
240
|
-
() => ({
|
|
241
|
-
view,
|
|
242
|
-
frame,
|
|
243
|
-
surface: { element: containerRef, size, canvases: canvasMap, layers }
|
|
244
|
-
}),
|
|
245
|
-
[view, frame, size, layers]
|
|
246
|
-
);
|
|
247
|
-
const containerStyle = { width, height };
|
|
248
|
-
const canvasPx = {
|
|
249
|
-
width: Math.max(0, Math.round(size.width * size.dpr)),
|
|
250
|
-
height: Math.max(0, Math.round(size.height * size.dpr))
|
|
251
|
-
};
|
|
252
|
-
const canvasCss = {
|
|
253
|
-
width: size.width,
|
|
254
|
-
height: size.height
|
|
255
|
-
};
|
|
256
|
-
return /* @__PURE__ */ jsx(CanvasStackContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxs(
|
|
257
|
-
"div",
|
|
258
|
-
{
|
|
259
|
-
ref: containerRef,
|
|
260
|
-
className: className ? `lk-canvas-stack ${className}` : "lk-canvas-stack",
|
|
261
|
-
style: containerStyle,
|
|
262
|
-
onPointerDown: handlers.onPointerDown,
|
|
263
|
-
children: [
|
|
264
|
-
layers.map((layer) => /* @__PURE__ */ jsx(
|
|
265
|
-
"canvas",
|
|
266
|
-
{
|
|
267
|
-
ref: (el) => setCanvasRef(layer.id, el),
|
|
268
|
-
className: "lk-canvas-stack__canvas",
|
|
269
|
-
width: canvasPx.width,
|
|
270
|
-
height: canvasPx.height,
|
|
271
|
-
style: { ...canvasCss, display: layer.visible ? "block" : "none" }
|
|
272
|
-
},
|
|
273
|
-
layer.id
|
|
274
|
-
)),
|
|
275
|
-
/* @__PURE__ */ jsx("div", { className: "lk-canvas-stack__overlay", children })
|
|
276
|
-
]
|
|
277
|
-
}
|
|
278
|
-
) });
|
|
279
|
-
}
|
|
280
|
-
function fitStage(size, viewport) {
|
|
281
|
-
if (!(size.width > 0 && size.height > 0 && viewport.width > 0 && viewport.height > 0)) {
|
|
282
|
-
return { zoom: 1, pan: { x: 0, y: 0 } };
|
|
283
|
-
}
|
|
284
|
-
const zoom = Math.min(1, viewport.width / size.width, viewport.height / size.height);
|
|
285
|
-
return {
|
|
286
|
-
zoom,
|
|
287
|
-
pan: {
|
|
288
|
-
x: (viewport.width - size.width * zoom) / 2,
|
|
289
|
-
y: (viewport.height - size.height * zoom) / 2
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
function Stage({
|
|
294
|
-
size,
|
|
295
|
-
view: viewProp,
|
|
296
|
-
onViewChange,
|
|
297
|
-
minZoom,
|
|
298
|
-
maxZoom,
|
|
299
|
-
onResize,
|
|
300
|
-
hostRef,
|
|
301
|
-
overlay,
|
|
302
|
-
children
|
|
303
|
-
}) {
|
|
304
|
-
const view = normalize2DView(viewProp);
|
|
305
|
-
const host = useRef(null);
|
|
306
|
-
const surface = useSurfaceOptional();
|
|
307
|
-
const handlers = usePanZoom({ view: viewProp, onViewChange, minZoom, maxZoom });
|
|
308
|
-
const onWheelRef = useRef(handlers.onWheel);
|
|
309
|
-
onWheelRef.current = handlers.onWheel;
|
|
310
|
-
const wheelSlot = useContext(CameraWheelContext);
|
|
311
|
-
useEffect(() => {
|
|
312
|
-
const el = host.current;
|
|
313
|
-
if (!el) return;
|
|
314
|
-
const wheel = (e) => onWheelRef.current(e, el);
|
|
315
|
-
el.addEventListener("wheel", wheel, { passive: false });
|
|
316
|
-
if (wheelSlot) wheelSlot.current = wheel;
|
|
317
|
-
return () => {
|
|
318
|
-
el.removeEventListener("wheel", wheel);
|
|
319
|
-
if (wheelSlot?.current === wheel) wheelSlot.current = null;
|
|
320
|
-
};
|
|
321
|
-
}, [wheelSlot]);
|
|
322
|
-
const onResizeRef = useRef(onResize);
|
|
323
|
-
onResizeRef.current = onResize;
|
|
324
|
-
useEffect(() => {
|
|
325
|
-
const el = host.current;
|
|
326
|
-
if (!el) return;
|
|
327
|
-
const measure = () => {
|
|
328
|
-
const rect = el.getBoundingClientRect();
|
|
329
|
-
if (rect.width > 0 && rect.height > 0) {
|
|
330
|
-
onResizeRef.current?.({ width: rect.width, height: rect.height });
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
measure();
|
|
334
|
-
if (typeof ResizeObserver === "undefined") return;
|
|
335
|
-
const ro = new ResizeObserver(measure);
|
|
336
|
-
ro.observe(el);
|
|
337
|
-
return () => ro.disconnect();
|
|
338
|
-
}, []);
|
|
339
|
-
useEffect(() => {
|
|
340
|
-
surface?.invalidateRects();
|
|
341
|
-
}, [surface, view.zoom, view.pan.x, view.pan.y]);
|
|
342
|
-
const camera = {
|
|
343
|
-
["--lk-stage-x"]: `${view.pan.x}px`,
|
|
344
|
-
["--lk-stage-y"]: `${view.pan.y}px`,
|
|
345
|
-
["--lk-stage-zoom"]: String(view.zoom),
|
|
346
|
-
["--lk-stage-w"]: `${size.width}px`,
|
|
347
|
-
["--lk-stage-h"]: `${size.height}px`
|
|
348
|
-
};
|
|
349
|
-
return /* @__PURE__ */ jsxs(
|
|
350
|
-
"div",
|
|
351
|
-
{
|
|
352
|
-
ref: (el) => {
|
|
353
|
-
host.current = el;
|
|
354
|
-
if (hostRef) hostRef.current = el;
|
|
355
|
-
},
|
|
356
|
-
className: "lk-stage",
|
|
357
|
-
onPointerDown: handlers.onPointerDown,
|
|
358
|
-
children: [
|
|
359
|
-
/* @__PURE__ */ jsx("div", { className: "lk-stage__content", style: camera, children }),
|
|
360
|
-
overlay
|
|
361
|
-
]
|
|
362
|
-
}
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
export { CameraWheelContext, CanvasStack, DEFAULT_VIEW, Stage, as2DView, fitStage, usePanZoom, withZoom };
|
|
367
|
-
//# sourceMappingURL=chunk-TT5C5S6R.js.map
|
|
368
|
-
//# sourceMappingURL=chunk-TT5C5S6R.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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"]}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
3
|
-
|
|
4
|
-
/** One card in a layer stack: its identity, the label shown when collapsed,
|
|
5
|
-
* and the optional select hoisted into its header. */
|
|
6
|
-
interface LayerStackItem {
|
|
7
|
-
/** Stable id used for keys, onRemove, onReorder. Numeric to match
|
|
8
|
-
* common id-from-nextId conventions; string ids also work. */
|
|
9
|
-
id: number | string;
|
|
10
|
-
/** Short kind label rendered in the header when no primary select
|
|
11
|
-
* is hoisted (e.g. "shadow", "stroke"). Omit it for items that have no
|
|
12
|
-
* kind; `label` then names the card. */
|
|
13
|
-
kind?: string;
|
|
14
|
-
/** Header text, when the item's name is not its kind. Falls back to
|
|
15
|
-
* `kind`. */
|
|
16
|
-
label?: string;
|
|
17
|
-
/** When present, hoist this select into the card header so the user
|
|
18
|
-
* can switch mode/shape without expanding. */
|
|
19
|
-
primaryValue?: string;
|
|
20
|
-
primaryOptions?: string[];
|
|
21
|
-
/** Accent CSS color used as the left border / index-badge fill. Sets
|
|
22
|
-
* --wzl-layer-stack-accent on the card, which re-binds --wzl-accent
|
|
23
|
-
* for everything inside it. */
|
|
24
|
-
accent?: string;
|
|
25
|
-
/** Optional badge text rendered before the primary control
|
|
26
|
-
* (e.g. tail index "1", "2", "3"). When omitted a drag handle
|
|
27
|
-
* glyph renders in its place. */
|
|
28
|
-
badge?: string;
|
|
29
|
-
/** Initial expanded state. Defaults to true for newly-added items. */
|
|
30
|
-
defaultExpanded?: boolean;
|
|
31
|
-
}
|
|
32
|
-
/** Props for `<LayerStack>`. */
|
|
33
|
-
interface LayerStackProps {
|
|
34
|
-
/** Heading above the list. Omit it, along with the palette, for a stack
|
|
35
|
-
* whose surroundings already name it. */
|
|
36
|
-
title?: string;
|
|
37
|
-
items: LayerStackItem[];
|
|
38
|
-
/** Kinds the user can add via the header palette. Omit both this and
|
|
39
|
-
* `onAdd` for a stack the user cannot add to. */
|
|
40
|
-
paletteKinds?: string[];
|
|
41
|
-
onAdd?: (kind: string) => void;
|
|
42
|
-
/** Omit for items the user cannot remove; the card then has no ✕. */
|
|
43
|
-
onRemove?: (id: number | string) => void;
|
|
44
|
-
onReorder: (orderedIds: Array<number | string>) => void;
|
|
45
|
-
/** Required for `primaryValue` to render as a select — without a handler
|
|
46
|
-
* the control could not be changed. */
|
|
47
|
-
onPrimaryChange?: (id: number | string, nextValue: string) => void;
|
|
48
|
-
/** Render the body controls for each item. */
|
|
49
|
-
renderBody: (item: LayerStackItem) => ReactNode;
|
|
50
|
-
/** Shown in place of the list when `items` is empty. Defaults to a line
|
|
51
|
-
* that points at the palette, or a bare one when there is no palette. */
|
|
52
|
-
emptyLabel?: ReactNode;
|
|
53
|
-
/** Hide the title + palette row (used when an outer wrap renders its
|
|
54
|
-
* own head — see speech-balloons Tails panel). */
|
|
55
|
-
hideHead?: boolean;
|
|
56
|
-
/** Appended to the root element's class list. The module's own class names
|
|
57
|
-
* are hashed, so this is the supported way to reach the stack from a
|
|
58
|
-
* consumer stylesheet. */
|
|
59
|
-
className?: string;
|
|
60
|
-
}
|
|
61
|
-
/** A drag-reorderable stack of expandable cards, with a palette in the header
|
|
62
|
-
* for adding more. The body of each card is the caller's to render. */
|
|
63
|
-
declare function LayerStack({ className, title, items, paletteKinds, onAdd, onRemove, onReorder, onPrimaryChange, renderBody, emptyLabel, hideHead, }: LayerStackProps): react_jsx_runtime.JSX.Element;
|
|
64
|
-
|
|
65
|
-
export { LayerStack };
|
|
66
|
-
export type { LayerStackItem, LayerStackProps };
|
package/dist/ui/layers/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|