@pixerate/editor 0.47.0 → 0.49.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 (91) hide show
  1. package/dist/agent/index.cjs +248 -29
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.d.cts +18 -6
  4. package/dist/agent/index.d.ts +18 -6
  5. package/dist/agent/index.js +228 -9
  6. package/dist/agent/index.js.map +1 -1
  7. package/dist/{builtins-xs7rK6ys.d.cts → builtins-1kqwLUnb.d.cts} +1 -1
  8. package/dist/{builtins-D2nMtw2W.d.ts → builtins-BKYlHH1s.d.ts} +1 -1
  9. package/dist/chart/index.cjs +216 -3541
  10. package/dist/chart/index.cjs.map +1 -1
  11. package/dist/chart/index.d.cts +4 -494
  12. package/dist/chart/index.d.ts +4 -494
  13. package/dist/chart/index.js +155 -3480
  14. package/dist/chart/index.js.map +1 -1
  15. package/dist/{chunk-5VXI5GED.js → chunk-2CJ3LPYQ.js} +3 -3
  16. package/dist/{chunk-TXXNBDQX.cjs → chunk-2Q46FKZK.cjs} +113 -34
  17. package/dist/chunk-2Q46FKZK.cjs.map +1 -0
  18. package/dist/chunk-3JNRQVTS.cjs +521 -0
  19. package/dist/chunk-3JNRQVTS.cjs.map +1 -0
  20. package/dist/chunk-5TWIN7ZJ.js +113 -0
  21. package/dist/chunk-5TWIN7ZJ.js.map +1 -0
  22. package/dist/{chunk-PQFAHT5O.js → chunk-DQPBQXKG.js} +27 -94
  23. package/dist/chunk-DQPBQXKG.js.map +1 -0
  24. package/dist/{chunk-ZFBBVGCI.js → chunk-EKYHKQPG.js} +243 -243
  25. package/dist/{chunk-ZFBBVGCI.js.map → chunk-EKYHKQPG.js.map} +1 -1
  26. package/dist/{chunk-J3R2OWOE.cjs → chunk-FEMIVHN3.cjs} +610 -15
  27. package/dist/chunk-FEMIVHN3.cjs.map +1 -0
  28. package/dist/{chunk-C3NWJE3K.js → chunk-GJBIVWB2.js} +11 -672
  29. package/dist/chunk-GJBIVWB2.js.map +1 -0
  30. package/dist/chunk-GTZXF4BI.cjs +3424 -0
  31. package/dist/chunk-GTZXF4BI.cjs.map +1 -0
  32. package/dist/chunk-JOX6MJW4.cjs +674 -0
  33. package/dist/chunk-JOX6MJW4.cjs.map +1 -0
  34. package/dist/{chunk-REAGGLXS.js → chunk-JQ3BB3E6.js} +2 -2
  35. package/dist/{chunk-H4PICYNL.cjs → chunk-LNKZPIQD.cjs} +113 -180
  36. package/dist/chunk-LNKZPIQD.cjs.map +1 -0
  37. package/dist/chunk-OV7UAKIY.js +674 -0
  38. package/dist/chunk-OV7UAKIY.js.map +1 -0
  39. package/dist/{chunk-TK2XZK6Z.js → chunk-QFTVLEVN.js} +596 -1
  40. package/dist/chunk-QFTVLEVN.js.map +1 -0
  41. package/dist/{chunk-KRGXUQ2Y.js → chunk-T6XU4B54.js} +82 -3
  42. package/dist/chunk-T6XU4B54.js.map +1 -0
  43. package/dist/chunk-TGBCBQFV.cjs +113 -0
  44. package/dist/chunk-TGBCBQFV.cjs.map +1 -0
  45. package/dist/{chunk-SQC26VQV.cjs → chunk-UN33YOXW.cjs} +191 -191
  46. package/dist/{chunk-SQC26VQV.cjs.map → chunk-UN33YOXW.cjs.map} +1 -1
  47. package/dist/chunk-WBOAXDKD.js +3424 -0
  48. package/dist/chunk-WBOAXDKD.js.map +1 -0
  49. package/dist/{chunk-LYGEEDNR.cjs → chunk-XP5IUZUO.cjs} +242 -242
  50. package/dist/chunk-XP5IUZUO.cjs.map +1 -0
  51. package/dist/{chunk-BBRK6MOI.cjs → chunk-YU4WQE5M.cjs} +100 -100
  52. package/dist/{chunk-BBRK6MOI.cjs.map → chunk-YU4WQE5M.cjs.map} +1 -1
  53. package/dist/commands/index.d.cts +1 -1
  54. package/dist/commands/index.d.ts +1 -1
  55. package/dist/controller-ChjCCMLl.d.cts +822 -0
  56. package/dist/controller-DtbEo3om.d.ts +822 -0
  57. package/dist/export/index.cjs +4 -2
  58. package/dist/export/index.cjs.map +1 -1
  59. package/dist/export/index.d.cts +5 -1
  60. package/dist/export/index.d.ts +5 -1
  61. package/dist/export/index.js +3 -1
  62. package/dist/extensions/index.cjs +33 -4
  63. package/dist/extensions/index.cjs.map +1 -1
  64. package/dist/extensions/index.d.cts +4 -2
  65. package/dist/extensions/index.d.ts +4 -2
  66. package/dist/extensions/index.js +32 -3
  67. package/dist/{index-QrqMmZ75.d.cts → index-DoHqT1mq.d.cts} +203 -7
  68. package/dist/{index-CSUCQYAH.d.ts → index-YLZ0fKqE.d.ts} +203 -7
  69. package/dist/index.cjs +39 -13
  70. package/dist/index.cjs.map +1 -1
  71. package/dist/index.d.cts +9 -7
  72. package/dist/index.d.ts +9 -7
  73. package/dist/index.js +33 -7
  74. package/dist/index.js.map +1 -1
  75. package/dist/spreadsheet/index.cjs +4 -4
  76. package/dist/spreadsheet/index.js +3 -3
  77. package/package.json +1 -1
  78. package/dist/chunk-C3NWJE3K.js.map +0 -1
  79. package/dist/chunk-H4PICYNL.cjs.map +0 -1
  80. package/dist/chunk-J3R2OWOE.cjs.map +0 -1
  81. package/dist/chunk-KRGXUQ2Y.js.map +0 -1
  82. package/dist/chunk-LYGEEDNR.cjs.map +0 -1
  83. package/dist/chunk-NEOO6QJD.cjs +0 -1182
  84. package/dist/chunk-NEOO6QJD.cjs.map +0 -1
  85. package/dist/chunk-PQFAHT5O.js.map +0 -1
  86. package/dist/chunk-TK2XZK6Z.js.map +0 -1
  87. package/dist/chunk-TXXNBDQX.cjs.map +0 -1
  88. package/dist/types-BVqWm3d1.d.cts +0 -320
  89. package/dist/types-BVqWm3d1.d.ts +0 -320
  90. /package/dist/{chunk-5VXI5GED.js.map → chunk-2CJ3LPYQ.js.map} +0 -0
  91. /package/dist/{chunk-REAGGLXS.js.map → chunk-JQ3BB3E6.js.map} +0 -0
