@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.
Files changed (112) hide show
  1. package/README.md +44 -2
  2. package/dist/HistoryManager-DWSLd6Tf.d.ts +150 -0
  3. package/dist/HistoryManager-DeQQMBCj.d.cts +150 -0
  4. package/dist/agent/index.cjs +20 -427
  5. package/dist/agent/index.cjs.map +1 -1
  6. package/dist/agent/index.d.cts +4 -342
  7. package/dist/agent/index.d.ts +4 -342
  8. package/dist/agent/index.js +14 -421
  9. package/dist/agent/index.js.map +1 -1
  10. package/dist/animation/index.cjs +62 -0
  11. package/dist/animation/index.cjs.map +1 -0
  12. package/dist/animation/index.d.cts +226 -0
  13. package/dist/animation/index.d.ts +226 -0
  14. package/dist/animation/index.js +62 -0
  15. package/dist/animation/index.js.map +1 -0
  16. package/dist/{builtins-nMXh9sT3.d.cts → builtins-DxC3aUR2.d.cts} +2 -2
  17. package/dist/{builtins-haN82vjT.d.ts → builtins-NGxNxQfJ.d.ts} +2 -2
  18. package/dist/canvas/index.cjs +177 -743
  19. package/dist/canvas/index.cjs.map +1 -1
  20. package/dist/canvas/index.d.cts +6 -289
  21. package/dist/canvas/index.d.ts +6 -289
  22. package/dist/canvas/index.js +49 -615
  23. package/dist/canvas/index.js.map +1 -1
  24. package/dist/chunk-36BLROHV.js +438 -0
  25. package/dist/chunk-36BLROHV.js.map +1 -0
  26. package/dist/{chunk-JT7AXQTE.js → chunk-3RPOW4CS.js} +7 -7
  27. package/dist/{chunk-AGR7EVRW.cjs → chunk-6MDQKHRH.cjs} +6 -6
  28. package/dist/{chunk-AGR7EVRW.cjs.map → chunk-6MDQKHRH.cjs.map} +1 -1
  29. package/dist/chunk-A6PHCAGX.cjs +87 -0
  30. package/dist/chunk-A6PHCAGX.cjs.map +1 -0
  31. package/dist/{chunk-HRMEDT2L.js → chunk-D6AVOTSD.js} +6 -85
  32. package/dist/chunk-D6AVOTSD.js.map +1 -0
  33. package/dist/{chunk-ARRTP33I.js → chunk-D6S5M7HV.js} +2 -2
  34. package/dist/{chunk-ARRTP33I.js.map → chunk-D6S5M7HV.js.map} +1 -1
  35. package/dist/{chunk-6IO7WUSU.js → chunk-DDADOHJW.js} +17 -17
  36. package/dist/{chunk-CPOKFNBG.cjs → chunk-I6BZB5ZH.cjs} +2 -2
  37. package/dist/{chunk-CPOKFNBG.cjs.map → chunk-I6BZB5ZH.cjs.map} +1 -1
  38. package/dist/{chunk-4BVP64JJ.cjs → chunk-K2UYKJ6M.cjs} +24 -103
  39. package/dist/chunk-K2UYKJ6M.cjs.map +1 -0
  40. package/dist/chunk-PIIAZV3L.cjs +244 -0
  41. package/dist/chunk-PIIAZV3L.cjs.map +1 -0
  42. package/dist/chunk-PWJARCI4.js +637 -0
  43. package/dist/chunk-PWJARCI4.js.map +1 -0
  44. package/dist/{chunk-G2I4QJOT.cjs → chunk-QKLRAA4T.cjs} +3 -244
  45. package/dist/chunk-QKLRAA4T.cjs.map +1 -0
  46. package/dist/{chunk-2H7ZHPEJ.js → chunk-QVZZGT4X.js} +1 -242
  47. package/dist/chunk-QVZZGT4X.js.map +1 -0
  48. package/dist/chunk-TGD52FEZ.js +87 -0
  49. package/dist/chunk-TGD52FEZ.js.map +1 -0
  50. package/dist/chunk-TTYCN6ZH.cjs +637 -0
  51. package/dist/chunk-TTYCN6ZH.cjs.map +1 -0
  52. package/dist/{chunk-YK5TATOF.cjs → chunk-U7VGDSNY.cjs} +3 -3
  53. package/dist/{chunk-YK5TATOF.cjs.map → chunk-U7VGDSNY.cjs.map} +1 -1
  54. package/dist/chunk-V7CC7RZ6.cjs +438 -0
  55. package/dist/chunk-V7CC7RZ6.cjs.map +1 -0
  56. package/dist/chunk-YK57D7PW.js +244 -0
  57. package/dist/chunk-YK57D7PW.js.map +1 -0
  58. package/dist/commands/index.cjs +2 -2
  59. package/dist/commands/index.cjs.map +1 -1
  60. package/dist/commands/index.d.cts +2 -2
  61. package/dist/commands/index.d.ts +2 -2
  62. package/dist/commands/index.js +1 -1
  63. package/dist/commands/index.js.map +1 -1
  64. package/dist/easing-B6iAnJHk.d.cts +74 -0
  65. package/dist/easing-B6iAnJHk.d.ts +74 -0
  66. package/dist/extensions/index.cjs +5 -5
  67. package/dist/extensions/index.cjs.map +1 -1
  68. package/dist/extensions/index.js +4 -4
  69. package/dist/generation/index.cjs +4 -4
  70. package/dist/generation/index.cjs.map +1 -1
  71. package/dist/generation/index.js +3 -3
  72. package/dist/generation/index.js.map +1 -1
  73. package/dist/history/index.cjs +4 -2
  74. package/dist/history/index.cjs.map +1 -1
  75. package/dist/history/index.d.cts +3 -149
  76. package/dist/history/index.d.ts +3 -149
  77. package/dist/history/index.js +5 -3
  78. package/dist/image-editor/index.cjs.map +1 -1
  79. package/dist/image-editor/index.js.map +1 -1
  80. package/dist/index.cjs +24 -22
  81. package/dist/index.cjs.map +1 -1
  82. package/dist/index.d.cts +3 -2
  83. package/dist/index.d.ts +3 -2
  84. package/dist/index.js +112 -110
  85. package/dist/index.js.map +1 -1
  86. package/dist/parameters/index.cjs +1283 -0
  87. package/dist/parameters/index.cjs.map +1 -0
  88. package/dist/parameters/index.d.cts +595 -0
  89. package/dist/parameters/index.d.ts +595 -0
  90. package/dist/parameters/index.js +1283 -0
  91. package/dist/parameters/index.js.map +1 -0
  92. package/dist/spreadsheet/index.cjs +4 -4
  93. package/dist/spreadsheet/index.cjs.map +1 -1
  94. package/dist/spreadsheet/index.js +8 -8
  95. package/dist/tokens/index.cjs +4 -2
  96. package/dist/tokens/index.cjs.map +1 -1
  97. package/dist/tokens/index.js +6 -4
  98. package/dist/tools/index.cjs +31 -0
  99. package/dist/tools/index.cjs.map +1 -0
  100. package/dist/tools/index.d.cts +343 -0
  101. package/dist/tools/index.d.ts +343 -0
  102. package/dist/tools/index.js +31 -0
  103. package/dist/tools/index.js.map +1 -0
  104. package/dist/{types-GT5a5YAX.d.cts → types-DsiXGmjo.d.cts} +1 -1
  105. package/dist/{types-GT5a5YAX.d.ts → types-DsiXGmjo.d.ts} +1 -1
  106. package/package.json +16 -1
  107. package/dist/chunk-2H7ZHPEJ.js.map +0 -1
  108. package/dist/chunk-4BVP64JJ.cjs.map +0 -1
  109. package/dist/chunk-G2I4QJOT.cjs.map +0 -1
  110. package/dist/chunk-HRMEDT2L.js.map +0 -1
  111. /package/dist/{chunk-JT7AXQTE.js.map → chunk-3RPOW4CS.js.map} +0 -0
  112. /package/dist/{chunk-6IO7WUSU.js.map → chunk-DDADOHJW.js.map} +0 -0
@@ -0,0 +1,31 @@
1
+ import {
2
+ EDITOR_MCP_TOOLS,
3
+ EXPORT_EXCLUDED_SELECTORS,
4
+ MCP_TOOL_EDIT_CANVAS,
5
+ MCP_TOOL_EDIT_PROMPT,
6
+ MCP_TOOL_GET_EDITOR_STATE,
7
+ MCP_TOOL_VIEW_EDITOR,
8
+ TOOL_NAMESPACE_SEPARATOR,
9
+ ToolRegistry,
10
+ ToolRegistryError,
11
+ createToolRegistry,
12
+ toToolResult
13
+ } from "../chunk-36BLROHV.js";
14
+ import {
15
+ validateJsonSchema
16
+ } from "../chunk-D6S5M7HV.js";
17
+ export {
18
+ EDITOR_MCP_TOOLS,
19
+ EXPORT_EXCLUDED_SELECTORS,
20
+ MCP_TOOL_EDIT_CANVAS,
21
+ MCP_TOOL_EDIT_PROMPT,
22
+ MCP_TOOL_GET_EDITOR_STATE,
23
+ MCP_TOOL_VIEW_EDITOR,
24
+ TOOL_NAMESPACE_SEPARATOR,
25
+ ToolRegistry,
26
+ ToolRegistryError,
27
+ createToolRegistry,
28
+ toToolResult,
29
+ validateJsonSchema
30
+ };
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -83,4 +83,4 @@ interface HistoryMark {
83
83
  readonly dropped: number;
84
84
  }
85
85
 
86
- export type { Command as C, HistoryState as H, MergedExecutionOptions as M, SnapshotCommandOptions as S, HistoryEntry as a, HistoryManagerOptions as b, HistoryMark as c };
86
+ export type { Command as C, HistoryState as H, MergedExecutionOptions as M, SnapshotCommandOptions as S, HistoryManagerOptions as a, HistoryMark as b, HistoryEntry as c };
@@ -83,4 +83,4 @@ interface HistoryMark {
83
83
  readonly dropped: number;
84
84
  }
85
85
 
86
- export type { Command as C, HistoryState as H, MergedExecutionOptions as M, SnapshotCommandOptions as S, HistoryEntry as a, HistoryManagerOptions as b, HistoryMark as c };
86
+ export type { Command as C, HistoryState as H, MergedExecutionOptions as M, SnapshotCommandOptions as S, HistoryManagerOptions as a, HistoryMark as b, HistoryEntry as c };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor",
3
- "version": "0.27.0",
3
+ "version": "0.29.0",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -44,6 +44,11 @@
44
44
  "import": "./dist/history/index.js",
45
45
  "require": "./dist/history/index.cjs"
46
46
  },
47
+ "./animation": {
48
+ "types": "./dist/animation/index.d.ts",
49
+ "import": "./dist/animation/index.js",
50
+ "require": "./dist/animation/index.cjs"
51
+ },
47
52
  "./canvas": {
48
53
  "types": "./dist/canvas/index.d.ts",
49
54
  "import": "./dist/canvas/index.js",
@@ -54,6 +59,11 @@
54
59
  "import": "./dist/agent/index.js",
55
60
  "require": "./dist/agent/index.cjs"
56
61
  },
62
+ "./tools": {
63
+ "types": "./dist/tools/index.d.ts",
64
+ "import": "./dist/tools/index.js",
65
+ "require": "./dist/tools/index.cjs"
66
+ },
57
67
  "./image-editor": {
58
68
  "types": "./dist/image-editor/index.d.ts",
59
69
  "import": "./dist/image-editor/index.js",
@@ -88,6 +98,11 @@
88
98
  "types": "./dist/export/index.d.ts",
89
99
  "import": "./dist/export/index.js",
90
100
  "require": "./dist/export/index.cjs"
101
+ },
102
+ "./parameters": {
103
+ "types": "./dist/parameters/index.d.ts",
104
+ "import": "./dist/parameters/index.js",
105
+ "require": "./dist/parameters/index.cjs"
91
106
  }
92
107
  },
