@pixerate/editor 0.162.1 → 0.164.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 (75) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/index.cjs +34 -34
  3. package/dist/agent/index.js +5 -5
  4. package/dist/canvas/displacement.d.cts +34 -2
  5. package/dist/canvas/displacement.d.ts +34 -2
  6. package/dist/canvas/explosion-tools.d.cts +43 -0
  7. package/dist/canvas/explosion-tools.d.ts +43 -0
  8. package/dist/canvas/explosionLayout.d.cts +50 -0
  9. package/dist/canvas/explosionLayout.d.ts +50 -0
  10. package/dist/canvas/explosionState.d.cts +52 -0
  11. package/dist/canvas/explosionState.d.ts +52 -0
  12. package/dist/canvas/index.cjs +430 -88
  13. package/dist/canvas/index.d.cts +3 -0
  14. package/dist/canvas/index.d.ts +3 -0
  15. package/dist/canvas/index.js +425 -83
  16. package/dist/canvas/types.d.cts +27 -2
  17. package/dist/canvas/types.d.ts +27 -2
  18. package/dist/chart/commands.d.cts +2 -1
  19. package/dist/chart/commands.d.ts +2 -1
  20. package/dist/chart/controller.d.cts +109 -1
  21. package/dist/chart/controller.d.ts +109 -1
  22. package/dist/chart/index.cjs +605 -130
  23. package/dist/chart/index.d.cts +1 -0
  24. package/dist/chart/index.d.ts +1 -0
  25. package/dist/chart/index.js +490 -15
  26. package/dist/chart/layout-annotations.d.cts +29 -0
  27. package/dist/chart/layout-annotations.d.ts +29 -0
  28. package/dist/chart/layout-families.d.cts +23 -0
  29. package/dist/chart/layout-families.d.ts +23 -0
  30. package/dist/chart/mermaid.d.cts +2 -1
  31. package/dist/chart/mermaid.d.ts +2 -1
  32. package/dist/chart/schemas.d.cts +13 -0
  33. package/dist/chart/schemas.d.ts +13 -0
  34. package/dist/chart/spec.d.cts +30 -5
  35. package/dist/chart/spec.d.ts +30 -5
  36. package/dist/chart/stats.d.cts +9 -1
  37. package/dist/chart/stats.d.ts +9 -1
  38. package/dist/chart/tools.d.cts +1 -1
  39. package/dist/chart/tools.d.ts +1 -1
  40. package/dist/chart/tree.d.cts +62 -0
  41. package/dist/chart/tree.d.ts +62 -0
  42. package/dist/chart/types.d.cts +77 -3
  43. package/dist/chart/types.d.ts +77 -3
  44. package/dist/{chunk-7YBDRJXT.cjs → chunk-22KLZZGH.cjs} +8 -8
  45. package/dist/{chunk-HLOKB7WW.js → chunk-3NEZJCBY.js} +366 -6
  46. package/dist/{chunk-EVPZ5IKN.js → chunk-5FNGLV2D.js} +65 -3
  47. package/dist/{chunk-EQ46F75O.cjs → chunk-D54JHQK2.cjs} +51 -51
  48. package/dist/{chunk-NO5QQDHZ.js → chunk-DAPQGA55.js} +2 -2
  49. package/dist/{chunk-3IHNXRUV.cjs → chunk-GKNEJ6EN.cjs} +399 -67
  50. package/dist/{chunk-4NGVHHJB.cjs → chunk-NZD2MZJC.cjs} +80 -18
  51. package/dist/{chunk-CX6JLDFC.js → chunk-OXERWBKE.js} +3 -3
  52. package/dist/{chunk-7CKPUUN4.js → chunk-POR54B55.js} +61 -10
  53. package/dist/{chunk-LL3H5XUH.cjs → chunk-R3P2M7HU.cjs} +367 -7
  54. package/dist/{chunk-HDGBM7EA.cjs → chunk-SBQVEBSU.cjs} +580 -53
  55. package/dist/{chunk-XDCFJEU7.js → chunk-SZA42R4N.js} +346 -14
  56. package/dist/{chunk-GLMP22FT.js → chunk-TALQONZ5.js} +3 -3
  57. package/dist/{chunk-NA4UVVJ4.cjs → chunk-YGG7WDWT.cjs} +76 -25
  58. package/dist/{chunk-EY22AY6R.cjs → chunk-YSAGBIRW.cjs} +16 -16
  59. package/dist/{chunk-DTSTNRPH.js → chunk-Z4P2RBMJ.js} +536 -9
  60. package/dist/export/index.cjs +4 -4
  61. package/dist/export/index.js +3 -3
  62. package/dist/extensions/index.cjs +7 -7
  63. package/dist/extensions/index.js +6 -6
  64. package/dist/index.cjs +13 -13
  65. package/dist/index.js +7 -7
  66. package/dist/paint-editor/index.cjs +0 -20
  67. package/dist/paint-editor/index.js +0 -20
  68. package/package.json +1 -1
  69. package/skills/README.md +12 -0
  70. package/skills/pixerate-agent-tools/SKILL.md +34 -1
  71. package/skills/pixerate-canvas/SKILL.md +16 -0
  72. package/skills/pixerate-chart/SKILL.md +41 -9
  73. package/skills/pixerate-image-editor/SKILL.md +2 -0
  74. package/skills/pixerate-paint-editor/SKILL.md +2 -0
  75. package/skills/pixerate-tokens/SKILL.md +5 -0
package/README.md CHANGED
@@ -473,7 +473,7 @@ Each module is also available as a subpath import:
473
473
  | `@pixerate/editor/spreadsheet` | `SpreadsheetController`, formula parser/evaluator and dependency graph, formula function registry (`registerFormulaFunction`, `listFormulaFunctions`, `searchFormulaFunctions`, `getFormulaSignature`) and autocomplete helpers (`getFormulaHints`, `applyFormulaSuggestion`) |
474
474
  | `@pixerate/editor/image-editor` | `ImageEditorController` and Canvas 2D renderer: crop, adjustments, annotations, depth masks, selections and layer masks, and AI hooks. Needs a DOM/canvas environment (the selection algorithms themselves are pure). |
475
475
  | `@pixerate/editor/animation` | The keyframe model without canvas nodes: `AnimationTrack` / `AnimationKeyframe`, easing (`resolveEasing`, `evaluateEasing`, `cubicBezierAt`, `springAt`, presets, `parseCssEasing`, `easingToCss`), `evaluateTrack`, `interpolateAnimationValue`, `normalizeKeyframes`, OKLab colour mixing, `AnimationPlayer` and the `Clock` / `ManualClock` / `realClock` time sources (no third-party imports) |