@@ -1,3 +1,16 @@
1
+ import {
2
+ ChartController,
3
+ chartFromMermaid,
4
+ chartSceneToDomSpec,
5
+ chartToMermaid,
6
+ describeChart,
7
+ layoutChart,
8
+ layoutSparkline
9
+ } from "./chunk-WBOAXDKD.js";
10
+ import {
11
+ DEFAULT_CHART_THEME,
12
+ normalizeChartSpec
13
+ } from "./chunk-OV7UAKIY.js";
1
14
  import {
2
15
  isTrackChangesEnabled
3
16
  } from "./chunk-SWE3NPOU.js";
@@ -1174,6 +1187,570 @@ function createTableExtensions(options = {}) {
1174
1187
  ];
1175
1188
  }
1176
1189
 
1190
+ // src/extensions/chart/node-view.ts
1191
+ import { DOMSerializer } from "@tiptap/pm/model";
1192
+ import { NodeSelection } from "@tiptap/pm/state";
1193
+ var specKey = (spec) => JSON.stringify(spec);
1194
+ var ChartNodeView = class {
1195
+ constructor(props, mount, renderStatic) {
1196
+ this.renderStatic = renderStatic;
1197
+ this.editor = props.editor;
1198
+ this.node = props.node;
1199
+ this.getPos = typeof props.getPos === "function" ? props.getPos : () => void 0;
1200
+ this.editable = this.editor.isEditable;
1201
+ this.dom = document.createElement("div");
1202
+ this.dom.className = "pixerate-chart-node";
1203
+ this.dom.setAttribute("data-type", "chart");
1204
+ this.dom.contentEditable = "false";
1205
+ this.syncAttributes();
1206
+ this.key = specKey(this.node.attrs.spec);
1207
+ this.controller = new ChartController({ spec: this.node.attrs.spec });
1208
+ this.unsubscribe = this.controller.subscribe((state) => {
1209
+ if (!state.gesture) this.writeBack();
1210
+ });
1211
+ this.editor.on("update", this.onEditorUpdate);
1212
+ this.renderer = mount ? mount(this.dom, this.viewState()) : null;
1213
+ if (!mount) this.drawStatic();
1214
+ }
1215
+ renderStatic;
1216
+ dom;
1217
+ node;
1218
+ editor;
1219
+ getPos;
1220
+ controller;
1221
+ renderer;
1222
+ unsubscribe;
1223
+ editing = false;
1224
+ selected = false;
1225
+ editable;
1226
+ key;
1227
+ viewState() {
1228
+ return {
1229
+ id: this.node.attrs.id ?? null,
1230
+ controller: this.controller,
1231
+ width: this.node.attrs.width ?? null,
1232
+ height: this.node.attrs.height,
1233
+ editable: this.editable,
1234
+ selected: this.selected,
1235
+ editing: this.editing,
1236
+ setEditing: this.setEditing,
1237
+ setSize: this.setSize
1238
+ };
1239
+ }
1240
+ render() {
1241
+ if (this.renderer) this.renderer.update(this.viewState());
1242
+ else this.drawStatic();
1243
+ this.dom.toggleAttribute("data-editing", this.editing);
1244
+ }
1245
+ drawStatic() {
1246
+ const { dom } = DOMSerializer.renderSpec(document, this.renderStatic(this.node));
1247
+ this.dom.replaceChildren(dom);
1248
+ }
1249
+ syncAttributes() {
1250
+ if (this.node.attrs.id) this.dom.setAttribute("data-chart-id", this.node.attrs.id);
1251
+ else this.dom.removeAttribute("data-chart-id");
1252
+ }
1253
+ onEditorUpdate = () => {
1254
+ if (this.editor.isEditable === this.editable) return;
1255
+ this.editable = this.editor.isEditable;
1256
+ if (!this.editable) this.editing = false;
1257
+ this.render();
1258
+ };
1259
+ /** Writes the controller's spec into the node, if it changed. */
1260
+ writeBack() {
1261
+ const spec = this.controller.toJSON();
1262
+ const key = specKey(spec);
1263
+ if (key === this.key) return;
1264
+ const pos = this.getPos();
1265
+ if (typeof pos !== "number" || this.editor.isDestroyed) return;
1266
+ this.key = key;
1267
+ this.editor.view.dispatch(this.editor.state.tr.setNodeMarkup(pos, void 0, { ...this.node.attrs, spec }));
1268
+ }
1269
+ setEditing = (editing) => {
1270
+ if (editing && !this.editor.isEditable) return;
1271
+ if (editing && !this.selected) {
1272
+ const pos = this.getPos();
1273
+ if (typeof pos === "number") {
1274
+ this.editor.view.dispatch(this.editor.state.tr.setSelection(NodeSelection.create(this.editor.state.doc, pos)));
1275
+ }
1276
+ }
1277
+ if (this.editing === editing) return;
1278
+ this.editing = editing;
1279
+ this.render();
1280
+ };
1281
+ setSize = (size) => {
1282
+ const pos = this.getPos();
1283
+ if (typeof pos !== "number" || !this.editor.isEditable) return;
1284
+ this.editor.view.dispatch(this.editor.state.tr.setNodeMarkup(pos, void 0, { ...this.node.attrs, ...size }));
1285
+ };
1286
+ update(node) {
1287
+ if (node.type !== this.node.type) return false;
1288
+ this.node = node;
1289
+ this.syncAttributes();
1290
+ const key = specKey(node.attrs.spec);
1291
+ if (key !== this.key) {
1292
+ this.key = key;
1293
+ if (specKey(this.controller.toJSON()) !== key) this.controller.load(node.attrs.spec, { clearHistory: true });
1294
+ }
1295
+ this.render();
1296
+ return true;
1297
+ }
1298
+ selectNode() {
1299
+ this.selected = true;
1300
+ this.dom.classList.add("ProseMirror-selectednode");
1301
+ this.render();
1302
+ }
1303
+ deselectNode() {
1304
+ this.selected = false;
1305
+ this.editing = false;
1306
+ this.dom.classList.remove("ProseMirror-selectednode");
1307
+ this.render();
1308
+ }
1309
+ /** The inspector's inputs, buttons and chart gestures keep their events while it is open. */
1310
+ stopEvent(event) {
1311
+ if (!this.editing) return false;
1312
+ return !(event.type === "dragstart" && event.target === this.dom);
1313
+ }
1314
+ ignoreMutation() {
1315
+ return true;
1316
+ }
1317
+ destroy() {
1318
+ this.editor.off("update", this.onEditorUpdate);
1319
+ this.unsubscribe();
1320
+ this.renderer?.destroy();
1321
+ this.controller.destroy();
1322
+ }
1323
+ };
1324
+ function createChartNodeView(mount, renderStatic) {
1325
+ return (props) => new ChartNodeView(props, mount, renderStatic);
1326
+ }
1327
+
1328
+ // src/extensions/chart/chart-node.ts
1329
+ import { Node, mergeAttributes } from "@tiptap/core";
1330
+ import { Plugin as Plugin2, PluginKey as PluginKey2 } from "@tiptap/pm/state";
1331
+
1332
+ // src/extensions/document-structure/utils.ts
1333
+ import { createDocument } from "@tiptap/core";
1334
+ import { EditorState } from "@tiptap/pm/state";
1335
+ import { ReplaceAroundStep, ReplaceStep } from "@tiptap/pm/transform";
1336
+ var idCounter = 0;
1337
+ function generateStructureId(prefix) {
1338
+ idCounter = (idCounter + 1) % 1296;
1339
+ const random = Math.random().toString(36).slice(2, 8).padEnd(6, "0");
1340
+ return `${prefix}-${random}${idCounter.toString(36).padStart(2, "0")}`;
1341
+ }
1342
+ function transactionsInsert(transactions, typeNames) {
1343
+ for (const tr of transactions) {
1344
+ for (const step of tr.steps) {
1345
+ if (!(step instanceof ReplaceStep || step instanceof ReplaceAroundStep)) {
1346
+ const mark = step.mark;
1347
+ if (mark && typeNames.includes(mark.type.name)) return true;
1348
+ continue;
1349
+ }
1350
+ let found = false;
1351
+ step.slice.content.descendants((node) => {
1352
+ if (found) return false;
1353
+ if (typeNames.includes(node.type.name) || node.marks.some((m) => typeNames.includes(m.type.name))) {
1354
+ found = true;
1355
+ }
1356
+ return !found;
1357
+ });
1358
+ if (found) return true;
1359
+ }
1360
+ }
1361
+ return false;
1362
+ }
1363
+ function docContains(doc, typeNames) {
1364
+ let found = false;
1365
+ doc.descendants((node) => {
1366
+ if (found) return false;
1367
+ if (typeNames.includes(node.type.name) || node.marks.some((m) => typeNames.includes(m.type.name))) {
1368
+ found = true;
1369
+ }
1370
+ return !found;
1371
+ });
1372
+ return found;
1373
+ }
1374
+ function presenceStateSpec(typeNames) {
1375
+ return {
1376
+ init: (_config, state) => docContains(state.doc, typeNames),
1377
+ apply: (tr, present, _oldState, newState) => {
1378
+ if (!tr.docChanged) return present;
1379
+ if (!present && !transactionsInsert([tr], typeNames)) return false;
1380
+ return docContains(newState.doc, typeNames);
1381
+ }
1382
+ };
1383
+ }
1384
+ function arraysEqual(a, b, eq) {
1385
+ if (a.length !== b.length) return false;
1386
+ for (let i = 0; i < a.length; i++) {
1387
+ if (!eq(a[i], b[i])) return false;
1388
+ }
1389
+ return true;
1390
+ }
1391
+ function scrollDomAtPos(view, pos, behavior = "smooth") {
1392
+ try {
1393
+ const dom = view?.nodeDOM?.(pos);
1394
+ if (dom && typeof dom.scrollIntoView === "function") {
1395
+ dom.scrollIntoView({ block: "start", behavior });
1396
+ }
1397
+ } catch {
1398
+ }
1399
+ }
1400
+ function syncInitialContent(editor, sync) {
1401
+ const { content } = editor.options;
1402
+ if (content == null || content === "") return;
1403
+ try {
1404
+ const doc = createDocument(content, editor.schema, editor.options.parseOptions, {
1405
+ errorOnInvalidContent: false
1406
+ });
1407
+ const tr = sync(EditorState.create({ doc }));
1408
+ if (tr?.docChanged) editor.options.content = tr.doc;
1409
+ } catch {
1410
+ }
1411
+ }
1412
+ var STRUCTURE_PRIORITY = 45;
1413
+
1414
+ // src/extensions/chart/chart-node.ts
1415
+ var chartPluginKey = new PluginKey2("chartNode");
1416
+ function getDocumentCharts(doc, typeName = "chart") {
1417
+ const charts = [];
1418
+ doc.descendants((node, pos) => {
1419
+ if (node.type.name === typeName) {
1420
+ charts.push({ id: node.attrs.id ?? null, pos, node, spec: node.attrs.spec });
1421
+ return false;
1422
+ }
1423
+ return !node.isTextblock;
1424
+ });
1425
+ return charts;
1426
+ }
1427
+ function isChartEnabled(editor) {
1428
+ return !!editor?.schema?.nodes?.chart;
1429
+ }
1430
+ function readSpec(value) {
1431
+ let input = value;
1432
+ if (typeof value === "string") {
1433
+ try {
1434
+ input = JSON.parse(value);
1435
+ } catch {
1436
+ return null;
1437
+ }
1438
+ }
1439
+ if (!input || typeof input !== "object" || Array.isArray(input)) return null;
1440
+ return normalizeChartSpec(input).spec;
1441
+ }
1442
+ var readSize = (value) => {
1443
+ const n = value === null ? NaN : Number(value);
1444
+ return Number.isFinite(n) && n >= 50 && n <= 4096 ? n : null;
1445
+ };
1446
+ function syncChartIds(state, typeName, generateId) {
1447
+ const seen = /* @__PURE__ */ new Set();
1448
+ let tr = null;
1449
+ for (const chart of getDocumentCharts(state.doc, typeName)) {
1450
+ if (chart.id && !seen.has(chart.id)) {
1451
+ seen.add(chart.id);
1452
+ continue;
1453
+ }
1454
+ let id = generateId();
1455
+ while (seen.has(id)) id = generateId();
1456
+ seen.add(id);
1457
+ tr = tr ?? state.tr;
1458
+ tr.setNodeMarkup(chart.pos, void 0, { ...chart.node.attrs, id });
1459
+ }
1460
+ return tr?.setMeta("addToHistory", false) ?? null;
1461
+ }
1462
+ function staticChartSvg(node, options) {
1463
+ const spec = node.attrs.spec;
1464
+ const width = node.attrs.width ?? options.defaultWidth;
1465
+ const height = node.attrs.height ?? options.defaultHeight;
1466
+ const scene = layoutChart(spec, { width, height, theme: options.theme, selection: null });
1467
+ return chartSceneToDomSpec(scene, {
1468
+ ariaLabel: spec.title || "Chart",
1469
+ description: describeChart(spec),
1470
+ attrs: { style: "max-width: 100%; height: auto; display: block" }
1471
+ });
1472
+ }
1473
+ var longestBacktickRun = (text) => Math.max(0, ...Array.from(text.matchAll(/`+/g), (m) => m[0].length));
1474
+ var Chart = Node.create({
1475
+ name: "chart",
1476
+ priority: STRUCTURE_PRIORITY,
1477
+ group: "block",
1478
+ atom: true,
1479
+ selectable: true,
1480
+ draggable: true,
1481
+ addOptions() {
1482
+ return {
1483
+ HTMLAttributes: {},
1484
+ nodeView: null,
1485
+ theme: DEFAULT_CHART_THEME,
1486
+ defaultWidth: 640,
1487
+ defaultHeight: 320,
1488
+ generateId: () => generateStructureId("chart")
1489
+ };
1490
+ },
1491
+ addAttributes() {
1492
+ return {
1493
+ id: {
1494
+ default: null,
1495
+ parseHTML: (element) => element.getAttribute("data-chart-id") || null,
1496
+ renderHTML: (attributes) => attributes.id ? { "data-chart-id": attributes.id } : {}
1497
+ },
1498
+ spec: {
1499
+ default: normalizeChartSpec({}).spec,
1500
+ // null (no `data-chart`) keeps what the parse rule found, e.g. a mermaid block's spec.
1501
+ parseHTML: (element) => readSpec(element.getAttribute("data-chart")),
1502
+ renderHTML: (attributes) => ({
1503
+ "data-chart": JSON.stringify(attributes.spec)
1504
+ })
1505
+ },
1506
+ width: {
1507
+ default: null,
1508
+ parseHTML: (element) => readSize(element.getAttribute("data-width")),
1509
+ renderHTML: (attributes) => attributes.width ? { "data-width": String(attributes.width) } : {}
1510
+ },
1511
+ height: {
1512
+ default: this.options.defaultHeight,
1513
+ parseHTML: (element) => readSize(element.getAttribute("data-height")),
1514
+ renderHTML: (attributes) => ({
1515
+ "data-height": String(attributes.height)
1516
+ })
1517
+ }
1518
+ };
1519
+ },
1520
+ parseHTML() {
1521
+ return [
1522
+ {
1523
+ tag: 'div[data-type="chart"]',
1524
+ priority: 60,
1525
+ // A missing or broken spec falls through, so the fallback content inside (e.g. a
1526
+ // DOCX import's caption and data table) is kept instead.
1527
+ getAttrs: (element) => readSpec(element.getAttribute("data-chart")) ? null : false
1528
+ },
1529
+ {
1530
+ // ```mermaid blocks (from markdown) that hold a chart; other diagrams stay code.
1531
+ tag: "pre",
1532
+ priority: 60,
1533
+ getAttrs: (element) => {
1534
+ const code = element.querySelector("code");
1535
+ const language = code?.getAttribute("class") ?? element.getAttribute("data-language") ?? "";
1536
+ if (!/(?:^|\s)language-mermaid(?:\s|$)/.test(language) && language !== "mermaid") return false;
1537
+ const result = chartFromMermaid((code ?? element).textContent ?? "");
1538
+ return result.family ? { spec: result.spec } : false;
1539
+ }
1540
+ }
1541
+ ];
1542
+ },
1543
+ renderHTML({ node, HTMLAttributes }) {
1544
+ const svg = staticChartSvg(node, this.options);
1545
+ return [
1546
+ "div",
1547
+ mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
1548
+ "data-type": "chart",
1549
+ class: "pixerate-chart"
1550
+ }),
1551
+ svg
1552
+ ];
1553
+ },
1554
+ renderText({ node }) {
1555
+ return `[Chart: ${node.attrs.spec?.title || "untitled"}]`;
1556
+ },
1557
+ addStorage() {
1558
+ return {
1559
+ markdown: {
1560
+ serialize(state, node) {
1561
+ const text = chartToMermaid(node.attrs.spec);
1562
+ const fence = "`".repeat(Math.max(3, longestBacktickRun(text) + 1));
1563
+ state.write(`${fence}mermaid
1564
+ `);
1565
+ state.text(text, false);
1566
+ state.ensureNewLine();
1567
+ state.write(fence);
1568
+ state.closeBlock(node);
1569
+ },
1570
+ parse: {
1571
+ // markdown-it renders ```mermaid as <pre><code class="language-mermaid">, which
1572
+ // `parseHTML` reads.
1573
+ }
1574
+ }
1575
+ };
1576
+ },
1577
+ addCommands() {
1578
+ return {
1579
+ insertChart: (options) => ({ commands }) => commands.insertContent({
1580
+ type: this.name,
1581
+ attrs: {
1582
+ id: options.id ?? this.options.generateId(),
1583
+ spec: normalizeChartSpec(options.spec ?? {}).spec,
1584
+ width: options.width ?? null,
1585
+ height: options.height ?? this.options.defaultHeight
1586
+ }
1587
+ }),
1588
+ updateChart: (id, changes) => ({ state, tr, dispatch }) => {
1589
+ const chart = getDocumentCharts(state.doc, this.name).find((c) => c.id === id);
1590
+ if (!chart) return false;
1591
+ if (dispatch) {
1592
+ tr.setNodeMarkup(chart.pos, void 0, {
1593
+ ...chart.node.attrs,
1594
+ ...changes.spec !== void 0 ? { spec: normalizeChartSpec(changes.spec).spec } : {},
1595
+ ...changes.width !== void 0 ? { width: changes.width } : {},
1596
+ ...changes.height !== void 0 ? { height: changes.height } : {}
1597
+ });
1598
+ }
1599
+ return true;
1600
+ }
1601
+ };
1602
+ },
1603
+ addNodeView() {
1604
+ return createChartNodeView(this.options.nodeView, (node) => staticChartSvg(node, this.options));
1605
+ },
1606
+ addProseMirrorPlugins() {
1607
+ const { name } = this;
1608
+ const { generateId } = this.options;
1609
+ return [
1610
+ new Plugin2({
1611
+ key: chartPluginKey,
1612
+ appendTransaction: (transactions, _oldState, newState) => {
1613
+ if (!transactions.some((tr) => tr.docChanged)) return null;
1614
+ if (!transactionsInsert(transactions, [name])) return null;
1615
+ return syncChartIds(newState, name, generateId);
1616
+ }
1617
+ })
1618
+ ];
1619
+ },
1620
+ onBeforeCreate() {
1621
+ const { generateId } = this.options;
1622
+ syncInitialContent(this.editor, (state) => syncChartIds(state, this.name, generateId));
1623
+ }
1624
+ });
1625
+
1626
+ // src/extensions/chart/sparkline-node.ts
1627
+ import { Node as Node2, mergeAttributes as mergeAttributes2 } from "@tiptap/core";
1628
+ var SPARKLINE_KINDS = ["line", "column", "win-loss"];
1629
+ var MAX_SPARKLINE_VALUES = 1e3;
1630
+ function normalizeSparklineValues(values) {
1631
+ if (!Array.isArray(values)) return [];
1632
+ return values.slice(0, MAX_SPARKLINE_VALUES).map((v) => typeof v === "number" && Number.isFinite(v) ? v : null);
1633
+ }
1634
+ function readValues(text) {
1635
+ if (!text) return [];
1636
+ try {
1637
+ return normalizeSparklineValues(JSON.parse(text));
1638
+ } catch {
1639
+ return normalizeSparklineValues(text.split(/[\s,]+/).filter(Boolean).map(Number));
1640
+ }
1641
+ }
1642
+ var readNumber = (text, fallback, max) => {
1643
+ const n = text === null ? NaN : Number(text);
1644
+ return Number.isFinite(n) && n >= 4 && n <= max ? n : fallback;
1645
+ };
1646
+ function sparklineLabel(node) {
1647
+ if (node.attrs.label) return node.attrs.label;
1648
+ const present = node.attrs.values.filter((v) => v !== null);
1649
+ return present.length ? `Trend from ${present[0]} to ${present[present.length - 1]}` : "No data";
1650
+ }
1651
+ var Sparkline = Node2.create({
1652
+ name: "sparkline",
1653
+ group: "inline",
1654
+ inline: true,
1655
+ atom: true,
1656
+ selectable: true,
1657
+ addOptions() {
1658
+ return { HTMLAttributes: {}, color: "#4269d0", negativeColor: "#e5484d" };
1659
+ },
1660
+ addAttributes() {
1661
+ return {
1662
+ values: {
1663
+ default: [],
1664
+ parseHTML: (element) => readValues(element.getAttribute("data-values")),
1665
+ renderHTML: (attributes) => ({ "data-values": JSON.stringify(attributes.values ?? []) })
1666
+ },
1667
+ kind: {
1668
+ default: "line",
1669
+ parseHTML: (element) => {
1670
+ const kind = element.getAttribute("data-kind");
1671
+ return SPARKLINE_KINDS.includes(kind) ? kind : "line";
1672
+ },
1673
+ renderHTML: (attributes) => ({ "data-kind": attributes.kind })
1674
+ },
1675
+ width: {
1676
+ default: 80,
1677
+ parseHTML: (element) => readNumber(element.getAttribute("data-width"), 80, 1e3),
1678
+ renderHTML: (attributes) => ({ "data-width": String(attributes.width) })
1679
+ },
1680
+ height: {
1681
+ default: 18,
1682
+ parseHTML: (element) => readNumber(element.getAttribute("data-height"), 18, 200),
1683
+ renderHTML: (attributes) => ({ "data-height": String(attributes.height) })
1684
+ },
1685
+ color: {
1686
+ default: null,
1687
+ parseHTML: (element) => element.getAttribute("data-color") || null,
1688
+ renderHTML: (attributes) => attributes.color ? { "data-color": attributes.color } : {}
1689
+ },
1690
+ label: {
1691
+ default: null,
1692
+ parseHTML: (element) => element.getAttribute("data-label") || null,
1693
+ renderHTML: (attributes) => attributes.label ? { "data-label": attributes.label } : {}
1694
+ }
1695
+ };
1696
+ },
1697
+ parseHTML() {
1698
+ return [{ tag: 'span[data-type="sparkline"]', priority: 60 }];
1699
+ },
1700
+ renderHTML({ node, HTMLAttributes }) {
1701
+ const scene = layoutSparkline(node.attrs.values, {
1702
+ kind: node.attrs.kind,
1703
+ width: node.attrs.width,
1704
+ height: node.attrs.height,
1705
+ color: node.attrs.color ?? this.options.color,
1706
+ negativeColor: this.options.negativeColor
1707
+ });
1708
+ const svg = chartSceneToDomSpec(scene, {
1709
+ ariaLabel: sparklineLabel(node),
1710
+ attrs: { style: "display: inline-block; vertical-align: middle" }
1711
+ });
1712
+ return [
1713
+ "span",
1714
+ mergeAttributes2(this.options.HTMLAttributes, HTMLAttributes, {
1715
+ "data-type": "sparkline",
1716
+ class: "pixerate-sparkline"
1717
+ }),
1718
+ svg
1719
+ ];
1720
+ },
1721
+ renderText({ node }) {
1722
+ return `[${sparklineLabel(node)}]`;
1723
+ },
1724
+ addStorage() {
1725
+ return {
1726
+ markdown: {
1727
+ serialize(state, node) {
1728
+ const attr = (name, value) => value === null || value === void 0 ? "" : ` ${name}="${String(value).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;")}"`;
1729
+ state.write(
1730
+ `<span data-type="sparkline"${attr("data-values", JSON.stringify(node.attrs.values))}${attr("data-kind", node.attrs.kind)}${attr("data-width", node.attrs.width)}${attr("data-height", node.attrs.height)}${attr("data-color", node.attrs.color)}${attr("data-label", node.attrs.label)}></span>`
1731
+ );
1732
+ },
1733
+ parse: {}
1734
+ }
1735
+ };
1736
+ },
1737
+ addCommands() {
1738
+ return {
1739
+ insertSparkline: (options) => ({ commands }) => commands.insertContent({
1740
+ type: this.name,
1741
+ attrs: {
1742
+ values: normalizeSparklineValues(options.values),
1743
+ kind: options.kind && SPARKLINE_KINDS.includes(options.kind) ? options.kind : "line",
1744
+ width: options.width ?? 80,
1745
+ height: options.height ?? 18,
1746
+ color: options.color ?? null,
1747
+ label: options.label ?? null
1748
+ }
1749
+ })
1750
+ };
1751
+ }
1752
+ });
1753
+
1177
1754
  // src/extensions/table/actions.ts