93
108
  "files": [
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/history/HistoryManager.ts","../src/dirty.ts"],"sourcesContent":["// 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","// Portions ported from soundcraft-main/crates/engine/src/lib.rs (MIT OR Apache-2.0,\n// © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * Compares two values for structural equality.\n * Handles primitives, objects, arrays, and null/undefined.\n */\nexport function defaultIsEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== \"object\" ||\n a === null ||\n typeof b !== \"object\" ||\n b === null\n ) {\n return false;\n }\n\n // Fast path for arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!defaultIsEqual(a[i], b[i])) return false;\n }\n return true;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b) as (keyof T)[];\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!defaultIsEqual(a[key], b[key])) return false;\n }\n\n return true;\n}\n\nexport interface DirtyTrackerOptions<T> {\n /**\n * Equality check. When `normalize` is set it receives the normalized values.\n */\n isEqual?: (a: T, b: T) => boolean;\n /**\n * Projects a value onto the part that counts as \"the document\" before\n * comparing, e.g. `({ selection, viewport, ...doc }) => doc` so that\n * selecting, scrolling or zooming never marks the document dirty.\n */\n normalize?: (value: T) => unknown;\n}\n\ntype Thenable = { then: (...args: any[]) => any };\n\nconst isThenable = (value: unknown): value is Thenable =>\n !!value &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n typeof (value as Thenable).then === \"function\";\n\n/**\n * Tracks a baseline (saved) value and determines whether the current value is\n * dirty (modified).\n *\n * Stateless use: `isDirty(current)`. Stateful use: feed values with\n * `update(current, revision?)`, read `dirty`, `subscribe` to changes, call\n * `markClean()` after saving and wrap programmatic loads in `suppress(fn)`.\n */\nexport class DirtyTracker<T = unknown> {\n private baseline: T;\n private readonly isEqual: (a: T, b: T) => boolean;\n private readonly normalize?: (value: T) => unknown;\n private normalizedBaseline: { value: unknown } | null = null;\n /** `isDirty` result as of a revision (and baseline version). */\n private cache: { revision: number; baseline: number; dirty: boolean } | null =\n null;\n private baselineVersion = 0;\n private suppressDepth = 0;\n private hasValue = false;\n private lastValue: T | undefined;\n private dirtyState = false;\n private listeners = new Set<(dirty: boolean) => void>();\n\n constructor(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n ) {\n this.baseline = initialBaseline;\n if (typeof options === \"function\") {\n this.isEqual = options;\n } else {\n this.isEqual = options?.isEqual ?? defaultIsEqual;\n this.normalize = options?.normalize;\n }\n }\n\n /**\n * Returns current baseline value.\n */\n public getBaseline(): T {\n return this.baseline;\n }\n\n private changeBaseline(value: T): void {\n this.baseline = value;\n this.baselineVersion++;\n this.normalizedBaseline = null;\n this.cache = null;\n }\n\n /**\n * Sets a new baseline value without triggering any dirty state.\n * If a value is being tracked (`update`), `dirty` is recomputed against it.\n */\n public setBaseline(value: T): void {\n this.changeBaseline(value);\n if (this.hasValue) {\n this.setDirtyState(this.compare(this.lastValue as T));\n }\n }\n\n private compare(current: T): boolean {\n if (!this.normalize) return !this.isEqual(this.baseline, current);\n this.normalizedBaseline ??= { value: this.normalize(this.baseline) };\n return !this.isEqual(\n this.normalizedBaseline.value as T,\n this.normalize(current) as T,\n );\n }\n\n /**\n * Checks whether the given value differs from the baseline.\n * With a `revision` (e.g. `HistoryManager.getRevision()`), the result is\n * cached and reused for the same revision until the baseline changes.\n */\n public isDirty(current: T, revision?: number): boolean {\n if (revision === undefined) return this.compare(current);\n const cache = this.cache;\n if (\n cache &&\n cache.revision === revision &&\n cache.baseline === this.baselineVersion\n ) {\n return cache.dirty;\n }\n const dirty = this.compare(current);\n this.cache = { revision, baseline: this.baselineVersion, dirty };\n return dirty;\n }\n\n /**\n * Resets the baseline to the provided current value (or clears dirty status).\n */\n public reset(current: T): void {\n this.changeBaseline(current);\n this.hasValue = true;\n this.lastValue = current;\n this.setDirtyState(false);\n }\n\n /**\n * Records the current value and returns whether it is dirty. While\n * suppressed (`suppress`), the value becomes the new baseline instead, so\n * programmatic loads and restores never mark the document dirty.\n */\n public update(current: T, revision?: number): boolean {\n this.hasValue = true;\n this.lastValue = current;\n if (this.suppressDepth > 0) {\n this.changeBaseline(current);\n this.setDirtyState(false);\n return false;\n }\n const dirty = this.isDirty(current, revision);\n this.setDirtyState(dirty);\n return dirty;\n }\n\n /** Whether the last value passed to `update` differs from the baseline. */\n public get dirty(): boolean {\n return this.dirtyState;\n }\n\n /** Whether `suppress` is currently running. */\n public get suppressed(): boolean {\n return this.suppressDepth > 0;\n }\n\n /**\n * Marks the document saved: `current` (default: the last value passed to\n * `update`) becomes the baseline.\n */\n public markClean(...args: [] | [current: T]): void {\n if (args.length > 0) {\n this.reset(args[0] as T);\n } else if (this.hasValue) {\n this.reset(this.lastValue as T);\n } else {\n this.setDirtyState(false);\n }\n }\n\n /**\n * Runs `fn` without marking anything dirty: every `update` during it\n * rebaselines. Re-entrant (depth counter). If `fn` returns a promise, the\n * suppression lasts until it settles.\n */\n public suppress<R>(fn: () => R): R {\n this.suppressDepth++;\n let result: R;\n try {\n result = fn();\n } catch (error) {\n this.suppressDepth--;\n throw error;\n }\n if (isThenable(result)) {\n const release = () => {\n this.suppressDepth--;\n };\n return (result as unknown as Promise<unknown>).then(\n (value) => {\n release();\n return value;\n },\n (error) => {\n release();\n throw error;\n },\n ) as unknown as R;\n }\n this.suppressDepth--;\n return result;\n }\n\n /**\n * Subscribes to changes of `dirty`. The listener is called immediately with\n * the current value. Returns an unsubscribe function.\n */\n public subscribe(listener: (dirty: boolean) => void): () => void {\n this.listeners.add(listener);\n listener(this.dirtyState);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private setDirtyState(dirty: boolean): void {\n if (dirty === this.dirtyState) return;\n this.dirtyState = dirty;\n this.listeners.forEach((listener) => {\n try {\n listener(dirty);\n } catch (err) {\n console.error(\"[DirtyTracker] Error in listener:\", err);\n }\n });\n }\n}\n\n/**\n * Creates a DirtyTracker instance.\n */\nexport function createDirtyTracker<T>(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n): DirtyTracker<T> {\n return new DirtyTracker(initialBaseline, options);\n}\n\n/**\n * Runs `fn` with dirty tracking suppressed (see `DirtyTracker.suppress`).\n */\nexport function withoutDirty<R>(tracker: DirtyTracker<any>, fn: () => R): R {\n return tracker.suppress(fn);\n}\n\n/** Minimal history surface used by `bindDirtyToHistory` (`HistoryManager` satisfies it). */\nexport interface DirtyHistorySource {\n subscribe(listener: (...args: any[]) => void): () => void;\n getRevision?(): number;\n}\n\nexport interface BindDirtyToHistoryOptions<T> extends DirtyTrackerOptions<T> {\n history: DirtyHistorySource;\n /** Reads the current document value. */\n getValue: () => T;\n /** Existing tracker to drive (default: a new one baselined on `getValue()`). */\n tracker?: DirtyTracker<T>;\n}\n\nexport interface HistoryDirtyBinding<T> {\n readonly tracker: DirtyTracker<T>;\n /** Whether the document differs from the saved baseline. */\n readonly dirty: boolean;\n /** Marks the current value as saved. */\n markClean(): void;\n /** Runs `fn` (e.g. a load or restore) without marking the document dirty. */\n suppress<R>(fn: () => R): R;\n /** Re-reads the value after a change made outside the history. */\n refresh(): boolean;\n subscribe(listener: (dirty: boolean) => void): () => void;\n /** Stops listening to the history. */\n destroy(): void;\n}\n\n/**\n * Keeps a `DirtyTracker` in step with a `HistoryManager`: every history change\n * re-reads the value (cached per history revision), so undoing back to the\n * saved state makes the document clean again.\n */\nexport function bindDirtyToHistory<T>(\n options: BindDirtyToHistoryOptions<T>,\n): HistoryDirtyBinding<T> {\n const { history, getValue } = options;\n const tracker =\n options.tracker ??\n new DirtyTracker<T>(getValue(), {\n isEqual: options.isEqual,\n normalize: options.normalize,\n });\n const unsubscribe = history.subscribe(() => {\n tracker.update(getValue(), history.getRevision?.());\n });\n return {\n tracker,\n get dirty() {\n return tracker.dirty;\n },\n markClean: () => tracker.markClean(getValue()),\n suppress: <R>(fn: () => R): R => {\n // The loaded value becomes the baseline even if the load never touched the history.\n const rebaseline = () => {\n if (!tracker.suppressed) tracker.reset(getValue());\n };\n const result = tracker.suppress(fn);\n if (isThenable(result)) {\n return (result as unknown as Promise<unknown>).then((value) => {\n rebaseline();\n return value;\n }) as unknown as R;\n }\n rebaseline();\n return result;\n },\n refresh: () => tracker.update(getValue()),\n subscribe: (listener) => tracker.subscribe(listener),\n destroy: unsubscribe,\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-4BVP64JJ.cjs","../src/tokens/types.ts","../src/tokens/color.ts","../src/tokens/model.ts","../src/tokens/store.ts","../src/tokens/css.ts","../src/tokens/w3c.ts"],"names":["g","w3cType"],"mappings":"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CD,IAAA;AACe,IAAA;AACV,MAAA;AACY,QAAA;AACD,QAAA;AACI,QAAA;AACO,QAAA;AACV,MAAA;AACQ,QAAA;AACvB,QAAA;AACD,MAAA;AACa,IAAA;AACS,IAAA;AAGc,IAAA;AACT,IAAA;AACJ,IAAA;AACI,MAAA;AACX,QAAA;AACU,QAAA;AAC1B,MAAA;AACM,IAAA;AACmB,MAAA;AACA,MAAA;AAC1B,IAAA;AACI,IAAA;AACwB,IAAA;AACH,MAAA;AACN,MAAA;AACQ,QAAA;AACzB,QAAA;AACD,MAAA;AACgB,MAAA;AACF,MAAA;AACE,QAAA;AACf,QAAA;AACD,MAAA;AACyB,MAAA;AACE,MAAA;AAC5B,IAAA;AAC4E,IAAA;AAC3D,IAAA;AACU,IAAA;AACJ,IAAA;AACF,IAAA;AACQ,IAAA;AACL,IAAA;AACnB,MAAA;AACI,QAAA;AACQ,MAAA;AACQ,QAAA;AACxB,MAAA;AACD,IAAA;AACD,EAAA;AAG+B,EAAA;AACT,IAAA;AACI,IAAA;AACJ,IAAA;AACN,IAAA;AAEa,MAAA;AACA,MAAA;AAEzB,MAAA;AAEuB,MAAA;AAC1B,IAAA;AACe,IAAA;AACC,MAAA;AACf,MAAA;AACD,IAAA;AACgB,IAAA;AACF,IAAA;AACH,IAAA;AACY,MAAA;AACtB,MAAA;AACD,IAAA;AAC2B,IAAA;AAC5B,EAAA;AAE6B,EAAA;AAC9B;ANuyBiC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-4BVP64JJ.cjs","sourcesContent":[null,"// Portions ported from figcraft/crates/doc/src/styles.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * Design tokens (Figma-style \"variables\"): collections hold modes (e.g. Light / Dark) and\n * typed variables with one value per mode. A value is a literal or an alias to another\n * variable of the same type, possibly in another collection.\n *\n * The state is plain, immutable, JSON-serialisable data. Every operation returns a new state.\n */\n\n/** A variable's type. */\nexport type TokenType = 'color' | 'number' | 'string' | 'boolean';\n\nexport const TOKEN_TYPES: readonly TokenType[] = ['color', 'number', 'string', 'boolean'];\n\n/** A resolved value: colours are normalised hex strings (`#rrggbb` or `#rrggbbaa`). */\nexport type TokenLiteral = string | number | boolean;\n\n/** A reference to another variable (by id). */\nexport interface TokenAlias {\n\talias: string;\n}\n\n/** What a variable holds in one mode. */\nexport type TokenValue = TokenLiteral | TokenAlias;\n\nexport interface TokenMode {\n\tid: string;\n\tname: string;\n}\n\nexport interface TokenCollection {\n\tid: string;\n\tname: string;\n\t/** At least one mode. The first one is the default mode. */\n\tmodes: readonly TokenMode[];\n}\n\n/**\n * Which properties pickers offer a variable for (figcraft / Figma scope ids). Scopes only\n * filter pickers: binding out of scope still works.\n */\nexport type TokenScope =\n\t| 'ALL_SCOPES'\n\t| 'ALL_FILLS'\n\t| 'FRAME_FILL'\n\t| 'SHAPE_FILL'\n\t| 'TEXT_FILL'\n\t| 'STROKE_COLOR'\n\t| 'EFFECT_COLOR'\n\t| 'CORNER_RADIUS'\n\t| 'WIDTH_HEIGHT'\n\t| 'GAP'\n\t| 'OPACITY'\n\t| 'STROKE_FLOAT'\n\t| 'EFFECT_FLOAT'\n\t| 'FONT_WEIGHT'\n\t| 'FONT_SIZE'\n\t| 'LINE_HEIGHT'\n\t| 'LETTER_SPACING'\n\t| 'PARAGRAPH_SPACING'\n\t| 'PARAGRAPH_INDENT'\n\t| 'TEXT_CONTENT'\n\t| 'FONT_FAMILY'\n\t| 'FONT_STYLE';\n\nexport interface TokenVariable {\n\tid: string;\n\t/** Unique within its collection. `/` separates groups (`color/bg`). */\n\tname: string;\n\tcollectionId: string;\n\ttype: TokenType;\n\t/** Value per mode id of the collection. */\n\tvaluesByMode: Readonly<Record<string, TokenValue>>;\n\tdescription?: string;\n\t/** Pickers offer the variable for these scopes; `undefined` = every supported property. */\n\tscopes?: readonly TokenScope[];\n\t/** Unit for number variables in CSS / W3C export (`px`, `rem`, `ms`, …). */\n\tunit?: string;\n}\n\nexport interface TokenState {\n\tcollections: readonly TokenCollection[];\n\tvariables: readonly TokenVariable[];\n}\n\n/**\n * Chosen mode per collection: `{ [collectionId]: modeId }`. Collections not listed (or with an\n * unknown mode) use their default (first) mode.\n */\nexport type TokenModeContext = Readonly<Record<string, string>>;\n\nexport type TokenErrorCode =\n\t| 'not-found'\n\t| 'invalid-name'\n\t| 'duplicate-name'\n\t| 'name-conflict'\n\t| 'invalid-type'\n\t| 'invalid-value'\n\t| 'type-mismatch'\n\t| 'alias-missing'\n\t| 'alias-cycle'\n\t| 'last-mode'\n\t| 'unknown-scope'\n\t| 'invalid-input';\n\n/** Thrown by token operations that are refused; `code` says why. */\nexport class TokenError extends Error {\n\treadonly code: TokenErrorCode;\n\tconstructor(code: TokenErrorCode, message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'TokenError';\n\t\tthis.code = code;\n\t}\n}\n\nexport function isTokenAlias(value: unknown): value is TokenAlias {\n\treturn typeof value === 'object' && value !== null && typeof (value as TokenAlias).alias === 'string';\n}\n\nexport const EMPTY_TOKEN_STATE: TokenState = Object.freeze({ collections: Object.freeze([]), variables: Object.freeze([]) }) as TokenState;\n","/**\n * Colour parsing for colour tokens. Colours are stored as lowercase hex: `#rrggbb`, or\n * `#rrggbbaa` when not opaque. Accepted input: `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`,\n * `rgb()` / `rgba()` (numbers or percentages, comma or space separated, `/ alpha`),\n * `transparent`, `black`, `white`, `{ r, g, b, a? }` with channels in 0–1 (Figma JSON) and\n * W3C colour objects (`{ colorSpace: 'srgb', components: [r, g, b], alpha?, hex? }`).\n */\n\nconst HEX = /^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;\n// Anchored with one character-class run: linear time.\nconst RGB = /^rgba?\\(([^()]*)\\)$/i;\n\nconst clamp01 = (v: number) => Math.min(1, Math.max(0, v));\nconst byte = (v: number) => Math.round(clamp01(v) * 255);\nconst hex2 = (n: number) => n.toString(16).padStart(2, '0');\n\n/** `#rrggbb` / `#rrggbbaa` from 0–1 channels. */\nexport function rgbaToHex(r: number, g: number, b: number, a = 1): string {\n\tconst head = `#${hex2(byte(r))}${hex2(byte(g))}${hex2(byte(b))}`;\n\tconst alpha = byte(a);\n\treturn alpha === 255 ? head : head + hex2(alpha);\n}\n\n/** 0–1 channels of a normalised hex colour. */\nexport function hexToRgba(hex: string): { r: number; g: number; b: number; a: number } | null {\n\tconst normal = normalizeTokenColor(hex);\n\tif (normal === null) return null;\n\tconst n = (i: number) => parseInt(normal.slice(i, i + 2), 16) / 255;\n\treturn { r: n(1), g: n(3), b: n(5), a: normal.length === 9 ? n(7) : 1 };\n}\n\nfunction channel(part: string, scale: number): number | null {\n\tconst pct = part.endsWith('%');\n\tconst n = Number(pct ? part.slice(0, -1) : part);\n\tif (!Number.isFinite(n)) return null;\n\treturn pct ? n / 100 : n / scale;\n}\n\n/** The colour as normalised hex, or `null` when it is not a colour this module reads. */\nexport function normalizeTokenColor(input: unknown): string | null {\n\tif (typeof input === 'string') {\n\t\tconst text = input.trim();\n\t\tif (text.length > 200) return null;\n\t\tconst lower = text.toLowerCase();\n\t\tif (lower === 'transparent') return '#00000000';\n\t\tif (lower === 'black') return '#000000';\n\t\tif (lower === 'white') return '#ffffff';\n\t\tconst hex = HEX.exec(text);\n\t\tif (hex) {\n\t\t\tlet digits = hex[1].toLowerCase();\n\t\t\tif (digits.length <= 4) digits = [...digits].map((c) => c + c).join('');\n\t\t\tif (digits.length === 8 && digits.endsWith('ff')) digits = digits.slice(0, 6);\n\t\t\treturn `#${digits}`;\n\t\t}\n\t\tconst rgb = RGB.exec(text);\n\t\tif (rgb) {\n\t\t\tconst [colour, alphaPart] = rgb[1].split('/');\n\t\t\tconst parts = colour.split(/[\\s,]+/).filter(Boolean);\n\t\t\tlet alpha: string | undefined = alphaPart?.trim();\n\t\t\tif (parts.length === 4 && alpha === undefined) alpha = parts.pop();\n\t\t\tif (parts.length !== 3) return null;\n\t\t\tconst channels = parts.map((p) => channel(p, 255));\n\t\t\tconst a = alpha === undefined || alpha === '' ? 1 : channel(alpha, 1);\n\t\t\tif (channels.some((c) => c === null) || a === null) return null;\n\t\t\treturn rgbaToHex(channels[0]!, channels[1]!, channels[2]!, a);\n\t\t}\n\t\treturn null;\n\t}\n\tif (typeof input === 'object' && input !== null) {\n\t\tconst obj = input as Record<string, unknown>;\n\t\tif (Array.isArray(obj.components)) {\n\t\t\tconst space = obj.colorSpace;\n\t\t\tif (space === undefined || space === 'srgb') {\n\t\t\t\tconst [r, g, b] = obj.components as unknown[];\n\t\t\t\tconst a = obj.alpha === undefined ? 1 : obj.alpha;\n\t\t\t\tif ([r, g, b, a].every((v) => typeof v === 'number' && Number.isFinite(v))) {\n\t\t\t\t\treturn rgbaToHex(r as number, g as number, b as number, a as number);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (typeof obj.hex === 'string') {\n\t\t\t\tconst base = normalizeTokenColor(obj.hex);\n\t\t\t\tif (base === null) return null;\n\t\t\t\tconst a = typeof obj.alpha === 'number' ? obj.alpha : 1;\n\t\t\t\tconst c = hexToRgba(base)!;\n\t\t\t\treturn rgbaToHex(c.r, c.g, c.b, a);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\tconst { r, g, b } = obj;\n\t\tconst a = obj.a === undefined ? 1 : obj.a;\n\t\tif ([r, g, b, a].every((v) => typeof v === 'number' && Number.isFinite(v))) {\n\t\t\treturn rgbaToHex(r as number, g as number, b as number, a as number);\n\t\t}\n\t}\n\treturn null;\n}\n","// Portions ported from figcraft/crates/doc/src/styles.rs and figcraft/crates/engine/src/cmd/variables.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\nimport { normalizeTokenColor } from './color.js';\nimport {\n\tTokenError,\n\tisTokenAlias,\n\ttype TokenCollection,\n\ttype TokenLiteral,\n\ttype TokenMode,\n\ttype TokenModeContext,\n\ttype TokenScope,\n\ttype TokenState,\n\ttype TokenType,\n\ttype TokenValue,\n\ttype TokenVariable\n} from './types.js';\n\n// ---------------------------------------------------------------------------------------------\n// Lookups\n\ninterface TokenIndex {\n\tcollections: Map<string, TokenCollection>;\n\tvariables: Map<string, TokenVariable>;\n}\n\nconst indexes = new WeakMap<TokenState, TokenIndex>();\n\nfunction indexOf(state: TokenState): TokenIndex {\n\tlet index = indexes.get(state);\n\tif (!index) {\n\t\tindex = {\n\t\t\tcollections: new Map(state.collections.map((c) => [c.id, c])),\n\t\t\tvariables: new Map(state.variables.map((v) => [v.id, v]))\n\t\t};\n\t\tindexes.set(state, index);\n\t}\n\treturn index;\n}\n\nexport function getTokenCollection(state: TokenState, id: string): TokenCollection | undefined {\n\treturn indexOf(state).collections.get(id);\n}\n\nexport function getTokenVariable(state: TokenState, id: string): TokenVariable | undefined {\n\treturn indexOf(state).variables.get(id);\n}\n\n/** The collection with this name. */\nexport function findTokenCollection(state: TokenState, name: string): TokenCollection | undefined {\n\treturn state.collections.find((c) => c.name === name);\n}\n\n/** The variable named `name` (in `collectionId` when given, else the first match). */\nexport function findTokenVariable(state: TokenState, name: string, collectionId?: string): TokenVariable | undefined {\n\treturn state.variables.find((v) => v.name === name && (collectionId === undefined || v.collectionId === collectionId));\n}\n\n/** The variables of a collection, in order. */\nexport function getCollectionVariables(state: TokenState, collectionId: string): TokenVariable[] {\n\treturn state.variables.filter((v) => v.collectionId === collectionId);\n}\n\n/** The collection's default (first) mode. */\nexport function getDefaultMode(collection: TokenCollection): TokenMode {\n\treturn collection.modes[0];\n}\n\n/** The mode with id `key`, else the one named `key`. */\nexport function findTokenMode(collection: TokenCollection, key: string): TokenMode | undefined {\n\treturn collection.modes.find((m) => m.id === key) ?? collection.modes.find((m) => m.name === key);\n}\n\n/** The mode `collection` is in under `modes` (its chosen mode if valid, else the default). */\nexport function getCurrentMode(collection: TokenCollection, modes: TokenModeContext | undefined): TokenMode {\n\tconst chosen = modes?.[collection.id];\n\treturn (chosen !== undefined && collection.modes.find((m) => m.id === chosen)) || collection.modes[0];\n}\n\n// ---------------------------------------------------------------------------------------------\n// Values\n\n/** A new variable's value per type: black, 0, empty, true (figcraft's pinned defaults). */\nexport function defaultTokenValue(type: TokenType): TokenLiteral {\n\tswitch (type) {\n\t\tcase 'color':\n\t\t\treturn '#000000';\n\t\tcase 'number':\n\t\t\treturn 0;\n\t\tcase 'string':\n\t\t\treturn '';\n\t\tcase 'boolean':\n\t\t\treturn true;\n\t}\n}\n\n/** The literal as `type`, or `null` when it does not fit (colours are normalised). */\nexport function coerceTokenLiteral(type: TokenType, value: unknown): TokenLiteral | null {\n\tswitch (type) {\n\t\tcase 'color':\n\t\t\treturn normalizeTokenColor(value);\n\t\tcase 'number': {\n\t\t\tif (typeof value === 'number') return Number.isFinite(value) ? value : null;\n\t\t\tif (typeof value === 'string' && value.trim() !== '') {\n\t\t\t\tconst n = Number(value);\n\t\t\t\treturn Number.isFinite(n) ? n : null;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\tcase 'string':\n\t\t\treturn typeof value === 'string' ? value : null;\n\t\tcase 'boolean':\n\t\t\tif (typeof value === 'boolean') return value;\n\t\t\tif (value === 'true') return true;\n\t\t\tif (value === 'false') return false;\n\t\t\treturn null;\n\t}\n}\n\n/** The type of a literal value (strings that are colours count as strings). */\nexport function literalTokenType(value: TokenLiteral): TokenType {\n\treturn typeof value === 'number' ? 'number' : typeof value === 'boolean' ? 'boolean' : 'string';\n}\n\n/** A short text for a value: hex, number, string, boolean, or `→ name` for an alias. */\nexport function formatTokenValue(state: TokenState, value: TokenValue | undefined): string {\n\tif (value === undefined) return '';\n\tif (isTokenAlias(value)) return `→ ${getTokenVariable(state, value.alias)?.name ?? value.alias}`;\n\treturn String(value);\n}\n\n// ---------------------------------------------------------------------------------------------\n// Resolution\n\nexport type TokenResolutionErrorCode = 'missing' | 'cycle' | 'no-value' | 'type-mismatch';\n\nexport type TokenResolution =\n\t| {\n\t\t\tok: true;\n\t\t\tvalue: TokenLiteral;\n\t\t\ttype: TokenType;\n\t\t\t/** The variable whose literal was used (the end of the alias chain). */\n\t\t\tvariable: TokenVariable;\n\t\t\t/** Mode of `variable`'s collection that supplied the value. */\n\t\t\tmodeId: string;\n\t\t\t/** Variable ids visited, starting with the requested one. */\n\t\t\tchain: string[];\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\tcode: TokenResolutionErrorCode;\n\t\t\tmessage: string;\n\t\t\tchain: string[];\n\t };\n\n/** The name of a variable for messages. */\nfunction label(state: TokenState, id: string): string {\n\tconst v = getTokenVariable(state, id);\n\treturn v ? `\\`${v.name}\\`` : `\\`${id}\\``;\n}\n\n/**\n * Resolves variable `id` under `modes` (collection id → mode id; the default mode otherwise),\n * following aliases. Each variable along the chain is read in its own collection's mode.\n * Cycles, missing variables and type changes along the chain are reported, never thrown.\n */\nexport function resolveToken(state: TokenState, id: string, modes?: TokenModeContext): TokenResolution {\n\tconst chain: string[] = [];\n\tconst seen = new Set<string>();\n\tlet current = id;\n\tlet type: TokenType | undefined;\n\tfor (;;) {\n\t\tif (seen.has(current)) {\n\t\t\tchain.push(current);\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tcode: 'cycle',\n\t\t\t\tmessage: `Alias cycle: ${chain.map((c) => label(state, c)).join(' → ')}`,\n\t\t\t\tchain\n\t\t\t};\n\t\t}\n\t\tseen.add(current);\n\t\tchain.push(current);\n\t\tconst variable = getTokenVariable(state, current);\n\t\tif (!variable) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tcode: 'missing',\n\t\t\t\tmessage:\n\t\t\t\t\tchain.length === 1\n\t\t\t\t\t\t? `No variable ${label(state, current)}`\n\t\t\t\t\t\t: `${label(state, chain[chain.length - 2])} aliases a missing variable ${label(state, current)}`,\n\t\t\t\tchain\n\t\t\t};\n\t\t}\n\t\tif (type !== undefined && variable.type !== type) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tcode: 'type-mismatch',\n\t\t\t\tmessage: `${label(state, chain[chain.length - 2])} (${type}) aliases ${label(state, current)} (${variable.type})`,\n\t\t\t\tchain\n\t\t\t};\n\t\t}\n\t\ttype = variable.type;\n\t\tconst collection = getTokenCollection(state, variable.collectionId);\n\t\tconst mode = collection ? getCurrentMode(collection, modes) : undefined;\n\t\tlet modeId = mode?.id;\n\t\tlet value = modeId !== undefined ? variable.valuesByMode[modeId] : undefined;\n\t\tif (value === undefined) {\n\t\t\t// figcraft: a missing per-mode value falls back to the default mode, then any value.\n\t\t\tconst fallback = collection?.modes[0]?.id;\n\t\t\tif (fallback !== undefined && variable.valuesByMode[fallback] !== undefined) {\n\t\t\t\tmodeId = fallback;\n\t\t\t\tvalue = variable.valuesByMode[fallback];\n\t\t\t} else {\n\t\t\t\tconst first = Object.keys(variable.valuesByMode)[0];\n\t\t\t\tif (first !== undefined) {\n\t\t\t\t\tmodeId = first;\n\t\t\t\t\tvalue = variable.valuesByMode[first];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (value === undefined || modeId === undefined) {\n\t\t\treturn { ok: false, code: 'no-value', message: `${label(state, current)} has no value`, chain };\n\t\t}\n\t\tif (isTokenAlias(value)) {\n\t\t\tcurrent = value.alias;\n\t\t\tcontinue;\n\t\t}\n\t\treturn { ok: true, value, type: variable.type, variable, modeId, chain };\n\t}\n}\n\n/** The resolved literal, or `undefined` when it does not resolve. */\nexport function resolveTokenValue(state: TokenState, id: string, modes?: TokenModeContext): TokenLiteral | undefined {\n\tconst result = resolveToken(state, id, modes);\n\treturn result.ok ? result.value : undefined;\n}\n\n/** The value of `variableId` in mode `modeId` of its own collection (other collections in their default mode). */\nexport function resolveTokenInMode(state: TokenState, variableId: string, modeId: string): TokenLiteral | undefined {\n\tconst variable = getTokenVariable(state, variableId);\n\tif (!variable) return undefined;\n\treturn resolveTokenValue(state, variableId, { [variable.collectionId]: modeId });\n}\n\n/**\n * Why `variable` cannot alias `targetId`, or `null` when it can: the target must exist, have\n * the same type, and not lead back to `variable` through any alias in any mode.\n */\nexport function checkTokenAlias(state: TokenState, variable: Pick<TokenVariable, 'id' | 'type' | 'name'>, targetId: string): TokenError | null {\n\tconst target = getTokenVariable(state, targetId);\n\tif (!target) return new TokenError('alias-missing', `No variable \\`${targetId}\\` to alias`);\n\tif (target.type !== variable.type) {\n\t\treturn new TokenError('type-mismatch', `Can't alias a ${variable.type} variable to a ${target.type} one (\\`${target.name}\\`)`);\n\t}\n\t// Depth-first search over alias edges in every mode, remembering the path for the message.\n\tconst parent = new Map<string, string | null>([[target.id, null]]);\n\tconst stack = [target.id];\n\twhile (stack.length > 0) {\n\t\tconst current = stack.pop()!;\n\t\tif (current === variable.id) {\n\t\t\tconst path: string[] = [];\n\t\t\tfor (let at: string | null | undefined = current; at != null; at = parent.get(at)) path.push(at);\n\t\t\tconst names = [variable.id, ...path.reverse()].map((id) => (id === variable.id ? `\\`${variable.name}\\`` : label(state, id)));\n\t\t\treturn new TokenError('alias-cycle', `The alias would create a cycle: ${names.join(' → ')}`);\n\t\t}\n\t\tconst v = getTokenVariable(state, current);\n\t\tif (!v) continue;\n\t\tfor (const value of Object.values(v.valuesByMode)) {\n\t\t\tif (isTokenAlias(value) && !parent.has(value.alias)) {\n\t\t\t\tparent.set(value.alias, current);\n\t\t\t\tstack.push(value.alias);\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Scopes\n\nexport const TOKEN_SCOPES_BY_TYPE: Readonly<Record<TokenType, readonly TokenScope[]>> = {\n\tnumber: [\n\t\t'CORNER_RADIUS',\n\t\t'WIDTH_HEIGHT',\n\t\t'GAP',\n\t\t'OPACITY',\n\t\t'STROKE_FLOAT',\n\t\t'EFFECT_FLOAT',\n\t\t'FONT_WEIGHT',\n\t\t'FONT_SIZE',\n\t\t'LINE_HEIGHT',\n\t\t'LETTER_SPACING',\n\t\t'PARAGRAPH_SPACING',\n\t\t'PARAGRAPH_INDENT',\n\t\t'TEXT_CONTENT'\n\t],\n\tcolor: ['FRAME_FILL', 'SHAPE_FILL', 'TEXT_FILL', 'STROKE_COLOR', 'EFFECT_COLOR'],\n\tstring: ['TEXT_CONTENT', 'FONT_FAMILY', 'FONT_STYLE'],\n\tboolean: []\n};\n\n/** Whether `scope` is a scope a variable of `type` can be limited to. */\nexport function isTokenScopeKnown(type: TokenType, scope: string): scope is TokenScope {\n\treturn scope === 'ALL_SCOPES' || (scope === 'ALL_FILLS' && type === 'color') || (TOKEN_SCOPES_BY_TYPE[type] as readonly string[]).includes(scope);\n}\n\n/**\n * Canonical scope list: known ids only, no repeats, `undefined` (no limit) when every\n * supported property is named. Unknown ids throw `unknown-scope`.\n */\nexport function normalizeTokenScopes(type: TokenType, scopes: readonly string[] | null | undefined): TokenScope[] | undefined {\n\tif (scopes == null) return undefined;\n\tconst list: TokenScope[] = [];\n\tfor (const scope of scopes) {\n\t\tif (!isTokenScopeKnown(type, scope)) throw new TokenError('unknown-scope', `Unknown ${type} scope \\`${scope}\\``);\n\t\tif (!list.includes(scope)) list.push(scope);\n\t}\n\tconst allowed = TOKEN_SCOPES_BY_TYPE[type];\n\tconst all = list.includes('ALL_SCOPES') || (allowed.length > 0 && allowed.every((s) => list.includes(s)));\n\treturn all ? undefined : list;\n}\n\n/** Whether pickers offer `variable` for a property of `scope` (no scope: any). */\nexport function isTokenInScope(variable: Pick<TokenVariable, 'scopes'>, scope: TokenScope | undefined): boolean {\n\tif (!variable.scopes || scope === undefined) return true;\n\treturn variable.scopes.some((s) => s === scope || s === 'ALL_SCOPES' || (s === 'ALL_FILLS' && scope.endsWith('_FILL')));\n}\n\n// ---------------------------------------------------------------------------------------------\n// Names\n\nconst BAD_NAME_CHARS = /[{}.]/;\n\n/** Trims each `/`-separated group; throws `invalid-name` when empty or not exportable. */\nexport function normalizeTokenName(name: unknown, what = 'Variable'): string {\n\tif (typeof name !== 'string') throw new TokenError('invalid-name', `${what} name must be a string`);\n\tconst segments = name.split('/').map((s) => s.trim());\n\tif (name.length > 500 || segments.some((s) => s === '')) {\n\t\tthrow new TokenError('invalid-name', `${what} name \\`${name}\\` has an empty group`);\n\t}\n\tfor (const segment of segments) {\n\t\tif (BAD_NAME_CHARS.test(segment) || segment.startsWith('$')) {\n\t\t\tthrow new TokenError('invalid-name', `${what} name \\`${name}\\` can't contain \\`{\\`, \\`}\\` or \\`.\\`, or start a group with \\`$\\``);\n\t\t}\n\t}\n\treturn segments.join('/');\n}\n\nfunction normalizeModeName(name: unknown): string {\n\tif (typeof name !== 'string' || name.trim() === '') throw new TokenError('invalid-name', 'Mode name can\\'t be empty');\n\treturn name.trim().slice(0, 200);\n}\n\nfunction checkVariableName(state: TokenState, collectionId: string, name: string, exceptId?: string): void {\n\tfor (const other of state.variables) {\n\t\tif (other.collectionId !== collectionId || other.id === exceptId) continue;\n\t\tif (other.name === name) throw new TokenError('duplicate-name', `A variable named \\`${name}\\` already exists in this collection`);\n\t\t// A token can't also be a group (W3C design tokens): `color` and `color/bg` clash.\n\t\tif (other.name.startsWith(name + '/') || name.startsWith(other.name + '/')) {\n\t\t\tthrow new TokenError('name-conflict', `\\`${name}\\` clashes with \\`${other.name}\\`: a name can't be both a variable and a group`);\n\t\t}\n\t}\n}\n\n// ---------------------------------------------------------------------------------------------\n// Operations (pure: each returns a new state, or throws a TokenError)\n\nexport type TokenIdFactory = (kind: 'collection' | 'mode' | 'variable') => string;\n\nlet fallbackCounter = 0;\n/** Default id factory: `crypto.randomUUID`, with a counter fallback. */\nexport const defaultTokenId: TokenIdFactory = (kind) => {\n\tif (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') return `${kind}-${crypto.randomUUID()}`;\n\tfallbackCounter += 1;\n\treturn `${kind}-${Date.now().toString(36)}-${fallbackCounter}`;\n};\n\nfunction requireCollection(state: TokenState, id: string): TokenCollection {\n\tconst c = getTokenCollection(state, id);\n\tif (!c) throw new TokenError('not-found', `No collection \\`${id}\\``);\n\treturn c;\n}\n\nfunction requireVariable(state: TokenState, id: string): TokenVariable {\n\tconst v = getTokenVariable(state, id);\n\tif (!v) throw new TokenError('not-found', `No variable \\`${id}\\``);\n\treturn v;\n}\n\nfunction requireMode(collection: TokenCollection, key: string): TokenMode {\n\tconst m = findTokenMode(collection, key);\n\tif (!m) throw new TokenError('not-found', `No mode \\`${key}\\` in \\`${collection.name}\\``);\n\treturn m;\n}\n\nfunction replaceCollection(state: TokenState, next: TokenCollection): TokenState {\n\treturn { ...state, collections: state.collections.map((c) => (c.id === next.id ? next : c)) };\n}\n\nfunction replaceVariable(state: TokenState, next: TokenVariable): TokenState {\n\treturn { ...state, variables: state.variables.map((v) => (v.id === next.id ? next : v)) };\n}\n\nexport interface CreateTokenCollectionInput {\n\tname: string;\n\t/** Mode names (default `['Default']`). */\n\tmodes?: readonly string[];\n}\n\nexport function createTokenCollection(\n\tstate: TokenState,\n\tinput: CreateTokenCollectionInput,\n\tcreateId: TokenIdFactory = defaultTokenId\n): { state: TokenState; collection: TokenCollection } {\n\tconst name = normalizeTokenName(input.name, 'Collection');\n\tif (state.collections.some((c) => c.name === name)) {\n\t\tthrow new TokenError('duplicate-name', `A collection named \\`${name}\\` already exists`);\n\t}\n\tconst modeNames = input.modes && input.modes.length > 0 ? input.modes.map(normalizeModeName) : ['Default'];\n\tconst collection: TokenCollection = {\n\t\tid: createId('collection'),\n\t\tname,\n\t\tmodes: modeNames.map((n) => ({ id: createId('mode'), name: n }))\n\t};\n\treturn { state: { ...state, collections: [...state.collections, collection] }, collection };\n}\n\nexport function renameTokenCollection(state: TokenState, id: string, name: string): TokenState {\n\tconst collection = requireCollection(state, id);\n\tconst next = normalizeTokenName(name, 'Collection');\n\tif (state.collections.some((c) => c.id !== id && c.name === next)) {\n\t\tthrow new TokenError('duplicate-name', `A collection named \\`${next}\\` already exists`);\n\t}\n\treturn replaceCollection(state, { ...collection, name: next });\n}\n\n/**\n * Deletes variables `ids`. Variables aliasing one of them take its values (per mode: the deleted\n * variable resolved in that mode when it is in the same collection, else in its default mode).\n */\nexport function deleteTokenVariables(state: TokenState, ids: Iterable<string>): { state: TokenState; deleted: string[] } {\n\tconst gone = new Set<string>();\n\tfor (const id of ids) if (getTokenVariable(state, id)) gone.add(id);\n\tif (gone.size === 0) return { state, deleted: [] };\n\tconst variables: TokenVariable[] = [];\n\tfor (const v of state.variables) {\n\t\tif (gone.has(v.id)) continue;\n\t\tlet values: Record<string, TokenValue> | null = null;\n\t\tfor (const [modeId, value] of Object.entries(v.valuesByMode)) {\n\t\t\tif (!isTokenAlias(value) || !gone.has(value.alias)) continue;\n\t\t\tconst target = getTokenVariable(state, value.alias)!;\n\t\t\tconst resolved = resolveTokenValue(state, target.id, { [target.collectionId]: modeId, [v.collectionId]: modeId });\n\t\t\tvalues ??= { ...v.valuesByMode };\n\t\t\tvalues[modeId] = resolved ?? defaultTokenValue(v.type);\n\t\t}\n\t\tvariables.push(values ? { ...v, valuesByMode: values } : v);\n\t}\n\treturn { state: { ...state, variables }, deleted: [...gone] };\n}\n\n/** Deletes a collection and its variables (aliases into it are detached to their values). */\nexport function deleteTokenCollection(state: TokenState, id: string): { state: TokenState; deleted: string[] } {\n\trequireCollection(state, id);\n\tconst result = deleteTokenVariables(\n\t\tstate,\n\t\tstate.variables.filter((v) => v.collectionId === id).map((v) => v.id)\n\t);\n\treturn { state: { ...result.state, collections: result.state.collections.filter((c) => c.id !== id) }, deleted: result.deleted };\n}\n\n/**\n * Adds a mode. Variables start with the values of mode `from` (default: the default mode).\n */\nexport function addTokenMode(\n\tstate: TokenState,\n\tcollectionId: string,\n\tname: string,\n\toptions: { from?: string } = {},\n\tcreateId: TokenIdFactory = defaultTokenId\n): { state: TokenState; mode: TokenMode } {\n\tconst collection = requireCollection(state, collectionId);\n\tconst modeName = normalizeModeName(name);\n\tif (collection.modes.some((m) => m.name === modeName)) {\n\t\tthrow new TokenError('duplicate-name', `\\`${collection.name}\\` already has a mode named \\`${modeName}\\``);\n\t}\n\tconst source = options.from !== undefined ? requireMode(collection, options.from) : collection.modes[0];\n\tconst mode: TokenMode = { id: createId('mode'), name: modeName };\n\tlet next = replaceCollection(state, { ...collection, modes: [...collection.modes, mode] });\n\tnext = {\n\t\t...next,\n\t\tvariables: next.variables.map((v) => {\n\t\t\tif (v.collectionId !== collectionId) return v;\n\t\t\tconst value = v.valuesByMode[source.id] ?? defaultTokenValue(v.type);\n\t\t\treturn { ...v, valuesByMode: { ...v.valuesByMode, [mode.id]: value } };\n\t\t})\n\t};\n\treturn { state: next, mode };\n}\n\nexport function renameTokenMode(state: TokenState, collectionId: string, modeId: string, name: string): TokenState {\n\tconst collection = requireCollection(state, collectionId);\n\tconst mode = requireMode(collection, modeId);\n\tconst modeName = normalizeModeName(name);\n\tif (collection.modes.some((m) => m.id !== mode.id && m.name === modeName)) {\n\t\tthrow new TokenError('duplicate-name', `\\`${collection.name}\\` already has a mode named \\`${modeName}\\``);\n\t}\n\treturn replaceCollection(state, { ...collection, modes: collection.modes.map((m) => (m.id === mode.id ? { ...m, name: modeName } : m)) });\n}\n\n/** Removes a mode and its values; a collection keeps at least one mode. */\nexport function removeTokenMode(state: TokenState, collectionId: string, modeId: string): TokenState {\n\tconst collection = requireCollection(state, collectionId);\n\tconst mode = requireMode(collection, modeId);\n\tif (collection.modes.length < 2) throw new TokenError('last-mode', 'A collection keeps at least one mode');\n\tconst next = replaceCollection(state, { ...collection, modes: collection.modes.filter((m) => m.id !== mode.id) });\n\treturn {\n\t\t...next,\n\t\tvariables: next.variables.map((v) => {\n\t\t\tif (v.collectionId !== collectionId || !(mode.id in v.valuesByMode)) return v;\n\t\t\tconst values = { ...v.valuesByMode };\n\t\t\tdelete values[mode.id];\n\t\t\treturn { ...v, valuesByMode: values };\n\t\t})\n\t};\n}\n\n/** Moves a mode to index `to` (clamped). Index 0 makes it the default mode. */\nexport function moveTokenMode(state: TokenState, collectionId: string, modeId: string, to: number): TokenState {\n\tconst collection = requireCollection(state, collectionId);\n\tconst mode = requireMode(collection, modeId);\n\tconst modes = collection.modes.filter((m) => m.id !== mode.id);\n\tconst at = Math.min(Math.max(Number.isFinite(to) ? Math.trunc(to) : 0, 0), modes.length);\n\tmodes.splice(at, 0, mode);\n\treturn replaceCollection(state, { ...collection, modes });\n}\n\nexport interface CreateTokenVariableInput {\n\tcollectionId: string;\n\tname: string;\n\ttype: TokenType;\n\t/** Value for every mode (literal or `{ alias }`). Default: the type's default. */\n\tvalue?: unknown;\n\t/** Values by mode id or name (win over `value`). */\n\tvalues?: Readonly<Record<string, unknown>>;\n\tdescription?: string;\n\tscopes?: readonly string[];\n\tunit?: string;\n}\n\n/** A value for `variable`: a normalised literal or a checked alias. Throws when refused. */\nexport function prepareTokenValue(state: TokenState, variable: Pick<TokenVariable, 'id' | 'type' | 'name'>, value: unknown): TokenValue {\n\tif (isTokenAlias(value)) {\n\t\tconst error = checkTokenAlias(state, variable, value.alias);\n\t\tif (error) throw error;\n\t\treturn { alias: value.alias };\n\t}\n\tconst literal = coerceTokenLiteral(variable.type, value);\n\tif (literal === null) {\n\t\tthrow new TokenError('invalid-value', `\\`${String(value)}\\` is not a ${variable.type} value for \\`${variable.name}\\``);\n\t}\n\treturn literal;\n}\n\nfunction normalizeUnit(unit: unknown): string | undefined {\n\tif (unit === undefined || unit === null || unit === '') return undefined;\n\tif (typeof unit !== 'string' || !/^[a-z%]{1,8}$/i.test(unit)) throw new TokenError('invalid-value', `Unknown unit \\`${String(unit)}\\``);\n\treturn unit.toLowerCase();\n}\n\nexport function createTokenVariable(\n\tstate: TokenState,\n\tinput: CreateTokenVariableInput,\n\tcreateId: TokenIdFactory = defaultTokenId\n): { state: TokenState; variable: TokenVariable } {\n\tconst collection = requireCollection(state, input.collectionId);\n\tif (!(['color', 'number', 'string', 'boolean'] as unknown[]).includes(input.type)) {\n\t\tthrow new TokenError('invalid-type', `Unknown variable type \\`${String(input.type)}\\``);\n\t}\n\tconst name = normalizeTokenName(input.name);\n\tcheckVariableName(state, collection.id, name);\n\tconst id = createId('variable');\n\tconst stub = { id, type: input.type, name };\n\tconst base = input.value === undefined ? defaultTokenValue(input.type) : prepareTokenValue(state, stub, input.value);\n\tconst valuesByMode: Record<string, TokenValue> = {};\n\tfor (const mode of collection.modes) valuesByMode[mode.id] = base;\n\tif (input.values) {\n\t\tfor (const [key, raw] of Object.entries(input.values)) {\n\t\t\tconst mode = requireMode(collection, key);\n\t\t\tvaluesByMode[mode.id] = prepareTokenValue(state, stub, raw);\n\t\t}\n\t}\n\tconst variable: TokenVariable = {\n\t\tid,\n\t\tname,\n\t\tcollectionId: collection.id,\n\t\ttype: input.type,\n\t\tvaluesByMode,\n\t\t...(input.description ? { description: String(input.description) } : {}),\n\t\t...(input.scopes !== undefined ? { scopes: normalizeTokenScopes(input.type, input.scopes) } : {}),\n\t};\n\tif (variable.scopes === undefined) delete variable.scopes;\n\tconst unit = normalizeUnit(input.unit);\n\tif (unit) variable.unit = unit;\n\treturn { state: { ...state, variables: [...state.variables, variable] }, variable };\n}\n\n/**\n * Sets a variable's value in one mode (id or name; default: the default mode) to a literal or\n * `{ alias: variableId }`. Aliases must keep the type and not create a cycle.\n */\nexport function setTokenValue(state: TokenState, variableId: string, value: unknown, modeId?: string): TokenState {\n\tconst variable = requireVariable(state, variableId);\n\tconst collection = requireCollection(state, variable.collectionId);\n\tconst mode = modeId === undefined ? collection.modes[0] : requireMode(collection, modeId);\n\tconst prepared = prepareTokenValue(state, variable, value);\n\tconst current = variable.valuesByMode[mode.id];\n\tif (current === prepared || (isTokenAlias(current) && isTokenAlias(prepared) && current.alias === prepared.alias)) return state;\n\treturn replaceVariable(state, { ...variable, valuesByMode: { ...variable.valuesByMode, [mode.id]: prepared } });\n}\n\nexport function renameTokenVariable(state: TokenState, variableId: string, name: string): TokenState {\n\tconst variable = requireVariable(state, variableId);\n\tconst next = normalizeTokenName(name);\n\tif (next === variable.name) return state;\n\tcheckVariableName(state, variable.collectionId, next, variable.id);\n\treturn replaceVariable(state, { ...variable, name: next });\n}\n\nexport interface UpdateTokenVariableInput {\n\tdescription?: string;\n\t/** `null` clears the limit (every property). */\n\tscopes?: readonly string[] | null;\n\t/** `null` clears the unit. */\n\tunit?: string | null;\n}\n\nexport function updateTokenVariable(state: TokenState, variableId: string, input: UpdateTokenVariableInput): TokenState {\n\tconst variable = requireVariable(state, variableId);\n\tconst next: TokenVariable = { ...variable };\n\tif (input.description !== undefined) {\n\t\tif (input.description) next.description = String(input.description);\n\t\telse delete next.description;\n\t}\n\tif (input.scopes !== undefined) {\n\t\tconst scopes = normalizeTokenScopes(variable.type, input.scopes);\n\t\tif (scopes) next.scopes = scopes;\n\t\telse delete next.scopes;\n\t}\n\tif (input.unit !== undefined) {\n\t\tconst unit = normalizeUnit(input.unit);\n\t\tif (unit) next.unit = unit;\n\t\telse delete next.unit;\n\t}\n\treturn replaceVariable(state, next);\n}\n\n// ---------------------------------------------------------------------------------------------\n// Validation of untrusted state\n\nexport interface TokenStateIssue {\n\tmessage: string;\n\tcollectionId?: string;\n\tvariableId?: string;\n}\n\n/**\n * Reads untrusted data (e.g. a saved `TokenState`) and keeps what is valid: junk collections,\n * modes and variables are dropped, bad values replaced by the type's default and alias cycles\n * broken, each with an issue.\n */\nexport function parseTokenState(input: unknown): { state: TokenState; issues: TokenStateIssue[] } {\n\tconst issues: TokenStateIssue[] = [];\n\tlet raw = input;\n\tif (typeof raw === 'string') {\n\t\ttry {\n\t\t\traw = JSON.parse(raw);\n\t\t} catch {\n\t\t\treturn { state: { collections: [], variables: [] }, issues: [{ message: 'Not JSON' }] };\n\t\t}\n\t}\n\tconst obj = (typeof raw === 'object' && raw !== null ? raw : {}) as Record<string, unknown>;\n\tconst collections: TokenCollection[] = [];\n\tconst ids = new Set<string>();\n\tfor (const c of Array.isArray(obj.collections) ? obj.collections : []) {\n\t\tconst item = c as Partial<TokenCollection> | null;\n\t\tconst modes = Array.isArray(item?.modes)\n\t\t\t? (item!.modes as unknown[]).filter(\n\t\t\t\t\t(m): m is TokenMode => typeof m === 'object' && m !== null && typeof (m as TokenMode).id === 'string' && typeof (m as TokenMode).name === 'string'\n\t\t\t\t)\n\t\t\t: [];\n\t\tif (!item || typeof item.id !== 'string' || typeof item.name !== 'string' || modes.length === 0 || ids.has(item.id)) {\n\t\t\tissues.push({ message: 'Dropped an invalid collection' });\n\t\t\tcontinue;\n\t\t}\n\t\tids.add(item.id);\n\t\tcollections.push({ id: item.id, name: item.name, modes: modes.map((m) => ({ id: m.id, name: m.name })) });\n\t}\n\tconst byId = new Map(collections.map((c) => [c.id, c]));\n\tconst variables: TokenVariable[] = [];\n\tconst varIds = new Set<string>();\n\tfor (const v of Array.isArray(obj.variables) ? obj.variables : []) {\n\t\tconst item = v as Partial<TokenVariable> | null;\n\t\tconst collection = item && typeof item.collectionId === 'string' ? byId.get(item.collectionId) : undefined;\n\t\tif (\n\t\t\t!item ||\n\t\t\ttypeof item.id !== 'string' ||\n\t\t\ttypeof item.name !== 'string' ||\n\t\t\t!collection ||\n\t\t\t!(['color', 'number', 'string', 'boolean'] as unknown[]).includes(item.type) ||\n\t\t\tvarIds.has(item.id)\n\t\t) {\n\t\t\tissues.push({ message: 'Dropped an invalid variable', variableId: typeof item?.id === 'string' ? item.id : undefined });\n\t\t\tcontinue;\n\t\t}\n\t\tvarIds.add(item.id);\n\t\tconst type = item.type as TokenType;\n\t\tconst values: Record<string, TokenValue> = {};\n\t\tconst rawValues = (typeof item.valuesByMode === 'object' && item.valuesByMode !== null ? item.valuesByMode : {}) as Record<string, unknown>;\n\t\tfor (const mode of collection.modes) {\n\t\t\tconst value = rawValues[mode.id];\n\t\t\tif (isTokenAlias(value)) values[mode.id] = { alias: value.alias };\n\t\t\telse {\n\t\t\t\tconst literal = coerceTokenLiteral(type, value);\n\t\t\t\tif (literal === null) issues.push({ message: `\\`${item.name}\\` had no valid value in \\`${mode.name}\\``, variableId: item.id });\n\t\t\t\tvalues[mode.id] = literal ?? defaultTokenValue(type);\n\t\t\t}\n\t\t}\n\t\tconst variable: TokenVariable = { id: item.id, name: item.name, collectionId: collection.id, type, valuesByMode: values };\n\t\tif (typeof item.description === 'string' && item.description) variable.description = item.description;\n\t\tif (Array.isArray(item.scopes)) {\n\t\t\ttry {\n\t\t\t\tconst scopes = normalizeTokenScopes(type, item.scopes as string[]);\n\t\t\t\tif (scopes) variable.scopes = scopes;\n\t\t\t} catch {\n\t\t\t\tissues.push({ message: `Dropped unknown scopes of \\`${item.name}\\``, variableId: item.id });\n\t\t\t}\n\t\t}\n\t\tif (typeof item.unit === 'string' && /^[a-z%]{1,8}$/i.test(item.unit)) variable.unit = item.unit.toLowerCase();\n\t\tvariables.push(variable);\n\t}\n\tlet state: TokenState = { collections, variables };\n\t// Aliases: drop missing / mistyped targets and break cycles.\n\tconst fixed = state.variables.map((variable) => {\n\t\tlet values: Record<string, TokenValue> | null = null;\n\t\tfor (const [modeId, value] of Object.entries(variable.valuesByMode)) {\n\t\t\tif (!isTokenAlias(value)) continue;\n\t\t\tconst target = state.variables.find((t) => t.id === value.alias);\n\t\t\tif (!target || target.type !== variable.type) {\n\t\t\t\tvalues ??= { ...variable.valuesByMode };\n\t\t\t\tvalues[modeId] = defaultTokenValue(variable.type);\n\t\t\t\tissues.push({ message: `\\`${variable.name}\\` aliased a missing or mistyped variable`, variableId: variable.id });\n\t\t\t}\n\t\t}\n\t\treturn values ? { ...variable, valuesByMode: values } : variable;\n\t});\n\tstate = { collections, variables: fixed };\n\t// Cycle breaking: rebuild alias by alias, keeping only those that do not close a loop.\n\tconst literalOnly = fixed.map((variable) => {\n\t\tconst values: Record<string, TokenValue> = {};\n\t\tfor (const [modeId, value] of Object.entries(variable.valuesByMode)) values[modeId] = isTokenAlias(value) ? defaultTokenValue(variable.type) : value;\n\t\treturn { ...variable, valuesByMode: values };\n\t});\n\tlet rebuilt: TokenState = { collections, variables: literalOnly };\n\tfor (const variable of fixed) {\n\t\tfor (const [modeId, value] of Object.entries(variable.valuesByMode)) {\n\t\t\tif (!isTokenAlias(value)) continue;\n\t\t\tconst error = checkTokenAlias(rebuilt, variable, value.alias);\n\t\t\tif (error) {\n\t\t\t\tissues.push({ message: `\\`${variable.name}\\`: ${error.message}`, variableId: variable.id });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst current = getTokenVariable(rebuilt, variable.id)!;\n\t\t\trebuilt = replaceVariable(rebuilt, { ...current, valuesByMode: { ...current.valuesByMode, [modeId]: { alias: value.alias } } });\n\t\t}\n\t}\n\treturn { state: rebuilt, issues };\n}\n","import {\n\taddTokenMode,\n\tcreateTokenCollection,\n\tcreateTokenVariable,\n\tdefaultTokenId,\n\tdeleteTokenCollection,\n\tdeleteTokenVariables,\n\tmoveTokenMode,\n\tparseTokenState,\n\tremoveTokenMode,\n\trenameTokenCollection,\n\trenameTokenMode,\n\trenameTokenVariable,\n\tresolveToken,\n\tresolveTokenValue,\n\tsetTokenValue,\n\tupdateTokenVariable,\n\ttype CreateTokenCollectionInput,\n\ttype CreateTokenVariableInput,\n\ttype TokenIdFactory,\n\ttype TokenResolution,\n\ttype UpdateTokenVariableInput\n} from './model.js';\nimport type { TokenCollection, TokenLiteral, TokenMode, TokenModeContext, TokenState, TokenVariable } from './types.js';\nimport { EMPTY_TOKEN_STATE } from './types.js';\n\n/** Why the state changed. */\nexport type TokenChangeSource = 'edit' | 'undo' | 'redo' | 'replace';\n\nexport interface TokenChangeEvent {\n\tsource: TokenChangeSource;\n\t/** Operation name (`setValue`, `deleteVariables`, a `transact` label, …). */\n\treason: string;\n\tstate: TokenState;\n\tprevious: TokenState;\n\t/**\n\t * Variables this edit deleted (also via `deleteCollection`). Detach canvas bindings to them\n\t * with `detachTokenBindings(nodes, event.previous, event.deletedVariableIds)`.\n\t */\n\tdeletedVariableIds: readonly string[];\n}\n\nexport type TokenChangeListener = (event: TokenChangeEvent) => void;\n\nexport interface TokenStoreOptions {\n\tinitialState?: TokenState;\n\tcreateId?: TokenIdFactory;\n\t/** Undo steps kept (default 100). */\n\thistoryLimit?: number;\n}\n\ninterface Pending {\n\treason: string;\n\tprevious: TokenState;\n\tdeleted: string[];\n}\n\n/**\n * Undoable design-token store. Every edit is one undo step (group several with `transact`)\n * and notifies subscribers once. `getState()` returns an immutable snapshot whose reference\n * only changes on edits, so it works with `useSyncExternalStore` and Svelte stores.\n * Refused edits throw a `TokenError` and change nothing.\n */\nexport class TokenStore {\n\tprivate state: TokenState;\n\tprivate undoStack: { state: TokenState; reason: string }[] = [];\n\tprivate redoStack: { state: TokenState; reason: string }[] = [];\n\tprivate listeners = new Set<TokenChangeListener>();\n\tprivate pending: Pending | null = null;\n\tprivate depth = 0;\n\tprivate readonly createId: TokenIdFactory;\n\tprivate readonly historyLimit: number;\n\n\tconstructor(options: TokenStoreOptions = {}) {\n\t\tthis.state = options.initialState ?? EMPTY_TOKEN_STATE;\n\t\tthis.createId = options.createId ?? defaultTokenId;\n\t\tthis.historyLimit = Math.max(0, options.historyLimit ?? 100);\n\t}\n\n\tgetState = (): TokenState => this.state;\n\n\tsubscribe = (listener: TokenChangeListener): (() => void) => {\n\t\tthis.listeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener);\n\t\t};\n\t};\n\n\tget collections(): readonly TokenCollection[] {\n\t\treturn this.state.collections;\n\t}\n\n\tget variables(): readonly TokenVariable[] {\n\t\treturn this.state.variables;\n\t}\n\n\tcanUndo(): boolean {\n\t\treturn this.undoStack.length > 0;\n\t}\n\n\tcanRedo(): boolean {\n\t\treturn this.redoStack.length > 0;\n\t}\n\n\t/** Resolves a variable under `modes` (see `resolveToken`). */\n\tresolve(id: string, modes?: TokenModeContext): TokenResolution {\n\t\treturn resolveToken(this.state, id, modes);\n\t}\n\n\tresolveValue(id: string, modes?: TokenModeContext): TokenLiteral | undefined {\n\t\treturn resolveTokenValue(this.state, id, modes);\n\t}\n\n\t/**\n\t * Runs `fn` as one undo step with one change event. If `fn` throws, every change it made is\n\t * rolled back and the error rethrown.\n\t */\n\ttransact<T>(reason: string, fn: (store: this) => T): T {\n\t\tconst outer = this.depth === 0;\n\t\tif (outer) this.pending = { reason, previous: this.state, deleted: [] };\n\t\tthis.depth += 1;\n\t\ttry {\n\t\t\tconst result = fn(this);\n\t\t\tthis.depth -= 1;\n\t\t\tif (outer) this.flush();\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tthis.depth -= 1;\n\t\t\tif (outer) {\n\t\t\t\tthis.state = this.pending!.previous;\n\t\t\t\tthis.pending = null;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate apply(reason: string, next: TokenState, deleted: readonly string[] = []): void {\n\t\tif (next === this.state) return;\n\t\tif (this.depth > 0) {\n\t\t\tthis.state = next;\n\t\t\tthis.pending!.deleted.push(...deleted);\n\t\t\treturn;\n\t\t}\n\t\tthis.pending = { reason, previous: this.state, deleted: [...deleted] };\n\t\tthis.state = next;\n\t\tthis.flush();\n\t}\n\n\tprivate flush(): void {\n\t\tconst pending = this.pending!;\n\t\tthis.pending = null;\n\t\tif (pending.previous === this.state) return;\n\t\tthis.undoStack.push({ state: pending.previous, reason: pending.reason });\n\t\tif (this.undoStack.length > this.historyLimit) this.undoStack.splice(0, this.undoStack.length - this.historyLimit);\n\t\tthis.redoStack = [];\n\t\tthis.emit({ source: 'edit', reason: pending.reason, state: this.state, previous: pending.previous, deletedVariableIds: pending.deleted });\n\t}\n\n\tprivate emit(event: TokenChangeEvent): void {\n\t\tfor (const listener of [...this.listeners]) listener(event);\n\t}\n\n\tundo(): boolean {\n\t\tconst entry = this.undoStack.pop();\n\t\tif (!entry) return false;\n\t\tconst previous = this.state;\n\t\tthis.redoStack.push({ state: previous, reason: entry.reason });\n\t\tthis.state = entry.state;\n\t\tthis.emit({ source: 'undo', reason: entry.reason, state: this.state, previous, deletedVariableIds: [] });\n\t\treturn true;\n\t}\n\n\tredo(): boolean {\n\t\tconst entry = this.redoStack.pop();\n\t\tif (!entry) return false;\n\t\tconst previous = this.state;\n\t\tthis.undoStack.push({ state: previous, reason: entry.reason });\n\t\tthis.state = entry.state;\n\t\tthis.emit({ source: 'redo', reason: entry.reason, state: this.state, previous, deletedVariableIds: [] });\n\t\treturn true;\n\t}\n\n\t/**\n\t * Replaces the whole state (e.g. after loading a file). Untrusted data should go through\n\t * `parseTokenState` first. With `record: true` it is an undo step; otherwise history is cleared.\n\t */\n\treplaceState(state: TokenState, options: { record?: boolean; reason?: string } = {}): void {\n\t\tif (options.record) {\n\t\t\tthis.apply(options.reason ?? 'replace', state);\n\t\t\treturn;\n\t\t}\n\t\tconst previous = this.state;\n\t\tthis.state = state;\n\t\tthis.undoStack = [];\n\t\tthis.redoStack = [];\n\t\tthis.emit({ source: 'replace', reason: options.reason ?? 'replace', state, previous, deletedVariableIds: [] });\n\t}\n\n\t/** Loads untrusted JSON (or an object) as the new state; returns the issues found. */\n\tload(input: unknown): ReturnType<typeof parseTokenState>['issues'] {\n\t\tconst { state, issues } = parseTokenState(input);\n\t\tthis.replaceState(state, { reason: 'load' });\n\t\treturn issues;\n\t}\n\n\t/** The state as JSON. */\n\ttoJSON(): TokenState {\n\t\treturn this.state;\n\t}\n\n\t// --- Collections and modes -----------------------------------------------------------------\n\n\tcreateCollection(name: string, modes?: readonly string[]): TokenCollection {\n\t\tconst input: CreateTokenCollectionInput = { name, modes };\n\t\tconst result = createTokenCollection(this.state, input, this.createId);\n\t\tthis.apply('createCollection', result.state);\n\t\treturn result.collection;\n\t}\n\n\trenameCollection(id: string, name: string): void {\n\t\tthis.apply('renameCollection', renameTokenCollection(this.state, id, name));\n\t}\n\n\tdeleteCollection(id: string): string[] {\n\t\tconst result = deleteTokenCollection(this.state, id);\n\t\tthis.apply('deleteCollection', result.state, result.deleted);\n\t\treturn result.deleted;\n\t}\n\n\taddMode(collectionId: string, name: string, options: { from?: string } = {}): TokenMode {\n\t\tconst result = addTokenMode(this.state, collectionId, name, options, this.createId);\n\t\tthis.apply('addMode', result.state);\n\t\treturn result.mode;\n\t}\n\n\trenameMode(collectionId: string, modeId: string, name: string): void {\n\t\tthis.apply('renameMode', renameTokenMode(this.state, collectionId, modeId, name));\n\t}\n\n\tremoveMode(collectionId: string, modeId: string): void {\n\t\tthis.apply('removeMode', removeTokenMode(this.state, collectionId, modeId));\n\t}\n\n\tmoveMode(collectionId: string, modeId: string, to: number): void {\n\t\tthis.apply('moveMode', moveTokenMode(this.state, collectionId, modeId, to));\n\t}\n\n\t/** Makes a mode the default by moving it first. */\n\tsetDefaultMode(collectionId: string, modeId: string): void {\n\t\tthis.apply('setDefaultMode', moveTokenMode(this.state, collectionId, modeId, 0));\n\t}\n\n\t// --- Variables -----------------------------------------------------------------------------\n\n\tcreateVariable(input: CreateTokenVariableInput): TokenVariable {\n\t\tconst result = createTokenVariable(this.state, input, this.createId);\n\t\tthis.apply('createVariable', result.state);\n\t\treturn result.variable;\n\t}\n\n\t/** Sets a literal or `{ alias }` in one mode (id or name; default: the default mode). */\n\tsetValue(variableId: string, value: unknown, modeId?: string): void {\n\t\tthis.apply('setValue', setTokenValue(this.state, variableId, value, modeId));\n\t}\n\n\trenameVariable(variableId: string, name: string): void {\n\t\tthis.apply('renameVariable', renameTokenVariable(this.state, variableId, name));\n\t}\n\n\tupdateVariable(variableId: string, input: UpdateTokenVariableInput): void {\n\t\tthis.apply('updateVariable', updateTokenVariable(this.state, variableId, input));\n\t}\n\n\t/** Deletes variables; aliases to them take their values. Returns the ids deleted. */\n\tdeleteVariables(ids: string | Iterable<string>): string[] {\n\t\tconst result = deleteTokenVariables(this.state, typeof ids === 'string' ? [ids] : ids);\n\t\tthis.apply('deleteVariables', result.state, result.deleted);\n\t\treturn result.deleted;\n\t}\n\n\t/** Applies a pure state transform (e.g. `importW3CTokens`) as one undo step. */\n\tupdate(reason: string, fn: (state: TokenState) => TokenState): void {\n\t\tthis.apply(reason, fn(this.state));\n\t}\n}\n\nexport function createTokenStore(options: TokenStoreOptions = {}): TokenStore {\n\treturn new TokenStore(options);\n}\n","// Portions ported from figcraft/crates/engine/src/variables_io_tests.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\nimport { getCurrentMode, getTokenCollection, getTokenVariable, resolveToken } from './model.js';\nimport { isTokenAlias, type TokenCollection, type TokenLiteral, type TokenMode, type TokenModeContext, type TokenState, type TokenVariable } from './types.js';\n\nexport interface TokenCssOptions {\n\t/** Collections to export (ids; default all). */\n\tcollections?: readonly string[];\n\t/** Prefix after `--` (e.g. `ds-` → `--ds-color-bg`). */\n\tprefix?: string;\n\t/** Also prefix each variable with its collection name (avoids clashes between collections). */\n\tcollectionPrefix?: boolean;\n\t/** Root selector (default `:root`). */\n\tselector?: string;\n\t/** Attribute that selects a mode (default `data-mode`), or one per collection. */\n\tattribute?: string | ((collection: TokenCollection) => string);\n\t/** Attribute value for a mode (default: the mode name as a lowercase slug, e.g. `dark`). */\n\tmodeValue?: (mode: TokenMode, collection: TokenCollection) => string;\n\t/**\n\t * Also emit `[data-mode=\"…\"]` rules that match any element (not just the root), so a subtree\n\t * can switch mode. Default `false`.\n\t */\n\tnested?: boolean;\n\t/** Formats numbers (default: the number with the variable's `unit`, if any). */\n\tformatNumber?: (value: number, variable: TokenVariable) => string;\n}\n\n/** Lowercase slug of a name: groups and spaces become `-` (`Color/Bg Muted` → `color-bg-muted`). */\nexport function tokenSlug(name: string): string {\n\tlet out = '';\n\tlet dash = false;\n\tfor (const ch of name.toLowerCase()) {\n\t\tif ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch === '_') {\n\t\t\tif (dash && out) out += '-';\n\t\t\tout += ch;\n\t\t\tdash = false;\n\t\t} else dash = true;\n\t}\n\treturn out || 'token';\n}\n\n/** The CSS custom property for a variable (e.g. `--color-bg`). */\nexport function getTokenCssName(state: TokenState, variable: TokenVariable, options: Pick<TokenCssOptions, 'prefix' | 'collectionPrefix'> = {}): string {\n\tconst collection = getTokenCollection(state, variable.collectionId);\n\tconst head = options.collectionPrefix && collection ? `${tokenSlug(collection.name)}-` : '';\n\tconst prefix = options.prefix ? `${tokenSlug(options.prefix)}-` : '';\n\treturn `--${prefix}${head}${tokenSlug(variable.name)}`;\n}\n\n/** A CSS string literal with `\"`, `\\`, newlines and `<` escaped. */\nexport function cssString(value: string): string {\n\tlet out = '\"';\n\tfor (const ch of value) {\n\t\tif (ch === '\"' || ch === '\\\\') out += '\\\\' + ch;\n\t\telse if (ch === '\\n') out += '\\\\a ';\n\t\telse if (ch === '\\r') out += '\\\\d ';\n\t\telse if (ch === '<') out += '\\\\3c ';\n\t\telse out += ch;\n\t}\n\treturn out + '\"';\n}\n\n/** A literal as CSS. */\nexport function formatTokenCssValue(value: TokenLiteral, variable: TokenVariable, options: Pick<TokenCssOptions, 'formatNumber'> = {}): string {\n\tswitch (variable.type) {\n\t\tcase 'color':\n\t\t\treturn String(value);\n\t\tcase 'number':\n\t\t\treturn options.formatNumber ? options.formatNumber(value as number, variable) : `${value}${variable.unit ?? ''}`;\n\t\tcase 'string':\n\t\t\treturn cssString(String(value));\n\t\tcase 'boolean':\n\t\t\treturn value ? 'true' : 'false';\n\t}\n}\n\nconst defaultModeValue = (mode: TokenMode) => tokenSlug(mode.name);\n\nfunction attributeFor(options: TokenCssOptions, collection: TokenCollection): string {\n\tconst attr = typeof options.attribute === 'function' ? options.attribute(collection) : options.attribute ?? 'data-mode';\n\treturn tokenSlug(attr);\n}\n\n/**\n * Flat CSS custom properties per mode: each collection's default mode on `:root`, its other\n * modes on `:root[data-mode=\"dark\"]`. Aliases to exported variables become `var(--target)`, so\n * switching the attribute re-themes everything; aliases to other variables are resolved.\n */\nexport function exportTokensCss(state: TokenState, options: TokenCssOptions = {}): string {\n\tconst selector = options.selector ?? ':root';\n\tconst wanted = options.collections ? new Set(options.collections) : null;\n\tconst collections = state.collections.filter((c) => !wanted || wanted.has(c.id));\n\tconst exported = new Set(state.variables.filter((v) => collections.some((c) => c.id === v.collectionId)).map((v) => v.id));\n\tconst modeValue = options.modeValue ?? defaultModeValue;\n\n\tconst declaration = (variable: TokenVariable, collection: TokenCollection, mode: TokenMode): string | null => {\n\t\tconst value = variable.valuesByMode[mode.id];\n\t\tif (isTokenAlias(value) && exported.has(value.alias)) {\n\t\t\tconst target = getTokenVariable(state, value.alias)!;\n\t\t\treturn ` ${getTokenCssName(state, variable, options)}: var(${getTokenCssName(state, target, options)});`;\n\t\t}\n\t\tconst resolved = resolveToken(state, variable.id, { [collection.id]: mode.id });\n\t\tif (!resolved.ok) return null;\n\t\treturn ` ${getTokenCssName(state, variable, options)}: ${formatTokenCssValue(resolved.value, variable, options)};`;\n\t};\n\n\tconst blocks: string[] = [];\n\tconst rootLines: string[] = [];\n\tfor (const collection of collections) {\n\t\tconst vars = state.variables.filter((v) => v.collectionId === collection.id);\n\t\tfor (const v of vars) {\n\t\t\tconst line = declaration(v, collection, collection.modes[0]);\n\t\t\tif (line) rootLines.push(line);\n\t\t}\n\t}\n\tconst rootSelectors = [selector];\n\tif (options.nested) {\n\t\tfor (const collection of collections) {\n\t\t\trootSelectors.push(`[${attributeFor(options, collection)}=\"${tokenSlug(modeValue(collection.modes[0], collection))}\"]`);\n\t\t}\n\t}\n\tblocks.push(`${[...new Set(rootSelectors)].join(', ')} {\\n${rootLines.join('\\n')}${rootLines.length ? '\\n' : ''}}`);\n\tfor (const collection of collections) {\n\t\tconst vars = state.variables.filter((v) => v.collectionId === collection.id);\n\t\tconst attr = attributeFor(options, collection);\n\t\tfor (const mode of collection.modes.slice(1)) {\n\t\t\tconst lines = vars.map((v) => declaration(v, collection, mode)).filter((l): l is string => l !== null);\n\t\t\tconst value = tokenSlug(modeValue(mode, collection));\n\t\t\tconst selectors = [`${selector}[${attr}=\"${value}\"]`];\n\t\t\tif (options.nested) selectors.push(`[${attr}=\"${value}\"]`);\n\t\t\tblocks.push(`${selectors.join(', ')} {\\n${lines.join('\\n')}${lines.length ? '\\n' : ''}}`);\n\t\t}\n\t}\n\treturn blocks.join('\\n\\n') + '\\n';\n}\n\n/**\n * Resolved CSS custom properties for one mode context, e.g. for an element's inline style:\n * `{ '--color-bg': '#ffffff', … }`. Aliases are resolved (no `var()`).\n */\nexport function getTokenCssVariables(\n\tstate: TokenState,\n\tmodes?: TokenModeContext,\n\toptions: Omit<TokenCssOptions, 'selector' | 'attribute' | 'modeValue' | 'nested'> = {}\n): Record<string, string> {\n\tconst wanted = options.collections ? new Set(options.collections) : null;\n\tconst out: Record<string, string> = {};\n\tfor (const variable of state.variables) {\n\t\tif (wanted && !wanted.has(variable.collectionId)) continue;\n\t\tconst collection = getTokenCollection(state, variable.collectionId);\n\t\tif (!collection) continue;\n\t\tconst resolved = resolveToken(state, variable.id, { ...modes, [collection.id]: getCurrentMode(collection, modes).id });\n\t\tif (resolved.ok) out[getTokenCssName(state, variable, options)] = formatTokenCssValue(resolved.value, variable, options);\n\t}\n\treturn out;\n}\n","// Portions ported from figcraft/crates/engine/src/variables_io_tests.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\nimport { hexToRgba, normalizeTokenColor } from './color.js';\nimport {\n\taddTokenMode,\n\tcheckTokenAlias,\n\tcoerceTokenLiteral,\n\tcreateTokenCollection,\n\tcreateTokenVariable,\n\tdefaultTokenId,\n\tfindTokenCollection,\n\tfindTokenMode,\n\tfindTokenVariable,\n\tgetTokenCollection,\n\tgetTokenVariable,\n\tnormalizeTokenName,\n\tsetTokenValue,\n\tupdateTokenVariable,\n\ttype TokenIdFactory\n} from './model.js';\nimport {\n\tTokenError,\n\tisTokenAlias,\n\ttype TokenCollection,\n\ttype TokenLiteral,\n\ttype TokenModeContext,\n\ttype TokenState,\n\ttype TokenType,\n\ttype TokenValue,\n\ttype TokenVariable\n} from './types.js';\n\n/**\n * W3C Design Tokens (DTCG) JSON. Each collection is a top-level group named after it; variable\n * names' `/` groups become nested groups; aliases are `{Collection.group.token}` references.\n * `$value` holds the default mode (or the modes passed in). Modes, ids and scopes ride along in\n * `$extensions[\"com.pixerate.tokens\"]`, so an export round-trips; tools that ignore extensions\n * still read the default mode. Strings and booleans use `$type: \"string\"` / `\"boolean\"`\n * (outside the spec, as Tokens Studio and Style Dictionary do).\n */\nexport const W3C_TOKENS_EXTENSION = 'com.pixerate.tokens';\n\nexport interface W3CTokensExportOptions {\n\t/** Collections to export (ids; default all). */\n\tcollections?: readonly string[];\n\t/** Modes that supply `$value` (default: each collection's default mode). */\n\tmodes?: TokenModeContext;\n\t/** Include `$extensions` with ids, every mode's value and scopes (default `true`). */\n\textensions?: boolean;\n\t/** Colours as `#hex` strings (default) or W3C colour objects. */\n\tcolorFormat?: 'hex' | 'object';\n}\n\ntype Json = null | boolean | number | string | Json[] | { [key: string]: Json };\n\nfunction path(name: string): string[] {\n\treturn name.split('/');\n}\n\nfunction reference(state: TokenState, variable: TokenVariable): string {\n\tconst collection = getTokenCollection(state, variable.collectionId);\n\treturn `{${[collection?.name ?? variable.collectionId, ...path(variable.name)].join('.')}}`;\n}\n\nfunction w3cType(variable: TokenVariable): string {\n\tif (variable.type === 'number') {\n\t\tif (variable.unit === 'ms' || variable.unit === 's') return 'duration';\n\t\tif (variable.unit) return 'dimension';\n\t}\n\treturn variable.type;\n}\n\nfunction w3cLiteral(variable: TokenVariable, value: TokenLiteral, colorFormat: 'hex' | 'object'): Json {\n\tif (variable.type === 'color' && colorFormat === 'object') {\n\t\tconst c = hexToRgba(String(value));\n\t\tif (c) {\n\t\t\tconst round = (n: number) => Math.round(n * 10000) / 10000;\n\t\t\treturn { colorSpace: 'srgb', components: [round(c.r), round(c.g), round(c.b)], alpha: round(c.a), hex: String(value).slice(0, 7) };\n\t\t}\n\t}\n\tif (variable.type === 'number' && variable.unit) return { value: value as number, unit: variable.unit };\n\treturn value;\n}\n\nfunction w3cValue(state: TokenState, variable: TokenVariable, value: TokenValue | undefined, colorFormat: 'hex' | 'object'): Json {\n\tif (value === undefined) return null;\n\tif (isTokenAlias(value)) {\n\t\tconst target = getTokenVariable(state, value.alias);\n\t\treturn target ? reference(state, target) : null;\n\t}\n\treturn w3cLiteral(variable, value, colorFormat);\n}\n\n/** The tokens as a W3C Design Tokens object (see {@link W3C_TOKENS_EXTENSION}). */\nexport function exportW3CTokens(state: TokenState, options: W3CTokensExportOptions = {}): Record<string, Json> {\n\tconst withExtensions = options.extensions !== false;\n\tconst colorFormat = options.colorFormat ?? 'hex';\n\tconst wanted = options.collections ? new Set(options.collections) : null;\n\tconst root: Record<string, Json> = {};\n\tfor (const collection of state.collections) {\n\t\tif (wanted && !wanted.has(collection.id)) continue;\n\t\tconst group: Record<string, Json> = {};\n\t\tif (withExtensions) {\n\t\t\tgroup.$extensions = {\n\t\t\t\t[W3C_TOKENS_EXTENSION]: { id: collection.id, modes: collection.modes.map((m) => ({ id: m.id, name: m.name })) }\n\t\t\t};\n\t\t}\n\t\tconst chosen = options.modes?.[collection.id];\n\t\tconst mode = (chosen !== undefined && collection.modes.find((m) => m.id === chosen)) || collection.modes[0];\n\t\tfor (const variable of state.variables) {\n\t\t\tif (variable.collectionId !== collection.id) continue;\n\t\t\tconst token: Record<string, Json> = {\n\t\t\t\t$type: w3cType(variable),\n\t\t\t\t$value: w3cValue(state, variable, variable.valuesByMode[mode.id], colorFormat)\n\t\t\t};\n\t\t\tif (variable.description) token.$description = variable.description;\n\t\t\tif (withExtensions) {\n\t\t\t\tconst modes: Record<string, Json> = {};\n\t\t\t\tfor (const m of collection.modes) modes[m.name] = w3cValue(state, variable, variable.valuesByMode[m.id], colorFormat);\n\t\t\t\tconst ext: Record<string, Json> = { id: variable.id, modes };\n\t\t\t\tif (variable.scopes) ext.scopes = [...variable.scopes];\n\t\t\t\tif (variable.unit) ext.unit = variable.unit;\n\t\t\t\ttoken.$extensions = { [W3C_TOKENS_EXTENSION]: ext };\n\t\t\t}\n\t\t\tlet at = group;\n\t\t\tconst segments = path(variable.name);\n\t\t\tfor (const segment of segments.slice(0, -1)) {\n\t\t\t\tconst next = at[segment];\n\t\t\t\tif (typeof next !== 'object' || next === null || Array.isArray(next) || '$value' in next) at[segment] = {};\n\t\t\t\tat = at[segment] as Record<string, Json>;\n\t\t\t}\n\t\t\tat[segments[segments.length - 1]] = token;\n\t\t}\n\t\troot[collection.name] = group;\n\t}\n\treturn root;\n}\n\n/** {@link exportW3CTokens} as indented JSON text. */\nexport function exportW3CTokensJson(state: TokenState, options: W3CTokensExportOptions = {}): string {\n\treturn JSON.stringify(exportW3CTokens(state, options), null, 2);\n}\n\n// ---------------------------------------------------------------------------------------------\n// Import\n\nexport interface W3CTokensImportOptions {\n\t/**\n\t * Collection for tokens outside a marked collection group (a plain W3C file). Default\n\t * `\"Tokens\"`; an existing collection with that name is updated.\n\t */\n\tcollection?: string;\n\t/** Mode that plain `$value`s go to (name; created when missing). Default: the default mode. */\n\tmode?: string;\n\tcreateId?: TokenIdFactory;\n}\n\nexport interface W3CTokensImportReport {\n\tcollectionsAdded: number;\n\tmodesAdded: number;\n\tvariablesAdded: number;\n\t/** Existing variables (matched by collection and name) that were updated in place. */\n\tvariablesUpdated: number;\n\t/** Entries skipped or values not taken, with the reason. */\n\twarnings: string[];\n}\n\ninterface RawToken {\n\tcollection: string;\n\tpath: string[];\n\ttype: string | undefined;\n\tvalue: unknown;\n\tdescription: unknown;\n\text: Record<string, unknown> | undefined;\n}\n\nconst MAX_DEPTH = 32;\nconst REF = /^\\{([^{}]+)\\}$/;\nconst MEASURE = /^(-?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?)\\s*([a-z%]*)$/i;\nconst FONT_WEIGHTS: Record<string, number> = {\n\tthin: 100,\n\thairline: 100,\n\t'extra-light': 200,\n\t'ultra-light': 200,\n\tlight: 300,\n\tnormal: 400,\n\tregular: 400,\n\tbook: 400,\n\tmedium: 500,\n\t'semi-bold': 600,\n\t'demi-bold': 600,\n\tbold: 700,\n\t'extra-bold': 800,\n\t'ultra-bold': 800,\n\tblack: 900,\n\theavy: 900,\n\t'extra-black': 950,\n\t'ultra-black': 950\n};\n\nconst isObject = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);\n\nfunction extensionOf(node: Record<string, unknown>): Record<string, unknown> | undefined {\n\tconst ext = node.$extensions;\n\tif (!isObject(ext)) return undefined;\n\tconst ours = ext[W3C_TOKENS_EXTENSION];\n\treturn isObject(ours) ? ours : undefined;\n}\n\nfunction aliasRef(value: unknown): string | null {\n\tif (typeof value !== 'string' || value.length > 1000) return null;\n\tconst match = REF.exec(value.trim());\n\treturn match ? match[1].trim() : null;\n}\n\n/** W3C type → our type, or `null` for types we don't take (composites). */\nfunction mapType(type: string): TokenType | null {\n\tswitch (type) {\n\t\tcase 'color':\n\t\t\treturn 'color';\n\t\tcase 'number':\n\t\tcase 'dimension':\n\t\tcase 'duration':\n\t\tcase 'fontWeight':\n\t\t\treturn 'number';\n\t\tcase 'string':\n\t\tcase 'text':\n\t\tcase 'fontFamily':\n\t\tcase 'fontStyle':\n\t\t\treturn 'string';\n\t\tcase 'boolean':\n\t\t\treturn 'boolean';\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nfunction inferType(value: unknown): string | undefined {\n\tif (typeof value === 'boolean') return 'boolean';\n\tif (typeof value === 'number') return 'number';\n\tif (typeof value === 'string') {\n\t\tconst text = value.trim();\n\t\tif ((text.startsWith('#') || /^rgba?\\(/i.test(text)) && normalizeTokenColor(text)) return 'color';\n\t\tif (MEASURE.test(text) && /[a-z%]$/i.test(text)) return 'dimension';\n\t\treturn 'string';\n\t}\n\tif (isObject(value) && Array.isArray(value.components)) return 'color';\n\tif (isObject(value) && typeof value.value === 'number' && typeof value.unit === 'string') return 'dimension';\n\treturn undefined;\n}\n\n/** A literal and (for numbers) unit from a W3C value of `w3cType`, or `null`. */\nfunction readLiteral(w3cType: string, type: TokenType, value: unknown): { value: TokenLiteral; unit?: string } | null {\n\tif (type === 'number') {\n\t\tif (w3cType === 'fontWeight' && typeof value === 'string') {\n\t\t\tconst weight = FONT_WEIGHTS[value.trim().toLowerCase()];\n\t\t\treturn weight === undefined ? null : { value: weight };\n\t\t}\n\t\tif (isObject(value) && typeof value.value === 'number' && Number.isFinite(value.value)) {\n\t\t\tconst unit = typeof value.unit === 'string' && /^[a-z%]{1,8}$/i.test(value.unit) ? value.unit.toLowerCase() : undefined;\n\t\t\treturn { value: value.value, unit };\n\t\t}\n\t\tif (typeof value === 'string' && value.length <= 100) {\n\t\t\tconst match = MEASURE.exec(value.trim());\n\t\t\tif (!match) return null;\n\t\t\tconst n = Number(match[1]);\n\t\t\tif (!Number.isFinite(n)) return null;\n\t\t\tconst unit = match[2] ? match[2].toLowerCase() : undefined;\n\t\t\treturn { value: n, unit: unit && unit.length <= 8 ? unit : undefined };\n\t\t}\n\t\tconst n = coerceTokenLiteral('number', value);\n\t\treturn n === null ? null : { value: n };\n\t}\n\tif (type === 'string' && w3cType === 'fontFamily' && Array.isArray(value)) {\n\t\treturn value.every((v) => typeof v === 'string') ? { value: value.join(', ') } : null;\n\t}\n\tconst literal = coerceTokenLiteral(type, value);\n\treturn literal === null ? null : { value: literal };\n}\n\nfunction collectTokens(\n\tgroup: Record<string, unknown>,\n\tcollection: string,\n\tprefix: string[],\n\tinheritedType: string | undefined,\n\tout: RawToken[],\n\twarnings: string[],\n\tdepth: number\n): void {\n\tif (depth > MAX_DEPTH) {\n\t\twarnings.push(`\\`${prefix.join('.')}\\` is nested too deeply; skipped`);\n\t\treturn;\n\t}\n\tconst groupType = typeof group.$type === 'string' ? group.$type : inheritedType;\n\tfor (const [key, child] of Object.entries(group)) {\n\t\tif (key.startsWith('$')) continue;\n\t\tconst at = [...prefix, key];\n\t\tif (!isObject(child)) {\n\t\t\twarnings.push(`\\`${at.join('.')}\\` is not a token or group; skipped`);\n\t\t\tcontinue;\n\t\t}\n\t\tif ('$value' in child) {\n\t\t\tout.push({\n\t\t\t\tcollection,\n\t\t\t\tpath: at,\n\t\t\t\ttype: typeof child.$type === 'string' ? child.$type : groupType,\n\t\t\t\tvalue: child.$value,\n\t\t\t\tdescription: child.$description,\n\t\t\t\text: extensionOf(child)\n\t\t\t});\n\t\t} else collectTokens(child, collection, at, groupType, out, warnings, depth + 1);\n\t}\n}\n\n/**\n * Merges a W3C Design Tokens document (object or JSON text) into `state`. Collections, modes\n * and variables are matched by name and updated in place (ids, and so canvas bindings, are\n * kept); new ones take the ids in the file's extensions when free. Junk entries, type clashes,\n * unresolved references and alias cycles are skipped with a warning. Throws `invalid-input`\n * only when the input is not a JSON object.\n */\nexport function importW3CTokens(\n\tstate: TokenState,\n\tinput: unknown,\n\toptions: W3CTokensImportOptions = {}\n): { state: TokenState; report: W3CTokensImportReport } {\n\tlet doc = input;\n\tif (typeof doc === 'string') {\n\t\ttry {\n\t\t\tdoc = JSON.parse(doc);\n\t\t} catch {\n\t\t\tthrow new TokenError('invalid-input', 'Not JSON');\n\t\t}\n\t}\n\tif (!isObject(doc)) throw new TokenError('invalid-input', 'Expected a design tokens object');\n\tconst createId = options.createId ?? defaultTokenId;\n\tconst report: W3CTokensImportReport = { collectionsAdded: 0, modesAdded: 0, variablesAdded: 0, variablesUpdated: 0, warnings: [] };\n\tconst warn = (message: string) => {\n\t\tif (report.warnings.length < 500) report.warnings.push(message);\n\t};\n\n\t// Which top-level groups are collections.\n\tconst marked = Object.entries(doc).filter(([key, value]) => !key.startsWith('$') && isObject(value) && !('$value' in value) && Array.isArray(extensionOf(value)?.modes));\n\tconst plainName = options.collection ?? 'Tokens';\n\tconst sources: { name: string; group: Record<string, unknown>; modes?: unknown[]; id?: unknown; plain: boolean }[] = [];\n\tif (marked.length > 0) {\n\t\tfor (const [key, value] of marked) {\n\t\t\tconst ext = extensionOf(value as Record<string, unknown>)!;\n\t\t\tsources.push({ name: key, group: value as Record<string, unknown>, modes: ext.modes as unknown[], id: ext.id, plain: false });\n\t\t}\n\t\tconst rest: Record<string, unknown> = {};\n\t\tfor (const [key, value] of Object.entries(doc)) if (!marked.some(([k]) => k === key)) rest[key] = value;\n\t\tif (Object.keys(rest).some((k) => !k.startsWith('$'))) sources.push({ name: plainName, group: rest, plain: true });\n\t} else sources.push({ name: plainName, group: doc, plain: true });\n\n\tconst usedIds = new Set<string>([...state.collections.map((c) => c.id), ...state.variables.map((v) => v.id)]);\n\tfor (const c of state.collections) for (const m of c.modes) usedIds.add(m.id);\n\tconst idFrom = (candidate: unknown, kind: 'collection' | 'mode' | 'variable'): TokenIdFactory => (k) => {\n\t\tif (k === kind && typeof candidate === 'string' && candidate.length > 0 && candidate.length <= 200 && !usedIds.has(candidate)) {\n\t\t\tusedIds.add(candidate);\n\t\t\treturn candidate;\n\t\t}\n\t\tconst id = createId(k);\n\t\tusedIds.add(id);\n\t\treturn id;\n\t};\n\n\tlet next = state;\n\tconst tokens: RawToken[] = [];\n\tconst collectionIds = new Map<string, string>();\n\tconst plainMode = new Map<string, string>();\n\n\tconst ensureMode = (collectionId: string, name: string, id?: unknown): string | null => {\n\t\tconst collection = getTokenCollection(next, collectionId)!;\n\t\tconst existing = findTokenMode(collection, name);\n\t\tif (existing) return existing.id;\n\t\ttry {\n\t\t\tconst result = addTokenMode(next, collectionId, name, {}, idFrom(id, 'mode'));\n\t\t\tnext = result.state;\n\t\t\treport.modesAdded += 1;\n\t\t\treturn result.mode.id;\n\t\t} catch (error) {\n\t\t\twarn(`Mode \\`${name}\\`: ${(error as Error).message}`);\n\t\t\treturn null;\n\t\t}\n\t};\n\n\tfor (const source of sources) {\n\t\tlet collection: TokenCollection | undefined = findTokenCollection(next, source.name);\n\t\tif (!collection) {\n\t\t\tconst declared = (source.modes ?? []).filter(isObject);\n\t\t\tconst names = declared.map((m) => m.name).filter((n): n is string => typeof n === 'string' && n.trim() !== '');\n\t\t\tif (source.plain && options.mode) names.splice(0, names.length, options.mode);\n\t\t\ttry {\n\t\t\t\tconst ids = [source.id, ...declared.map((m) => m.id)];\n\t\t\t\tlet i = 0;\n\t\t\t\tconst factory: TokenIdFactory = (kind) => idFrom(kind === 'collection' ? ids[0] : ids[++i], kind)(kind);\n\t\t\t\tconst result = createTokenCollection(next, { name: source.name, modes: names.length ? names : undefined }, factory);\n\t\t\t\tnext = result.state;\n\t\t\t\tcollection = result.collection;\n\t\t\t\treport.collectionsAdded += 1;\n\t\t\t} catch (error) {\n\t\t\t\twarn(`Collection \\`${source.name}\\`: ${(error as Error).message}`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const m of (source.modes ?? []).filter(isObject)) {\n\t\t\t\tif (typeof m.name === 'string' && m.name.trim()) ensureMode(collection.id, m.name, m.id);\n\t\t\t}\n\t\t}\n\t\tcollectionIds.set(source.name, collection.id);\n\t\tconst modeId = options.mode && source.plain ? ensureMode(collection.id, options.mode) : getTokenCollection(next, collection.id)!.modes[0].id;\n\t\tif (modeId) plainMode.set(source.name, modeId);\n\t\tcollectTokens(source.group, source.name, [], undefined, tokens, report.warnings, 0);\n\t}\n\n\t// Paths for references: `Collection.a.b` and (within a collection) `a.b`.\n\tconst byFullPath = new Map<string, RawToken>();\n\tfor (const token of tokens) byFullPath.set([token.collection, ...token.path].join('.'), token);\n\tconst findRaw = (ref: string, from: RawToken): RawToken | undefined =>\n\t\tbyFullPath.get(ref) ?? byFullPath.get(`${from.collection}.${ref}`);\n\n\t// Types of untyped aliases follow their targets.\n\tconst typeOf = (token: RawToken): string | undefined => {\n\t\tlet current: RawToken | undefined = token;\n\t\tfor (let i = 0; i < MAX_DEPTH && current; i++) {\n\t\t\tif (current.type) return current.type;\n\t\t\tconst ref = aliasRef(current.value);\n\t\t\tif (ref === null) return inferType(current.value);\n\t\t\tcurrent = findRaw(ref, current);\n\t\t}\n\t\treturn undefined;\n\t};\n\n\tconst pending: { variable: TokenVariable; modeId: string; ref: string; token: RawToken }[] = [];\n\tconst variableFor = new Map<RawToken, string>();\n\tfor (const token of tokens) {\n\t\tconst label = [token.collection, ...token.path].join('.');\n\t\tconst collectionId = collectionIds.get(token.collection);\n\t\tif (!collectionId) continue;\n\t\tconst w3cType = typeOf(token);\n\t\tconst type = w3cType ? mapType(w3cType) : null;\n\t\tif (!w3cType || !type) {\n\t\t\twarn(`\\`${label}\\` has an unsupported type \\`${w3cType ?? 'unknown'}\\`; skipped`);\n\t\t\tcontinue;\n\t\t}\n\t\tlet name: string;\n\t\ttry {\n\t\t\tname = normalizeTokenName(token.path.join('/'));\n\t\t} catch (error) {\n\t\t\twarn(`\\`${label}\\`: ${(error as Error).message}`);\n\t\t\tcontinue;\n\t\t}\n\t\tlet variable = findTokenVariable(next, name, collectionId);\n\t\tif (variable && variable.type !== type) {\n\t\t\twarn(`\\`${name}\\` is a ${variable.type} variable; the ${type} token \\`${label}\\` was skipped`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!variable) {\n\t\t\ttry {\n\t\t\t\tconst result = createTokenVariable(next, { collectionId, name, type }, idFrom(token.ext?.id, 'variable'));\n\t\t\t\tnext = result.state;\n\t\t\t\tvariable = result.variable;\n\t\t\t\treport.variablesAdded += 1;\n\t\t\t} catch (error) {\n\t\t\t\twarn(`\\`${label}\\`: ${(error as Error).message}`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t} else report.variablesUpdated += 1;\n\t\tvariableFor.set(token, variable.id);\n\n\t\t// Values: per mode from our extension, else `$value` into the plain mode.\n\t\tconst values: [string, unknown][] = [];\n\t\tconst extModes = token.ext?.modes;\n\t\tif (isObject(extModes)) {\n\t\t\tfor (const [modeName, value] of Object.entries(extModes)) {\n\t\t\t\tconst modeId = ensureMode(collectionId, modeName);\n\t\t\t\tif (modeId) values.push([modeId, value]);\n\t\t\t}\n\t\t} else {\n\t\t\tconst modeId = plainMode.get(token.collection);\n\t\t\tif (modeId) values.push([modeId, token.value]);\n\t\t}\n\t\tlet unit: string | undefined;\n\t\tfor (const [modeId, raw] of values) {\n\t\t\tconst ref = aliasRef(raw);\n\t\t\tif (ref !== null) {\n\t\t\t\tpending.push({ variable, modeId, ref, token });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst literal = readLiteral(w3cType, type, raw);\n\t\t\tif (!literal) {\n\t\t\t\twarn(`\\`${label}\\` has an invalid ${w3cType} value; kept the previous value`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (literal.unit) unit = literal.unit;\n\t\t\tnext = setTokenValue(next, variable.id, literal.value, modeId);\n\t\t}\n\t\tconst update: { description?: string; scopes?: string[]; unit?: string } = {};\n\t\tif (typeof token.description === 'string') update.description = token.description;\n\t\tconst extUnit = token.ext?.unit;\n\t\tif (typeof extUnit === 'string') unit = extUnit;\n\t\tif (unit && unit !== variable.unit) update.unit = unit;\n\t\tif (Array.isArray(token.ext?.scopes)) update.scopes = (token.ext!.scopes as unknown[]).filter((s): s is string => typeof s === 'string');\n\t\tif (Object.keys(update).length > 0) {\n\t\t\ttry {\n\t\t\t\tnext = updateTokenVariable(next, variable.id, update);\n\t\t\t} catch (error) {\n\t\t\t\twarn(`\\`${label}\\`: ${(error as Error).message}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Aliases, once every variable exists.\n\tfor (const { variable, modeId, ref, token } of pending) {\n\t\tconst label = [token.collection, ...token.path].join('.');\n\t\tconst raw = findRaw(ref, token);\n\t\tlet targetId = raw ? variableFor.get(raw) : undefined;\n\t\tif (!targetId) {\n\t\t\t// A variable already in the state: `Collection.a.b` or `a.b` in this collection.\n\t\t\tconst dot = ref.indexOf('.');\n\t\t\tconst inCollection = dot > 0 ? findTokenCollection(next, ref.slice(0, dot)) : undefined;\n\t\t\tconst found =\n\t\t\t\t(inCollection && findTokenVariable(next, ref.slice(dot + 1).split('.').join('/'), inCollection.id)) ||\n\t\t\t\tfindTokenVariable(next, ref.split('.').join('/'), variable.collectionId);\n\t\t\ttargetId = found ? found.id : undefined;\n\t\t}\n\t\tif (!targetId) {\n\t\t\twarn(`\\`${label}\\` refers to \\`{${ref}}\\`, which doesn't exist; kept the previous value`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst current = getTokenVariable(next, variable.id)!;\n\t\tconst error = checkTokenAlias(next, current, targetId);\n\t\tif (error) {\n\t\t\twarn(`\\`${label}\\`: ${error.message}`);\n\t\t\tcontinue;\n\t\t}\n\t\tnext = setTokenValue(next, variable.id, { alias: targetId }, modeId);\n\t}\n\n\treturn { state: next, report };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-G2I4QJOT.cjs","../src/history/HistoryManager.ts","../src/dirty.ts"],"names":[],"mappings":"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","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-G2I4QJOT.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","// Portions ported from soundcraft-main/crates/engine/src/lib.rs (MIT OR Apache-2.0,\n// © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * Compares two values for structural equality.\n * Handles primitives, objects, arrays, and null/undefined.\n */\nexport function defaultIsEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== \"object\" ||\n a === null ||\n typeof b !== \"object\" ||\n b === null\n ) {\n return false;\n }\n\n // Fast path for arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!defaultIsEqual(a[i], b[i])) return false;\n }\n return true;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b) as (keyof T)[];\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!defaultIsEqual(a[key], b[key])) return false;\n }\n\n return true;\n}\n\nexport interface DirtyTrackerOptions<T> {\n /**\n * Equality check. When `normalize` is set it receives the normalized values.\n */\n isEqual?: (a: T, b: T) => boolean;\n /**\n * Projects a value onto the part that counts as \"the document\" before\n * comparing, e.g. `({ selection, viewport, ...doc }) => doc` so that\n * selecting, scrolling or zooming never marks the document dirty.\n */\n normalize?: (value: T) => unknown;\n}\n\ntype Thenable = { then: (...args: any[]) => any };\n\nconst isThenable = (value: unknown): value is Thenable =>\n !!value &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n typeof (value as Thenable).then === \"function\";\n\n/**\n * Tracks a baseline (saved) value and determines whether the current value is\n * dirty (modified).\n *\n * Stateless use: `isDirty(current)`. Stateful use: feed values with\n * `update(current, revision?)`, read `dirty`, `subscribe` to changes, call\n * `markClean()` after saving and wrap programmatic loads in `suppress(fn)`.\n */\nexport class DirtyTracker<T = unknown> {\n private baseline: T;\n private readonly isEqual: (a: T, b: T) => boolean;\n private readonly normalize?: (value: T) => unknown;\n private normalizedBaseline: { value: unknown } | null = null;\n /** `isDirty` result as of a revision (and baseline version). */\n private cache: { revision: number; baseline: number; dirty: boolean } | null =\n null;\n private baselineVersion = 0;\n private suppressDepth = 0;\n private hasValue = false;\n private lastValue: T | undefined;\n private dirtyState = false;\n private listeners = new Set<(dirty: boolean) => void>();\n\n constructor(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n ) {\n this.baseline = initialBaseline;\n if (typeof options === \"function\") {\n this.isEqual = options;\n } else {\n this.isEqual = options?.isEqual ?? defaultIsEqual;\n this.normalize = options?.normalize;\n }\n }\n\n /**\n * Returns current baseline value.\n */\n public getBaseline(): T {\n return this.baseline;\n }\n\n private changeBaseline(value: T): void {\n this.baseline = value;\n this.baselineVersion++;\n this.normalizedBaseline = null;\n this.cache = null;\n }\n\n /**\n * Sets a new baseline value without triggering any dirty state.\n * If a value is being tracked (`update`), `dirty` is recomputed against it.\n */\n public setBaseline(value: T): void {\n this.changeBaseline(value);\n if (this.hasValue) {\n this.setDirtyState(this.compare(this.lastValue as T));\n }\n }\n\n private compare(current: T): boolean {\n if (!this.normalize) return !this.isEqual(this.baseline, current);\n this.normalizedBaseline ??= { value: this.normalize(this.baseline) };\n return !this.isEqual(\n this.normalizedBaseline.value as T,\n this.normalize(current) as T,\n );\n }\n\n /**\n * Checks whether the given value differs from the baseline.\n * With a `revision` (e.g. `HistoryManager.getRevision()`), the result is\n * cached and reused for the same revision until the baseline changes.\n */\n public isDirty(current: T, revision?: number): boolean {\n if (revision === undefined) return this.compare(current);\n const cache = this.cache;\n if (\n cache &&\n cache.revision === revision &&\n cache.baseline === this.baselineVersion\n ) {\n return cache.dirty;\n }\n const dirty = this.compare(current);\n this.cache = { revision, baseline: this.baselineVersion, dirty };\n return dirty;\n }\n\n /**\n * Resets the baseline to the provided current value (or clears dirty status).\n */\n public reset(current: T): void {\n this.changeBaseline(current);\n this.hasValue = true;\n this.lastValue = current;\n this.setDirtyState(false);\n }\n\n /**\n * Records the current value and returns whether it is dirty. While\n * suppressed (`suppress`), the value becomes the new baseline instead, so\n * programmatic loads and restores never mark the document dirty.\n */\n public update(current: T, revision?: number): boolean {\n this.hasValue = true;\n this.lastValue = current;\n if (this.suppressDepth > 0) {\n this.changeBaseline(current);\n this.setDirtyState(false);\n return false;\n }\n const dirty = this.isDirty(current, revision);\n this.setDirtyState(dirty);\n return dirty;\n }\n\n /** Whether the last value passed to `update` differs from the baseline. */\n public get dirty(): boolean {\n return this.dirtyState;\n }\n\n /** Whether `suppress` is currently running. */\n public get suppressed(): boolean {\n return this.suppressDepth > 0;\n }\n\n /**\n * Marks the document saved: `current` (default: the last value passed to\n * `update`) becomes the baseline.\n */\n public markClean(...args: [] | [current: T]): void {\n if (args.length > 0) {\n this.reset(args[0] as T);\n } else if (this.hasValue) {\n this.reset(this.lastValue as T);\n } else {\n this.setDirtyState(false);\n }\n }\n\n /**\n * Runs `fn` without marking anything dirty: every `update` during it\n * rebaselines. Re-entrant (depth counter). If `fn` returns a promise, the\n * suppression lasts until it settles.\n */\n public suppress<R>(fn: () => R): R {\n this.suppressDepth++;\n let result: R;\n try {\n result = fn();\n } catch (error) {\n this.suppressDepth--;\n throw error;\n }\n if (isThenable(result)) {\n const release = () => {\n this.suppressDepth--;\n };\n return (result as unknown as Promise<unknown>).then(\n (value) => {\n release();\n return value;\n },\n (error) => {\n release();\n throw error;\n },\n ) as unknown as R;\n }\n this.suppressDepth--;\n return result;\n }\n\n /**\n * Subscribes to changes of `dirty`. The listener is called immediately with\n * the current value. Returns an unsubscribe function.\n */\n public subscribe(listener: (dirty: boolean) => void): () => void {\n this.listeners.add(listener);\n listener(this.dirtyState);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private setDirtyState(dirty: boolean): void {\n if (dirty === this.dirtyState) return;\n this.dirtyState = dirty;\n this.listeners.forEach((listener) => {\n try {\n listener(dirty);\n } catch (err) {\n console.error(\"[DirtyTracker] Error in listener:\", err);\n }\n });\n }\n}\n\n/**\n * Creates a DirtyTracker instance.\n */\nexport function createDirtyTracker<T>(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n): DirtyTracker<T> {\n return new DirtyTracker(initialBaseline, options);\n}\n\n/**\n * Runs `fn` with dirty tracking suppressed (see `DirtyTracker.suppress`).\n */\nexport function withoutDirty<R>(tracker: DirtyTracker<any>, fn: () => R): R {\n return tracker.suppress(fn);\n}\n\n/** Minimal history surface used by `bindDirtyToHistory` (`HistoryManager` satisfies it). */\nexport interface DirtyHistorySource {\n subscribe(listener: (...args: any[]) => void): () => void;\n getRevision?(): number;\n}\n\nexport interface BindDirtyToHistoryOptions<T> extends DirtyTrackerOptions<T> {\n history: DirtyHistorySource;\n /** Reads the current document value. */\n getValue: () => T;\n /** Existing tracker to drive (default: a new one baselined on `getValue()`). */\n tracker?: DirtyTracker<T>;\n}\n\nexport interface HistoryDirtyBinding<T> {\n readonly tracker: DirtyTracker<T>;\n /** Whether the document differs from the saved baseline. */\n readonly dirty: boolean;\n /** Marks the current value as saved. */\n markClean(): void;\n /** Runs `fn` (e.g. a load or restore) without marking the document dirty. */\n suppress<R>(fn: () => R): R;\n /** Re-reads the value after a change made outside the history. */\n refresh(): boolean;\n subscribe(listener: (dirty: boolean) => void): () => void;\n /** Stops listening to the history. */\n destroy(): void;\n}\n\n/**\n * Keeps a `DirtyTracker` in step with a `HistoryManager`: every history change\n * re-reads the value (cached per history revision), so undoing back to the\n * saved state makes the document clean again.\n */\nexport function bindDirtyToHistory<T>(\n options: BindDirtyToHistoryOptions<T>,\n): HistoryDirtyBinding<T> {\n const { history, getValue } = options;\n const tracker =\n options.tracker ??\n new DirtyTracker<T>(getValue(), {\n isEqual: options.isEqual,\n normalize: options.normalize,\n });\n const unsubscribe = history.subscribe(() => {\n tracker.update(getValue(), history.getRevision?.());\n });\n return {\n tracker,\n get dirty() {\n return tracker.dirty;\n },\n markClean: () => tracker.markClean(getValue()),\n suppress: <R>(fn: () => R): R => {\n // The loaded value becomes the baseline even if the load never touched the history.\n const rebaseline = () => {\n if (!tracker.suppressed) tracker.reset(getValue());\n };\n const result = tracker.suppress(fn);\n if (isThenable(result)) {\n return (result as unknown as Promise<unknown>).then((value) => {\n rebaseline();\n return value;\n }) as unknown as R;\n }\n rebaseline();\n return result;\n },\n refresh: () => tracker.update(getValue()),\n subscribe: (listener) => tracker.subscribe(listener),\n destroy: unsubscribe,\n };\n}\n"]}