476
- | `@pixerate/editor/canvas` | Node-graph layout (needs the optional `@dagrejs/dagre` peer), placement, trajectories, displacement, clipboard and streaming layout helpers, and node keyframe animation (re-exports everything in `/animation`) |
476
+ | `@pixerate/editor/canvas` | Node-graph layout (needs the optional `@dagrejs/dagre` peer), placement, trajectories, displacement, node explosion (pure layout, headless explode / collapse state and agent tools), clipboard and streaming layout helpers, and node keyframe animation (re-exports everything in `/animation`) |
477
477
  | `@pixerate/editor/agent` | MCP tool schemas, a planner for agent-driven canvas edits, and the dynamic `ToolRegistry` with editor/spreadsheet tool providers |
478
478
  | `@pixerate/editor/tools` | `ToolRegistry`, tool types, `validateJsonSchema` and the static MCP tool definitions, without TipTap or dagre (no third-party imports) |
479
479
  | `@pixerate/editor/commands` | `CommandRegistry`, `ShortcutMap`, palette ranking, `createCommandToolProvider` and built-in history / arrange / spreadsheet commands (no third-party imports) |
@@ -2,7 +2,7 @@
2
2
 
3
3
 
4
4
 
5
- var _chunk4NGVHHJBcjs = require('../chunk-4NGVHHJB.cjs');
5
+ var _chunkNZD2MZJCcjs = require('../chunk-NZD2MZJC.cjs');
6
6
 
7
7
 
8
8
  var _chunkGLQQ2VILcjs = require('../chunk-GLQQ2VIL.cjs');
@@ -115,15 +115,15 @@ var _chunkN2FGYZ4Qcjs = require('../chunk-N2FGYZ4Q.cjs');
115
115
 
116
116
 
117
117
 
118
- var _chunkEY22AY6Rcjs = require('../chunk-EY22AY6R.cjs');
118
+ var _chunkYSAGBIRWcjs = require('../chunk-YSAGBIRW.cjs');
119
119
 
120
120
 
121
- var _chunk3IHNXRUVcjs = require('../chunk-3IHNXRUV.cjs');
122
- require('../chunk-HDGBM7EA.cjs');
121
+ var _chunkGKNEJ6ENcjs = require('../chunk-GKNEJ6EN.cjs');
122
+ require('../chunk-SBQVEBSU.cjs');
123
123
 
124
124
 
125
125
 
126
- var _chunkLL3H5XUHcjs = require('../chunk-LL3H5XUH.cjs');
126
+ var _chunkR3P2M7HUcjs = require('../chunk-R3P2M7HU.cjs');
127
127
 
128
128
 
129
129
 
@@ -624,14 +624,14 @@ var SIZE_WIDTH = {
624
624
  };
625
625
  var SIZE_HEIGHT = { type: "number", minimum: 50, maximum: 4096, description: "Height in pixels (default 320)." };
626
626
  var SPEC_PROPERTIES = {
627
- ..._chunk4NGVHHJBcjs.CHART_UPDATE_PROPERTIES,
627
+ ..._chunkNZD2MZJCcjs.CHART_UPDATE_PROPERTIES,
628
628
  categories: { type: "array", items: { type: "string" }, description: "Category labels in order (x axis labels, or pie slices)." },
629
629
  series: {
630
630
  type: "array",
631
631
  description: "The series, each with one value per category (padded with gaps).",
632
632
  items: {
633
633
  type: "object",
634
- properties: { id: { type: "string", description: "Stable id (default: from the name)." }, ..._chunk4NGVHHJBcjs.SERIES_PROPS },
634
+ properties: { id: { type: "string", description: "Stable id (default: from the name)." }, ..._chunkNZD2MZJCcjs.SERIES_PROPS },
635
635
  required: ["name", "values"],
636
636
  additionalProperties: false
637
637
  }
@@ -642,7 +642,7 @@ function cleanSeries(series) {
642
642
  return series.map((s) => s && typeof s === "object" ? Object.fromEntries(Object.entries(s).filter(([, v]) => v !== null)) : s);
643
643
  }
644
644
  function checkedSpec(input) {
645
- const { spec, issues } = _chunkLL3H5XUHcjs.normalizeChartSpec.call(void 0, { ...input, ...input.series !== void 0 ? { series: cleanSeries(input.series) } : {} });
645
+ const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, { ...input, ...input.series !== void 0 ? { series: cleanSeries(input.series) } : {} });
646
646
  if (issues.length) throw new Error(`The chart was not changed: ${issues.map((i) => i.message).join(" ")}`);
647
647
  return spec;
648
648
  }
@@ -657,14 +657,14 @@ function describe(chart, includeSpec) {
657
657
  series: spec.series.map((s) => ({ id: s.id, name: s.name })),
658
658
  width: _nullishCoalesce(node.attrs.width, () => ( null)),
659
659
  height: node.attrs.height,
660
- description: _chunk3IHNXRUVcjs.describeChart.call(void 0, spec),
660
+ description: _chunkGKNEJ6ENcjs.describeChart.call(void 0, spec),
661
661
  ...includeSpec ? { spec } : {}
662
662
  };
663
663
  }
664
664
  function sparklines(doc) {
665
665
  const found = [];
666
666
  doc.descendants((node, pos) => {
667
- if (node.type.name === "sparkline") found.push({ pos, kind: node.attrs.kind, values: node.attrs.values, label: _chunkEY22AY6Rcjs.sparklineLabel.call(void 0, node) });
667
+ if (node.type.name === "sparkline") found.push({ pos, kind: node.attrs.kind, values: node.attrs.values, label: _chunkYSAGBIRWcjs.sparklineLabel.call(void 0, node) });
668
668
  });
669
669
  return found;
670
670
  }
