@pixerate/editor 0.27.0 → 0.29.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 +44 -2
- package/dist/HistoryManager-DWSLd6Tf.d.ts +150 -0
- package/dist/HistoryManager-DeQQMBCj.d.cts +150 -0
- package/dist/agent/index.cjs +20 -427
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +4 -342
- package/dist/agent/index.d.ts +4 -342
- package/dist/agent/index.js +14 -421
- package/dist/agent/index.js.map +1 -1
- package/dist/animation/index.cjs +62 -0
- package/dist/animation/index.cjs.map +1 -0
- package/dist/animation/index.d.cts +226 -0
- package/dist/animation/index.d.ts +226 -0
- package/dist/animation/index.js +62 -0
- package/dist/animation/index.js.map +1 -0
- package/dist/{builtins-nMXh9sT3.d.cts → builtins-DxC3aUR2.d.cts} +2 -2
- package/dist/{builtins-haN82vjT.d.ts → builtins-NGxNxQfJ.d.ts} +2 -2
- package/dist/canvas/index.cjs +177 -743
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +6 -289
- package/dist/canvas/index.d.ts +6 -289
- package/dist/canvas/index.js +49 -615
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-36BLROHV.js +438 -0
- package/dist/chunk-36BLROHV.js.map +1 -0
- package/dist/{chunk-JT7AXQTE.js → chunk-3RPOW4CS.js} +7 -7
- package/dist/{chunk-AGR7EVRW.cjs → chunk-6MDQKHRH.cjs} +6 -6
- package/dist/{chunk-AGR7EVRW.cjs.map → chunk-6MDQKHRH.cjs.map} +1 -1
- package/dist/chunk-A6PHCAGX.cjs +87 -0
- package/dist/chunk-A6PHCAGX.cjs.map +1 -0
- package/dist/{chunk-HRMEDT2L.js → chunk-D6AVOTSD.js} +6 -85
- package/dist/chunk-D6AVOTSD.js.map +1 -0
- package/dist/{chunk-ARRTP33I.js → chunk-D6S5M7HV.js} +2 -2
- package/dist/{chunk-ARRTP33I.js.map → chunk-D6S5M7HV.js.map} +1 -1
- package/dist/{chunk-6IO7WUSU.js → chunk-DDADOHJW.js} +17 -17
- package/dist/{chunk-CPOKFNBG.cjs → chunk-I6BZB5ZH.cjs} +2 -2
- package/dist/{chunk-CPOKFNBG.cjs.map → chunk-I6BZB5ZH.cjs.map} +1 -1
- package/dist/{chunk-4BVP64JJ.cjs → chunk-K2UYKJ6M.cjs} +24 -103
- package/dist/chunk-K2UYKJ6M.cjs.map +1 -0
- package/dist/chunk-PIIAZV3L.cjs +244 -0
- package/dist/chunk-PIIAZV3L.cjs.map +1 -0
- package/dist/chunk-PWJARCI4.js +637 -0
- package/dist/chunk-PWJARCI4.js.map +1 -0
- package/dist/{chunk-G2I4QJOT.cjs → chunk-QKLRAA4T.cjs} +3 -244
- package/dist/chunk-QKLRAA4T.cjs.map +1 -0
- package/dist/{chunk-2H7ZHPEJ.js → chunk-QVZZGT4X.js} +1 -242
- package/dist/chunk-QVZZGT4X.js.map +1 -0
- package/dist/chunk-TGD52FEZ.js +87 -0
- package/dist/chunk-TGD52FEZ.js.map +1 -0
- package/dist/chunk-TTYCN6ZH.cjs +637 -0
- package/dist/chunk-TTYCN6ZH.cjs.map +1 -0
- package/dist/{chunk-YK5TATOF.cjs → chunk-U7VGDSNY.cjs} +3 -3
- package/dist/{chunk-YK5TATOF.cjs.map → chunk-U7VGDSNY.cjs.map} +1 -1
- package/dist/chunk-V7CC7RZ6.cjs +438 -0
- package/dist/chunk-V7CC7RZ6.cjs.map +1 -0
- package/dist/chunk-YK57D7PW.js +244 -0
- package/dist/chunk-YK57D7PW.js.map +1 -0
- package/dist/commands/index.cjs +2 -2
- package/dist/commands/index.cjs.map +1 -1
- package/dist/commands/index.d.cts +2 -2
- package/dist/commands/index.d.ts +2 -2
- package/dist/commands/index.js +1 -1
- package/dist/commands/index.js.map +1 -1
- package/dist/easing-B6iAnJHk.d.cts +74 -0
- package/dist/easing-B6iAnJHk.d.ts +74 -0
- package/dist/extensions/index.cjs +5 -5
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.js +4 -4
- package/dist/generation/index.cjs +4 -4
- package/dist/generation/index.cjs.map +1 -1
- package/dist/generation/index.js +3 -3
- package/dist/generation/index.js.map +1 -1
- package/dist/history/index.cjs +4 -2
- package/dist/history/index.cjs.map +1 -1
- package/dist/history/index.d.cts +3 -149
- package/dist/history/index.d.ts +3 -149
- package/dist/history/index.js +5 -3
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.js.map +1 -1
- package/dist/index.cjs +24 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +112 -110
- package/dist/index.js.map +1 -1
- package/dist/parameters/index.cjs +1283 -0
- package/dist/parameters/index.cjs.map +1 -0
- package/dist/parameters/index.d.cts +595 -0
- package/dist/parameters/index.d.ts +595 -0
- package/dist/parameters/index.js +1283 -0
- package/dist/parameters/index.js.map +1 -0
- package/dist/spreadsheet/index.cjs +4 -4
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.js +8 -8
- package/dist/tokens/index.cjs +4 -2
- package/dist/tokens/index.cjs.map +1 -1
- package/dist/tokens/index.js +6 -4
- package/dist/tools/index.cjs +31 -0
- package/dist/tools/index.cjs.map +1 -0
- package/dist/tools/index.d.cts +343 -0
- package/dist/tools/index.d.ts +343 -0
- package/dist/tools/index.js +31 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/{types-GT5a5YAX.d.cts → types-DsiXGmjo.d.cts} +1 -1
- package/dist/{types-GT5a5YAX.d.ts → types-DsiXGmjo.d.ts} +1 -1
- package/package.json +16 -1
- package/dist/chunk-2H7ZHPEJ.js.map +0 -1
- package/dist/chunk-4BVP64JJ.cjs.map +0 -1
- package/dist/chunk-G2I4QJOT.cjs.map +0 -1
- package/dist/chunk-HRMEDT2L.js.map +0 -1
- /package/dist/{chunk-JT7AXQTE.js.map → chunk-3RPOW4CS.js.map} +0 -0
- /package/dist/{chunk-6IO7WUSU.js.map → chunk-DDADOHJW.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/animation/easing.ts","../src/animation/color.ts","../src/animation/keyframes.ts","../src/animation/evaluate.ts","../src/animation/clock.ts","../src/animation/player.ts"],"sourcesContent":["// Portions ported from filmcraft-main/crates/project/src/keyframe.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * Keyframe easing: the curve a segment follows from one keyframe to the next.\n *\n * - `hold` keeps the first keyframe's value until the next one (a step).\n * - `linear` and the CSS presets (`ease`, `ease-in`, `ease-out`, `ease-in-out`) are\n * CSS-compatible `cubic-bezier()` curves; `{ type: 'cubic-bezier', x1, y1, x2, y2 }` is any\n * such curve (x1 / y1 is the leaving keyframe's out handle, x2 / y2 the next one's in handle).\n * - `spring` is a damped spring settling on the next value (it may overshoot).\n */\n\n/** Named easing presets. */\nexport type AnimationEasingPreset =\n\t| 'linear'\n\t| 'hold'\n\t| 'ease'\n\t| 'ease-in'\n\t| 'ease-out'\n\t| 'ease-in-out'\n\t| 'ease-in-back'\n\t| 'ease-out-back'\n\t| 'spring';\n\nexport interface CubicBezierEasing {\n\ttype: 'cubic-bezier';\n\tx1: number;\n\ty1: number;\n\tx2: number;\n\ty2: number;\n}\n\nexport interface SpringEasing {\n\ttype: 'spring';\n\t/** Spring stiffness (default 170). */\n\tstiffness?: number;\n\t/** Damping (default 26). */\n\tdamping?: number;\n\t/** Mass (default 1). */\n\tmass?: number;\n\t/** Initial velocity in units of the segment's value change per second (default 0). */\n\tvelocity?: number;\n}\n\nexport type AnimationEasing = AnimationEasingPreset | CubicBezierEasing | SpringEasing;\n\n/** Preset names, in picker order. */\nexport const ANIMATION_EASING_PRESETS: readonly AnimationEasingPreset[] = [\n\t'linear',\n\t'ease',\n\t'ease-in',\n\t'ease-out',\n\t'ease-in-out',\n\t'ease-in-back',\n\t'ease-out-back',\n\t'spring',\n\t'hold'\n];\n\n/** Picker labels for the presets. */\nexport const ANIMATION_EASING_LABELS: Readonly<Record<AnimationEasingPreset, string>> = {\n\tlinear: 'Linear',\n\thold: 'Hold',\n\tease: 'Ease',\n\t'ease-in': 'Ease in',\n\t'ease-out': 'Ease out',\n\t'ease-in-out': 'Ease in-out',\n\t'ease-in-back': 'Back in',\n\t'ease-out-back': 'Back out',\n\tspring: 'Spring'\n};\n\n/** The CSS control points of the bezier presets (CSS Easing Functions Level 1 values for the CSS keywords). */\nexport const CUBIC_BEZIER_PRESETS: Readonly<Record<string, readonly [number, number, number, number]>> = {\n\tlinear: [0, 0, 1, 1],\n\tease: [0.25, 0.1, 0.25, 1],\n\t'ease-in': [0.42, 0, 1, 1],\n\t'ease-out': [0, 0, 0.58, 1],\n\t'ease-in-out': [0.42, 0, 0.58, 1],\n\t'ease-in-back': [0.36, 0, 0.66, -0.56],\n\t'ease-out-back': [0.34, 1.56, 0.64, 1]\n};\n\nconst DEFAULT_SPRING = { stiffness: 170, damping: 26, mass: 1, velocity: 0 };\n\nconst clamp = (v: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, v));\nconst finite = (v: unknown, fallback: number) => (typeof v === 'number' && Number.isFinite(v) ? v : fallback);\n\n/**\n * Solves a CSS `cubic-bezier(x1, y1, x2, y2)` for y at progress x (Newton steps with a\n * bisection fallback). x1 / x2 are clamped to 0–1 as CSS requires.\n */\nexport function cubicBezierAt(x1: number, y1: number, x2: number, y2: number, x: number): number {\n\tif (x <= 0) return 0;\n\tif (x >= 1) return 1;\n\tx1 = clamp(x1, 0, 1);\n\tx2 = clamp(x2, 0, 1);\n\tconst bx = (s: number) => 3 * (1 - s) * (1 - s) * s * x1 + 3 * (1 - s) * s * s * x2 + s * s * s;\n\tconst by = (s: number) => 3 * (1 - s) * (1 - s) * s * y1 + 3 * (1 - s) * s * s * y2 + s * s * s;\n\tconst dbx = (s: number) => 3 * (1 - s) * (1 - s) * x1 + 6 * (1 - s) * s * (x2 - x1) + 3 * s * s * (1 - x2);\n\tlet s = x;\n\tfor (let i = 0; i < 8; i++) {\n\t\tconst d = dbx(s);\n\t\tif (Math.abs(d) < 1e-9) break;\n\t\tconst next = s - (bx(s) - x) / d;\n\t\tif (!(next >= 0 && next <= 1)) break;\n\t\ts = next;\n\t}\n\tif (Math.abs(bx(s) - x) > 1e-7) {\n\t\tlet lo = 0;\n\t\tlet hi = 1;\n\t\tfor (let i = 0; i < 60; i++) {\n\t\t\ts = (lo + hi) / 2;\n\t\t\tif (bx(s) < x) lo = s;\n\t\t\telse hi = s;\n\t\t}\n\t}\n\treturn by(s);\n}\n\n/**\n * Normalised position of a damped spring released from 0 towards 1, `seconds` after release.\n * Closed form for under-, critically and over-damped springs.\n */\nexport function springAt(spring: Omit<SpringEasing, 'type'>, seconds: number): number {\n\tconst stiffness = Math.max(1e-6, finite(spring.stiffness, DEFAULT_SPRING.stiffness));\n\tconst damping = Math.max(0, finite(spring.damping, DEFAULT_SPRING.damping));\n\tconst mass = Math.max(1e-6, finite(spring.mass, DEFAULT_SPRING.mass));\n\tconst v0 = -finite(spring.velocity, DEFAULT_SPRING.velocity);\n\tconst t = Math.max(0, seconds);\n\tconst w0 = Math.sqrt(stiffness / mass);\n\tconst zeta = damping / (2 * Math.sqrt(stiffness * mass));\n\t// x(t) is the displacement from the target (starts at 1); progress = 1 - x.\n\tlet x: number;\n\tif (zeta < 1 - 1e-6) {\n\t\tconst wd = w0 * Math.sqrt(1 - zeta * zeta);\n\t\tx = Math.exp(-zeta * w0 * t) * (Math.cos(wd * t) + ((zeta * w0 + v0) / wd) * Math.sin(wd * t));\n\t} else if (zeta <= 1 + 1e-6) {\n\t\tx = Math.exp(-w0 * t) * (1 + (w0 + v0) * t);\n\t} else {\n\t\tconst r = Math.sqrt(zeta * zeta - 1);\n\t\tconst s1 = -w0 * (zeta - r);\n\t\tconst s2 = -w0 * (zeta + r);\n\t\tconst c2 = (v0 - s1) / (s2 - s1);\n\t\tconst c1 = 1 - c2;\n\t\tx = c1 * Math.exp(s1 * t) + c2 * Math.exp(s2 * t);\n\t}\n\treturn 1 - x;\n}\n\n/** Resolves an easing to a cubic-bezier, spring or hold descriptor (unknown input → linear). */\nexport function resolveEasing(easing: AnimationEasing | string | undefined | null): CubicBezierEasing | Required<SpringEasing> | 'hold' {\n\tif (easing === 'hold') return 'hold';\n\tif (easing === 'spring') return { type: 'spring', ...DEFAULT_SPRING };\n\tif (typeof easing === 'string') {\n\t\tconst preset = CUBIC_BEZIER_PRESETS[easing];\n\t\tif (preset) return { type: 'cubic-bezier', x1: preset[0], y1: preset[1], x2: preset[2], y2: preset[3] };\n\t\tconst parsed = parseCssEasing(easing);\n\t\treturn parsed ? resolveEasing(parsed) : { type: 'cubic-bezier', x1: 0, y1: 0, x2: 1, y2: 1 };\n\t}\n\tif (easing && typeof easing === 'object') {\n\t\tif (easing.type === 'spring') {\n\t\t\treturn {\n\t\t\t\ttype: 'spring',\n\t\t\t\tstiffness: finite(easing.stiffness, DEFAULT_SPRING.stiffness),\n\t\t\t\tdamping: finite(easing.damping, DEFAULT_SPRING.damping),\n\t\t\t\tmass: finite(easing.mass, DEFAULT_SPRING.mass),\n\t\t\t\tvelocity: finite(easing.velocity, DEFAULT_SPRING.velocity)\n\t\t\t};\n\t\t}\n\t\tif (easing.type === 'cubic-bezier') {\n\t\t\treturn {\n\t\t\t\ttype: 'cubic-bezier',\n\t\t\t\tx1: clamp(finite(easing.x1, 0), 0, 1),\n\t\t\t\ty1: finite(easing.y1, 0),\n\t\t\t\tx2: clamp(finite(easing.x2, 1), 0, 1),\n\t\t\t\ty2: finite(easing.y2, 1)\n\t\t\t};\n\t\t}\n\t}\n\treturn { type: 'cubic-bezier', x1: 0, y1: 0, x2: 1, y2: 1 };\n}\n\n/**\n * Eased progress for linear progress `u` (0–1) through a segment lasting `durationMs`\n * (springs depend on real time; other curves ignore it). `hold` returns 0 until `u` reaches 1.\n */\nexport function evaluateEasing(easing: AnimationEasing | string | undefined | null, u: number, durationMs = 1000): number {\n\tif (!(u > 0)) return 0;\n\tif (u >= 1) return 1;\n\tconst resolved = resolveEasing(easing);\n\tif (resolved === 'hold') return 0;\n\tif (resolved.type === 'spring') return springAt(resolved, (u * Math.max(0, durationMs)) / 1000);\n\tconst { x1, y1, x2, y2 } = resolved;\n\tif (x1 === y1 && x2 === y2) return u; // linear\n\treturn cubicBezierAt(x1, y1, x2, y2, u);\n}\n\n/**\n * The easing filmcraft (and Premiere) derive from temporal \"influence\" handles: flat handles of\n * the given influences (0.01–1, default 1/3) on the leaving and arriving keyframe.\n */\nexport function easingFromInfluence(outInfluence = 1 / 3, inInfluence = 1 / 3): CubicBezierEasing {\n\treturn {\n\t\ttype: 'cubic-bezier',\n\t\tx1: clamp(outInfluence, 0.01, 1),\n\t\ty1: 0,\n\t\tx2: 1 - clamp(inInfluence, 0.01, 1),\n\t\ty2: 1\n\t};\n}\n\nconst NUMBER = String.raw`\\s*(-?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?)\\s*`;\nconst CUBIC_RE = new RegExp(`^cubic-bezier\\\\(${NUMBER},${NUMBER},${NUMBER},${NUMBER}\\\\)$`, 'i');\n\n/**\n * Parses a CSS easing (`linear`, `ease…`, `cubic-bezier(…)`, `steps(1, end)` / `step-end` →\n * hold) or a preset name. Returns `null` for anything else.\n */\nexport function parseCssEasing(text: string): AnimationEasing | null {\n\tconst value = text.trim().toLowerCase();\n\tif (value.length > 200) return null;\n\tif ((ANIMATION_EASING_PRESETS as readonly string[]).includes(value)) return value as AnimationEasingPreset;\n\tif (value === 'step-end' || /^steps\\(\\s*1\\s*(,\\s*(end|jump-end)\\s*)?\\)$/.test(value)) return 'hold';\n\tconst m = CUBIC_RE.exec(value);\n\tif (!m) return null;\n\tconst [x1, y1, x2, y2] = m.slice(1).map(Number);\n\tif (![x1, y1, x2, y2].every(Number.isFinite) || x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1) return null;\n\treturn { type: 'cubic-bezier', x1, y1, x2, y2 };\n}\n\n/** Whether a value is a usable easing (preset name, CSS easing string or descriptor). */\nexport function isAnimationEasing(value: unknown): value is AnimationEasing {\n\tif (typeof value === 'string') return parseCssEasing(value) !== null;\n\tif (typeof value !== 'object' || value === null) return false;\n\tconst e = value as Record<string, unknown>;\n\tif (e.type === 'spring') return true;\n\treturn e.type === 'cubic-bezier' && [e.x1, e.y1, e.x2, e.y2].every((v) => typeof v === 'number' && Number.isFinite(v));\n}\n\nconst round = (v: number, digits = 4) => {\n\tconst p = 10 ** digits;\n\treturn Math.round(v * p) / p;\n};\n\n/**\n * The CSS `animation-timing-function` for an easing: a keyword or `cubic-bezier()`,\n * `steps(1, end)` for hold, and a sampled `linear(…)` for springs over `durationMs`.\n */\nexport function easingToCss(easing: AnimationEasing | string | undefined | null, durationMs = 1000, samples = 24): string {\n\tconst resolved = resolveEasing(easing);\n\tif (resolved === 'hold') return 'steps(1, end)';\n\tif (resolved.type === 'spring') {\n\t\tconst n = Math.max(2, Math.floor(samples));\n\t\tconst points: string[] = [];\n\t\tfor (let i = 0; i <= n; i++) points.push(String(round(i === n ? 1 : springAt(resolved, ((i / n) * durationMs) / 1000))));\n\t\treturn `linear(${points.join(', ')})`;\n\t}\n\tconst { x1, y1, x2, y2 } = resolved;\n\tfor (const [name, p] of Object.entries(CUBIC_BEZIER_PRESETS)) {\n\t\tif (['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out'].includes(name) && p[0] === x1 && p[1] === y1 && p[2] === x2 && p[3] === y2) {\n\t\t\treturn name;\n\t\t}\n\t}\n\treturn `cubic-bezier(${round(x1)}, ${round(y1)}, ${round(x2)}, ${round(y2)})`;\n}\n\n/** Short label for an easing (a preset's label, or `Custom` / `Spring`). */\nexport function easingLabel(easing: AnimationEasing | undefined | null): string {\n\tif (easing === undefined || easing === null) return ANIMATION_EASING_LABELS.linear;\n\tif (typeof easing === 'string') return ANIMATION_EASING_LABELS[easing as AnimationEasingPreset] ?? easing;\n\treturn easing.type === 'spring' ? 'Spring' : 'Custom';\n}\n","import { hexToRgba, normalizeTokenColor, rgbaToHex } from '../tokens/color.js';\n\n/**\n * Colour interpolation in OKLab (Björn Ottosson's perceptual space, as CSS Color 4 uses for\n * `color-mix(in oklab, …)`), with premultiplied alpha so a fade to `transparent` does not\n * darken through black.\n */\n\nexport interface OklabColor {\n\t/** Lightness, 0–1. */\n\tl: number;\n\ta: number;\n\tb: number;\n\t/** Alpha, 0–1. */\n\talpha: number;\n}\n\nconst toLinear = (c: number) => (c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);\nconst toGamma = (c: number) => (c <= 0.0031308 ? 12.92 * c : 1.055 * Math.sign(c) * Math.abs(c) ** (1 / 2.4) - 0.055);\n\n/** sRGB channels (0–1) to OKLab. */\nexport function rgbToOklab(r: number, g: number, b: number, alpha = 1): OklabColor {\n\tconst lr = toLinear(r);\n\tconst lg = toLinear(g);\n\tconst lb = toLinear(b);\n\tconst l = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);\n\tconst m = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);\n\tconst s = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);\n\treturn {\n\t\tl: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n\t\ta: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n\t\tb: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,\n\t\talpha\n\t};\n}\n\n/** OKLab to sRGB channels (0–1, clamped into gamut). */\nexport function oklabToRgb(color: OklabColor): { r: number; g: number; b: number; a: number } {\n\tconst l_ = color.l + 0.3963377774 * color.a + 0.2158037573 * color.b;\n\tconst m_ = color.l - 0.1055613458 * color.a - 0.0638541728 * color.b;\n\tconst s_ = color.l - 0.0894841775 * color.a - 1.291485548 * color.b;\n\tconst l = l_ ** 3;\n\tconst m = m_ ** 3;\n\tconst s = s_ ** 3;\n\tconst clamp01 = (v: number) => Math.min(1, Math.max(0, v));\n\treturn {\n\t\tr: clamp01(toGamma(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s)),\n\t\tg: clamp01(toGamma(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s)),\n\t\tb: clamp01(toGamma(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s)),\n\t\ta: clamp01(color.alpha)\n\t};\n}\n\n/** Parses a CSS colour (hex, `rgb()` / `rgba()`, `transparent`, `black`, `white`) to OKLab, or `null`. */\nexport function parseOklab(input: unknown): OklabColor | null {\n\tconst hex = normalizeTokenColor(input);\n\tif (hex === null) return null;\n\tconst c = hexToRgba(hex)!;\n\treturn rgbToOklab(c.r, c.g, c.b, c.a);\n}\n\n/** Formats OKLab as `#rrggbb` (or `#rrggbbaa` when translucent). */\nexport function formatOklab(color: OklabColor): string {\n\tconst { r, g, b, a } = oklabToRgb(color);\n\treturn rgbaToHex(r, g, b, a);\n}\n\n/**\n * Mixes two colours at `t` (0 = `from`, 1 = `to`) in OKLab with premultiplied alpha.\n * Returns `null` when either is not a readable colour.\n */\nexport function mixColorsOklab(from: unknown, to: unknown, t: number): string | null {\n\tconst a = parseOklab(from);\n\tconst b = parseOklab(to);\n\tif (!a || !b) return null;\n\tconst alpha = a.alpha + (b.alpha - a.alpha) * t;\n\tconst premul = (k: 'l' | 'a' | 'b') => a[k] * a.alpha + (b[k] * b.alpha - a[k] * a.alpha) * t;\n\tif (alpha <= 1e-9) return formatOklab({ l: a.l + (b.l - a.l) * t, a: 0, b: 0, alpha: 0 });\n\treturn formatOklab({ l: premul('l') / alpha, a: premul('a') / alpha, b: premul('b') / alpha, alpha });\n}\n","// Portions ported from filmcraft-main/crates/project/src/keyframe.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\nimport { isAnimationEasing, type AnimationEasing } from './easing.js';\n\n/**\n * Keyframe tracks, independent of what they animate: each track is a list of keyframes\n * `{ time (ms), value, easing }`, where the easing governs the segment *leaving* the keyframe\n * (filmcraft / After Effects convention).\n */\n\n/** Keyframe times closer than this (ms) are the same time. */\nexport const ANIMATION_TIME_EPSILON = 1e-6;\n\n/** A keyframe value: a number, or a CSS colour for colour properties. */\nexport type AnimationValue = number | string;\n\nexport interface AnimationKeyframe {\n\t/** Time in milliseconds from the start of the timeline. */\n\ttime: number;\n\tvalue: AnimationValue;\n\t/** Easing of the segment from this keyframe to the next (default `linear`). */\n\teasing?: AnimationEasing;\n}\n\nexport interface AnimationTrack {\n\tkeyframes: AnimationKeyframe[];\n\t/** Disabled tracks keep their keyframes but do not animate (default `true`). */\n\tenabled?: boolean;\n}\n\n/** How a track's values interpolate: numbers linearly, colours in OKLab. */\nexport type AnimationValueType = 'number' | 'color';\n\nfunction isValue(value: unknown): value is AnimationValue {\n\treturn (typeof value === 'number' && Number.isFinite(value)) || typeof value === 'string';\n}\n\n/** Whether `value` is a well-formed keyframe. */\nexport function isAnimationKeyframe(value: unknown): value is AnimationKeyframe {\n\tif (typeof value !== 'object' || value === null) return false;\n\tconst k = value as Record<string, unknown>;\n\treturn (\n\t\ttypeof k.time === 'number' &&\n\t\tNumber.isFinite(k.time) &&\n\t\tisValue(k.value) &&\n\t\t(k.easing === undefined || isAnimationEasing(k.easing))\n\t);\n}\n\nconst sortedCache = new WeakMap<readonly AnimationKeyframe[], { items: AnimationKeyframe[]; out: AnimationKeyframe[] }>();\n\n/**\n * Keyframes sorted by time, invalid entries dropped and duplicate times merged (the *later*\n * entry in the array wins, so appending a keyframe replaces one at the same time). Cached per\n * array (revalidated by element identity), so evaluating every frame does not re-sort; treat\n * keyframe objects as immutable.\n */\nexport function normalizeKeyframes(keyframes: readonly AnimationKeyframe[] | undefined | null): AnimationKeyframe[] {\n\tif (!Array.isArray(keyframes)) return [];\n\tconst cached = sortedCache.get(keyframes);\n\t// The array may have been edited in place since: reuse only while it holds the same keyframes.\n\tif (cached && cached.items.length === keyframes.length && cached.items.every((k, i) => k === keyframes[i])) return cached.out;\n\tconst indexed = keyframes\n\t\t.map((k, i) => ({ k, i }))\n\t\t.filter(({ k }) => isAnimationKeyframe(k))\n\t\t.sort((a, b) => a.k.time - b.k.time || a.i - b.i);\n\tconst out: AnimationKeyframe[] = [];\n\tlet lastIndex = -1;\n\tfor (const { k, i } of indexed) {\n\t\tconst prev = out[out.length - 1];\n\t\tif (prev && Math.abs(k.time - prev.time) <= ANIMATION_TIME_EPSILON) {\n\t\t\tif (i > lastIndex) {\n\t\t\t\tout[out.length - 1] = k;\n\t\t\t\tlastIndex = i;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tout.push(k);\n\t\tlastIndex = i;\n\t}\n\tsortedCache.set(keyframes, { items: [...keyframes], out });\n\treturn out;\n}\n","// Portions ported from filmcraft-main/crates/project/src/keyframe.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\nimport { mixColorsOklab } from './color.js';\nimport { evaluateEasing } from './easing.js';\nimport { normalizeKeyframes, type AnimationKeyframe, type AnimationTrack, type AnimationValue, type AnimationValueType } from './keyframes.js';\n\n/** How time past the end of the timeline maps back into it. */\nexport type AnimationLoopMode = 'none' | 'loop' | 'ping-pong';\n\n/**\n * Interpolates between two keyframe values: numbers linearly, colours in OKLab (premultiplied\n * alpha). Mismatched or unreadable values hold `from` until `t` reaches 1.\n */\nexport function interpolateAnimationValue(from: AnimationValue, to: AnimationValue, t: number, type: AnimationValueType = 'number'): AnimationValue {\n\t// Numbers extrapolate, so overshooting easings (back, spring) overshoot the value too.\n\tif (typeof from === 'number' && typeof to === 'number') return from + (to - from) * t;\n\tif (t <= 0) return from;\n\tif (t >= 1) return to;\n\tif (type === 'color' || (typeof from === 'string' && typeof to === 'string')) {\n\t\tconst mixed = mixColorsOklab(from, to, t);\n\t\tif (mixed !== null) return mixed;\n\t}\n\treturn from;\n}\n\n/** Index of the last keyframe at or before `time` (-1 before the first). Binary search. */\nfunction segmentIndex(keys: readonly AnimationKeyframe[], time: number): number {\n\tlet lo = 0;\n\tlet hi = keys.length - 1;\n\tlet found = -1;\n\twhile (lo <= hi) {\n\t\tconst mid = (lo + hi) >> 1;\n\t\tif (keys[mid].time <= time) {\n\t\t\tfound = mid;\n\t\t\tlo = mid + 1;\n\t\t} else hi = mid - 1;\n\t}\n\treturn found;\n}\n\n/**\n * A track's value at `time`. Before the first keyframe it holds the first value, after the\n * last the last value. Keyframes may be unsorted or share times (see `normalizeKeyframes`).\n * Returns `undefined` for a track without valid keyframes.\n */\nexport function evaluateTrack(track: AnimationTrack | readonly AnimationKeyframe[] | undefined | null, time: number, type: AnimationValueType = 'number'): AnimationValue | undefined {\n\tconst keyframes = Array.isArray(track) ? track : (track as AnimationTrack | undefined)?.keyframes;\n\tconst keys = normalizeKeyframes(keyframes as AnimationKeyframe[]);\n\tif (keys.length === 0) return undefined;\n\tif (!(time > keys[0].time)) return keys[0].value;\n\tconst last = keys[keys.length - 1];\n\tif (time >= last.time) return last.value;\n\tconst i = segmentIndex(keys, time);\n\tconst a = keys[i];\n\tconst b = keys[i + 1];\n\tif (time === a.time) return a.value;\n\tconst span = b.time - a.time;\n\tconst u = (time - a.time) / span;\n\tif (a.easing === 'hold') return a.value;\n\treturn interpolateAnimationValue(a.value, b.value, evaluateEasing(a.easing, u, span), type);\n}\n\n/**\n * Maps a running time onto the timeline `[0, duration]`: clamped (`none`), wrapped (`loop`)\n * or bounced (`ping-pong`).\n */\nexport function wrapAnimationTime(time: number, duration: number, loop: AnimationLoopMode = 'none'): number {\n\tif (!Number.isFinite(time)) return 0;\n\tif (!(duration > 0)) return 0;\n\tif (loop === 'loop') return ((time % duration) + duration) % duration;\n\tif (loop === 'ping-pong') {\n\t\tconst period = duration * 2;\n\t\tconst m = ((time % period) + period) % period;\n\t\treturn m <= duration ? m : period - m;\n\t}\n\treturn Math.min(duration, Math.max(0, time));\n}\n","/**\n * The time source that animations (and canvas agent performances) play on.\n *\n * Defaults to `realClock` (requestAnimationFrame and setTimeout).\n * A `ManualClock` moves only when told to via `advance(ms)` or `tick(fps)`,\n * enabling deterministic frame-by-frame stepping for testing, video generation,\n * or headless server environments.\n */\n\nexport interface Clock {\n\t/** Current time in milliseconds. */\n\tnow(): number;\n\t/** Resolves on the next animation frame. */\n\tframe(): Promise<void>;\n\t/** Resolves after `ms` milliseconds of this clock's time. */\n\tsleep(ms: number): Promise<void>;\n\t/**\n\t * Whether the clock follows wall time. Live clocks stop or degrade when the\n\t * tab is in the background (browsers pause animation frames), so transitions\n\t * can commit immediately rather than leaving operations hanging.\n\t */\n\treadonly live: boolean;\n}\n\n/** Whether the browser tab is hidden (where RAF pauses). */\nexport const pageHidden = (): boolean =>\n\ttypeof document !== 'undefined' && document.hidden;\n\n/** Real-time clock using requestAnimationFrame and setTimeout. */\nexport const realClock: Clock = {\n\tlive: true,\n\tnow: () => (typeof performance !== 'undefined' ? performance.now() : Date.now()),\n\tframe: () =>\n\t\tnew Promise<void>((resolve) => {\n\t\t\tif (typeof requestAnimationFrame === 'function' && !pageHidden()) {\n\t\t\t\trequestAnimationFrame(() => resolve());\n\t\t\t} else {\n\t\t\t\tsetTimeout(resolve, 16);\n\t\t\t}\n\t\t}),\n\tsleep: (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, Math.max(0, ms)))\n};\n\nconst settle = () => new Promise<void>((resolve) => setTimeout(resolve, 0));\n\n/**\n * A deterministic clock that only moves forward when `advance` or `tick` is called.\n * Allows step-by-step frame testing and video rendering without waiting for real time.\n */\nexport class ManualClock implements Clock {\n\treadonly live = false;\n\tprivate time: number;\n\tprivate frames: (() => void)[] = [];\n\tprivate sleepers: { at: number; seq: number; resolve: () => void }[] = [];\n\tprivate seq = 0;\n\n\tconstructor(start = 0) {\n\t\tthis.time = start;\n\t}\n\n\tpublic now(): number {\n\t\treturn this.time;\n\t}\n\n\tpublic frame(): Promise<void> {\n\t\treturn new Promise<void>((resolve) => this.frames.push(resolve));\n\t}\n\n\tpublic sleep(ms: number): Promise<void> {\n\t\treturn new Promise<void>((resolve) =>\n\t\t\tthis.sleepers.push({\n\t\t\t\tat: this.time + Math.max(0, ms),\n\t\t\t\tseq: this.seq++,\n\t\t\t\tresolve\n\t\t\t})\n\t\t);\n\t}\n\n\t/** Whether any frames or sleep timers are currently pending. */\n\tpublic get pending(): boolean {\n\t\treturn this.frames.length > 0 || this.sleepers.length > 0;\n\t}\n\n\t/** Advances time by `ms`, resolving due sleep timers in order, followed by queued frames. */\n\tpublic async advance(ms: number): Promise<void> {\n\t\tconst end = this.time + Math.max(0, ms);\n\t\tawait settle();\n\n\t\twhile (true) {\n\t\t\tlet next: (typeof this.sleepers)[number] | undefined;\n\t\t\tfor (const s of this.sleepers) {\n\t\t\t\tif (s.at <= end && (!next || s.at < next.at || (s.at === next.at && s.seq < next.seq))) {\n\t\t\t\t\tnext = s;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!next) break;\n\n\t\t\tthis.sleepers.splice(this.sleepers.indexOf(next), 1);\n\t\t\tthis.time = Math.max(this.time, next.at);\n\t\t\tnext.resolve();\n\t\t\tawait settle();\n\t\t}\n\n\t\tthis.time = end;\n\t\tconst dueFrames = this.frames.splice(0, this.frames.length);\n\t\tfor (const resolveFrame of dueFrames) {\n\t\t\tresolveFrame();\n\t\t}\n\t\tawait settle();\n\t}\n\n\t/** Convenience method to advance by 1 frame at a given fps (default: 60fps = 16.67ms). */\n\tpublic async tick(fps = 60): Promise<void> {\n\t\tawait this.advance(Math.round(1000 / fps));\n\t}\n}\n","import { realClock, type Clock } from './clock.js';\nimport { wrapAnimationTime, type AnimationLoopMode } from './evaluate.js';\n\nexport interface AnimationPlayerState {\n\t/** Playhead time in ms, inside `[0, duration]`. */\n\ttime: number;\n\tplaying: boolean;\n\t/** True between `scrub` and `endScrub`. */\n\tscrubbing: boolean;\n\tloop: AnimationLoopMode;\n\t/** Speed multiplier (negative plays backwards). */\n\tplaybackRate: number;\n\tduration: number;\n}\n\nexport interface AnimationPlayerOptions {\n\t/** Time source (default `realClock`: requestAnimationFrame). Pass a `ManualClock` in tests or for rendering. */\n\tclock?: Clock;\n\t/** Timeline length in ms, or a getter (e.g. the last keyframe time). Default 1000. */\n\tduration?: number | (() => number);\n\tloop?: AnimationLoopMode;\n\tplaybackRate?: number;\n\t/** Initial playhead time (default 0). */\n\ttime?: number;\n\t/** Called whenever the playhead moves (playback, seek, scrub). */\n\tonTime?: (time: number) => void;\n\t/** Called when non-looping playback reaches the end (or the start, playing backwards). */\n\tonEnd?: () => void;\n}\n\n/**\n * Plays a timeline on an injectable `Clock`: play / pause / seek / scrub with looping,\n * ping-pong and playback rate. It only asks the clock for frames while playing, so a\n * `ManualClock` steps it deterministically and the real clock's requestAnimationFrame is the\n * only place wall time enters.\n *\n * `getState()` returns a cached snapshot replaced on change (usable with `useSyncExternalStore`).\n */\nexport class AnimationPlayer {\n\tprivate readonly clock: Clock;\n\tprivate durationSource: number | (() => number);\n\tprivate onTime?: (time: number) => void;\n\tprivate onEnd?: () => void;\n\tprivate time: number;\n\tprivate playing = false;\n\tprivate scrubbing = false;\n\tprivate resumeAfterScrub = false;\n\tprivate loop: AnimationLoopMode;\n\tprivate rate: number;\n\t/** Unwrapped time at `anchorAt` (keeps the ping-pong direction across frames). */\n\tprivate anchorRaw = 0;\n\tprivate anchorAt = 0;\n\tprivate generation = 0;\n\tprivate cached: AnimationPlayerState;\n\tprivate listeners = new Set<(state: AnimationPlayerState) => void>();\n\n\tconstructor(options: AnimationPlayerOptions = {}) {\n\t\tthis.clock = options.clock ?? realClock;\n\t\tthis.durationSource = options.duration ?? 1000;\n\t\tthis.loop = options.loop ?? 'none';\n\t\tthis.rate = Number.isFinite(options.playbackRate) && options.playbackRate !== 0 ? options.playbackRate! : 1;\n\t\tthis.onTime = options.onTime;\n\t\tthis.onEnd = options.onEnd;\n\t\tthis.time = this.clamp(options.time ?? 0);\n\t\tthis.cached = this.snapshot();\n\t}\n\n\t/** Current timeline length (ms). */\n\tget duration(): number {\n\t\tconst d = typeof this.durationSource === 'function' ? this.durationSource() : this.durationSource;\n\t\treturn Number.isFinite(d) && d > 0 ? d : 0;\n\t}\n\n\tget currentTime(): number {\n\t\treturn this.time;\n\t}\n\n\tget isPlaying(): boolean {\n\t\treturn this.playing;\n\t}\n\n\tgetState(): AnimationPlayerState {\n\t\treturn this.cached;\n\t}\n\n\tsubscribe(listener: (state: AnimationPlayerState) => void): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener);\n\t\t};\n\t}\n\n\t/** Replaces the callbacks (hooks keep them current without recreating the player). */\n\tsetCallbacks(callbacks: { onTime?: (time: number) => void; onEnd?: () => void }): void {\n\t\tthis.onTime = callbacks.onTime;\n\t\tthis.onEnd = callbacks.onEnd;\n\t}\n\n\tsetDuration(duration: number | (() => number)): void {\n\t\tthis.durationSource = duration;\n\t\tthis.time = this.clamp(this.time);\n\t\tthis.emit(false);\n\t}\n\n\tsetLoop(loop: AnimationLoopMode): void {\n\t\tif (loop === this.loop) return;\n\t\tthis.reanchor();\n\t\tthis.loop = loop;\n\t\tthis.emit(false);\n\t}\n\n\tsetPlaybackRate(rate: number): void {\n\t\tif (!Number.isFinite(rate) || rate === 0 || rate === this.rate) return;\n\t\tthis.reanchor();\n\t\tthis.rate = rate;\n\t\tthis.emit(false);\n\t}\n\n\t/** Starts playing from the playhead (from the start again when a one-shot play had ended). */\n\tplay(): void {\n\t\tif (this.playing) return;\n\t\tconst d = this.duration;\n\t\tif (this.loop === 'none' && d > 0) {\n\t\t\tif (this.rate > 0 && this.time >= d) this.time = 0;\n\t\t\tif (this.rate < 0 && this.time <= 0) this.time = d;\n\t\t}\n\t\tthis.playing = true;\n\t\tthis.scrubbing = false;\n\t\tthis.anchorRaw = this.time;\n\t\tthis.anchorAt = this.clock.now();\n\t\tthis.emit(false);\n\t\tthis.schedule();\n\t}\n\n\tpause(): void {\n\t\tif (!this.playing) return;\n\t\tthis.tick(false);\n\t\tthis.playing = false;\n\t\tthis.generation++;\n\t\tthis.emit(true);\n\t}\n\n\ttoggle(): void {\n\t\tif (this.playing) this.pause();\n\t\telse this.play();\n\t}\n\n\t/** Pauses and returns to the start. */\n\tstop(): void {\n\t\tthis.playing = false;\n\t\tthis.generation++;\n\t\tthis.seek(0);\n\t}\n\n\t/** Moves the playhead (clamped to the timeline); playback continues from there. */\n\tseek(time: number): void {\n\t\tif (!Number.isFinite(time)) return;\n\t\tthis.time = this.clamp(time);\n\t\tthis.anchorRaw = this.time;\n\t\tthis.anchorAt = this.clock.now();\n\t\tthis.emit(true);\n\t}\n\n\t/** Seeks while dragging the playhead: playback pauses until `endScrub`. */\n\tscrub(time: number): void {\n\t\tif (!this.scrubbing) {\n\t\t\tthis.resumeAfterScrub = this.playing;\n\t\t\tif (this.playing) {\n\t\t\t\tthis.playing = false;\n\t\t\t\tthis.generation++;\n\t\t\t}\n\t\t\tthis.scrubbing = true;\n\t\t}\n\t\tthis.seek(time);\n\t}\n\n\t/** Ends a scrub, resuming playback if it was playing when the scrub began. */\n\tendScrub(): void {\n\t\tif (!this.scrubbing) return;\n\t\tthis.scrubbing = false;\n\t\tconst resume = this.resumeAfterScrub;\n\t\tthis.resumeAfterScrub = false;\n\t\tif (resume) this.play();\n\t\telse this.emit(false);\n\t}\n\n\t/** Stops scheduling frames and drops listeners. */\n\tdestroy(): void {\n\t\tthis.playing = false;\n\t\tthis.generation++;\n\t\tthis.listeners.clear();\n\t}\n\n\tprivate clamp(time: number): number {\n\t\treturn Math.min(this.duration, Math.max(0, Number.isFinite(time) ? time : 0));\n\t}\n\n\tprivate reanchor() {\n\t\tif (!this.playing) return;\n\t\tthis.tick(false);\n\t\tthis.anchorRaw = this.rawNow();\n\t\tthis.anchorAt = this.clock.now();\n\t}\n\n\tprivate rawNow(): number {\n\t\treturn this.anchorRaw + (this.clock.now() - this.anchorAt) * this.rate;\n\t}\n\n\tprivate schedule() {\n\t\tconst generation = this.generation;\n\t\tthis.clock.frame().then(() => {\n\t\t\tif (generation !== this.generation || !this.playing) return;\n\t\t\tthis.tick(true);\n\t\t\tif (this.playing) this.schedule();\n\t\t});\n\t}\n\n\t/** Advances the playhead to the clock's time; `notify` emits the change. */\n\tprivate tick(notify: boolean) {\n\t\tif (!this.playing) return;\n\t\tconst d = this.duration;\n\t\tconst raw = this.rawNow();\n\t\tlet ended = false;\n\t\tif (this.loop === 'none' || d <= 0) {\n\t\t\tif (this.rate > 0 && raw >= d) {\n\t\t\t\tthis.time = d;\n\t\t\t\tended = true;\n\t\t\t} else if (this.rate < 0 && raw <= 0) {\n\t\t\t\tthis.time = 0;\n\t\t\t\tended = true;\n\t\t\t} else this.time = this.clamp(raw);\n\t\t} else {\n\t\t\tthis.time = wrapAnimationTime(raw, d, this.loop);\n\t\t}\n\t\tif (ended) {\n\t\t\tthis.playing = false;\n\t\t\tthis.generation++;\n\t\t}\n\t\tif (notify || ended) this.emit(true);\n\t\tif (ended) this.onEnd?.();\n\t}\n\n\tprivate snapshot(): AnimationPlayerState {\n\t\treturn {\n\t\t\ttime: this.time,\n\t\t\tplaying: this.playing,\n\t\t\tscrubbing: this.scrubbing,\n\t\t\tloop: this.loop,\n\t\t\tplaybackRate: this.rate,\n\t\t\tduration: this.duration\n\t\t};\n\t}\n\n\tprivate emit(timeChanged: boolean) {\n\t\tconst next = this.snapshot();\n\t\tconst prev = this.cached;\n\t\tif (\n\t\t\tprev.time === next.time &&\n\t\t\tprev.playing === next.playing &&\n\t\t\tprev.scrubbing === next.scrubbing &&\n\t\t\tprev.loop === next.loop &&\n\t\t\tprev.playbackRate === next.playbackRate &&\n\t\t\tprev.duration === next.duration\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tthis.cached = next;\n\t\tif (timeChanged && prev.time !== next.time) this.onTime?.(next.time);\n\t\tfor (const listener of this.listeners) listener(next);\n\t}\n}\n\nexport function createAnimationPlayer(options?: AnimationPlayerOptions): AnimationPlayer {\n\treturn new AnimationPlayer(options);\n}\n"],"mappings":"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","names":["s"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;// src/history/HistoryManager.ts
|
|
2
2
|
var sumBytes = (parts) => parts.reduce((n, p) => n + p.bytes, 0);
|
|
3
3
|
function undoParts(parts) {
|
|
4
4
|
for (let i = parts.length - 1; i >= 0; i--) parts[i].undo();
|
|
@@ -514,249 +514,8 @@ function createHistoryManager(options = {}) {
|
|
|
514
514
|
return new HistoryManager(options);
|
|
515
515
|
}
|
|
516
516
|
|
|
517
|
-
// src/dirty.ts
|
|
518
|
-
function defaultIsEqual(a, b) {
|
|
519
|
-
if (Object.is(a, b)) return true;
|
|
520
|
-
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
|
|
521
|
-
return false;
|
|
522
|
-
}
|
|
523
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
524
|
-
if (a.length !== b.length) return false;
|
|
525
|
-
for (let i = 0; i < a.length; i++) {
|
|
526
|
-
if (!defaultIsEqual(a[i], b[i])) return false;
|
|
527
|
-
}
|
|
528
|
-
return true;
|
|
529
|
-
}
|
|
530
|
-
if (Array.isArray(a) !== Array.isArray(b)) {
|
|
531
|
-
return false;
|
|
532
|
-
}
|
|
533
|
-
const keysA = Object.keys(a);
|
|
534
|
-
const keysB = Object.keys(b);
|
|
535
|
-
if (keysA.length !== keysB.length) return false;
|
|
536
|
-
for (const key of keysA) {
|
|
537
|
-
if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
|
|
538
|
-
if (!defaultIsEqual(a[key], b[key])) return false;
|
|
539
|
-
}
|
|
540
|
-
return true;
|
|
541
|
-
}
|
|
542
|
-
var isThenable = (value) => !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
543
|
-
var DirtyTracker = (_class2 = class {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
__init15() {this.normalizedBaseline = null}
|
|
548
|
-
/** `isDirty` result as of a revision (and baseline version). */
|
|
549
|
-
__init16() {this.cache = null}
|
|
550
|
-
__init17() {this.baselineVersion = 0}
|
|
551
|
-
__init18() {this.suppressDepth = 0}
|
|
552
|
-
__init19() {this.hasValue = false}
|
|
553
|
-
|
|
554
|
-
__init20() {this.dirtyState = false}
|
|
555
|
-
__init21() {this.listeners = /* @__PURE__ */ new Set()}
|
|
556
|
-
constructor(initialBaseline, options) {;_class2.prototype.__init15.call(this);_class2.prototype.__init16.call(this);_class2.prototype.__init17.call(this);_class2.prototype.__init18.call(this);_class2.prototype.__init19.call(this);_class2.prototype.__init20.call(this);_class2.prototype.__init21.call(this);
|
|
557
|
-
this.baseline = initialBaseline;
|
|
558
|
-
if (typeof options === "function") {
|
|
559
|
-
this.isEqual = options;
|
|
560
|
-
} else {
|
|
561
|
-
this.isEqual = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _3 => _3.isEqual]), () => ( defaultIsEqual));
|
|
562
|
-
this.normalize = _optionalChain([options, 'optionalAccess', _4 => _4.normalize]);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
/**
|
|
566
|
-
* Returns current baseline value.
|
|
567
|
-
*/
|
|
568
|
-
getBaseline() {
|
|
569
|
-
return this.baseline;
|
|
570
|
-
}
|
|
571
|
-
changeBaseline(value) {
|
|
572
|
-
this.baseline = value;
|
|
573
|
-
this.baselineVersion++;
|
|
574
|
-
this.normalizedBaseline = null;
|
|
575
|
-
this.cache = null;
|
|
576
|
-
}
|
|
577
|
-
/**
|
|
578
|
-
* Sets a new baseline value without triggering any dirty state.
|
|
579
|
-
* If a value is being tracked (`update`), `dirty` is recomputed against it.
|
|
580
|
-
*/
|
|
581
|
-
setBaseline(value) {
|
|
582
|
-
this.changeBaseline(value);
|
|
583
|
-
if (this.hasValue) {
|
|
584
|
-
this.setDirtyState(this.compare(this.lastValue));
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
compare(current) {
|
|
588
|
-
if (!this.normalize) return !this.isEqual(this.baseline, current);
|
|
589
|
-
this.normalizedBaseline ??= { value: this.normalize(this.baseline) };
|
|
590
|
-
return !this.isEqual(
|
|
591
|
-
this.normalizedBaseline.value,
|
|
592
|
-
this.normalize(current)
|
|
593
|
-
);
|
|
594
|
-
}
|
|
595
|
-
/**
|
|
596
|
-
* Checks whether the given value differs from the baseline.
|
|
597
|
-
* With a `revision` (e.g. `HistoryManager.getRevision()`), the result is
|
|
598
|
-
* cached and reused for the same revision until the baseline changes.
|
|
599
|
-
*/
|
|
600
|
-
isDirty(current, revision) {
|
|
601
|
-
if (revision === void 0) return this.compare(current);
|
|
602
|
-
const cache = this.cache;
|
|
603
|
-
if (cache && cache.revision === revision && cache.baseline === this.baselineVersion) {
|
|
604
|
-
return cache.dirty;
|
|
605
|
-
}
|
|
606
|
-
const dirty = this.compare(current);
|
|
607
|
-
this.cache = { revision, baseline: this.baselineVersion, dirty };
|
|
608
|
-
return dirty;
|
|
609
|
-
}
|
|
610
|
-
/**
|
|
611
|
-
* Resets the baseline to the provided current value (or clears dirty status).
|
|
612
|
-
*/
|
|
613
|
-
reset(current) {
|
|
614
|
-
this.changeBaseline(current);
|
|
615
|
-
this.hasValue = true;
|
|
616
|
-
this.lastValue = current;
|
|
617
|
-
this.setDirtyState(false);
|
|
618
|
-
}
|
|
619
|
-
/**
|
|
620
|
-
* Records the current value and returns whether it is dirty. While
|
|
621
|
-
* suppressed (`suppress`), the value becomes the new baseline instead, so
|
|
622
|
-
* programmatic loads and restores never mark the document dirty.
|
|
623
|
-
*/
|
|
624
|
-
update(current, revision) {
|
|
625
|
-
this.hasValue = true;
|
|
626
|
-
this.lastValue = current;
|
|
627
|
-
if (this.suppressDepth > 0) {
|
|
628
|
-
this.changeBaseline(current);
|
|
629
|
-
this.setDirtyState(false);
|
|
630
|
-
return false;
|
|
631
|
-
}
|
|
632
|
-
const dirty = this.isDirty(current, revision);
|
|
633
|
-
this.setDirtyState(dirty);
|
|
634
|
-
return dirty;
|
|
635
|
-
}
|
|
636
|
-
/** Whether the last value passed to `update` differs from the baseline. */
|
|
637
|
-
get dirty() {
|
|
638
|
-
return this.dirtyState;
|
|
639
|
-
}
|
|
640
|
-
/** Whether `suppress` is currently running. */
|
|
641
|
-
get suppressed() {
|
|
642
|
-
return this.suppressDepth > 0;
|
|
643
|
-
}
|
|
644
|
-
/**
|
|
645
|
-
* Marks the document saved: `current` (default: the last value passed to
|
|
646
|
-
* `update`) becomes the baseline.
|
|
647
|
-
*/
|
|
648
|
-
markClean(...args) {
|
|
649
|
-
if (args.length > 0) {
|
|
650
|
-
this.reset(args[0]);
|
|
651
|
-
} else if (this.hasValue) {
|
|
652
|
-
this.reset(this.lastValue);
|
|
653
|
-
} else {
|
|
654
|
-
this.setDirtyState(false);
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
/**
|
|
658
|
-
* Runs `fn` without marking anything dirty: every `update` during it
|
|
659
|
-
* rebaselines. Re-entrant (depth counter). If `fn` returns a promise, the
|
|
660
|
-
* suppression lasts until it settles.
|
|
661
|
-
*/
|
|
662
|
-
suppress(fn) {
|
|
663
|
-
this.suppressDepth++;
|
|
664
|
-
let result;
|
|
665
|
-
try {
|
|
666
|
-
result = fn();
|
|
667
|
-
} catch (error) {
|
|
668
|
-
this.suppressDepth--;
|
|
669
|
-
throw error;
|
|
670
|
-
}
|
|
671
|
-
if (isThenable(result)) {
|
|
672
|
-
const release = () => {
|
|
673
|
-
this.suppressDepth--;
|
|
674
|
-
};
|
|
675
|
-
return result.then(
|
|
676
|
-
(value) => {
|
|
677
|
-
release();
|
|
678
|
-
return value;
|
|
679
|
-
},
|
|
680
|
-
(error) => {
|
|
681
|
-
release();
|
|
682
|
-
throw error;
|
|
683
|
-
}
|
|
684
|
-
);
|
|
685
|
-
}
|
|
686
|
-
this.suppressDepth--;
|
|
687
|
-
return result;
|
|
688
|
-
}
|
|
689
|
-
/**
|
|
690
|
-
* Subscribes to changes of `dirty`. The listener is called immediately with
|
|
691
|
-
* the current value. Returns an unsubscribe function.
|
|
692
|
-
*/
|
|
693
|
-
subscribe(listener) {
|
|
694
|
-
this.listeners.add(listener);
|
|
695
|
-
listener(this.dirtyState);
|
|
696
|
-
return () => {
|
|
697
|
-
this.listeners.delete(listener);
|
|
698
|
-
};
|
|
699
|
-
}
|
|
700
|
-
setDirtyState(dirty) {
|
|
701
|
-
if (dirty === this.dirtyState) return;
|
|
702
|
-
this.dirtyState = dirty;
|
|
703
|
-
this.listeners.forEach((listener) => {
|
|
704
|
-
try {
|
|
705
|
-
listener(dirty);
|
|
706
|
-
} catch (err) {
|
|
707
|
-
console.error("[DirtyTracker] Error in listener:", err);
|
|
708
|
-
}
|
|
709
|
-
});
|
|
710
|
-
}
|
|
711
|
-
}, _class2);
|
|
712
|
-
function createDirtyTracker(initialBaseline, options) {
|
|
713
|
-
return new DirtyTracker(initialBaseline, options);
|
|
714
|
-
}
|
|
715
|
-
function withoutDirty(tracker, fn) {
|
|
716
|
-
return tracker.suppress(fn);
|
|
717
|
-
}
|
|
718
|
-
function bindDirtyToHistory(options) {
|
|
719
|
-
const { history, getValue } = options;
|
|
720
|
-
const tracker = _nullishCoalesce(options.tracker, () => ( new DirtyTracker(getValue(), {
|
|
721
|
-
isEqual: options.isEqual,
|
|
722
|
-
normalize: options.normalize
|
|
723
|
-
})));
|
|
724
|
-
const unsubscribe = history.subscribe(() => {
|
|
725
|
-
tracker.update(getValue(), _optionalChain([history, 'access', _5 => _5.getRevision, 'optionalCall', _6 => _6()]));
|
|
726
|
-
});
|
|
727
|
-
return {
|
|
728
|
-
tracker,
|
|
729
|
-
get dirty() {
|
|
730
|
-
return tracker.dirty;
|
|
731
|
-
},
|
|
732
|
-
markClean: () => tracker.markClean(getValue()),
|
|
733
|
-
suppress: (fn) => {
|
|
734
|
-
const rebaseline = () => {
|
|
735
|
-
if (!tracker.suppressed) tracker.reset(getValue());
|
|
736
|
-
};
|
|
737
|
-
const result = tracker.suppress(fn);
|
|
738
|
-
if (isThenable(result)) {
|
|
739
|
-
return result.then((value) => {
|
|
740
|
-
rebaseline();
|
|
741
|
-
return value;
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
rebaseline();
|
|
745
|
-
return result;
|
|
746
|
-
},
|
|
747
|
-
refresh: () => tracker.update(getValue()),
|
|
748
|
-
subscribe: (listener) => tracker.subscribe(listener),
|
|
749
|
-
destroy: unsubscribe
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
517
|
|
|
759
518
|
|
|
760
519
|
|
|
761
|
-
exports.
|
|
762
|
-
//# sourceMappingURL=chunk-
|
|
520
|
+
exports.HistoryManager = HistoryManager; exports.createHistoryManager = createHistoryManager;
|
|
521
|
+
//# sourceMappingURL=chunk-QKLRAA4T.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-QKLRAA4T.cjs","../src/history/HistoryManager.ts"],"names":[],"mappings":"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","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-QKLRAA4T.cjs","sourcesContent":[null,"// Portions ported from filmcraft-main/crates/engine/src/lib.rs, soundcraft-main/crates/engine/src/lib.rs\n// and photocraft-main/crates/ops/src/lib.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors).\n// See THIRD_PARTY_NOTICES.md.\nimport {\n Command,\n HistoryEntry,\n HistoryManagerOptions,\n HistoryMark,\n HistoryState,\n MergedExecutionOptions,\n SnapshotCommandOptions,\n} from \"./types\";\n\n/** One reversible piece of a step. A gesture step holds one part per distinct command. */\ninterface Part {\n undo: () => void;\n redo: () => void;\n tag?: string;\n bytes: number;\n}\n\n/** One undo step. */\ninterface Entry {\n id: number;\n name: string;\n tag?: string;\n timestamp: number;\n parts: Part[];\n bytes: number;\n}\n\nconst sumBytes = (parts: Part[]) => parts.reduce((n, p) => n + p.bytes, 0);\n\nfunction undoParts(parts: Part[]): void {\n for (let i = parts.length - 1; i >= 0; i--) parts[i].undo();\n}\n\nfunction redoParts(parts: Part[]): void {\n for (let i = 0; i < parts.length; i++) parts[i].redo();\n}\n\n/**\n * UI-agnostic History and Undo/Redo manager supporting command closures,\n * snapshot diffs, transaction batching, high-frequency event coalescing,\n * keyed gestures, undo marks, a memory budget and a History-panel listing.\n */\nexport class HistoryManager {\n private undoStack: Entry[] = [];\n private redoStack: Entry[] = [];\n private readonly maxDepth: number;\n private readonly maxBytes: number;\n private readonly sizeOf?: (command: Command) => number;\n private isApplying = false;\n private batchDepth = 0;\n private currentBatch: Command[] | null = null;\n private listeners: Set<(state: HistoryState) => void> = new Set();\n private onStateChange?: (state: HistoryState) => void;\n private cachedState: HistoryState;\n private cachedEntries: HistoryEntry[] | null = null;\n\n private nextId = 1;\n private revision = 0;\n /** Bumped by `clear()`; marks from an earlier epoch are stale. */\n private epoch = 0;\n /** Number of steps dropped from the bottom (depth / byte budget) so far. */\n private dropped = 0;\n /** Key of the gesture that the top step belongs to (see `executeMerged`). */\n private gestureKey: string | null = null;\n private gestureEntryId: number | null = null;\n /** Key every merged execute takes while a gesture is held (`beginGesture`). */\n private heldKey: string | null = null;\n\n constructor(options: HistoryManagerOptions = {}) {\n this.maxDepth = options.maxDepth ?? 50;\n this.maxBytes = Math.max(0, options.maxBytes ?? 0);\n this.sizeOf = options.sizeOf;\n this.onStateChange = options.onStateChange;\n this.cachedState = this.computeState();\n }\n\n private computeState(): HistoryState {\n const canUndo = this.undoStack.length > 0;\n const canRedo = this.redoStack.length > 0;\n return {\n canUndo,\n canRedo,\n undoName: canUndo ? this.undoStack[this.undoStack.length - 1].name : \"\",\n redoName: canRedo ? this.redoStack[this.redoStack.length - 1].name : \"\",\n undoCount: this.undoStack.length,\n redoCount: this.redoStack.length,\n };\n }\n\n /**\n * Returns a snapshot of the current history state.\n * Cached to maintain referential equality across renders for useSyncExternalStore.\n */\n public getState(): HistoryState {\n return this.cachedState;\n }\n\n /**\n * Monotonic counter bumped on every history change (execute, merge, undo,\n * redo, revert, clear). Useful as a cache key, e.g. for `DirtyTracker`.\n */\n public getRevision(): number {\n return this.revision;\n }\n\n private notify(): void {\n this.revision++;\n this.cachedState = this.computeState();\n this.cachedEntries = null;\n const state = this.cachedState;\n this.onStateChange?.(state);\n this.listeners.forEach((listener) => {\n try {\n listener(state);\n } catch (err) {\n console.error(\"[HistoryManager] Error in state listener:\", err);\n }\n });\n }\n\n private measure(command: Command): number {\n const n = this.sizeOf ? this.sizeOf(command) : (command.byteSize ?? 0);\n return Number.isFinite(n) && n > 0 ? n : 0;\n }\n\n private makeEntry(command: Command, timestamp: number): Entry {\n const part: Part = {\n undo: command.undo,\n redo: command.redo ?? command.execute,\n tag: command.tag,\n bytes: this.measure(command),\n };\n return {\n id: this.nextId++,\n name: command.name,\n tag: command.tag,\n timestamp,\n parts: [part],\n bytes: part.bytes,\n };\n }\n\n /** Pushes a step, clears redo and applies the depth and byte limits. */\n private record(entry: Entry): void {\n this.undoStack.push(entry);\n while (this.undoStack.length > this.maxDepth) {\n this.undoStack.shift();\n this.dropped++;\n }\n this.redoStack = [];\n this.trim();\n }\n\n /**\n * Keeps the stacks within `maxBytes`: the oldest undo steps that do not fit\n * are dropped, but the most recent undo step is always kept.\n */\n private trim(): void {\n if (this.maxBytes <= 0 || this.undoStack.length <= 1) return;\n let total = this.getByteSize();\n while (total > this.maxBytes && this.undoStack.length > 1) {\n total -= this.undoStack.shift()!.bytes;\n this.dropped++;\n }\n }\n\n /** Approximate bytes held by the undo and redo stacks (see `maxBytes`). */\n public getByteSize(): number {\n let total = 0;\n for (const e of this.undoStack) total += e.bytes;\n for (const e of this.redoStack) total += e.bytes;\n return total;\n }\n\n private resetGesture(): void {\n this.gestureKey = null;\n this.gestureEntryId = null;\n }\n\n /**\n * Executes a command and pushes it onto the undo stack.\n * Clears the redo stack and ends the current gesture.\n */\n public execute(command: Command): void {\n if (this.isApplying) {\n command.execute();\n return;\n }\n\n if (this.batchDepth > 0 && this.currentBatch) {\n command.execute();\n this.currentBatch.push({\n ...command,\n timestamp: command.timestamp ?? Date.now(),\n });\n return;\n }\n\n command.execute();\n this.record(this.makeEntry(command, command.timestamp ?? Date.now()));\n this.resetGesture();\n this.notify();\n }\n\n /**\n * Executes a command as part of a continuous interaction (slider scrub, node drag).\n *\n * - With `options.key` (or while a gesture is held with `beginGesture`):\n * consecutive merged executes with the same key fold into one undo step,\n * however long the gesture lasts. Recording any other command, undo, redo,\n * `revertTo`, `goTo`, `clear` or `endGesture()` ends the gesture.\n * - Without a key: coalesces with the previous command if they share the same\n * `tag` and occurred within `windowMs` (default: 300ms).\n */\n public executeMerged(\n command: Command,\n options: MergedExecutionOptions = {},\n ): void {\n const now = Date.now();\n const key = this.heldKey ?? options.key;\n\n if (key !== undefined) {\n if (this.isApplying || this.batchDepth > 0) {\n this.execute({ ...command, timestamp: now });\n return;\n }\n const top = this.undoStack[this.undoStack.length - 1];\n if (top && this.gestureKey === key && this.gestureEntryId === top.id) {\n command.execute();\n const redo = command.redo ?? command.execute;\n const bytes = this.measure(command);\n const last = top.parts[top.parts.length - 1];\n if (last.tag !== undefined && last.tag === command.tag) {\n // Same (absolute) command again: keep the pre-gesture undo, take the new redo.\n top.parts[top.parts.length - 1] = { undo: last.undo, redo, tag: last.tag, bytes };\n } else {\n top.parts.push({ undo: command.undo, redo, tag: command.tag, bytes });\n }\n top.bytes = sumBytes(top.parts);\n top.timestamp = now;\n this.redoStack = [];\n this.trim();\n this.notify();\n return;\n }\n this.execute({ ...command, timestamp: now });\n const pushed = this.undoStack[this.undoStack.length - 1];\n if (pushed) {\n this.gestureKey = key;\n this.gestureEntryId = pushed.id;\n }\n return;\n }\n\n const windowMs = options.windowMs ?? 300;\n\n if (\n command.tag &&\n this.undoStack.length > 0 &&\n this.batchDepth === 0 &&\n !this.isApplying\n ) {\n const top = this.undoStack[this.undoStack.length - 1];\n const elapsed = top.timestamp ? now - top.timestamp : Infinity;\n\n if (top.tag === command.tag && elapsed <= windowMs) {\n command.execute();\n // Replace top with merged command keeping the original initial undo\n const initialParts = top.parts;\n const bytes = this.measure(command);\n this.undoStack[this.undoStack.length - 1] = {\n id: top.id,\n name: command.name,\n tag: command.tag,\n timestamp: now,\n parts: [\n {\n undo: () => undoParts(initialParts),\n redo: command.redo ?? command.execute,\n tag: command.tag,\n bytes,\n },\n ],\n bytes,\n };\n this.redoStack = [];\n this.resetGesture();\n this.trim();\n this.notify();\n return;\n }\n }\n\n this.execute({ ...command, timestamp: now });\n }\n\n /**\n * Holds a gesture: until `endGesture()`, every `executeMerged` call (whatever\n * its own key or tag) joins one undo step, e.g. an automation pass and\n * whatever is dragged during it. Commands recorded with `execute` still end\n * the current step; the next merged execute then starts a new one.\n */\n public beginGesture(key: string): void {\n if (this.heldKey === key) return;\n this.heldKey = key;\n this.resetGesture();\n }\n\n /** Ends the current (keyed or held) gesture; the next merged execute starts a new step. */\n public endGesture(): void {\n this.heldKey = null;\n this.resetGesture();\n }\n\n /** The key of the gesture currently merging into the top step, if any. */\n public getGestureKey(): string | null {\n return this.heldKey ?? this.gestureKey;\n }\n\n /**\n * Batches multiple commands executed within `fn` into a single atomic undo entry.\n */\n public batch(name: string, fn: () => void): void {\n if (this.isApplying) {\n fn();\n return;\n }\n\n if (this.batchDepth > 0) {\n // Already inside a batch; execute directly\n fn();\n return;\n }\n\n this.batchDepth++;\n this.currentBatch = [];\n\n try {\n fn();\n } catch (error) {\n const executed = this.currentBatch ?? [];\n this.batchDepth--;\n this.currentBatch = null;\n this.rollback(executed);\n throw error;\n }\n\n this.batchDepth--;\n const batchCommands: Command[] = this.currentBatch ?? [];\n this.currentBatch = null;\n\n if (batchCommands.length > 0) {\n const run = () => {\n for (let i = 0; i < batchCommands.length; i++) {\n (batchCommands[i].redo ?? batchCommands[i].execute)();\n }\n };\n const bytes = batchCommands.reduce((n, c) => n + this.measure(c), 0);\n this.record({\n id: this.nextId++,\n name,\n timestamp: Date.now(),\n parts: [\n {\n undo: () => {\n for (let i = batchCommands.length - 1; i >= 0; i--) {\n batchCommands[i].undo();\n }\n },\n redo: run,\n bytes,\n },\n ],\n bytes,\n });\n this.resetGesture();\n this.notify();\n }\n }\n\n /**\n * Reverts already-executed commands of an aborted batch, newest first.\n * Commands executed by the undo closures themselves are not recorded.\n */\n private rollback(commands: Command[]): void {\n const wasApplying = this.isApplying;\n this.isApplying = true;\n try {\n for (let i = commands.length - 1; i >= 0; i--) {\n try {\n commands[i].undo();\n } catch (err) {\n console.error(\n `[HistoryManager] Error rolling back \"${commands[i].name}\" of a failed batch:`,\n err,\n );\n }\n }\n } finally {\n this.isApplying = wasApplying;\n }\n }\n\n /** Undoes the top step (caller holds `isApplying`). Throws leave it on the stack. */\n private undoOne(): void {\n const entry = this.undoStack[this.undoStack.length - 1];\n undoParts(entry.parts);\n this.undoStack.pop();\n this.redoStack.push(entry);\n }\n\n private redoOne(): void {\n const entry = this.redoStack[this.redoStack.length - 1];\n redoParts(entry.parts);\n this.redoStack.pop();\n this.undoStack.push(entry);\n }\n\n /**\n * Reverts the most recent command on the undo stack.\n * Returns true if a command was undone, false otherwise.\n */\n public undo(): boolean {\n if (this.undoStack.length === 0 || this.isApplying || this.batchDepth > 0) {\n return false;\n }\n\n this.isApplying = true;\n this.resetGesture();\n try {\n // If undo throws, the command stays on the undo stack and the error propagates.\n this.undoOne();\n return true;\n } finally {\n this.isApplying = false;\n this.notify();\n }\n }\n\n /**\n * Re-applies the most recent undone command on the redo stack.\n * Returns true if a command was redone, false otherwise.\n */\n public redo(): boolean {\n if (this.redoStack.length === 0 || this.isApplying || this.batchDepth > 0) {\n return false;\n }\n\n this.isApplying = true;\n this.resetGesture();\n try {\n // If redo throws, the command stays on the redo stack and the error propagates.\n this.redoOne();\n return true;\n } finally {\n this.isApplying = false;\n this.notify();\n }\n }\n\n /**\n * Captures the current point in the history (its top step), for `revertTo`.\n */\n public mark(): HistoryMark {\n const top = this.undoStack[this.undoStack.length - 1];\n return {\n topId: top ? top.id : null,\n nextId: this.nextId,\n epoch: this.epoch,\n dropped: this.dropped,\n };\n }\n\n /** Whether `mark` still points into the undo history. */\n public isMarkValid(mark: HistoryMark): boolean {\n if (mark.epoch !== this.epoch) return false;\n if (mark.topId === null) return mark.dropped === this.dropped;\n return this.undoStack.some((e) => e.id === mark.topId);\n }\n\n /**\n * Takes back every step made since `mark` (merged or not), e.g. to cancel a\n * drag with Escape: the state returns to how it was at `mark`, and neither\n * undo nor redo keeps the reverted steps. Does nothing when `mark` has left\n * the history (undone past, dropped by the limits, or cleared).\n * Returns how many steps were taken back.\n */\n public revertTo(mark: HistoryMark): number {\n if (this.isApplying || this.batchDepth > 0 || !this.isMarkValid(mark)) {\n return 0;\n }\n const redoBefore = this.redoStack.length;\n let n = 0;\n this.isApplying = true;\n this.resetGesture();\n try {\n while (this.undoStack.length > 0) {\n const top = this.undoStack[this.undoStack.length - 1];\n if (top.id === mark.topId) break;\n undoParts(top.parts);\n this.undoStack.pop();\n n++;\n }\n } finally {\n this.isApplying = false;\n // Steps made after the mark are gone for good, including undone ones.\n this.redoStack =\n n > 0 ? [] : this.redoStack.filter((e) => e.id < mark.nextId);\n if (n > 0 || this.redoStack.length !== redoBefore) this.notify();\n }\n return n;\n }\n\n /**\n * Lists the steps for a History panel: undo steps oldest first, then redo\n * steps (the next redo first). Cached until the history changes.\n */\n public getEntries(): HistoryEntry[] {\n if (this.cachedEntries) return this.cachedEntries;\n const u = this.undoStack.length;\n const entries: HistoryEntry[] = this.undoStack.map((e, index) => ({\n id: e.id,\n label: e.name,\n index,\n current: index === u - 1,\n undone: false,\n }));\n for (let i = this.redoStack.length - 1; i >= 0; i--) {\n const e = this.redoStack[i];\n entries.push({\n id: e.id,\n label: e.name,\n index: entries.length,\n current: false,\n undone: true,\n });\n }\n this.cachedEntries = entries;\n return entries;\n }\n\n /**\n * Undoes or redoes until the step at `index` (from `getEntries`) is the\n * current one; `-1` undoes everything. Returns how many steps were applied.\n */\n public goTo(index: number): number {\n if (this.isApplying || this.batchDepth > 0) return 0;\n const total = this.undoStack.length + this.redoStack.length;\n const target = Math.max(0, Math.min(total, Math.floor(index) + 1));\n if (target === this.undoStack.length) return 0;\n let n = 0;\n this.isApplying = true;\n this.resetGesture();\n try {\n while (this.undoStack.length > target) {\n this.undoOne();\n n++;\n }\n while (this.undoStack.length < target) {\n this.redoOne();\n n++;\n }\n } finally {\n this.isApplying = false;\n this.notify();\n }\n return n;\n }\n\n /**\n * Clears both undo and redo stacks.\n */\n public clear(): void {\n this.undoStack = [];\n this.redoStack = [];\n this.epoch++;\n this.resetGesture();\n this.notify();\n }\n\n /**\n * Subscribes to history state changes.\n * The listener is immediately invoked with the current state.\n * Returns an unsubscribe function.\n */\n public subscribe(listener: (state: HistoryState) => void): () => void {\n this.listeners.add(listener);\n listener(this.getState());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Utility helper to create a Command from before/after state snapshots.\n */\n public static createSnapshotCommand<T>(\n options: SnapshotCommandOptions<T>,\n ): Command {\n return {\n name: options.name,\n tag: options.tag,\n execute: () => options.apply(options.after),\n undo: () => options.apply(options.before),\n redo: () => options.apply(options.after),\n };\n }\n}\n\n/**\n * Creates and initializes a new HistoryManager instance.\n */\nexport function createHistoryManager(\n options: HistoryManagerOptions = {},\n): HistoryManager {\n return new HistoryManager(options);\n}\n"]}
|