@pixerate/editor 0.272.0 → 0.272.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/agent/index.cjs +34 -32
  2. package/dist/agent/index.js +10 -8
  3. package/dist/chart/contract.d.cts +95 -0
  4. package/dist/chart/contract.d.ts +95 -0
  5. package/dist/chart/controller.d.cts +4 -0
  6. package/dist/chart/controller.d.ts +4 -0
  7. package/dist/chart/index.cjs +492 -26
  8. package/dist/chart/index.d.cts +1 -0
  9. package/dist/chart/index.d.ts +1 -0
  10. package/dist/chart/index.js +476 -10
  11. package/dist/chart/tools.d.cts +3 -0
  12. package/dist/chart/tools.d.ts +3 -0
  13. package/dist/chart-maps/index.cjs +4 -64
  14. package/dist/chart-maps/index.js +3 -63
  15. package/dist/{chunk-NMZQMPFZ.js → chunk-4LZQO5Y7.js} +2 -0
  16. package/dist/chunk-5UGRMVNE.js +328 -0
  17. package/dist/{chunk-X4FTNFIA.js → chunk-7MGPW2OV.js} +1 -1
  18. package/dist/{chunk-DGITFN73.cjs → chunk-BWJBZAUE.cjs} +8 -8
  19. package/dist/chunk-CHZYVNXZ.js +336 -0
  20. package/dist/chunk-DRMZ5R3S.cjs +67 -0
  21. package/dist/chunk-EI5GFTKG.js +67 -0
  22. package/dist/chunk-JV7DKLMX.js +1073 -0
  23. package/dist/chunk-MFBUQC67.cjs +328 -0
  24. package/dist/{chunk-IBXEQOGI.js → chunk-PYHB2EHE.js} +2 -324
  25. package/dist/chunk-QEUI6OGE.cjs +336 -0
  26. package/dist/{chunk-6ZSFRRJI.js → chunk-RSF6BT34.js} +1 -1
  27. package/dist/chunk-T2HUQBRC.cjs +1073 -0
  28. package/dist/{chunk-GSLOH2IN.cjs → chunk-VF6ODSYX.cjs} +2 -0
  29. package/dist/{chunk-NQUKTRKN.cjs → chunk-WZLNNGG3.cjs} +45 -45
  30. package/dist/{chunk-NRBGAEFI.cjs → chunk-Y3RUYOOW.cjs} +8 -330
  31. package/dist/commands/index.cjs +7 -323
  32. package/dist/commands/index.js +5 -321
  33. package/dist/extensions/index.cjs +4 -4
  34. package/dist/extensions/index.js +3 -3
  35. package/dist/index.cjs +9 -9
  36. package/dist/index.js +3 -3
  37. package/dist/persistence/index.cjs +24 -1042
  38. package/dist/persistence/index.js +22 -1040
  39. package/dist/tools/index.cjs +5 -3
  40. package/dist/tools/index.js +8 -6
  41. package/package.json +1 -1
@@ -34,3 +34,4 @@ export * from './file-tools.cjs';
34
34
  export * from './playback.cjs';
35
35
  export * from './editorDocument.cjs';
36
36
  export * from './style.cjs';
37
+ export * from './contract.cjs';
@@ -34,3 +34,4 @@ export * from './file-tools.js';
34
34
  export * from './playback.js';
35
35
  export * from './editorDocument.js';
36
36
  export * from './style.js';