@@ -675,7 +675,7 @@ function checkPosition(editor, at) {
675
675
  function createDocumentChartTools(editor) {
676
676
  const chartType = () => editor().schema.nodes.chart;
677
677
  const findChart = (args) => {
678
- const charts = _chunkEY22AY6Rcjs.getDocumentCharts.call(void 0, editor().state.doc);
678
+ const charts = _chunkYSAGBIRWcjs.getDocumentCharts.call(void 0, editor().state.doc);
679
679
  const list = charts.map((c) => `"${c.id}" at ${c.pos}`).join(", ") || "none; add one with insert_chart";
680
680
  if (args.chartId !== void 0) {
681
681
  const chart = charts.find((c) => c.id === args.chartId);
@@ -702,7 +702,7 @@ function createDocumentChartTools(editor) {
702
702
  annotations: { title: "List charts in the document", ...READ },
703
703
  handler: ({ includeSpec = false }) => {
704
704
  const doc = editor().state.doc;
705
- return { charts: _chunkEY22AY6Rcjs.getDocumentCharts.call(void 0, doc).map((c) => describe(c, includeSpec)), sparklines: editor().schema.nodes.sparkline ? sparklines(doc) : [] };
705
+ return { charts: _chunkYSAGBIRWcjs.getDocumentCharts.call(void 0, doc).map((c) => describe(c, includeSpec)), sparklines: editor().schema.nodes.sparkline ? sparklines(doc) : [] };
706
706
  }
707
707
  };
708
708
  const insertChart = {
@@ -729,7 +729,7 @@ function createDocumentChartTools(editor) {
729
729
  const node = { type: "chart", attrs: { id, spec, width, ...height !== void 0 ? { height } : {} } };
730
730
  const chain = ed.chain().command(({ tr }) => (_history.closeHistory.call(void 0, tr), true));
731
731
  const ok = (at !== void 0 ? chain.insertContentAt(at, node) : chain.insertContent(node)).run();
732
- const chart = _chunkEY22AY6Rcjs.getDocumentCharts.call(void 0, ed.state.doc).find((c) => c.id === id);
732
+ const chart = _chunkYSAGBIRWcjs.getDocumentCharts.call(void 0, ed.state.doc).find((c) => c.id === id);
733
733
  if (!ok || !chart) throw new Error(`A chart cannot go at ${_nullishCoalesce(at, () => ( ed.state.selection.from))}; pass a position between blocks or inside a paragraph.`);
734
734
  return { id: chart.id, pos: chart.pos, spec: chart.spec, width: chart.node.attrs.width, height: chart.node.attrs.height };
735
735
  }
@@ -776,8 +776,8 @@ function createDocumentChartTools(editor) {
776
776
  inputSchema: {
777
777
  type: "object",
778
778
  properties: {
779
- values: { type: "array", items: _chunk4NGVHHJBcjs.VALUE, minItems: 1, maxItems: _chunkEY22AY6Rcjs.MAX_SPARKLINE_VALUES, description: "Values in order (null for a gap)." },
780
- kind: { type: "string", enum: [..._chunkEY22AY6Rcjs.SPARKLINE_KINDS], description: "line (default), column, or win-loss (sign only)." },
779
+ values: { type: "array", items: _chunkNZD2MZJCcjs.VALUE, minItems: 1, maxItems: _chunkYSAGBIRWcjs.MAX_SPARKLINE_VALUES, description: "Values in order (null for a gap)." },
780
+ kind: { type: "string", enum: [..._chunkYSAGBIRWcjs.SPARKLINE_KINDS], description: "line (default), column, or win-loss (sign only)." },
781
781
  at: { type: "integer", minimum: 0, description: "Document position inside a paragraph (default: the selection)." },
782
782
  width: { type: "number", minimum: 4, maximum: 1e3, description: "Width in pixels (default 80)." },
783
783
  height: { type: "number", minimum: 4, maximum: 200, description: "Height in pixels (default 18)." },
@@ -791,12 +791,12 @@ function createDocumentChartTools(editor) {
791
791
  handler: ({ values, kind = "line", at, width = 80, height = 18, color = null, label = null }) => {
792
792
  const ed = editor();
793
793
  checkPosition(ed, at);
794
- const parsed = values.map((v) => _chunkLL3H5XUHcjs.parseChartValue.call(void 0, v));
794
+ const parsed = values.map((v) => _chunkR3P2M7HUcjs.parseChartValue.call(void 0, v));
795
795
  const bad = parsed.findIndex((v) => v === void 0);
796
796
  if (bad >= 0) throw new Error(`values[${bad}] ("${String(values[bad])}") is not a number; pass numbers, numeric text or null. Nothing was inserted.`);
797
797
  const pos = _nullishCoalesce(at, () => ( ed.state.selection.from));
798
798
  if (!ed.state.doc.resolve(pos).parent.inlineContent) throw new Error(`Position ${pos} is between blocks; a sparkline goes inside a paragraph (use a position from get_text {blocks: true}).`);
799
- const stored = _chunkEY22AY6Rcjs.normalizeSparklineValues.call(void 0, parsed);
799
+ const stored = _chunkYSAGBIRWcjs.normalizeSparklineValues.call(void 0, parsed);
800
800
  ed.chain().command(({ tr }) => (_history.closeHistory.call(void 0, tr), true)).insertContentAt(pos, { type: "sparkline", attrs: { values: stored, kind, width, height, color, label } }).run();
801
801
  return { pos, kind, values: stored };
802
802
  }
@@ -1134,8 +1134,8 @@ function createTextPresence(editor, providerId, option) {
1134
1134
  const config = option === false ? null : option === true || option === void 0 ? {} : option;
1135
1135
  const caret = {
1136
1136
  id: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _43 => _43.id]), () => ( providerId)),
1137
- name: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _44 => _44.name]), () => ( _chunkEY22AY6Rcjs.DEFAULT_AGENT_CARET_NAME)),
1138
- color: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _45 => _45.color]), () => ( _chunkEY22AY6Rcjs.DEFAULT_AGENT_CARET_COLOR))
1137
+ name: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _44 => _44.name]), () => ( _chunkYSAGBIRWcjs.DEFAULT_AGENT_CARET_NAME)),
1138
+ color: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _45 => _45.color]), () => ( _chunkYSAGBIRWcjs.DEFAULT_AGENT_CARET_COLOR))
1139
1139
  };
1140
1140
  const typing = !_optionalChain([config, 'optionalAccess', _46 => _46.typing]) ? null : config.typing === true ? {} : config.typing;
1141
1141
  const idleMs = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _47 => _47.idleMs]), () => ( 12e3));
@@ -1148,19 +1148,19 @@ function createTextPresence(editor, providerId, option) {
1148
1148
  };
1149
1149
  const touch = () => {
1150
1150
  clearTimeout(idleTimer);
1151
- if (idleMs > 0) idleTimer = setTimeout(() => live() && _chunkEY22AY6Rcjs.clearAgentCaret.call(void 0, live(), caret.id), idleMs);
1151
+ if (idleMs > 0) idleTimer = setTimeout(() => live() && _chunkYSAGBIRWcjs.clearAgentCaret.call(void 0, live(), caret.id), idleMs);
1152
1152
  };