1178
1755
  import { CellSelection as CellSelection2, isInTable, selectedRect } from "@tiptap/pm/tables";
1179
1756
  var TABLE_ACTIONS = [
@@ -1430,6 +2007,12 @@ export {
1430
2007
  handleTablePasteWithoutNesting,
1431
2008
  unnestTables,
1432
2009
  createTableNestingPlugin,
2010
+ generateStructureId,
2011
+ presenceStateSpec,
2012
+ arraysEqual,
2013
+ scrollDomAtPos,
2014
+ syncInitialContent,
2015
+ STRUCTURE_PRIORITY,
1433
2016
  FIND_PARAGRAPH_MARK,
1434
2017
  MAX_FIND_PATTERN_LENGTH,
1435
2018
  createSearchBudget,
@@ -1449,6 +2032,18 @@ export {
1449
2032
  TableCell,
1450
2033
  TableHeader,
1451
2034
  createTableExtensions,
2035
+ ChartNodeView,
2036
+ createChartNodeView,
2037
+ chartPluginKey,
2038
+ getDocumentCharts,
2039
+ isChartEnabled,
2040
+ staticChartSvg,
2041
+ Chart,
2042
+ SPARKLINE_KINDS,
2043
+ MAX_SPARKLINE_VALUES,
2044
+ normalizeSparklineValues,
2045
+ sparklineLabel,
2046
+ Sparkline,
1452
2047
  TABLE_ACTIONS,
1453
2048
  DEFAULT_TABLE_TOOLBAR,
1454
2049
  MAX_TABLE_ROWS,
@@ -1462,4 +2057,4 @@ export {
1462
2057
  getTableState,
1463
2058
  createTableStore
1464
2059
  };
1465
- //# sourceMappingURL=chunk-TK2XZK6Z.js.map
2060
+ //# sourceMappingURL=chunk-QFTVLEVN.js.map