37
+ export * from './contract.js';
@@ -1,3 +1,12 @@
1
+ import {
2
+ EUROPE_CHART_MAP
3
+ } from "../chunk-EI5GFTKG.js";
4
+ import "../chunk-CHZYVNXZ.js";
5
+ import {
6
+ CommandRegistry,
7
+ createCommandToolProvider
8
+ } from "../chunk-HAEB3MZD.js";
9
+ import "../chunk-JV7DKLMX.js";
1
10
  import {
2
11
  CATEGORY_REF,
3
12
  CHART_UPDATE_PROPERTIES,
@@ -18,6 +27,18 @@ import {
18
27
  VALUE,
19
28
  WIDTH
20
29
  } from "../chunk-6NQPKNUZ.js";
30
+ import "../chunk-ZA7L5YJB.js";
31
+ import "../chunk-55ALHYJY.js";
32
+ import "../chunk-PXXXRCME.js";
33
+ import {
34
+ createStyleResolver,
35
+ memoryStyleStore
36
+ } from "../chunk-5UGRMVNE.js";
37
+ import {
38
+ ToolRegistry
39
+ } from "../chunk-K4BGRCSH.js";
40
+ import "../chunk-EHTX34RE.js";
41
+ import "../chunk-NZ3CTY7K.js";
21
42
  import {
22
43
  CHART_OOXML_CONTENT_TYPE,
23
44
  CHART_OOXML_NS,
@@ -47,7 +68,7 @@ import {
47
68
  monochromeChartPalette,
48
69
  sparklineToSvg,
49
70
  summarizeChart
50
- } from "../chunk-NMZQMPFZ.js";
71
+ } from "../chunk-4LZQO5Y7.js";
51
72
  import "../chunk-KGRZMHZB.js";
52
73
  import {
53
74
  CHART_DATE_STEPS,
@@ -208,14 +229,19 @@ import {
208
229
  realPresenceClock,
209
230
  tweenPresenceCursor
210
231
  } from "../chunk-IVSWRVB4.js";
232
+ import "../chunk-V2ZCJRDM.js";
211
233
  import {
212
234
  readZip
213
235
  } from "../chunk-CIQIM2IP.js";
214
236
  import {
215
- defineEditorDocument
237
+ EDITOR_DOCUMENT_FORMAT,
238
+ defineEditorDocument,
239
+ toEditorDocumentFile
216
240
  } from "../chunk-XBQX76CT.js";
217
241
  import "../chunk-HF5QZS7Z.js";
218
- import "../chunk-GAZPHCTV.js";
242
+ import {
243
+ HistoryManager
244
+ } from "../chunk-GAZPHCTV.js";
219
245
  import "../chunk-2EUW2XZX.js";
220
246
  import "../chunk-E2V5DA3W.js";
221
247
  import "../chunk-VR6OGHU5.js";
@@ -513,7 +539,7 @@ function createChartCommands(controller, options = {}) {
513
539
  params: object({ width: WIDTH, height: HEIGHT }),
514
540
  run: (_ctx, params = {}) => {
515
541
  const spec = controller.getSpec();
516
- return { spec: controller.toJSON(), table: chartDataToTable(spec), summary: summarizeChart(controller.toJSON(), { width: params?.width ?? 640, height: params?.height ?? 400 }), issues: controller.getState().issues };
542
+ return { spec: controller.toJSON(), table: chartDataToTable(spec), summary: summarizeChart(controller.toJSON(), { width: params?.width ?? 640, height: params?.height ?? 400, measureText: controller.measureText }), issues: controller.getState().issues };
517
543
  }
518
544
  },
519
545
  {
@@ -1068,7 +1094,7 @@ function createChartCommands(controller, options = {}) {
1068
1094
  description: "Returns the chart drawn as a standalone, accessible SVG string (with <title> and <desc>).",
1069
1095
  params: object({ width: WIDTH, height: HEIGHT }),
1070
1096
  run: (_ctx, params = {}) => ({
1071
- svg: chartToSvg(controller.toJSON(), { width: params?.width ?? 640, height: params?.height ?? 400 })
1097
+ svg: chartToSvg(controller.toJSON(), { width: params?.width ?? 640, height: params?.height ?? 400, measureText: controller.measureText })
1072
1098
  })
1073
1099
  },
1074
1100
  {
@@ -1686,6 +1712,7 @@ function resolve(result) {
1686
1712
  }
1687
1713
  function createChartToolProvider(controller, options = {}) {
1688
1714
  const size = options.size ?? { width: 640, height: 400 };
1715
+ const measureText = options.measureText ?? controller.measureText;
1689
1716
  const readOnlyReason = () => {
1690
1717
  const r = typeof options.readOnly === "function" ? options.readOnly() : options.readOnly;
1691
1718
  if (!r) return null;
@@ -1741,7 +1768,7 @@ function createChartToolProvider(controller, options = {}) {
1741
1768
  spec: controller.toJSON(),
1742
1769
  table: table(),
1743
1770
  selection: controller.getState().selection,
1744
- summary: summarizeChart(controller.toJSON(), { width, height }),
1771
+ summary: summarizeChart(controller.toJSON(), { width, height, measureText }),
1745
1772
  ...spec().tree.length ? { treeTable: treeTable() } : {},
1746
1773
  issues: controller.getState().issues,
1747
1774
  ...reason ? { readOnly: reason } : {}
@@ -1766,7 +1793,7 @@ function createChartToolProvider(controller, options = {}) {
1766
1793
  handler: async ({ width = size.width, height = size.height, format = "svg", time }) => {
1767
1794
  const json = controller.toJSON();
1768
1795
  const raceFrame = time !== void 0 ? raceFrameOf(time) : controller.getState().raceFrame;
1769
- const scene = layoutChart(json, { width, height, selection: null, raceFrame });
1796
+ const scene = layoutChart(json, { width, height, selection: null, raceFrame, measureText });
1770
1797
  const svg = chartSceneToSvg(scene, { ariaLabel: json.title || void 0, description: describeChart(json) });
1771
1798
  const warnings = scene.warnings;
1772
1799
  if (format === "png") {
@@ -2505,9 +2532,9 @@ function createChartToolProvider(controller, options = {}) {
2505
2532
  },
2506
2533
  annotations: { title: "Drag a chart point", ...WRITE },
2507
2534
  handler: ({ from, to, fine, lockAxis, width = size.width, height = size.height }) => {
2508
- const scene = layoutChart(controller.toJSON(), { width, height });
2535
+ const scene = layoutChart(controller.toJSON(), { width, height, measureText });
2509
2536
  const start = { x: from.x * width, y: from.y * height };
2510
- const target = chartHitTest(scene, start);
2537
+ const target = chartHitTest(scene, start, measureText);
2511
2538
  if (target?.kind !== "point") fail2(`There is no bar or point at (${from.x}, ${from.y}); ${target ? `that is the ${target.kind}` : "that is outside the chart"}. Use render_chart to find marks.`);
2512
2539
  const t = target;
2513
2540
  const before = controller.getSeries(t.seriesId)?.values[t.index] ?? null;
@@ -2535,7 +2562,7 @@ function createChartToolProvider(controller, options = {}) {
2535
2562
  },
2536
2563
  annotations: { title: "Press a key on the chart", ...DESTRUCTIVE },
2537
2564
  handler: ({ key: k, shift, alt }) => {
2538
- const scene = layoutChart(controller.toJSON(), size);
2565
+ const scene = layoutChart(controller.toJSON(), { ...size, measureText });
2539
2566
  const used = handleChartKey(controller, scene, { key: k, shiftKey: shift, altKey: alt });
2540
2567
  const sel = controller.getState().selection;
2541
2568
  const value = sel?.kind === "point" ? controller.getSeries(sel.seriesId)?.values[sel.index] ?? null : void 0;
@@ -3283,12 +3310,448 @@ function createChartStyleToolProvider(controller, styles, options = {}) {
3283
3310
  tools: [check2]
3284
3311
  };
3285
3312
  }
3313
+
3314
+ // src/chart/contract.ts
3315
+ var CHART_CONTRACT_FORMAT_VERSION = 1;
3316
+ var conformanceChartTextMeasure = estimateChartTextWidth;
3317
+ var NULLABLE_NUMBER_ARRAY = {
3318
+ type: "array",
3319
+ items: { type: ["number", "null"] }
3320
+ };
3321
+ var CHART_TRENDLINE_JSON_SCHEMA = {
3322
+ type: "object",
3323
+ properties: TRENDLINE_PROPS,
3324
+ required: ["type"],
3325
+ additionalProperties: false
3326
+ };
3327
+ var CHART_LINK_JSON_SCHEMA = {
3328
+ type: "object",
3329
+ properties: LINK_PROPS,
3330
+ required: ["source", "target", "value"],
3331
+ additionalProperties: false
3332
+ };
3333
+ var CHART_SERIES_JSON_SCHEMA = {
3334
+ type: "object",
3335
+ required: ["id", "name", "values"],
3336
+ additionalProperties: false,
3337
+ properties: {
3338
+ id: { type: "string", minLength: 1, description: "Unique series id (`series-1`, `series-2`, \u2026)." },
3339
+ ...SERIES_PROPS,
3340
+ values: { ...NULLABLE_NUMBER_ARRAY, description: SERIES_PROPS.values.description },
3341
+ x: { ...NULLABLE_NUMBER_ARRAY, description: SERIES_PROPS.x.description },
3342
+ sizes: { ...NULLABLE_NUMBER_ARRAY, description: SERIES_PROPS.sizes.description },
3343
+ trendlines: {
3344
+ type: "array",
3345
+ items: CHART_TRENDLINE_JSON_SCHEMA,
3346
+ description: "Fitted trendlines drawn over the series."
3347
+ }
3348
+ }
3349
+ };
3350
+ var CHART_SPEC_PROPERTIES = {
3351
+ version: { type: "integer", const: 1, description: "Always 1." },
3352
+ ...CHART_UPDATE_PROPERTIES,
3353
+ categories: {
3354
+ type: "array",
3355
+ items: { type: "string" },
3356
+ description: "Category labels along the x axis (or slice / time-point labels)."
3357
+ },
3358
+ series: {
3359
+ type: "array",
3360
+ items: CHART_SERIES_JSON_SCHEMA,
3361
+ description: "Data series."
3362
+ },
3363
+ tree: {
3364
+ type: "array",
3365
+ items: { $ref: "#/$defs/chartTreeNode" },
3366
+ description: "Hierarchical nodes for treemap and sunburst charts."
3367
+ },
3368
+ links: {
3369
+ type: "array",
3370
+ items: CHART_LINK_JSON_SCHEMA,
3371
+ description: "Directed weighted links for sankey charts."
3372
+ }
3373
+ };
3374
+ var CHART_DOCUMENT_JSON_SCHEMA = {
3375
+ type: "object",
3376
+ description: "A saved chart document, as the chart editor's save tools and autosave write it.",
3377
+ $defs: TREE_DEFS,
3378
+ properties: {
3379
+ format: { type: "string", const: EDITOR_DOCUMENT_FORMAT, description: `Always "${EDITOR_DOCUMENT_FORMAT}".` },
3380
+ kind: { type: "string", const: "chart", description: 'Always "chart".' },
3381
+ formatVersion: { type: "integer", minimum: 1, description: "Version of the envelope for this kind; readers migrate older ones." },
3382
+ name: { type: "string", description: "Display name, when it has one." },
3383
+ document: {
3384
+ type: "object",
3385
+ description: "The chart (`ChartSpec`, as get_chart returns it in `spec`).",
3386
+ properties: CHART_SPEC_PROPERTIES,
3387
+ required: Object.keys(CHART_SPEC_PROPERTIES),
3388
+ additionalProperties: false
3389
+ }
3390
+ },
3391
+ required: ["format", "kind", "formatVersion", "document"],
3392
+ additionalProperties: false
3393
+ };
3394
+ var XML_ENTITIES = {
3395
+ lt: "<",
3396
+ gt: ">",
3397
+ amp: "&",
3398
+ quot: '"',
3399
+ apos: "'"
3400
+ };
3401
+ function decodeXmlEntities(raw) {
3402
+ return raw.replace(/&(#x[0-9a-fA-F]+|#[0-9]+|[a-zA-Z]+);/g, (match, code) => {
3403
+ if (code.startsWith("#x") || code.startsWith("#X")) return String.fromCodePoint(parseInt(code.slice(2), 16));
3404
+ if (code.startsWith("#")) return String.fromCodePoint(parseInt(code.slice(1), 10));
3405
+ return XML_ENTITIES[code] ?? match;
3406
+ });
3407
+ }
3408
+ var MiniXmlElement = class {
3409
+ nodeType = 1;
3410
+ tagName;
3411
+ localName;
3412
+ prefix;
3413
+ namespaceURI;
3414
+ parentElement = null;
3415
+ childNodes = [];
3416
+ attributes = [];
3417
+ constructor(tagName, localName, prefix, namespaceURI) {
3418
+ this.tagName = tagName;
3419
+ this.localName = localName;
3420
+ this.prefix = prefix;
3421
+ this.namespaceURI = namespaceURI;
3422
+ }
3423
+ get children() {
3424
+ return this.childNodes.filter((n) => n.nodeType === 1);
3425
+ }
3426
+ get textContent() {
3427
+ return this.childNodes.map((n) => n.textContent).join("");
3428
+ }
3429
+ getAttribute(name) {
3430
+ const found = this.attributes.find((a) => a.name === name);
3431
+ return found ? found.value : null;
3432
+ }
3433
+ getElementsByTagName(name) {
3434
+ const out = [];
3435
+ const visit = (el) => {
3436
+ for (const child of el.children) {
3437
+ if (name === "*" || child.tagName === name || child.localName === name) out.push(child);
3438
+ visit(child);
3439
+ }
3440
+ };
3441
+ visit(this);
3442
+ return out;
3443
+ }
3444
+ getElementsByTagNameNS(ns, localName) {
3445
+ const out = [];
3446
+ const visit = (el) => {
3447
+ for (const child of el.children) {
3448
+ const nsMatch = ns === "*" || child.namespaceURI === ns;
3449
+ const nameMatch = localName === "*" || child.localName === localName;
3450
+ if (nsMatch && nameMatch) out.push(child);
3451
+ visit(child);
3452
+ }
3453
+ };
3454
+ visit(this);
3455
+ return out;
3456
+ }
3457
+ };
3458
+ var FallbackXmlDomParser = class {
3459
+ parseFromString(xml, _type) {
3460
+ const stripped = xml.replace(/^\uFEFF/, "").replace(/<\?[\s\S]*?\?>/g, "").replace(/<!--[\s\S]*?-->/g, "").replace(/<!DOCTYPE[^>]*>/gi, "").trim();
3461
+ const tokenRe = /<!\[CDATA\[([\s\S]*?)\]\]>|<\/([A-Za-z_][\w:.-]*)\s*>|<([A-Za-z_][\w:.-]*)((?:\s+[A-Za-z_][\w:.-]*\s*=\s*(?:"[^"]*"|'[^']*'))*)\s*(\/?)>|([^<]+)/g;
3462
+ const stack = [];
3463
+ let root = null;
3464
+ let hasError = false;
3465
+ let lastIndex = 0;
3466
+ for (let m = tokenRe.exec(stripped); m !== null; m = tokenRe.exec(stripped)) {
3467
+ if (m.index !== lastIndex) {
3468
+ hasError = true;
3469
+ break;
3470
+ }
3471
+ lastIndex = tokenRe.lastIndex;
3472
+ const [, cdata, closeName, openName, attrText, selfClose, text] = m;
3473
+ if (cdata !== void 0) {
3474
+ const top = stack[stack.length - 1];
3475
+ if (top) top.el.childNodes.push({ nodeType: 3, textContent: cdata });
3476
+ } else if (closeName !== void 0) {
3477
+ const popped = stack.pop();
3478
+ if (!popped || popped.el.tagName !== closeName) {
3479
+ hasError = true;
3480
+ break;
3481
+ }
3482
+ } else if (openName !== void 0) {
3483
+ const parent = stack[stack.length - 1];
3484
+ const ns = new Map(parent ? parent.ns : [["xml", "http://www.w3.org/XML/1998/namespace"]]);
3485
+ const rawAttrs = [];
3486
+ const attrRe = /([A-Za-z_][\w:.-]*)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
3487
+ for (let am = attrRe.exec(attrText ?? ""); am !== null; am = attrRe.exec(attrText ?? "")) {
3488
+ const name = am[1];
3489
+ const val = decodeXmlEntities(am[2] ?? am[3] ?? "");
3490
+ rawAttrs.push([name, val]);
3491
+ if (name === "xmlns") ns.set("", val);
3492
+ else if (name.startsWith("xmlns:")) ns.set(name.slice(6), val);
3493
+ }
3494
+ const colon = openName.indexOf(":");
3495
+ const prefix = colon >= 0 ? openName.slice(0, colon) : null;
3496
+ const localName = colon >= 0 ? openName.slice(colon + 1) : openName;
3497
+ const namespaceURI = prefix ? ns.get(prefix) ?? null : ns.get("") ?? null;
3498
+ const el = new MiniXmlElement(openName, localName, prefix, namespaceURI);
3499
+ for (const [name, value] of rawAttrs) {
3500
+ const ac = name.indexOf(":");
3501
+ const ap = ac >= 0 ? name.slice(0, ac) : null;
3502
+ const al = ac >= 0 ? name.slice(ac + 1) : name;
3503
+ const ans = name === "xmlns" || ap === "xmlns" ? "http://www.w3.org/2000/xmlns/" : ap ? ns.get(ap) ?? null : null;
3504
+ el.attributes.push({ name, localName: al, prefix: ap, namespaceURI: ans, value });
3505
+ }
3506
+ if (parent) {
3507
+ el.parentElement = parent.el;
3508
+ parent.el.childNodes.push(el);
3509
+ } else if (!root) {
3510
+ root = el;
3511
+ } else {
3512
+ hasError = true;
3513
+ break;
3514
+ }
3515
+ if (!selfClose) stack.push({ el, ns });
3516
+ } else if (text !== void 0) {
3517
+ const top = stack[stack.length - 1];
3518
+ if (top) top.el.childNodes.push({ nodeType: 3, textContent: decodeXmlEntities(text) });
3519
+ else if (text.trim() !== "") {
3520
+ hasError = true;
3521
+ break;
3522
+ }
3523
+ }
3524
+ }
3525
+ if (lastIndex !== stripped.length || !root || stack.length > 0) hasError = true;
3526
+ const errorEl = new MiniXmlElement("parsererror", "parsererror", null, null);
3527
+ const doc = {
3528
+ documentElement: root,
3529
+ getElementsByTagName(name) {
3530
+ if (name === "parsererror") return hasError ? [errorEl] : [];
3531
+ if (!root) return [];
3532
+ const own = name === "*" || root.tagName === name || root.localName === name ? [root] : [];
3533
+ return [...own, ...root.getElementsByTagName(name)];
3534
+ },
3535
+ getElementsByTagNameNS(ns, localName) {
3536
+ if (!root) return [];
3537
+ const nsMatch = ns === "*" || root.namespaceURI === ns;
3538
+ const nameMatch = localName === "*" || root.localName === localName;
3539
+ const own = nsMatch && nameMatch ? [root] : [];
3540
+ return [...own, ...root.getElementsByTagNameNS(ns, localName)];
3541
+ }
3542
+ };
3543
+ return doc;
3544
+ }
3545
+ };
3546
+ function defaultDomParser() {
3547
+ return globalThis.DOMParser ?? FallbackXmlDomParser;
3548
+ }
3549
+ function toolList(provider) {
3550
+ const tools = typeof provider.tools === "function" ? provider.tools() : provider.tools;
3551
+ return {
3552
+ id: provider.id,
3553
+ title: provider.title,
3554
+ ...provider.skill ? { skill: provider.skill } : {},
3555
+ tools: tools.map((t) => ({ name: t.name, title: t.title, description: t.description, inputSchema: t.inputSchema, annotations: t.annotations }))
3556
+ };
3557
+ }
3558
+ function uiTables() {
3559
+ return {
3560
+ layoutPresets: CHART_LAYOUT_PRESETS,
3561
+ colorSchemes: CHART_COLOR_SCHEMES,
3562
+ errorBars: {
3563
+ types: CHART_ERROR_BAR_TYPES,
3564
+ directions: CHART_ERROR_BAR_DIRECTIONS,
3565
+ labels: CHART_ERROR_BAR_LABELS
3566
+ },
3567
+ paletteShades: CHART_PALETTE_SHADES,
3568
+ dateSteps: CHART_DATE_STEPS,
3569
+ types: CHART_TYPES,
3570
+ typeLabels: CHART_TYPE_LABELS,
3571
+ seriesTypes: CHART_SERIES_TYPES,
3572
+ stackings: CHART_STACKINGS,
3573
+ orientations: CHART_ORIENTATIONS,
3574
+ curves: CHART_CURVES,
3575
+ markers: CHART_MARKERS,
3576
+ labelPositions: CHART_LABEL_POSITIONS,
3577
+ legendPositions: CHART_LEGEND_POSITIONS,
3578
+ numberStyles: CHART_NUMBER_STYLES,
3579
+ trendlineTypes: CHART_TRENDLINE_TYPES,
3580
+ axisKinds: CHART_AXIS_KINDS,
3581
+ axisScales: CHART_AXIS_SCALES,
3582
+ radarGraticules: CHART_RADAR_GRATICULES,
3583
+ likertNeutrals: CHART_LIKERT_NEUTRALS,
3584
+ likertSorts: CHART_LIKERT_SORTS,
3585
+ sankeyLinkColors: CHART_SANKEY_LINK_COLORS,
3586
+ referenceAxes: CHART_REFERENCE_AXES,
3587
+ defaultPalette: DEFAULT_CHART_PALETTE,
3588
+ defaultTheme: DEFAULT_CHART_THEME,
3589
+ textMeasure: {
3590
+ normalEm: 0.56,
3591
+ boldEm: 0.6,
3592
+ boldWeight: 600,
3593
+ formula: "text.length * size * (weight >= 600 ? 0.6 : 0.56)"
3594
+ }
3595
+ };
3596
+ }
3597
+ function chartContracts() {
3598
+ const controller = new ChartController({ measureText: conformanceChartTextMeasure });
3599
+ const specs = createChartCommands(controller);
3600
+ const styles = createStyleResolver({
3601
+ layers: [{ id: "org", store: memoryStyleStore() }],
3602
+ domains: [chartStyleDomain]
3603
+ });
3604
+ const DOMParser = defaultDomParser();
3605
+ const providers = [
3606
+ createChartToolProvider(controller, { namespace: "", DOMParser, measureText: conformanceChartTextMeasure }),
3607
+ createChartStyleToolProvider(controller, styles, { namespace: "" }),
3608
+ createOfficeChartToolProvider({ namespace: "", files: () => [], controller, DOMParser })
3609
+ ].map(toolList);
3610
+ const document = createChartEditorDocument(controller);
3611
+ const files = {
3612
+ "document.schema.json": { $schema: "https://json-schema.org/draft/2020-12/schema", $id: "document.schema.json", ...CHART_DOCUMENT_JSON_SCHEMA },
3613
+ "tools.json": { providers },
3614
+ "commands.json": specs.map((s) => ({
3615
+ id: s.id,
3616
+ label: s.label,
3617
+ ...s.group ? { group: s.group } : {},
3618
+ ...s.keywords?.length ? { keywords: s.keywords } : {},
3619
+ ...s.description ? { description: s.description } : {},
3620
+ ...s.params ? { params: s.params } : {},
3621
+ ...s.shortcut !== void 0 ? { shortcut: s.shortcut } : {},
3622
+ ...s.scope ? { scope: s.scope } : {},
3623
+ undoable: !!s.undoable,
3624
+ readOnly: !!s.readOnly,
3625
+ ...s.hidden ? { hidden: true } : {}
3626
+ })),
3627
+ "ui.json": uiTables()
3628
+ };
3629
+ files["manifest.json"] = {
3630
+ domain: "chart",
3631
+ formatVersion: CHART_CONTRACT_FORMAT_VERSION,
3632
+ document: { kind: document.kind, formatVersion: document.formatVersion },
3633
+ counts: { providers: providers.length, tools: providers.reduce((n, p) => n + p.tools.length, 0), commands: specs.length },
3634
+ files: Object.keys(files).sort()
3635
+ };
3636
+ document.destroy?.();
3637
+ controller.destroy();
3638
+ return files;
3639
+ }
3640
+ function decodeBase64Bytes(data) {
3641
+ if (data instanceof Uint8Array) return data;
3642
+ const clean = String(data).replace(/^data:[^,]*,/, "").replace(/\s+/g, "");
3643
+ const binary = atob(clean);
3644
+ const out = new Uint8Array(binary.length);
3645
+ for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
3646
+ return out;
3647
+ }
3648
+ function parseSetupFiles(raw) {
3649
+ if (!raw) return [];
3650
+ if (Array.isArray(raw)) {
3651
+ return raw.map((entry) => ({ name: entry.name, data: decodeBase64Bytes(entry.data) }));
3652
+ }
3653
+ return Object.entries(raw).map(([name, data]) => ({
3654
+ name,
3655
+ data: decodeBase64Bytes(data)
3656
+ }));
3657
+ }
3658
+ function createChartConformanceHost(setup = {}) {
3659
+ registerChartMap(EUROPE_CHART_MAP);
3660
+ if (Array.isArray(setup.maps)) {
3661
+ for (const map of setup.maps) registerChartMap(map);
3662
+ }
3663
+ let raceClock = 0;
3664
+ let raceQueue = [];
3665
+ const raceTicker = {
3666
+ now: () => raceClock,
3667
+ next: (step) => {
3668
+ raceQueue.push(step);
3669
+ return () => {
3670
+ raceQueue = raceQueue.filter((q) => q !== step);
3671
+ };
3672
+ }
3673
+ };
3674
+ const advanceRace = (ms = 16) => {
3675
+ raceClock += ms;
3676
+ const pending = raceQueue;
3677
+ raceQueue = [];
3678
+ for (const step of pending) step();
3679
+ };
3680
+ const width = typeof setup.width === "number" ? setup.width : 640;
3681
+ const height = typeof setup.height === "number" ? setup.height : 400;
3682
+ const history = new HistoryManager();
3683
+ const controller = new ChartController({
3684
+ spec: setup.spec,
3685
+ history,
3686
+ raceTicker,
3687
+ measureText: conformanceChartTextMeasure
3688
+ });
3689
+ const openFiles = parseSetupFiles(setup.files);
3690
+ const styleFiles = setup.style ? {
3691
+ "house/SKILL.md": "---\nname: house\ndescription: House chart style.\n---\nFollow the house chart style.",
3692
+ "house/chart.json": JSON.stringify(setup.style)
3693
+ } : {};
3694
+ const styles = createStyleResolver({
3695
+ layers: [{ id: "org", store: memoryStyleStore(styleFiles) }],
3696
+ domains: [chartStyleDomain]
3697
+ });
3698
+ const commands = new CommandRegistry({ context: controller, history });
3699
+ commands.register(createChartCommands(controller));
3700
+ const DOMParser = defaultDomParser();
3701
+ const registry = new ToolRegistry({ validateArguments: true });
3702
+ registry.register(
3703
+ createChartToolProvider(controller, {
3704
+ namespace: "",
3705
+ size: { width, height },
3706
+ readOnly: setup.readOnly,
3707
+ DOMParser,
3708
+ measureText: conformanceChartTextMeasure
3709
+ })
3710
+ );
3711
+ registry.register(createChartStyleToolProvider(controller, styles, { namespace: "" }));
3712
+ registry.register(
3713
+ createOfficeChartToolProvider({
3714
+ namespace: "",
3715
+ files: () => openFiles,
3716
+ controller,
3717
+ readOnly: setup.readOnly,
3718
+ DOMParser
3719
+ })
3720
+ );
3721
+ registry.register(createCommandToolProvider(commands, { id: "chart-commands", namespace: "" }));
3722
+ const document = createChartEditorDocument(controller);
3723
+ return {
3724
+ controller,
3725
+ advanceRace,
3726
+ callTool: (name, args) => registry.callTool(name, args),
3727
+ document: () => toEditorDocumentFile(document),
3728
+ pixels: () => {
3729
+ throw new Error("The chart conformance host has no pixels; compare its document, results, render data and SVG export.");
3730
+ },
3731
+ render: () => {
3732
+ const state = controller.getState();
3733
+ return layoutChart(controller.toJSON(), {
3734
+ width,
3735
+ height,
3736
+ selection: state.selection,
3737
+ raceFrame: state.raceFrame,
3738
+ measureText: conformanceChartTextMeasure
3739
+ });
3740
+ },
3741
+ dispose: () => {
3742
+ document.destroy?.();
3743
+ controller.destroy();
3744
+ }
3745
+ };
3746
+ }
3286
3747
  export {
3287
3748
  CHART_AXIS_KINDS,
3288
3749
  CHART_AXIS_SCALES,
3289
3750
  CHART_COLOR_SCHEMES,
3751
+ CHART_CONTRACT_FORMAT_VERSION,
3290
3752
  CHART_CURVES,
3291
3753
  CHART_DATE_STEPS,
3754
+ CHART_DOCUMENT_JSON_SCHEMA,
3292
3755
  CHART_ERROR_BAR_DIRECTIONS,
3293
3756
  CHART_ERROR_BAR_LABELS,
3294
3757
  CHART_ERROR_BAR_TYPES,
@@ -3341,6 +3804,7 @@ export {
3341
3804
  chartColorDistance,
3342
3805
  chartColorInputValue,
3343
3806
  chartColorsByCategory,
3807
+ chartContracts,
3344
3808
  chartContrastRatio,
3345
3809
  chartDataFromTable,
3346
3810
  chartDataToTable,
@@ -3414,8 +3878,10 @@ export {
3414
3878
  cloneChartSpec,
3415
3879
  cloneChartTree,
3416
3880
  compileChartFormatCode,
3881
+ conformanceChartTextMeasure,
3417
3882
  contrastingTextColor,
3418
3883
  createChartCommands,
3884
+ createChartConformanceHost,
3419
3885
  createChartController,
3420
3886
  createChartEditorDocument,
3421
3887
  createChartRasterizer,
@@ -1,5 +1,6 @@
1
1
  import type { AgentToolProvider } from '../tools/registry.cjs';
2
2
  import type { ChartController } from './controller.cjs';
3
+ import { type ChartTextMeasure } from './layout.cjs';
3
4
  import type { ChartDirector, ChartDirectorActor } from './presence.cjs';
4
5
  type ParserCtor = {
5
6
  new (): DOMParser;
@@ -19,6 +20,8 @@ export interface ChartToolProviderOptions {
19
20
  width: number;
20
21
  height: number;
21
22
  };
23
+ /** Text width in pixels for layout, summaries and hit testing (default: the controller's `measureText`, else `estimateChartTextWidth`). */
24
+ measureText?: ChartTextMeasure;
22
25
  /** Enables `import_chart_ooxml` (reading Office chart XML needs a DOMParser). Default: the global one, if any. */
23
26
  DOMParser?: ParserCtor;
24
27
  /**
@@ -1,5 +1,6 @@
1
1
  import type { AgentToolProvider } from '../tools/registry.js';
2
2
  import type { ChartController } from './controller.js';
3
+ import { type ChartTextMeasure } from './layout.js';
3
4
  import type { ChartDirector, ChartDirectorActor } from './presence.js';
4
5
  type ParserCtor = {
5
6
  new (): DOMParser;
@@ -19,6 +20,8 @@ export interface ChartToolProviderOptions {
19
20
  width: number;
20
21
  height: number;
21
22
  };
23
+ /** Text width in pixels for layout, summaries and hit testing (default: the controller's `measureText`, else `estimateChartTextWidth`). */
24
+ measureText?: ChartTextMeasure;
22
25
  /** Enables `import_chart_ooxml` (reading Office chart XML needs a DOMParser). Default: the global one, if any. */
23
26
  DOMParser?: ParserCtor;
24
27
  /**