1153
1153
  const tint = (ed, ranges) => {
1154
1154
  clearTimeout(tintTimer);
1155
- _chunkEY22AY6Rcjs.markAgentChanges.call(void 0, ed, caret.id, ranges);
1156
- if (changedMs > 0 && ranges.length) tintTimer = setTimeout(() => live() && _chunkEY22AY6Rcjs.markAgentChanges.call(void 0, live(), caret.id, []), changedMs);
1155
+ _chunkYSAGBIRWcjs.markAgentChanges.call(void 0, ed, caret.id, ranges);
1156
+ if (changedMs > 0 && ranges.length) tintTimer = setTimeout(() => live() && _chunkYSAGBIRWcjs.markAgentChanges.call(void 0, live(), caret.id, []), changedMs);
1157
1157
  };
1158
1158
  return {
1159
1159
  /** Puts the caret at `head`, selecting from `anchor`. */
1160
1160
  show(anchor, head = anchor) {
1161
1161
  const ed = live();
1162
1162
  if (!ed) return;
1163
- _chunkEY22AY6Rcjs.setAgentCaret.call(void 0, ed, { ...caret, from: anchor, to: head });
1163
+ _chunkYSAGBIRWcjs.setAgentCaret.call(void 0, ed, { ...caret, from: anchor, to: head });
1164
1164
  touch();
1165
1165
  },
1166
1166
  /** Shows the caret after ranges just changed by a tool, tinting them. */
@@ -1168,7 +1168,7 @@ function createTextPresence(editor, providerId, option) {
1168
1168
  const ed = live();
1169
1169
  if (!ed || !ranges.length) return;
1170
1170
  const last = ranges[ranges.length - 1];
1171
- _chunkEY22AY6Rcjs.setAgentCaret.call(void 0, ed, { ...caret, from: last.to });
1171
+ _chunkYSAGBIRWcjs.setAgentCaret.call(void 0, ed, { ...caret, from: last.to });
1172
1172
  tint(ed, ranges);
1173
1173
  touch();
1174
1174
  },
@@ -1176,12 +1176,12 @@ function createTextPresence(editor, providerId, option) {
1176
1176
  async write(ed, from, to, text, signal) {
1177
1177
  if (live() && typing) {
1178
1178
  clearTimeout(tintTimer);
1179
- const range2 = await _chunkEY22AY6Rcjs.typeAgentText.call(void 0, ed, { ...typing, from, to, text, caret, signal });
1180
- if (changedMs > 0) tintTimer = setTimeout(() => live() && _chunkEY22AY6Rcjs.markAgentChanges.call(void 0, live(), caret.id, []), changedMs);
1179
+ const range2 = await _chunkYSAGBIRWcjs.typeAgentText.call(void 0, ed, { ...typing, from, to, text, caret, signal });
1180
+ if (changedMs > 0) tintTimer = setTimeout(() => live() && _chunkYSAGBIRWcjs.markAgentChanges.call(void 0, live(), caret.id, []), changedMs);
1181
1181
  touch();
1182
1182
  return range2;
1183
1183
  }
1184
- const tr = _history.closeHistory.call(void 0, _chunkEY22AY6Rcjs.replaceWithTextTransaction.call(void 0, ed.state, from, to, text));
1184
+ const tr = _history.closeHistory.call(void 0, _chunkYSAGBIRWcjs.replaceWithTextTransaction.call(void 0, ed.state, from, to, text));
1185
1185
  const end = tr.mapping.map(to, 1);
1186
1186
  const range = { from: Math.min(tr.mapping.map(from, -1), end), to: end };
1187
1187
  ed.view.dispatch(tr.scrollIntoView());
@@ -1210,7 +1210,7 @@ function findMatches(editor, query, args, replacement) {
1210
1210
  wholeWord: !!args.wholeWord,
1211
1211
  ...args.regex ? { regex: true } : { literal: true }
1212
1212
  };
1213
- const result = _chunkEY22AY6Rcjs.searchDocument.call(void 0, editor.state.doc, query, options, replacement !== void 0 ? { replacement } : {});
1213
+ const result = _chunkYSAGBIRWcjs.searchDocument.call(void 0, editor.state.doc, query, options, replacement !== void 0 ? { replacement } : {});
1214
1214
  if (result.error) throw new Error(`Invalid search pattern: ${result.error.message}`);
1215
1215
  return { matches: result.matches, truncated: result.truncated };
1216
1216
  }
@@ -1372,7 +1372,7 @@ function createRichTextToolProvider(target, options) {
1372
1372
  replacement: String(replace).replace(/\r\n?|\n/g, "\r")
1373
1373
  }));
1374
1374
  const tr = _history.closeHistory.call(void 0, ed.state.tr);
1375
- const ends = _chunkEY22AY6Rcjs.applyReplacements.call(void 0, tr, chosen);
1375
+ const ends = _chunkYSAGBIRWcjs.applyReplacements.call(void 0, tr, chosen);
1376
1376
  ed.view.dispatch(tr.scrollIntoView());
1377
1377
  const ranges = chosen.map((m, i) => ({ from: tr.mapping.map(m.from, -1), to: ends[i] }));
1378
1378
  presence.changed(ranges.filter((r) => r.from < r.to));
@@ -1473,7 +1473,7 @@ function createRichTextToolProvider(target, options) {
1473
1473
  inputSchema: {
1474
1474
  type: "object",
1475
1475
  properties: {
1476
- operation: { type: "string", enum: _chunkEY22AY6Rcjs.TABLE_ACTIONS.map((a) => a.action), description: "Table operation." },
1476
+ operation: { type: "string", enum: _chunkYSAGBIRWcjs.TABLE_ACTIONS.map((a) => a.action), description: "Table operation." },
1477
1477
  at: { type: "integer", minimum: 0, description: "Document position to place the cursor first (e.g. inside a cell)." },
1478
1478
  rows: { type: "integer", minimum: 1, maximum: 100, description: "insertTable: rows (default 3)." },
1479
1479
  cols: { type: "integer", minimum: 1, maximum: 50, description: "insertTable: columns (default 3)." },
@@ -1503,10 +1503,10 @@ function createRichTextToolProvider(target, options) {
1503
1503
  ed.view.dispatch(ed.state.tr.setSelection(_state.TextSelection.near(ed.state.doc.resolve(at))));
1504
1504
  }
1505
1505
  const action = operation;
1506
- const state = _chunkEY22AY6Rcjs.getTableActionState.call(void 0, ed, action, params);
1506
+ const state = _chunkYSAGBIRWcjs.getTableActionState.call(void 0, ed, action, params);
1507
1507
  if (state !== true) throw new Error(state);
1508
- _chunkEY22AY6Rcjs.runTableAction.call(void 0, ed, action, params);
1509
- const table = _chunkEY22AY6Rcjs.getTableState.call(void 0, ed);
1508
+ _chunkYSAGBIRWcjs.runTableAction.call(void 0, ed, action, params);
1509
+ const table = _chunkYSAGBIRWcjs.getTableState.call(void 0, ed);
1510
1510
  return {
1511
1511
  operation,
1512
1512
  table: table.inTable ? { rows: table.rows, columns: table.columns, row: table.row, column: table.column } : null,
@@ -1525,7 +1525,7 @@ function createRichTextToolProvider(target, options) {
1525
1525
  if (!ed || ed.isDestroyed) return [];
1526
1526
  if (!ed.isEditable) return [getText, findText, ...charts.read()];
1527
1527
  const tools = [getText, findText, insertText, replaceText, replaceRange, replaceSelection, setSelection, ...formatting.tools(ed)];
1528
- return [...tools, ..._chunkEY22AY6Rcjs.isTableEnabled.call(void 0, ed) ? [editTable] : [], ...charts.read(), ...charts.write().map(withCaret)];
1528
+ return [...tools, ..._chunkYSAGBIRWcjs.isTableEnabled.call(void 0, ed) ? [editTable] : [], ...charts.read(), ...charts.write().map(withCaret)];
1529
1529
  },
1530
1530
  subscribe: (notify) => {
1531
1531
  const ed = editor();
@@ -2,7 +2,7 @@ import {
2
2
  CHART_UPDATE_PROPERTIES,
3
3
  SERIES_PROPS,
4
4
  VALUE
5
- } from "../chunk-EVPZ5IKN.js";
5
+ } from "../chunk-5FNGLV2D.js";
6
6
  import {
7
7
  hasVariantCommands
8
8
  } from "../chunk-3TNA7JKI.js";
@@ -115,15 +115,15 @@ import {
115
115
  setAgentCaret,
116
116
  sparklineLabel,
117
117
  typeAgentText
118
- } from "../chunk-CX6JLDFC.js";
118
+ } from "../chunk-OXERWBKE.js";
119
119
  import {
120
120
  describeChart
121
- } from "../chunk-XDCFJEU7.js";
122
- import "../chunk-DTSTNRPH.js";
121
+ } from "../chunk-SZA42R4N.js";
122
+ import "../chunk-Z4P2RBMJ.js";
123
123
  import {
124
124
  normalizeChartSpec,
125
125
  parseChartValue
126
- } from "../chunk-HLOKB7WW.js";
126
+ } from "../chunk-3NEZJCBY.js";
127
127
  import {
128
128
  getEditorMarkdown,
129
129
  getEditorText
@@ -1,11 +1,30 @@
1
- import type { CanvasEdge, CanvasNode, DirectionalDisplacementOptions, Rect, ReflowDisplacementOptions, XYPosition } from './types.cjs';
1
+ import type { CanvasEdge, CanvasLayoutOptions, CanvasNode, DirectionalDisplacementOptions, Rect, ReflowDisplacementOptions, XYPosition } from './types.cjs';
2
2
  /**
3
3
  * Calculates a bounding rectangle for a set of nodes if not provided by getNodesBounds.
4
4
  */
5
5
  export declare function computeNodesBoundingBox<TNode extends CanvasNode = CanvasNode>(nodes: TNode[], defaultWidth?: number, defaultHeight?: number): Rect;
6
+ /** A node's size: measured, then explicit, then the defaults. */
7
+ export declare function nodeSizeOf<TNode extends CanvasNode = CanvasNode>(node: TNode, defaultWidth?: number, defaultHeight?: number): {
8
+ width: number;
9
+ height: number;
10
+ };
6
11
  /**
7
12
  * Pure directional displacement calculation.
8
- * Shifts downstream or surrounding nodes along an axis to clear space for newly inserted child nodes.
13
+ *
14
+ * Shifts surrounding nodes along an axis to clear space for a cluster of child nodes inserted
15
+ * next to `originNode`, and returns the new positions of the nodes that move (nothing is mutated).
16
+ *
17
+ * - `right` / `left` push nodes on that side by the cluster's width plus `gap`; Y is preserved
18
+ * (except for `spreadSiblingLanes` with `right`).
19
+ * - `up` / `down` push nodes on that side by the cluster's height plus `gap`; X is preserved.
20
+ * - `vertical` opens the origin's row: nodes above move up and nodes below move down by the same
21
+ * amount (the larger of the two clearances); X is preserved and the origin's row stays put.
22
+ * - `layoutMode: 'row-lane'` buckets nodes into lanes `rowSpacing` apart and rounds vertical
23
+ * deltas up to whole lanes.
24
+ * - `minY` / `maxY` keep moved rows inside a band, stacking clamped rows `rowSpacing` apart.
25
+ *
26
+ * @throws RangeError when `gap`, `rowSpacing`, `minY` or `maxY` are not finite, `rowSpacing <= 0`,
27
+ * or `minY > maxY`.
9
28
  */
10
29
  export declare function calculateDirectionalDisplacement<TNode extends CanvasNode = CanvasNode>(params: {
11
30
  existingNodes: TNode[];
@@ -14,6 +33,19 @@ export declare function calculateDirectionalDisplacement<TNode extends CanvasNod
14
33
  getNodesBounds?: (nodes: TNode[]) => Rect;
15
34
  options?: DirectionalDisplacementOptions;
16
35
  }): Map<string, XYPosition>;
36
+ /**
37
+ * Hierarchical Dagre reflow displacement for an explosion: lays out the existing graph plus the
38
+ * child cluster, anchoring the origin node at its current position so the layout does not jump,
39
+ * and returns the new positions of existing nodes that move.
40
+ */
41
+ export declare function calculateReflowDisplacement<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge>(params: {
42
+ existingNodes: TNode[];
43
+ existingEdges: TEdge[];
44
+ originNode: TNode;
45
+ childNodes: TNode[];
46
+ childEdges?: TEdge[];
47
+ options?: CanvasLayoutOptions;
48
+ }): Map<string, XYPosition>;
17
49
  /**
18
50
  * Calculates Dagre reflow displacement preserving the position of an anchor node.
19
51
  */
@@ -1,11 +1,30 @@
1
- import type { CanvasEdge, CanvasNode, DirectionalDisplacementOptions, Rect, ReflowDisplacementOptions, XYPosition } from './types.js';
1
+ import type { CanvasEdge, CanvasLayoutOptions, CanvasNode, DirectionalDisplacementOptions, Rect, ReflowDisplacementOptions, XYPosition } from './types.js';
2
2
  /**
3
3
  * Calculates a bounding rectangle for a set of nodes if not provided by getNodesBounds.
4
4
  */
5
5
  export declare function computeNodesBoundingBox<TNode extends CanvasNode = CanvasNode>(nodes: TNode[], defaultWidth?: number, defaultHeight?: number): Rect;
6
+ /** A node's size: measured, then explicit, then the defaults. */
7
+ export declare function nodeSizeOf<TNode extends CanvasNode = CanvasNode>(node: TNode, defaultWidth?: number, defaultHeight?: number): {
8
+ width: number;
9
+ height: number;
10
+ };
6
11
  /**
7
12
  * Pure directional displacement calculation.
8
- * Shifts downstream or surrounding nodes along an axis to clear space for newly inserted child nodes.
13
+ *
14
+ * Shifts surrounding nodes along an axis to clear space for a cluster of child nodes inserted
15
+ * next to `originNode`, and returns the new positions of the nodes that move (nothing is mutated).
16
+ *
17
+ * - `right` / `left` push nodes on that side by the cluster's width plus `gap`; Y is preserved
18
+ * (except for `spreadSiblingLanes` with `right`).
19
+ * - `up` / `down` push nodes on that side by the cluster's height plus `gap`; X is preserved.
20
+ * - `vertical` opens the origin's row: nodes above move up and nodes below move down by the same
21
+ * amount (the larger of the two clearances); X is preserved and the origin's row stays put.
22
+ * - `layoutMode: 'row-lane'` buckets nodes into lanes `rowSpacing` apart and rounds vertical
23
+ * deltas up to whole lanes.
24
+ * - `minY` / `maxY` keep moved rows inside a band, stacking clamped rows `rowSpacing` apart.
25
+ *
26
+ * @throws RangeError when `gap`, `rowSpacing`, `minY` or `maxY` are not finite, `rowSpacing <= 0`,
27
+ * or `minY > maxY`.
9
28
  */
10
29
  export declare function calculateDirectionalDisplacement<TNode extends CanvasNode = CanvasNode>(params: {
11
30
  existingNodes: TNode[];
@@ -14,6 +33,19 @@ export declare function calculateDirectionalDisplacement<TNode extends CanvasNod
14
33
  getNodesBounds?: (nodes: TNode[]) => Rect;
15
34
  options?: DirectionalDisplacementOptions;
16
35
  }): Map<string, XYPosition>;
36
+ /**
37
+ * Hierarchical Dagre reflow displacement for an explosion: lays out the existing graph plus the
38
+ * child cluster, anchoring the origin node at its current position so the layout does not jump,
39
+ * and returns the new positions of existing nodes that move.
40
+ */
41
+ export declare function calculateReflowDisplacement<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge>(params: {
42
+ existingNodes: TNode[];
43
+ existingEdges: TEdge[];
44
+ originNode: TNode;
45
+ childNodes: TNode[];
46
+ childEdges?: TEdge[];
47
+ options?: CanvasLayoutOptions;
48
+ }): Map<string, XYPosition>;
17
49
  /**
18
50
  * Calculates Dagre reflow displacement preserving the position of an anchor node.
19
51
  */
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Agent tools for canvas node explosion: `list_explodable_nodes`, `explode_node` and
3
+ * `collapse_node`. They drive a {@link CanvasExplosionToolTarget}, which a host adapts from the
4
+ * declarative state (`canvasExplosionToolTarget`) or from an imperative explosion coordinator
5
+ * (`createCanvasExplosion` / `useCanvasExplosion`, whose `explodeNode` needs the host's children).
6
+ */
7
+ import type { AgentToolProvider } from '../tools/registry.cjs';
8
+ import type { CanvasExplosionState } from './explosionState.cjs';
9
+ import type { CanvasNode } from './types.cjs';
10
+ /** What the explosion tools drive. */
11
+ export interface CanvasExplosionToolTarget<TNode extends CanvasNode = CanvasNode> {
12
+ /** The nodes on the canvas (exploded children included or not; they are only listed when explodable). */
13
+ getNodes: () => readonly TNode[];
14
+ /** Ids of the exploded nodes. */
15
+ exploded: () => readonly string[];
16
+ /** Ids of nodes whose collapse is still animating. Default none. */
17
+ collapsing?: () => readonly string[];
18
+ /** `true` when the node can explode, otherwise false or the reason it cannot. Default: every node. */
19
+ canExplode?: (node: TNode) => boolean | string;
20
+ /** Explodes a node. Return false (or throw) to refuse. */
21
+ explode: (nodeId: string) => void | boolean | Promise<void | boolean>;
22
+ /** Collapses an exploded node. Return false (or throw) to refuse. */
23
+ collapse: (nodeId: string) => void | boolean | Promise<void | boolean>;
24
+ /** Several nodes can be exploded at once. Default false: exploding one collapses the other. */
25
+ multiple?: boolean;
26
+ }
27
+ /** Adapts the declarative explosion state (`createCanvasExplosionState`, `useCanvasExplosionState`) for the tools. */
28
+ export declare function canvasExplosionToolTarget<TNode extends CanvasNode = CanvasNode>(state: CanvasExplosionState, options: {
29
+ getNodes: () => readonly TNode[];
30
+ canExplode?: (node: TNode) => boolean | string;
31
+ }): CanvasExplosionToolTarget<TNode>;
32
+ export interface CanvasExplosionToolProviderOptions {
33
+ /** Provider id (unique per registry). Default `canvas-explosion`. */
34
+ id?: string;
35
+ /** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
36
+ namespace?: string;
37
+ /** Exploding is not allowed: `explode_node` and `collapse_node` are hidden. A string is the reason. */
38
+ readOnly?: boolean | string | (() => boolean | string);
39
+ /** Lets the tool list follow changes (e.g. the state's `subscribe`). */
40
+ subscribe?: (notify: () => void) => () => void;
41
+ }
42
+ /** The explosion tools for a canvas (see the module comment). */
43
+ export declare function createCanvasExplosionToolProvider<TNode extends CanvasNode = CanvasNode>(target: CanvasExplosionToolTarget<TNode>, options?: CanvasExplosionToolProviderOptions): AgentToolProvider;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Agent tools for canvas node explosion: `list_explodable_nodes`, `explode_node` and
3
+ * `collapse_node`. They drive a {@link CanvasExplosionToolTarget}, which a host adapts from the
4
+ * declarative state (`canvasExplosionToolTarget`) or from an imperative explosion coordinator
5
+ * (`createCanvasExplosion` / `useCanvasExplosion`, whose `explodeNode` needs the host's children).
6
+ */
7
+ import type { AgentToolProvider } from '../tools/registry.js';
8
+ import type { CanvasExplosionState } from './explosionState.js';
9
+ import type { CanvasNode } from './types.js';
10
+ /** What the explosion tools drive. */
11
+ export interface CanvasExplosionToolTarget<TNode extends CanvasNode = CanvasNode> {
12
+ /** The nodes on the canvas (exploded children included or not; they are only listed when explodable). */
13
+ getNodes: () => readonly TNode[];
14
+ /** Ids of the exploded nodes. */
15
+ exploded: () => readonly string[];
16
+ /** Ids of nodes whose collapse is still animating. Default none. */
17
+ collapsing?: () => readonly string[];
18
+ /** `true` when the node can explode, otherwise false or the reason it cannot. Default: every node. */
19
+ canExplode?: (node: TNode) => boolean | string;
20
+ /** Explodes a node. Return false (or throw) to refuse. */
21
+ explode: (nodeId: string) => void | boolean | Promise<void | boolean>;
22
+ /** Collapses an exploded node. Return false (or throw) to refuse. */
23
+ collapse: (nodeId: string) => void | boolean | Promise<void | boolean>;
24
+ /** Several nodes can be exploded at once. Default false: exploding one collapses the other. */
25
+ multiple?: boolean;
26
+ }
27
+ /** Adapts the declarative explosion state (`createCanvasExplosionState`, `useCanvasExplosionState`) for the tools. */
28
+ export declare function canvasExplosionToolTarget<TNode extends CanvasNode = CanvasNode>(state: CanvasExplosionState, options: {
29
+ getNodes: () => readonly TNode[];
30
+ canExplode?: (node: TNode) => boolean | string;
31
+ }): CanvasExplosionToolTarget<TNode>;
32
+ export interface CanvasExplosionToolProviderOptions {
33
+ /** Provider id (unique per registry). Default `canvas-explosion`. */
34
+ id?: string;
35
+ /** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
36
+ namespace?: string;
37
+ /** Exploding is not allowed: `explode_node` and `collapse_node` are hidden. A string is the reason. */
38
+ readOnly?: boolean | string | (() => boolean | string);
39
+ /** Lets the tool list follow changes (e.g. the state's `subscribe`). */
40
+ subscribe?: (notify: () => void) => () => void;
41
+ }
42
+ /** The explosion tools for a canvas (see the module comment). */
43
+ export declare function createCanvasExplosionToolProvider<TNode extends CanvasNode = CanvasNode>(target: CanvasExplosionToolTarget<TNode>, options?: CanvasExplosionToolProviderOptions): AgentToolProvider;
@@ -0,0 +1,50 @@
1
+ import type { CanvasEdge, CanvasLayoutOptions, CanvasNode, DirectionalDisplacementOptions, ExplosionDisplacementStrategy, Rect, XYPosition } from './types.cjs';
2
+ export interface ComputeCanvasExplosionLayoutParams<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge> {
3
+ /** Every node on the canvas, including the origin. Never mutated. */
4
+ existingNodes: TNode[];
5
+ /** Every edge on the canvas (only read by the `dagre` strategy). */
6
+ existingEdges?: TEdge[];
7
+ /** The node that explodes. */
8
+ originNode: TNode;
9
+ /** The child nodes at their final positions. Never mutated: the result holds copies. */
10
+ childNodes: TNode[];
11
+ /** Edges between children (or from children to existing nodes). */
12
+ childEdges?: TEdge[];
13
+ /** How existing nodes make room. Default `directional`. */
14
+ strategy?: ExplosionDisplacementStrategy;
15
+ /** Options for the `directional` strategy. */
16
+ options?: DirectionalDisplacementOptions;
17
+ /** Options for the `dagre` strategy. */
18
+ reflowOptions?: CanvasLayoutOptions;
19
+ /** Add parent-to-child edges: every child (`true` / `'all'`), the first child only, or none. Default `false`. */
20
+ connectParentToChildren?: boolean | 'first' | 'all';
21
+ /** Builds a parent-to-child edge. Default `{ id: 'explode:<parent>:<child>', source, target, type: 'default' }`. */
22
+ createEdge?: (sourceId: string, targetId: string) => TEdge;
23
+ /** Bounds of a set of nodes (e.g. the flow instance's `getNodesBounds`). Default: measured sizes. */
24
+ getNodesBounds?: (nodes: TNode[]) => Rect;
25
+ }
26
+ export interface CanvasExplosionLayoutResult<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge> {
27
+ /** New positions of the existing nodes that move to make room, by id. */
28
+ displacedPositions: Map<string, XYPosition>;
29
+ /** Where each displaced node was before, by id (what a collapse restores). */
30
+ originalPositions: Map<string, XYPosition>;
31
+ /** Copies of the child nodes at their final positions. */
32
+ childNodes: TNode[];
33
+ /** The child edges plus any parent-to-child edges (deduplicated). */
34
+ childEdges: TEdge[];
35
+ /** Bounds of the child cluster. */
36
+ childBounds: Rect;
37
+ /** The largest distance any displaced node moves along either axis (0 when nothing moves). */
38
+ totalDisplacementDelta: number;
39
+ }
40
+ /** The default id of a parent-to-child edge added by an explosion. */
41
+ export declare const explosionEdgeId: (sourceId: string, targetId: string) => string;
42
+ /**
43
+ * Pure explosion layout: works out where existing nodes move to make room for a child cluster
44
+ * and which edges the explosion adds, without touching the inputs. Feed the result to a
45
+ * declarative derivation (`$derived`, `useMemo`) or to an imperative graph coordinator.
46
+ *
47
+ * @throws Error when the origin is not in `existingNodes`, or a child id is already on the canvas
48
+ * or repeated.
49
+ */
50
+ export declare function computeCanvasExplosionLayout<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge>(params: ComputeCanvasExplosionLayoutParams<TNode, TEdge>): CanvasExplosionLayoutResult<TNode, TEdge>;
@@ -0,0 +1,50 @@
1
+ import type { CanvasEdge, CanvasLayoutOptions, CanvasNode, DirectionalDisplacementOptions, ExplosionDisplacementStrategy, Rect, XYPosition } from './types.js';
2
+ export interface ComputeCanvasExplosionLayoutParams<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge> {
3
+ /** Every node on the canvas, including the origin. Never mutated. */
4
+ existingNodes: TNode[];
5
+ /** Every edge on the canvas (only read by the `dagre` strategy). */
6
+ existingEdges?: TEdge[];
7
+ /** The node that explodes. */
8
+ originNode: TNode;
9
+ /** The child nodes at their final positions. Never mutated: the result holds copies. */
10
+ childNodes: TNode[];
11
+ /** Edges between children (or from children to existing nodes). */
12
+ childEdges?: TEdge[];
13
+ /** How existing nodes make room. Default `directional`. */
14
+ strategy?: ExplosionDisplacementStrategy;
15
+ /** Options for the `directional` strategy. */
16
+ options?: DirectionalDisplacementOptions;
17
+ /** Options for the `dagre` strategy. */
18
+ reflowOptions?: CanvasLayoutOptions;
19
+ /** Add parent-to-child edges: every child (`true` / `'all'`), the first child only, or none. Default `false`. */
20
+ connectParentToChildren?: boolean | 'first' | 'all';
21
+ /** Builds a parent-to-child edge. Default `{ id: 'explode:<parent>:<child>', source, target, type: 'default' }`. */
22
+ createEdge?: (sourceId: string, targetId: string) => TEdge;
23
+ /** Bounds of a set of nodes (e.g. the flow instance's `getNodesBounds`). Default: measured sizes. */
24
+ getNodesBounds?: (nodes: TNode[]) => Rect;
25
+ }
26
+ export interface CanvasExplosionLayoutResult<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge> {
27
+ /** New positions of the existing nodes that move to make room, by id. */
28
+ displacedPositions: Map<string, XYPosition>;
29
+ /** Where each displaced node was before, by id (what a collapse restores). */
30
+ originalPositions: Map<string, XYPosition>;
31
+ /** Copies of the child nodes at their final positions. */
32
+ childNodes: TNode[];
33
+ /** The child edges plus any parent-to-child edges (deduplicated). */
34
+ childEdges: TEdge[];
35
+ /** Bounds of the child cluster. */
36
+ childBounds: Rect;
37
+ /** The largest distance any displaced node moves along either axis (0 when nothing moves). */
38
+ totalDisplacementDelta: number;
39
+ }
40
+ /** The default id of a parent-to-child edge added by an explosion. */
41
+ export declare const explosionEdgeId: (sourceId: string, targetId: string) => string;
42
+ /**
43
+ * Pure explosion layout: works out where existing nodes move to make room for a child cluster
44
+ * and which edges the explosion adds, without touching the inputs. Feed the result to a
45
+ * declarative derivation (`$derived`, `useMemo`) or to an imperative graph coordinator.
46
+ *
47
+ * @throws Error when the origin is not in `existingNodes`, or a child id is already on the canvas
48
+ * or repeated.
49
+ */
50
+ export declare function computeCanvasExplosionLayout<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge>(params: ComputeCanvasExplosionLayoutParams<TNode, TEdge>): CanvasExplosionLayoutResult<TNode, TEdge>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Headless, framework-free state machine for canvas node explosion: which node is exploded,
3
+ * which is collapsing (children still mounted while a collapse animation plays), and the timer
4
+ * that ends the collapse. It never touches a graph or the DOM, so a declarative canvas can derive
5
+ * its nodes from it. The Svelte rune `createCanvasExplosionState` and the React hook
6
+ * `useCanvasExplosionState` wrap it.
7
+ */
8
+ export interface CanvasExplosionStateOptions {
9
+ /** How long children stay rendered after a collapse starts, in ms. Default 380. `0` ends the collapse at once. */
10
+ collapseDurationMs?: number;
11
+ /** The node exploded at creation. Default none. */
12
+ initialActiveId?: string | null;
13
+ /** Called after a node explodes. */
14
+ onExplode?: (nodeId: string) => void;
15
+ /** Called when a node starts collapsing (including when exploding another node replaces it). */
16
+ onCollapse?: (nodeId: string) => void;
17
+ }
18
+ /** The state at one moment. A new object each time it changes, so it can be compared by identity. */
19
+ export interface CanvasExplosionStateSnapshot {
20
+ /** The exploded node, or null. */
21
+ readonly activeId: string | null;
22
+ /** The node whose collapse animation is playing, or null. */
23
+ readonly collapsingId: string | null;
24
+ }
25
+ export interface CanvasExplosionState extends CanvasExplosionStateSnapshot {
26
+ /** True while a node is exploded or collapsing (children are on screen). */
27
+ readonly isExplodingOrCollapsing: boolean;
28
+ isExploded: (nodeId: string) => boolean;
29
+ isCollapsing: (nodeId: string) => boolean;
30
+ /** True when the node's children should be rendered: it is exploded or still collapsing. */
31
+ shouldRenderChildren: (nodeId: string) => boolean;
32
+ /** Explodes a node, replacing (collapsing) any other exploded node. Returns false when it already was. */
33
+ explode: (nodeId: string) => boolean;
34
+ /** Collapses the exploded node (only if it is `nodeId`, when given). Returns false when nothing collapsed. */
35
+ collapse: (nodeId?: string) => boolean;
36
+ /** Collapses the node when it is exploded, otherwise explodes it. Returns true when it is now exploded. */
37
+ toggle: (nodeId: string) => boolean;
38
+ /** Ends a running collapse now (e.g. from an `animationend` handler) instead of waiting for the timer. */
39
+ finishCollapse: () => void;
40
+ /** Clears the collapse timer and listeners; later calls do nothing. */
41
+ destroy: () => void;
42
+ }
43
+ export interface CanvasExplosionStateController extends CanvasExplosionState {
44
+ /** The current state; the same object until something changes. */
45
+ getSnapshot: () => CanvasExplosionStateSnapshot;
46
+ /** Calls `listener` after every change; returns an unsubscribe function. */
47
+ subscribe: (listener: () => void) => () => void;
48
+ /** True after `destroy()`. */
49
+ readonly destroyed: boolean;
50
+ }
51
+ /** Creates the headless explosion state machine (see the module comment). */
52
+ export declare function createCanvasExplosionStateController(options?: CanvasExplosionStateOptions): CanvasExplosionStateController;