@harbour-enterprises/superdoc 0.22.0-next.1 → 0.22.0-next.10

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 (47) hide show
  1. package/dist/chunks/{PdfViewer-BpwMPbUj.es.js → PdfViewer-CJdQmuIm.es.js} +1 -1
  2. package/dist/chunks/{PdfViewer-B3KmcDup.cjs → PdfViewer-DE1NR4Ve.cjs} +1 -1
  3. package/dist/chunks/{index-Cw4YywoD.es.js → index-B9sHxXr_.es.js} +53 -26
  4. package/dist/chunks/{index-BOf6E2I4.cjs → index-nfoifSpX.cjs} +53 -26
  5. package/dist/chunks/{super-editor.es-DHDx2fsy.cjs → super-editor.es-DAP-fnHo.cjs} +2264 -1648
  6. package/dist/chunks/{super-editor.es-vfoWxyZL.es.js → super-editor.es-_iVPQ8J8.es.js} +2264 -1648
  7. package/dist/core/SuperDoc.d.ts +5 -0
  8. package/dist/core/SuperDoc.d.ts.map +1 -1
  9. package/dist/core/types/index.d.ts +4 -4
  10. package/dist/core/types/index.d.ts.map +1 -1
  11. package/dist/stores/comments-store.d.ts +4 -1
  12. package/dist/stores/comments-store.d.ts.map +1 -1
  13. package/dist/style.css +48 -44
  14. package/dist/super-editor/ai-writer.es.js +2 -2
  15. package/dist/super-editor/chunks/{converter-BcqEfCTg.js → converter-DK1NMJZB.js} +439 -169
  16. package/dist/super-editor/chunks/{docx-zipper-DZ9ph0iQ.js → docx-zipper-CmK8TyNb.js} +73 -12
  17. package/dist/super-editor/chunks/{editor-BC2sSIVa.js → editor-YR4uV-dp.js} +1902 -1607
  18. package/dist/super-editor/chunks/{toolbar-DNTo5DDf.js → toolbar-DzJyRvb0.js} +2 -2
  19. package/dist/super-editor/converter.es.js +1 -1
  20. package/dist/super-editor/docx-zipper.es.js +2 -2
  21. package/dist/super-editor/editor.es.js +3 -3
  22. package/dist/super-editor/file-zipper.es.js +1 -1
  23. package/dist/super-editor/src/core/DocxZipper.d.ts +1 -1
  24. package/dist/super-editor/src/core/super-converter/SuperConverter.d.ts +1 -13
  25. package/dist/super-editor/src/core/super-converter/exporter.d.ts +1 -0
  26. package/dist/super-editor/src/core/super-converter/helpers/tableFallbackHelpers.d.ts +24 -0
  27. package/dist/super-editor/src/extensions/custom-selection/custom-selection.d.ts +5 -1
  28. package/dist/super-editor/src/extensions/index.d.ts +2 -1
  29. package/dist/super-editor/src/extensions/structured-content/index.d.ts +1 -0
  30. package/dist/super-editor/src/extensions/structured-content/structured-content-commands.d.ts +67 -0
  31. package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/getStructuredContentBlockTags.d.ts +7 -0
  32. package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/getStructuredContentInlineTags.d.ts +7 -0
  33. package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/getStructuredContentTags.d.ts +7 -0
  34. package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/getStructuredContentTagsById.d.ts +8 -0
  35. package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/index.d.ts +4 -0
  36. package/dist/super-editor/src/utils/contextmenu-helpers.d.ts +24 -0
  37. package/dist/super-editor/style.css +4 -0
  38. package/dist/super-editor/super-editor.es.js +8 -16
  39. package/dist/super-editor/toolbar.es.js +2 -2
  40. package/dist/super-editor.cjs +1 -1
  41. package/dist/super-editor.es.js +1 -1
  42. package/dist/superdoc.cjs +2 -2
  43. package/dist/superdoc.es.js +2 -2
  44. package/dist/superdoc.umd.js +1665 -1022
  45. package/dist/superdoc.umd.js.map +1 -1
  46. package/package.json +1 -1
  47. package/dist/super-editor/src/components/slash-menu/contextmenu-helpers.d.ts +0 -1
@@ -32581,17 +32581,16 @@ Please report this to https://github.com/markedjs/marked.`, e) {
32581
32581
  };
32582
32582
  const getDefaultParagraphStyle = (docx, styleId = "") => {
32583
32583
  const styles = docx["word/styles.xml"];
32584
- if (!styles) {
32584
+ const rootElements = styles?.elements?.[0]?.elements;
32585
+ if (!rootElements?.length) {
32585
32586
  return {};
32586
32587
  }
32587
- const defaults = styles.elements[0].elements?.find((el) => el.name === "w:docDefaults");
32588
- const pDefault = defaults.elements.find((el) => el.name === "w:pPrDefault");
32588
+ const defaults = rootElements.find((el) => el.name === "w:docDefaults");
32589
+ const pDefault = defaults?.elements?.find((el) => el.name === "w:pPrDefault") || {};
32589
32590
  const pPrDefault = pDefault?.elements?.find((el) => el.name === "w:pPr");
32590
32591
  const pPrDefaultSpacingTag = pPrDefault?.elements?.find((el) => el.name === "w:spacing") || {};
32591
32592
  const pPrDefaultIndentTag = pPrDefault?.elements?.find((el) => el.name === "w:ind") || {};
32592
- const stylesNormal = styles.elements[0].elements?.find(
32593
- (el) => el.name === "w:style" && el.attributes["w:styleId"] === "Normal"
32594
- );
32593
+ const stylesNormal = rootElements.find((el) => el.name === "w:style" && el.attributes["w:styleId"] === "Normal");
32595
32594
  const pPrNormal = stylesNormal?.elements?.find((el) => el.name === "w:pPr");
32596
32595
  const pPrNormalSpacingTag = pPrNormal?.elements?.find((el) => el.name === "w:spacing") || {};
32597
32596
  const pPrNormalIndentTag = pPrNormal?.elements?.find((el) => el.name === "w:ind") || {};
@@ -32600,9 +32599,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
32600
32599
  let pPrStyleIdIndentTag = {};
32601
32600
  let pPrStyleJc = {};
32602
32601
  if (styleId) {
32603
- const stylesById = styles.elements[0].elements?.find(
32604
- (el) => el.name === "w:style" && el.attributes["w:styleId"] === styleId
32605
- );
32602
+ const stylesById = rootElements.find((el) => el.name === "w:style" && el.attributes["w:styleId"] === styleId);
32606
32603
  const pPrById = stylesById?.elements?.find((el) => el.name === "w:pPr");
32607
32604
  pPrStyleIdSpacingTag = pPrById?.elements?.find((el) => el.name === "w:spacing") || {};
32608
32605
  pPrStyleIdIndentTag = pPrById?.elements?.find((el) => el.name === "w:ind") || {};
@@ -34905,6 +34902,68 @@ Please report this to https://github.com/markedjs/marked.`, e) {
34905
34902
  decode: decode$h
34906
34903
  };
34907
34904
  const translator$a = NodeTranslator.from(config$a);
34905
+ const DEFAULT_PAGE_WIDTH_TWIPS = 12240;
34906
+ const DEFAULT_PAGE_MARGIN_TWIPS = 1440;
34907
+ const DEFAULT_CONTENT_WIDTH_TWIPS = DEFAULT_PAGE_WIDTH_TWIPS - 2 * DEFAULT_PAGE_MARGIN_TWIPS;
34908
+ const MIN_COLUMN_WIDTH_TWIPS = pixelsToTwips(10);
34909
+ const pctToPercent = (value) => {
34910
+ if (value == null) return null;
34911
+ return value / 50;
34912
+ };
34913
+ const resolveContentWidthTwips = () => DEFAULT_CONTENT_WIDTH_TWIPS;
34914
+ const resolveMeasurementWidthPx = (measurement) => {
34915
+ if (!measurement || typeof measurement.value !== "number" || measurement.value <= 0) return null;
34916
+ const { value, type: type2 } = measurement;
34917
+ if (!type2 || type2 === "auto") return null;
34918
+ if (type2 === "dxa") return twipsToPixels(value);
34919
+ if (type2 === "pct") {
34920
+ const percent2 = pctToPercent(value);
34921
+ if (percent2 == null || percent2 <= 0) return null;
34922
+ const widthTwips = resolveContentWidthTwips() * percent2 / 100;
34923
+ return twipsToPixels(widthTwips);
34924
+ }
34925
+ return null;
34926
+ };
34927
+ const countColumnsInRow = (row) => {
34928
+ if (!row?.elements?.length) return 0;
34929
+ return row.elements.reduce((count, element) => {
34930
+ if (element.name !== "w:tc") return count;
34931
+ const tcPr = element.elements?.find((el) => el.name === "w:tcPr");
34932
+ const gridSpan = tcPr?.elements?.find((el) => el.name === "w:gridSpan");
34933
+ const spanValue = parseInt(gridSpan?.attributes?.["w:val"] || "1", 10);
34934
+ return count + (Number.isFinite(spanValue) && spanValue > 0 ? spanValue : 1);
34935
+ }, 0);
34936
+ };
34937
+ const clampColumnWidthTwips = (value) => Math.max(Math.round(value), MIN_COLUMN_WIDTH_TWIPS);
34938
+ const createFallbackGrid = (columnCount, columnWidthTwips) => Array.from({ length: columnCount }, () => ({ col: clampColumnWidthTwips(columnWidthTwips) }));
34939
+ const buildFallbackGridForTable = ({ params: params2, rows, tableWidth, tableWidthMeasurement }) => {
34940
+ const firstRow = rows.find((row) => row.elements?.some((el) => el.name === "w:tc"));
34941
+ const columnCount = countColumnsInRow(firstRow);
34942
+ if (!columnCount) return null;
34943
+ const schemaDefaultPx = getSchemaDefaultColumnWidthPx(
34944
+ /** @type {any} */
34945
+ params2
34946
+ );
34947
+ const minimumColumnWidthPx = Number.isFinite(schemaDefaultPx) && schemaDefaultPx > 0 ? schemaDefaultPx : DEFAULT_COLUMN_WIDTH_PX;
34948
+ let totalWidthPx;
34949
+ if (tableWidthMeasurement) {
34950
+ const resolved = resolveMeasurementWidthPx(tableWidthMeasurement);
34951
+ if (resolved != null) totalWidthPx = resolved;
34952
+ }
34953
+ if (totalWidthPx == null && tableWidth?.width && tableWidth.width > 0) {
34954
+ totalWidthPx = tableWidth.width;
34955
+ }
34956
+ if (totalWidthPx == null) {
34957
+ totalWidthPx = minimumColumnWidthPx * columnCount;
34958
+ }
34959
+ const rawColumnWidthPx = Math.max(totalWidthPx / columnCount, minimumColumnWidthPx);
34960
+ const columnWidthTwips = clampColumnWidthTwips(pixelsToTwips(rawColumnWidthPx));
34961
+ const fallbackColumnWidthPx = twipsToPixels(columnWidthTwips);
34962
+ return {
34963
+ grid: createFallbackGrid(columnCount, columnWidthTwips),
34964
+ columnWidths: Array(columnCount).fill(fallbackColumnWidthPx)
34965
+ };
34966
+ };
34908
34967
  const XML_NODE_NAME$9 = "w:tbl";
34909
34968
  const SD_NODE_NAME$9 = "table";
34910
34969
  const encode$g = (params2, encodedAttrs) => {
@@ -34924,7 +34983,6 @@ Please report this to https://github.com/markedjs/marked.`, e) {
34924
34983
  "justification",
34925
34984
  "tableLayout",
34926
34985
  ["tableIndent", ({ value, type: type2 }) => ({ width: twipsToPixels(value), type: type2 })],
34927
- ["tableWidth", ({ value, type: type2 }) => ({ width: twipsToPixels(value), type: type2 })],
34928
34986
  ["tableCellSpacing", ({ value, type: type2 }) => ({ w: String(value), type: type2 })]
34929
34987
  ].forEach((prop) => {
34930
34988
  let key2;
@@ -34942,6 +35000,21 @@ Please report this to https://github.com/markedjs/marked.`, e) {
34942
35000
  if (encodedAttrs.tableCellSpacing) {
34943
35001
  encodedAttrs["borderCollapse"] = "separate";
34944
35002
  }
35003
+ if (encodedAttrs.tableProperties?.tableWidth) {
35004
+ const tableWidthMeasurement = encodedAttrs.tableProperties.tableWidth;
35005
+ const widthPx = twipsToPixels(tableWidthMeasurement.value);
35006
+ if (widthPx != null) {
35007
+ encodedAttrs.tableWidth = {
35008
+ width: widthPx,
35009
+ type: tableWidthMeasurement.type
35010
+ };
35011
+ } else if (tableWidthMeasurement.type === "auto") {
35012
+ encodedAttrs.tableWidth = {
35013
+ width: 0,
35014
+ type: tableWidthMeasurement.type
35015
+ };
35016
+ }
35017
+ }
34945
35018
  const { borders, rowBorders } = _processTableBorders(encodedAttrs.tableProperties?.borders || {});
34946
35019
  const referencedStyles = _getReferencedTableStyles(encodedAttrs.tableStyleId, params2);
34947
35020
  if (referencedStyles?.cellMargins && !encodedAttrs.tableProperties?.cellMargins) {
@@ -34955,7 +35028,19 @@ Please report this to https://github.com/markedjs/marked.`, e) {
34955
35028
  const borderRowData = Object.assign({}, referencedStyles?.rowBorders || {}, rowBorders || {});
34956
35029
  encodedAttrs["borders"] = borderData;
34957
35030
  const tblStyleTag = tblPr?.elements?.find((el) => el.name === "w:tblStyle");
34958
- const columnWidths = (encodedAttrs["grid"] ?? []).map((item) => twipsToPixels(item.col));
35031
+ let columnWidths = Array.isArray(encodedAttrs["grid"]) ? encodedAttrs["grid"].map((item) => twipsToPixels(item.col)) : [];
35032
+ if (!columnWidths.length) {
35033
+ const fallback = buildFallbackGridForTable({
35034
+ params: params2,
35035
+ rows,
35036
+ tableWidth: encodedAttrs.tableWidth,
35037
+ tableWidthMeasurement: encodedAttrs.tableProperties?.tableWidth
35038
+ });
35039
+ if (fallback) {
35040
+ encodedAttrs.grid = fallback.grid;
35041
+ columnWidths = fallback.columnWidths;
35042
+ }
35043
+ }
34959
35044
  const content = [];
34960
35045
  rows.forEach((row) => {
34961
35046
  const result = translator$G.encode({
@@ -35817,6 +35902,9 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35817
35902
  const node = nodes[0];
35818
35903
  const sdtPr = node.elements.find((el) => el.name === "w:sdtPr");
35819
35904
  const sdtContent = node.elements.find((el) => el.name === "w:sdtContent");
35905
+ const id = sdtPr?.elements?.find((el) => el.name === "w:id");
35906
+ const tag = sdtPr?.elements?.find((el) => el.name === "w:tag");
35907
+ const alias = sdtPr?.elements?.find((el) => el.name === "w:alias");
35820
35908
  if (!sdtContent) {
35821
35909
  return null;
35822
35910
  }
@@ -35828,15 +35916,16 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35828
35916
  nodes: sdtContent.elements,
35829
35917
  path: [...params2.path || [], sdtContent]
35830
35918
  });
35831
- let sdtContentType = "structuredContent";
35832
- if (paragraph || table) {
35833
- sdtContentType = "structuredContentBlock";
35834
- }
35919
+ const isBlockNode2 = paragraph || table;
35920
+ const sdtContentType = isBlockNode2 ? "structuredContentBlock" : "structuredContent";
35835
35921
  let result = {
35836
35922
  type: sdtContentType,
35837
35923
  content: translatedContent,
35838
35924
  marks,
35839
35925
  attrs: {
35926
+ id: id?.attributes?.["w:val"] || null,
35927
+ tag: tag?.attributes?.["w:val"] || null,
35928
+ alias: alias?.attributes?.["w:val"] || null,
35840
35929
  sdtPr
35841
35930
  }
35842
35931
  };
@@ -38094,21 +38183,55 @@ Please report this to https://github.com/markedjs/marked.`, e) {
38094
38183
  };
38095
38184
  function translateStructuredContent(params2) {
38096
38185
  const { node } = params2;
38097
- const { attrs = {} } = node;
38098
38186
  const childContent = translateChildNodes({ ...params2, nodes: node.content });
38099
- const nodeElements = [
38100
- {
38101
- name: "w:sdtContent",
38102
- elements: childContent
38103
- }
38104
- ];
38105
- nodeElements.unshift(attrs.sdtPr);
38187
+ const sdtContent = { name: "w:sdtContent", elements: childContent };
38188
+ const sdtPr = generateSdtPrTagForStructuredContent({ node });
38189
+ const nodeElements = [sdtPr, sdtContent];
38106
38190
  const result = {
38107
38191
  name: "w:sdt",
38108
38192
  elements: nodeElements
38109
38193
  };
38110
38194
  return result;
38111
38195
  }
38196
+ function generateSdtPrTagForStructuredContent({ node }) {
38197
+ const { attrs = {} } = node;
38198
+ const id = {
38199
+ name: "w:id",
38200
+ type: "element",
38201
+ attributes: { "w:val": attrs.id }
38202
+ };
38203
+ const alias = {
38204
+ name: "w:alias",
38205
+ type: "element",
38206
+ attributes: { "w:val": attrs.alias }
38207
+ };
38208
+ const tag = {
38209
+ name: "w:tag",
38210
+ type: "element",
38211
+ attributes: { "w:val": attrs.tag }
38212
+ };
38213
+ const resultElements = [];
38214
+ if (attrs.id) resultElements.push(id);
38215
+ if (attrs.alias) resultElements.push(alias);
38216
+ if (attrs.tag) resultElements.push(tag);
38217
+ if (attrs.sdtPr) {
38218
+ const elements = attrs.sdtPr.elements || [];
38219
+ const elementsToExclude = ["w:id", "w:alias", "w:tag"];
38220
+ const restElements = elements.filter((el) => !elementsToExclude.includes(el.name));
38221
+ const result2 = {
38222
+ name: "w:sdtPr",
38223
+ type: "element",
38224
+ elements: [...resultElements, ...restElements]
38225
+ };
38226
+ return result2;
38227
+ }
38228
+ const result = {
38229
+ name: "w:sdtPr",
38230
+ type: "element",
38231
+ elements: resultElements
38232
+ };
38233
+ return result;
38234
+ }
38112
38235
  const XML_NODE_NAME$3 = "w:sdt";
38113
38236
  const SD_NODE_NAME$3 = ["fieldAnnotation", "structuredContent", "structuredContentBlock", "documentSection"];
38114
38237
  const validXmlAttributes$3 = [];
@@ -38336,6 +38459,63 @@ Please report this to https://github.com/markedjs/marked.`, e) {
38336
38459
  attributes: validXmlAttributes
38337
38460
  };
38338
38461
  const translator = NodeTranslator.from(config);
38462
+ const DEFAULT_SECTION_PROPS_TWIPS = Object.freeze({
38463
+ pageSize: Object.freeze({ width: "12240", height: "15840" }),
38464
+ pageMargins: Object.freeze({
38465
+ top: "1440",
38466
+ right: "1440",
38467
+ bottom: "1440",
38468
+ left: "1440",
38469
+ header: "720",
38470
+ footer: "720",
38471
+ gutter: "0"
38472
+ })
38473
+ });
38474
+ const ensureSectionLayoutDefaults = (sectPr, converter) => {
38475
+ if (!sectPr) {
38476
+ return {
38477
+ type: "element",
38478
+ name: "w:sectPr",
38479
+ elements: []
38480
+ };
38481
+ }
38482
+ if (!sectPr.elements) sectPr.elements = [];
38483
+ const ensureChild = (name) => {
38484
+ let child = sectPr.elements.find((n) => n.name === name);
38485
+ if (!child) {
38486
+ child = {
38487
+ type: "element",
38488
+ name,
38489
+ elements: [],
38490
+ attributes: {}
38491
+ };
38492
+ sectPr.elements.push(child);
38493
+ } else {
38494
+ if (!child.elements) child.elements = [];
38495
+ if (!child.attributes) child.attributes = {};
38496
+ }
38497
+ return child;
38498
+ };
38499
+ const pageSize = converter?.pageStyles?.pageSize;
38500
+ const pgSz = ensureChild("w:pgSz");
38501
+ if (pageSize?.width != null) pgSz.attributes["w:w"] = String(inchesToTwips(pageSize.width));
38502
+ if (pageSize?.height != null) pgSz.attributes["w:h"] = String(inchesToTwips(pageSize.height));
38503
+ if (pgSz.attributes["w:w"] == null) pgSz.attributes["w:w"] = DEFAULT_SECTION_PROPS_TWIPS.pageSize.width;
38504
+ if (pgSz.attributes["w:h"] == null) pgSz.attributes["w:h"] = DEFAULT_SECTION_PROPS_TWIPS.pageSize.height;
38505
+ const pageMargins = converter?.pageStyles?.pageMargins;
38506
+ const pgMar = ensureChild("w:pgMar");
38507
+ if (pageMargins) {
38508
+ Object.entries(pageMargins).forEach(([key2, value]) => {
38509
+ const converted = inchesToTwips(value);
38510
+ if (converted != null) pgMar.attributes[`w:${key2}`] = String(converted);
38511
+ });
38512
+ }
38513
+ Object.entries(DEFAULT_SECTION_PROPS_TWIPS.pageMargins).forEach(([key2, value]) => {
38514
+ const attrKey = `w:${key2}`;
38515
+ if (pgMar.attributes[attrKey] == null) pgMar.attributes[attrKey] = value;
38516
+ });
38517
+ return sectPr;
38518
+ };
38339
38519
  const isLineBreakOnlyRun = (node) => {
38340
38520
  if (!node) return false;
38341
38521
  if (node.type === "lineBreak" || node.type === "hardBreak") return true;
@@ -38388,28 +38568,30 @@ Please report this to https://github.com/markedjs/marked.`, e) {
38388
38568
  return handler2(params2);
38389
38569
  }
38390
38570
  function translateBodyNode(params2) {
38391
- let sectPr = params2.bodyNode?.elements.find((n) => n.name === "w:sectPr") || {};
38571
+ let sectPr = params2.bodyNode?.elements?.find((n) => n.name === "w:sectPr");
38572
+ if (!sectPr) {
38573
+ sectPr = {
38574
+ type: "element",
38575
+ name: "w:sectPr",
38576
+ elements: []
38577
+ };
38578
+ } else if (!sectPr.elements) {
38579
+ sectPr = { ...sectPr, elements: [] };
38580
+ }
38581
+ sectPr = ensureSectionLayoutDefaults(sectPr, params2.converter);
38392
38582
  if (params2.converter) {
38393
- const hasHeader = sectPr?.elements?.some((n) => n.name === "w:headerReference");
38583
+ const hasHeader = sectPr.elements?.some((n) => n.name === "w:headerReference");
38394
38584
  const hasDefaultHeader = params2.converter.headerIds?.default;
38395
38585
  if (!hasHeader && hasDefaultHeader && !params2.editor.options.isHeaderOrFooter) {
38396
38586
  const defaultHeader = generateDefaultHeaderFooter("header", params2.converter.headerIds?.default);
38397
38587
  sectPr.elements.push(defaultHeader);
38398
38588
  }
38399
- const hasFooter = sectPr?.elements?.some((n) => n.name === "w:footerReference");
38589
+ const hasFooter = sectPr.elements?.some((n) => n.name === "w:footerReference");
38400
38590
  const hasDefaultFooter = params2.converter.footerIds?.default;
38401
38591
  if (!hasFooter && hasDefaultFooter && !params2.editor.options.isHeaderOrFooter) {
38402
38592
  const defaultFooter = generateDefaultHeaderFooter("footer", params2.converter.footerIds?.default);
38403
38593
  sectPr.elements.push(defaultFooter);
38404
38594
  }
38405
- const newMargins = params2.converter.pageStyles.pageMargins;
38406
- const sectPrMargins = sectPr.elements.find((n) => n.name === "w:pgMar");
38407
- const { attributes } = sectPrMargins;
38408
- Object.entries(newMargins).forEach(([key2, value]) => {
38409
- const convertedValue = inchesToTwips(value);
38410
- attributes[`w:${key2}`] = convertedValue;
38411
- });
38412
- sectPrMargins.attributes = attributes;
38413
38595
  }
38414
38596
  const elements = translateChildNodes(params2);
38415
38597
  if (params2.isHeaderFooter) {
@@ -39836,8 +40018,15 @@ Please report this to https://github.com/markedjs/marked.`, e) {
39836
40018
  return { nodes: [], consumed: 0 };
39837
40019
  }
39838
40020
  const [pNode] = nodes;
39839
- const run2 = pNode.elements?.find((el) => el.name === "w:r");
39840
- const pict = run2?.elements?.find((el) => el.name === "w:pict");
40021
+ const runs = pNode.elements?.filter((el) => el.name === "w:r") || [];
40022
+ let pict = null;
40023
+ for (const run2 of runs) {
40024
+ const foundPict = run2.elements?.find((el) => el.name === "w:pict");
40025
+ if (foundPict) {
40026
+ pict = foundPict;
40027
+ break;
40028
+ }
40029
+ }
39841
40030
  if (!pict) {
39842
40031
  return { nodes: [], consumed: 0 };
39843
40032
  }
@@ -40397,6 +40586,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
40397
40586
  const nodeListHandler = defaultNodeListHandler();
40398
40587
  const bodyNode = json.elements[0].elements.find((el) => el.name === "w:body");
40399
40588
  if (bodyNode) {
40589
+ ensureSectionProperties(bodyNode);
40400
40590
  const node = bodyNode;
40401
40591
  const contentElements = node.elements?.filter((n) => n.name !== "w:sectPr") ?? [];
40402
40592
  const content = pruneIgnoredNodes(contentElements);
@@ -40630,6 +40820,59 @@ Please report this to https://github.com/markedjs/marked.`, e) {
40630
40820
  styles.alternateHeaders = isAlternatingHeadersOddEven(docx);
40631
40821
  return styles;
40632
40822
  }
40823
+ const DEFAULT_SECTION_PROPS = Object.freeze({
40824
+ pageSize: Object.freeze({ width: "12240", height: "15840" }),
40825
+ pageMargins: Object.freeze({
40826
+ top: "1440",
40827
+ right: "1440",
40828
+ bottom: "1440",
40829
+ left: "1440",
40830
+ header: "720",
40831
+ footer: "720",
40832
+ gutter: "0"
40833
+ })
40834
+ });
40835
+ function ensureSectionProperties(bodyNode, converter) {
40836
+ if (!bodyNode.elements) bodyNode.elements = [];
40837
+ let sectPr = bodyNode.elements.find((el) => el.name === "w:sectPr");
40838
+ if (!sectPr) {
40839
+ sectPr = {
40840
+ type: "element",
40841
+ name: "w:sectPr",
40842
+ elements: []
40843
+ };
40844
+ bodyNode.elements.push(sectPr);
40845
+ } else if (!sectPr.elements) {
40846
+ sectPr.elements = [];
40847
+ }
40848
+ const ensureChild = (name, factory) => {
40849
+ let child = sectPr.elements.find((el) => el.name === name);
40850
+ if (!child) {
40851
+ child = factory();
40852
+ sectPr.elements.push(child);
40853
+ } else if (!child.attributes) {
40854
+ child.attributes = {};
40855
+ }
40856
+ return child;
40857
+ };
40858
+ const pgSz = ensureChild("w:pgSz", () => ({
40859
+ type: "element",
40860
+ name: "w:pgSz",
40861
+ attributes: {}
40862
+ }));
40863
+ pgSz.attributes["w:w"] = pgSz.attributes["w:w"] ?? DEFAULT_SECTION_PROPS.pageSize.width;
40864
+ pgSz.attributes["w:h"] = pgSz.attributes["w:h"] ?? DEFAULT_SECTION_PROPS.pageSize.height;
40865
+ const pgMar = ensureChild("w:pgMar", () => ({
40866
+ type: "element",
40867
+ name: "w:pgMar",
40868
+ attributes: {}
40869
+ }));
40870
+ Object.entries(DEFAULT_SECTION_PROPS.pageMargins).forEach(([key2, value]) => {
40871
+ const attrKey = `w:${key2}`;
40872
+ if (pgMar.attributes[attrKey] == null) pgMar.attributes[attrKey] = value;
40873
+ });
40874
+ return sectPr;
40875
+ }
40633
40876
  function getStyleDefinitions(docx) {
40634
40877
  const styles = docx["word/styles.xml"];
40635
40878
  if (!styles) return [];
@@ -40822,6 +41065,36 @@ Please report this to https://github.com/markedjs/marked.`, e) {
40822
41065
  auto: "sans-serif"
40823
41066
  });
40824
41067
  const DEFAULT_GENERIC_FALLBACK = "sans-serif";
41068
+ const DEFAULT_FONT_SIZE_PT = 10;
41069
+ const collectRunDefaultProperties = (runProps, { allowOverrideTypeface = true, allowOverrideSize = true, themeResolver, state: state2 }) => {
41070
+ if (!runProps?.elements?.length || !state2) return;
41071
+ const fontsNode = runProps.elements.find((el) => el.name === "w:rFonts");
41072
+ if (fontsNode?.attributes) {
41073
+ const themeName = fontsNode.attributes["w:asciiTheme"];
41074
+ if (themeName) {
41075
+ const themeInfo = themeResolver?.(themeName) || {};
41076
+ if ((allowOverrideTypeface || !state2.typeface) && themeInfo.typeface) state2.typeface = themeInfo.typeface;
41077
+ if ((allowOverrideTypeface || !state2.panose) && themeInfo.panose) state2.panose = themeInfo.panose;
41078
+ }
41079
+ const ascii = fontsNode.attributes["w:ascii"];
41080
+ if ((allowOverrideTypeface || !state2.typeface) && ascii) {
41081
+ state2.typeface = ascii;
41082
+ }
41083
+ }
41084
+ const sizeNode = runProps.elements.find((el) => el.name === "w:sz");
41085
+ if (sizeNode?.attributes?.["w:val"]) {
41086
+ const sizeTwips = Number(sizeNode.attributes["w:val"]);
41087
+ if (Number.isFinite(sizeTwips)) {
41088
+ if (state2.fallbackSzTwips === void 0) state2.fallbackSzTwips = sizeTwips;
41089
+ const sizePt = sizeTwips / 2;
41090
+ if (allowOverrideSize || state2.fontSizePt === void 0) state2.fontSizePt = sizePt;
41091
+ }
41092
+ }
41093
+ const kernNode = runProps.elements.find((el) => el.name === "w:kern");
41094
+ if (kernNode?.attributes?.["w:val"]) {
41095
+ if (allowOverrideSize || state2.kern === void 0) state2.kern = kernNode.attributes["w:val"];
41096
+ }
41097
+ };
40825
41098
  const _SuperConverter = class _SuperConverter2 {
40826
41099
  constructor(params2 = null) {
40827
41100
  __privateAdd$2(this, _SuperConverter_instances);
@@ -40949,49 +41222,45 @@ Please report this to https://github.com/markedjs/marked.`, e) {
40949
41222
  }
40950
41223
  getDocumentDefaultStyles() {
40951
41224
  const styles = this.convertedXml["word/styles.xml"];
40952
- if (!styles) return {};
40953
- const defaults = styles.elements[0].elements.find((el) => el.name === "w:docDefaults");
40954
- const rDefault = defaults.elements.find((el) => el.name === "w:rPrDefault");
40955
- if (!rDefault.elements) return {};
40956
- const rElements = rDefault.elements[0].elements;
40957
- const rFonts = rElements?.find((el) => el.name === "w:rFonts");
40958
- if ("elements" in rDefault) {
40959
- const fontThemeName = rElements.find((el) => el.name === "w:rFonts")?.attributes["w:asciiTheme"];
40960
- let typeface, panose, fontSizeNormal;
40961
- if (fontThemeName) {
40962
- const fontInfo = this.getThemeInfo(fontThemeName);
40963
- typeface = fontInfo.typeface;
40964
- panose = fontInfo.panose;
40965
- } else if (rFonts) {
40966
- typeface = rFonts?.attributes["w:ascii"];
40967
- }
40968
- const paragraphDefaults = styles.elements[0].elements.filter((el) => {
40969
- return el.name === "w:style" && el.attributes["w:styleId"] === "Normal";
40970
- }) || [];
40971
- paragraphDefaults.forEach((el) => {
40972
- const rPr = el.elements.find((el2) => el2.name === "w:rPr");
40973
- const fonts = rPr?.elements?.find((el2) => el2.name === "w:rFonts");
40974
- typeface = fonts?.attributes["w:ascii"];
40975
- fontSizeNormal = Number(rPr?.elements?.find((el2) => el2.name === "w:sz")?.attributes["w:val"]) / 2;
40976
- });
40977
- const rPrDefaults = defaults?.elements?.find((el) => el.name === "w:rPrDefault");
40978
- if (rPrDefaults) {
40979
- const rPr = rPrDefaults.elements?.find((el) => el.name === "w:rPr");
40980
- const fonts = rPr?.elements?.find((el) => el.name === "w:rFonts");
40981
- if (fonts?.attributes?.["w:ascii"]) {
40982
- typeface = fonts.attributes["w:ascii"];
40983
- }
40984
- const fontSizeRaw = rPr?.elements?.find((el) => el.name === "w:sz")?.attributes?.["w:val"];
40985
- if (!fontSizeNormal && fontSizeRaw) {
40986
- fontSizeNormal = Number(fontSizeRaw) / 2;
40987
- }
40988
- }
40989
- const fallbackSz = Number(rElements.find((el) => el.name === "w:sz")?.attributes?.["w:val"]);
40990
- const fontSizePt = fontSizeNormal ?? (Number.isFinite(fallbackSz) ? fallbackSz / 2 : void 0) ?? 10;
40991
- const kern = rElements.find((el) => el.name === "w:kern")?.attributes["w:val"];
40992
- const fontFamilyCss = _SuperConverter2.toCssFontFamily(typeface, this.convertedXml);
40993
- return { fontSizePt, kern, typeface, panose, fontFamilyCss };
40994
- }
41225
+ const styleRoot = styles?.elements?.[0];
41226
+ const styleElements = styleRoot?.elements || [];
41227
+ if (!styleElements.length) return {};
41228
+ const defaults = styleElements.find((el) => el.name === "w:docDefaults");
41229
+ const normalStyle = styleElements.find((el) => el.name === "w:style" && el.attributes?.["w:styleId"] === "Normal");
41230
+ const defaultsState = {
41231
+ typeface: void 0,
41232
+ panose: void 0,
41233
+ fontSizePt: void 0,
41234
+ kern: void 0,
41235
+ fallbackSzTwips: void 0
41236
+ };
41237
+ const docDefaultRun = defaults?.elements?.find((el) => el.name === "w:rPrDefault");
41238
+ const docDefaultProps = docDefaultRun?.elements?.find((el) => el.name === "w:rPr") ?? docDefaultRun;
41239
+ collectRunDefaultProperties(docDefaultProps, {
41240
+ allowOverrideTypeface: true,
41241
+ allowOverrideSize: true,
41242
+ themeResolver: (theme) => this.getThemeInfo(theme),
41243
+ state: defaultsState
41244
+ });
41245
+ const normalRunProps = normalStyle?.elements?.find((el) => el.name === "w:rPr") ?? null;
41246
+ collectRunDefaultProperties(normalRunProps, {
41247
+ allowOverrideTypeface: true,
41248
+ allowOverrideSize: true,
41249
+ themeResolver: (theme) => this.getThemeInfo(theme),
41250
+ state: defaultsState
41251
+ });
41252
+ if (defaultsState.fontSizePt === void 0) {
41253
+ if (Number.isFinite(defaultsState.fallbackSzTwips)) defaultsState.fontSizePt = defaultsState.fallbackSzTwips / 2;
41254
+ else defaultsState.fontSizePt = DEFAULT_FONT_SIZE_PT;
41255
+ }
41256
+ const fontFamilyCss = defaultsState.typeface ? _SuperConverter2.toCssFontFamily(defaultsState.typeface, this.convertedXml) : void 0;
41257
+ const result = {};
41258
+ if (defaultsState.fontSizePt !== void 0) result.fontSizePt = defaultsState.fontSizePt;
41259
+ if (defaultsState.kern !== void 0) result.kern = defaultsState.kern;
41260
+ if (defaultsState.typeface) result.typeface = defaultsState.typeface;
41261
+ if (defaultsState.panose) result.panose = defaultsState.panose;
41262
+ if (fontFamilyCss) result.fontFamilyCss = fontFamilyCss;
41263
+ return result;
40995
41264
  }
40996
41265
  getDocumentFonts() {
40997
41266
  const fontTable = this.convertedXml["word/fontTable.xml"];
@@ -43858,14 +44127,19 @@ Please report this to https://github.com/markedjs/marked.`, e) {
43858
44127
  /**
43859
44128
  * Update [Content_Types].xml with extensions of new Image annotations
43860
44129
  */
43861
- async updateContentTypes(docx, media, fromJson) {
44130
+ async updateContentTypes(docx, media, fromJson, updatedDocs = {}) {
44131
+ const additionalPartNames = Object.keys(updatedDocs || {});
43862
44132
  const newMediaTypes = Object.keys(media).map((name) => {
43863
44133
  return this.getFileExtension(name);
43864
44134
  }).filter(Boolean);
43865
44135
  const contentTypesPath = "[Content_Types].xml";
43866
44136
  let contentTypesXml;
43867
44137
  if (fromJson) {
43868
- contentTypesXml = docx.files.find((file) => file.name === contentTypesPath)?.content || "";
44138
+ if (Array.isArray(docx.files)) {
44139
+ contentTypesXml = docx.files.find((file) => file.name === contentTypesPath)?.content || "";
44140
+ } else {
44141
+ contentTypesXml = docx.files?.[contentTypesPath] || "";
44142
+ }
43869
44143
  } else contentTypesXml = await docx.file(contentTypesPath).async("string");
43870
44144
  let typesString = "";
43871
44145
  const defaultMediaTypes = getContentTypesFromXml(contentTypesXml);
@@ -43891,24 +44165,39 @@ Please report this to https://github.com/markedjs/marked.`, e) {
43891
44165
  const hasCommentsExtensible = types2.elements?.some(
43892
44166
  (el) => el.name === "Override" && el.attributes.PartName === "/word/commentsExtensible.xml"
43893
44167
  );
43894
- if (docx.files["word/comments.xml"]) {
44168
+ const hasFile = (filename) => {
44169
+ if (!docx?.files) return false;
44170
+ if (!fromJson) return Boolean(docx.files[filename]);
44171
+ if (Array.isArray(docx.files)) return docx.files.some((file) => file.name === filename);
44172
+ return Boolean(docx.files[filename]);
44173
+ };
44174
+ if (hasFile("word/comments.xml")) {
43895
44175
  const commentsDef = `<Override PartName="/word/comments.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml" />`;
43896
44176
  if (!hasComments) typesString += commentsDef;
43897
44177
  }
43898
- if (docx.files["word/commentsExtended.xml"]) {
44178
+ if (hasFile("word/commentsExtended.xml")) {
43899
44179
  const commentsExtendedDef = `<Override PartName="/word/commentsExtended.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml" />`;
43900
44180
  if (!hasCommentsExtended) typesString += commentsExtendedDef;
43901
44181
  }
43902
- if (docx.files["word/commentsIds.xml"]) {
44182
+ if (hasFile("word/commentsIds.xml")) {
43903
44183
  const commentsIdsDef = `<Override PartName="/word/commentsIds.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.commentsIds+xml" />`;
43904
44184
  if (!hasCommentsIds) typesString += commentsIdsDef;
43905
44185
  }
43906
- if (docx.files["word/commentsExtensible.xml"]) {
44186
+ if (hasFile("word/commentsExtensible.xml")) {
43907
44187
  const commentsExtendedDef = `<Override PartName="/word/commentsExtensible.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtensible+xml" />`;
43908
44188
  if (!hasCommentsExtensible) typesString += commentsExtendedDef;
43909
44189
  }
43910
- Object.keys(docx.files).forEach((name) => {
43911
- if (name.includes(".rels") || !name.includes("header") && !name.includes("footer")) return;
44190
+ const partNames = new Set(additionalPartNames);
44191
+ if (docx?.files) {
44192
+ if (fromJson && Array.isArray(docx.files)) {
44193
+ docx.files.forEach((file) => partNames.add(file.name));
44194
+ } else {
44195
+ Object.keys(docx.files).forEach((key2) => partNames.add(key2));
44196
+ }
44197
+ }
44198
+ partNames.forEach((name) => {
44199
+ if (name.includes(".rels")) return;
44200
+ if (!name.includes("header") && !name.includes("footer")) return;
43912
44201
  const hasExtensible = types2.elements?.some(
43913
44202
  (el) => el.name === "Override" && el.attributes.PartName === `/${name}`
43914
44203
  );
@@ -43919,7 +44208,48 @@ Please report this to https://github.com/markedjs/marked.`, e) {
43919
44208
  }
43920
44209
  });
43921
44210
  const beginningString = '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">';
43922
- const updatedContentTypesXml = contentTypesXml.replace(beginningString, `${beginningString}${typesString}`);
44211
+ let updatedContentTypesXml = contentTypesXml.replace(beginningString, `${beginningString}${typesString}`);
44212
+ let relationshipsXml = updatedDocs["word/_rels/document.xml.rels"];
44213
+ if (!relationshipsXml) {
44214
+ if (fromJson) {
44215
+ if (Array.isArray(docx.files)) {
44216
+ relationshipsXml = docx.files.find((file) => file.name === "word/_rels/document.xml.rels")?.content;
44217
+ } else {
44218
+ relationshipsXml = docx.files?.["word/_rels/document.xml.rels"];
44219
+ }
44220
+ } else {
44221
+ relationshipsXml = await docx.file("word/_rels/document.xml.rels")?.async("string");
44222
+ }
44223
+ }
44224
+ if (relationshipsXml) {
44225
+ try {
44226
+ const relJson = xmljs.xml2js(relationshipsXml, { compact: false });
44227
+ const relationships = relJson.elements?.find((el) => el.name === "Relationships");
44228
+ relationships?.elements?.forEach((rel) => {
44229
+ const type2 = rel.attributes?.Type;
44230
+ const target = rel.attributes?.Target;
44231
+ if (!type2 || !target) return;
44232
+ const isHeader = type2.includes("/header");
44233
+ const isFooter = type2.includes("/footer");
44234
+ if (!isHeader && !isFooter) return;
44235
+ let sanitizedTarget = target.replace(/^\.\//, "");
44236
+ if (sanitizedTarget.startsWith("../")) sanitizedTarget = sanitizedTarget.slice(3);
44237
+ if (sanitizedTarget.startsWith("/")) sanitizedTarget = sanitizedTarget.slice(1);
44238
+ const partName = sanitizedTarget.startsWith("word/") ? sanitizedTarget : `word/${sanitizedTarget}`;
44239
+ partNames.add(partName);
44240
+ });
44241
+ } catch (error) {
44242
+ console.warn("Failed to parse document relationships while updating content types", error);
44243
+ }
44244
+ }
44245
+ partNames.forEach((name) => {
44246
+ if (name.includes(".rels")) return;
44247
+ if (!name.includes("header") && !name.includes("footer")) return;
44248
+ if (updatedContentTypesXml.includes(`PartName="/${name}"`)) return;
44249
+ const type2 = name.includes("header") ? "header" : "footer";
44250
+ const extendedDef = `<Override PartName="/${name}" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.${type2}+xml"/>`;
44251
+ updatedContentTypesXml = updatedContentTypesXml.replace("</Types>", `${extendedDef}</Types>`);
44252
+ });
43923
44253
  if (fromJson) return updatedContentTypesXml;
43924
44254
  docx.file(contentTypesPath, updatedContentTypesXml);
43925
44255
  }
@@ -43960,7 +44290,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
43960
44290
  for (const [fontName, fontUintArray] of Object.entries(fonts)) {
43961
44291
  zip.file(fontName, fontUintArray);
43962
44292
  }
43963
- await this.updateContentTypes(zip, media);
44293
+ await this.updateContentTypes(zip, media, false, updatedDocs);
43964
44294
  return zip;
43965
44295
  }
43966
44296
  /**
@@ -43986,7 +44316,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
43986
44316
  Object.keys(media).forEach((path) => {
43987
44317
  unzippedOriginalDocx.file(path, media[path]);
43988
44318
  });
43989
- await this.updateContentTypes(unzippedOriginalDocx, media);
44319
+ await this.updateContentTypes(unzippedOriginalDocx, media, false, updatedDocs);
43990
44320
  return unzippedOriginalDocx;
43991
44321
  }
43992
44322
  }
@@ -44001,7 +44331,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
44001
44331
  var __privateAdd$1 = (obj, member, value) => member.has(obj) ? __typeError$1("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
44002
44332
  var __privateSet = (obj, member, value, setter) => (__accessCheck$1(obj, member, "write to private field"), member.set(obj, value), value);
44003
44333
  var __privateMethod$1 = (obj, member, method) => (__accessCheck$1(obj, member, "access private method"), method);
44004
- var _Attribute_static, getGlobalAttributes_fn, getNodeAndMarksAttributes_fn, _Schema_static, createNodesSchema_fn, createMarksSchema_fn, _events, _ExtensionService_instances, setupExtensions_fn, attachEditorEvents_fn, _editor, _stateValidators, _xmlValidators, _requiredNodeTypes, _requiredMarkTypes, _SuperValidator_instances, initializeValidators_fn, collectValidatorRequirements_fn, analyzeDocument_fn, _commandService, _Editor_instances, initContainerElement_fn, init_fn, initRichText_fn, onFocus_fn, checkHeadless_fn, registerCopyHandler_fn, insertNewFileData_fn, registerPluginByNameIfNotExists_fn, createExtensionService_fn, createCommandService_fn, createConverter_fn, initMedia_fn, initFonts_fn, createSchema_fn, generatePmData_fn, createView_fn, onCollaborationReady_fn, initComments_fn, initPagination_fn, dispatchTransaction_fn, handleNodeSelection_fn, prepareDocumentForImport_fn, prepareDocumentForExport_fn, endCollaboration_fn, validateDocumentInit_fn, validateDocumentExport_fn, initDevTools_fn, _ListItemNodeView_instances, init_fn2, _FieldAnnotationView_instances, createAnnotation_fn, _AutoPageNumberNodeView_instances, renderDom_fn, scheduleUpdateNodeStyle_fn, _DocumentSectionView_instances, init_fn3, addToolTip_fn;
44334
+ var _Attribute_static, getGlobalAttributes_fn, getNodeAndMarksAttributes_fn, _Schema_static, createNodesSchema_fn, createMarksSchema_fn, _events, _ExtensionService_instances, setupExtensions_fn, attachEditorEvents_fn, _editor, _stateValidators, _xmlValidators, _requiredNodeTypes, _requiredMarkTypes, _SuperValidator_instances, initializeValidators_fn, collectValidatorRequirements_fn, analyzeDocument_fn, _commandService, _Editor_instances, initContainerElement_fn, init_fn, initRichText_fn, onFocus_fn, checkHeadless_fn, registerCopyHandler_fn, insertNewFileData_fn, registerPluginByNameIfNotExists_fn, createExtensionService_fn, createCommandService_fn, createConverter_fn, initMedia_fn, initFonts_fn, createSchema_fn, generatePmData_fn, createView_fn, onCollaborationReady_fn, initComments_fn, initPagination_fn, dispatchTransaction_fn, handleNodeSelection_fn, prepareDocumentForImport_fn, prepareDocumentForExport_fn, endCollaboration_fn, validateDocumentInit_fn, validateDocumentExport_fn, initDevTools_fn, _DocumentSectionView_instances, init_fn2, addToolTip_fn, _ListItemNodeView_instances, init_fn3, _FieldAnnotationView_instances, createAnnotation_fn, _AutoPageNumberNodeView_instances, renderDom_fn, scheduleUpdateNodeStyle_fn;
44005
44335
  var GOOD_LEAF_SIZE = 200;
44006
44336
  var RopeSequence = function RopeSequence2() {
44007
44337
  };
@@ -55644,9 +55974,11 @@ Please report this to https://github.com/markedjs/marked.`, e) {
55644
55974
  item.editor.view.dom.setAttribute("documentmode", documentMode);
55645
55975
  });
55646
55976
  if (isEditMode) {
55647
- const pm = document.querySelector(".ProseMirror");
55648
- pm.classList.add("header-footer-edit");
55649
- pm.setAttribute("aria-readonly", true);
55977
+ const pm = editor.view?.dom || editor.options.element?.querySelector?.(".ProseMirror");
55978
+ if (pm) {
55979
+ pm.classList.add("header-footer-edit");
55980
+ pm.setAttribute("aria-readonly", true);
55981
+ }
55650
55982
  }
55651
55983
  if (focusedSectionEditor) {
55652
55984
  focusedSectionEditor.view.focus();
@@ -56074,28 +56406,25 @@ Please report this to https://github.com/markedjs/marked.`, e) {
56074
56406
  if (emitParams) editor.emit("commentsUpdate", emitParams);
56075
56407
  return newTrackedChanges;
56076
56408
  };
56077
- const getTrackedChangeText = ({ state: state2, node, mark, marks, trackedChangeType, isDeletionInsertion }) => {
56409
+ const getTrackedChangeText = ({ state: state2, nodes, mark, marks, trackedChangeType, isDeletionInsertion }) => {
56078
56410
  let trackedChangeText = "";
56079
56411
  let deletionText = "";
56080
56412
  if (trackedChangeType === TrackInsertMarkName) {
56081
- trackedChangeText = node?.text ?? "";
56413
+ trackedChangeText = nodes.reduce((acc, node) => {
56414
+ if (!node.marks.find((nodeMark) => nodeMark.type.name === mark.type.name)) return acc;
56415
+ acc += node?.text || node?.textContent || "";
56416
+ return acc;
56417
+ }, "");
56082
56418
  }
56083
56419
  if (trackedChangeType === TrackFormatMarkName) {
56084
56420
  trackedChangeText = translateFormatChangesToEnglish(mark.attrs);
56085
56421
  }
56086
56422
  if (trackedChangeType === TrackDeleteMarkName || isDeletionInsertion) {
56087
- deletionText = node?.text ?? "";
56088
- if (isDeletionInsertion) {
56089
- let { id } = marks.deletionMark.attrs;
56090
- let deletionNode = findNode$1(state2.doc, (node2) => {
56091
- const { marks: marks2 = [] } = node2;
56092
- const changeMarks = marks2.filter((mark2) => TRACK_CHANGE_MARKS.includes(mark2.type.name));
56093
- if (!changeMarks.length) return false;
56094
- const hasMatchingId = changeMarks.find((mark2) => mark2.attrs.id === id);
56095
- if (hasMatchingId) return true;
56096
- });
56097
- deletionText = deletionNode?.node.text ?? "";
56098
- }
56423
+ deletionText = nodes.reduce((acc, node) => {
56424
+ if (!node.marks.find((nodeMark) => nodeMark.type.name === TrackDeleteMarkName)) return acc;
56425
+ acc += node?.text || node?.textContent || "";
56426
+ return acc;
56427
+ }, "");
56099
56428
  }
56100
56429
  return {
56101
56430
  deletionText,
@@ -56110,18 +56439,17 @@ Please report this to https://github.com/markedjs/marked.`, e) {
56110
56439
  const id = attrs.id;
56111
56440
  const node = nodes[0];
56112
56441
  const isDeletionInsertion = !!(marks.insertedMark && marks.deletionMark);
56113
- let existingNode;
56442
+ let nodesWithMark = [];
56114
56443
  newEditorState.doc.descendants((node2) => {
56115
56444
  const { marks: marks2 = [] } = node2;
56116
56445
  const changeMarks = marks2.filter((mark) => TRACK_CHANGE_MARKS.includes(mark.type.name));
56117
56446
  if (!changeMarks.length) return;
56118
56447
  const hasMatchingId = changeMarks.find((mark) => mark.attrs.id === id);
56119
- if (hasMatchingId) existingNode = node2;
56120
- if (existingNode) return false;
56448
+ if (hasMatchingId) nodesWithMark.push(node2);
56121
56449
  });
56122
56450
  const { deletionText, trackedChangeText } = getTrackedChangeText({
56123
56451
  state: newEditorState,
56124
- node: existingNode || node,
56452
+ nodes: nodesWithMark.length ? nodesWithMark : [node],
56125
56453
  mark: trackedMark,
56126
56454
  marks,
56127
56455
  trackedChangeType,
@@ -56151,14 +56479,6 @@ Please report this to https://github.com/markedjs/marked.`, e) {
56151
56479
  else if (event === "update") params2.event = comments_module_events$1.UPDATE;
56152
56480
  return params2;
56153
56481
  };
56154
- function findNode$1(node, predicate) {
56155
- let found2 = null;
56156
- node.descendants((node2, pos) => {
56157
- if (predicate(node2)) found2 = { node: node2, pos };
56158
- if (found2) return false;
56159
- });
56160
- return found2;
56161
- }
56162
56482
  function findRangeById(doc2, id) {
56163
56483
  let from2 = null, to = null;
56164
56484
  doc2.descendants((node, pos) => {
@@ -56676,6 +56996,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
56676
56996
  const mappedRowStart = tr.mapping.map(absoluteRowStart);
56677
56997
  const rowEnd = mappedRowStart + rowNode.nodeSize;
56678
56998
  tr.replaceWith(mappedRowStart, rowEnd, Fragment.from(newRows));
56999
+ tr.setMeta("tableGeneration", true);
56679
57000
  } catch (error) {
56680
57001
  console.error("Error during row generation:", error);
56681
57002
  throw error;
@@ -57080,7 +57401,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
57080
57401
  }
57081
57402
  function findRemovedFieldAnnotations(tr) {
57082
57403
  let removedNodes = [];
57083
- if (!tr.steps.length || tr.meta && !Object.keys(tr.meta).every((meta) => ["inputType", "uiEvent", "paste"].includes(meta)) || ["historyUndo", "historyRedo"].includes(tr.getMeta("inputType")) || ["drop"].includes(tr.getMeta("uiEvent")) || tr.getMeta("fieldAnnotationUpdate") === true) {
57404
+ if (!tr.steps.length || tr.meta && !Object.keys(tr.meta).every((meta) => ["inputType", "uiEvent", "paste"].includes(meta)) || ["historyUndo", "historyRedo"].includes(tr.getMeta("inputType")) || ["drop"].includes(tr.getMeta("uiEvent")) || tr.getMeta("fieldAnnotationUpdate") === true || tr.getMeta("tableGeneration") === true) {
57084
57405
  return removedNodes;
57085
57406
  }
57086
57407
  const hasDeletion = transactionDeletedAnything(tr);
@@ -58258,7 +58579,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
58258
58579
  setDocumentMode(documentMode) {
58259
58580
  let cleanedMode = documentMode?.toLowerCase() || "editing";
58260
58581
  if (!this.extensionService || !this.state) return;
58261
- const pm = document.querySelector(".ProseMirror");
58582
+ const pm = this.view?.dom || this.options.element?.querySelector?.(".ProseMirror");
58262
58583
  if (this.options.role === "viewer") cleanedMode = "viewing";
58263
58584
  if (this.options.role === "suggester" && cleanedMode === "editing") cleanedMode = "suggesting";
58264
58585
  if (cleanedMode === "viewing") {
@@ -58746,7 +59067,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
58746
59067
  files: this.options.content
58747
59068
  },
58748
59069
  media,
58749
- true
59070
+ true,
59071
+ updatedDocs
58750
59072
  );
58751
59073
  return updatedDocs;
58752
59074
  }
@@ -59232,9 +59554,11 @@ Please report this to https://github.com/markedjs/marked.`, e) {
59232
59554
  isEditMode: false,
59233
59555
  documentMode: this.options.documentMode
59234
59556
  });
59235
- const pm = document.querySelector(".ProseMirror");
59236
- pm.classList.remove("header-footer-edit");
59237
- pm.setAttribute("aria-readonly", false);
59557
+ const pm = this.view?.dom || this.options.element?.querySelector?.(".ProseMirror");
59558
+ if (pm) {
59559
+ pm.classList.remove("header-footer-edit");
59560
+ pm.setAttribute("aria-readonly", false);
59561
+ }
59238
59562
  }
59239
59563
  setWordSelection(view, pos);
59240
59564
  }
@@ -60782,6 +61106,1004 @@ Please report this to https://github.com/markedjs/marked.`, e) {
60782
61106
  return this.editor.options.isHeadless ? [] : [slashMenuPlugin];
60783
61107
  }
60784
61108
  });
61109
+ class StructuredContentViewBase {
61110
+ constructor(props) {
61111
+ __publicField$1(this, "node");
61112
+ __publicField$1(this, "view");
61113
+ __publicField$1(this, "getPos");
61114
+ __publicField$1(this, "decorations");
61115
+ __publicField$1(this, "innerDecorations");
61116
+ __publicField$1(this, "editor");
61117
+ __publicField$1(this, "extension");
61118
+ __publicField$1(this, "htmlAttributes");
61119
+ __publicField$1(this, "root");
61120
+ __publicField$1(this, "isDragging", false);
61121
+ this.node = props.node;
61122
+ this.view = props.editor.view;
61123
+ this.getPos = props.getPos;
61124
+ this.decorations = props.decorations;
61125
+ this.innerDecorations = props.innerDecorations;
61126
+ this.editor = props.editor;
61127
+ this.extension = props.extension;
61128
+ this.htmlAttributes = props.htmlAttributes;
61129
+ this.mount(props);
61130
+ }
61131
+ mount() {
61132
+ return;
61133
+ }
61134
+ get dom() {
61135
+ return this.root;
61136
+ }
61137
+ get contentDOM() {
61138
+ return null;
61139
+ }
61140
+ update(node, decorations, innerDecorations) {
61141
+ if (node.type !== this.node.type) {
61142
+ return false;
61143
+ }
61144
+ this.node = node;
61145
+ this.decorations = decorations;
61146
+ this.innerDecorations = innerDecorations;
61147
+ this.updateHTMLAttributes();
61148
+ return true;
61149
+ }
61150
+ stopEvent(event) {
61151
+ if (!this.dom) return false;
61152
+ const target = event.target;
61153
+ const isInElement = this.dom.contains(target) && !this.contentDOM?.contains(target);
61154
+ if (!isInElement) return false;
61155
+ const isDragEvent = event.type.startsWith("drag");
61156
+ const isDropEvent = event.type === "drop";
61157
+ const isInput = ["INPUT", "BUTTON", "SELECT", "TEXTAREA"].includes(target.tagName) || target.isContentEditable;
61158
+ if (isInput && !isDropEvent && !isDragEvent) return true;
61159
+ const { isEditable } = this.editor;
61160
+ const { isDragging } = this;
61161
+ const isDraggable = !!this.node.type.spec.draggable;
61162
+ const isSelectable = NodeSelection.isSelectable(this.node);
61163
+ const isCopyEvent = event.type === "copy";
61164
+ const isPasteEvent = event.type === "paste";
61165
+ const isCutEvent = event.type === "cut";
61166
+ const isClickEvent = event.type === "mousedown";
61167
+ if (!isDraggable && isSelectable && isDragEvent && event.target === this.dom) {
61168
+ event.preventDefault();
61169
+ }
61170
+ if (isDraggable && isDragEvent && !isDragging && event.target === this.dom) {
61171
+ event.preventDefault();
61172
+ return false;
61173
+ }
61174
+ if (isDraggable && isEditable && !isDragging && isClickEvent) {
61175
+ const dragHandle = target.closest("[data-drag-handle]");
61176
+ const isValidDragHandle = dragHandle && (this.dom === dragHandle || this.dom.contains(dragHandle));
61177
+ if (isValidDragHandle) {
61178
+ this.isDragging = true;
61179
+ document.addEventListener(
61180
+ "dragend",
61181
+ () => {
61182
+ this.isDragging = false;
61183
+ },
61184
+ { once: true }
61185
+ );
61186
+ document.addEventListener(
61187
+ "drop",
61188
+ () => {
61189
+ this.isDragging = false;
61190
+ },
61191
+ { once: true }
61192
+ );
61193
+ document.addEventListener(
61194
+ "mouseup",
61195
+ () => {
61196
+ this.isDragging = false;
61197
+ },
61198
+ { once: true }
61199
+ );
61200
+ }
61201
+ }
61202
+ if (isDragging || isDropEvent || isCopyEvent || isPasteEvent || isCutEvent || isClickEvent && isSelectable) {
61203
+ return false;
61204
+ }
61205
+ return true;
61206
+ }
61207
+ ignoreMutation(mutation) {
61208
+ if (!this.dom || !this.contentDOM) return true;
61209
+ if (this.node.isLeaf || this.node.isAtom) return true;
61210
+ if (mutation.type === "selection") return false;
61211
+ if (this.contentDOM === mutation.target && mutation.type === "attributes") return true;
61212
+ if (this.contentDOM.contains(mutation.target)) return false;
61213
+ return true;
61214
+ }
61215
+ destroy() {
61216
+ this.dom.remove();
61217
+ this.contentDOM?.remove();
61218
+ }
61219
+ updateAttributes(attrs) {
61220
+ const pos = this.getPos();
61221
+ if (typeof pos !== "number") {
61222
+ return;
61223
+ }
61224
+ return this.view.dispatch(
61225
+ this.view.state.tr.setNodeMarkup(pos, void 0, {
61226
+ ...this.node.attrs,
61227
+ ...attrs
61228
+ })
61229
+ );
61230
+ }
61231
+ updateHTMLAttributes() {
61232
+ const { extensionService } = this.editor;
61233
+ const { attributes } = extensionService;
61234
+ const extensionAttrs = attributes.filter((i2) => i2.type === this.node.type.name);
61235
+ this.htmlAttributes = Attribute.getAttributesToRender(this.node, extensionAttrs);
61236
+ }
61237
+ createDragHandle() {
61238
+ const dragHandle = document.createElement("span");
61239
+ dragHandle.classList.add("sd-structured-content-draggable");
61240
+ dragHandle.draggable = true;
61241
+ dragHandle.contentEditable = "false";
61242
+ dragHandle.dataset.dragHandle = "";
61243
+ const textElement = document.createElement("span");
61244
+ textElement.textContent = this.node.attrs.alias || "Structured content";
61245
+ dragHandle.append(textElement);
61246
+ return dragHandle;
61247
+ }
61248
+ onDragStart(event) {
61249
+ const { view } = this.editor;
61250
+ const target = event.target;
61251
+ const dragHandle = target.nodeType === 3 ? target.parentElement?.closest("[data-drag-handle]") : target.closest("[data-drag-handle]");
61252
+ if (!this.dom || this.contentDOM?.contains(target) || !dragHandle) {
61253
+ return;
61254
+ }
61255
+ let x = 0;
61256
+ let y2 = 0;
61257
+ if (this.dom !== dragHandle) {
61258
+ const domBox = this.dom.getBoundingClientRect();
61259
+ const handleBox = dragHandle.getBoundingClientRect();
61260
+ const offsetX = event.offsetX ?? event.nativeEvent?.offsetX;
61261
+ const offsetY = event.offsetY ?? event.nativeEvent?.offsetY;
61262
+ x = handleBox.x - domBox.x + offsetX;
61263
+ y2 = handleBox.y - domBox.y + offsetY;
61264
+ }
61265
+ event.dataTransfer?.setDragImage(this.dom, x, y2);
61266
+ const pos = this.getPos();
61267
+ if (typeof pos !== "number") {
61268
+ return;
61269
+ }
61270
+ const selection = NodeSelection.create(view.state.doc, pos);
61271
+ const transaction = view.state.tr.setSelection(selection);
61272
+ view.dispatch(transaction);
61273
+ }
61274
+ }
61275
+ class StructuredContentInlineView extends StructuredContentViewBase {
61276
+ constructor(props) {
61277
+ super(props);
61278
+ }
61279
+ mount() {
61280
+ this.buildView();
61281
+ }
61282
+ get contentDOM() {
61283
+ const contentElement = this.dom?.querySelector(`.${structuredContentInnerClass$1}`);
61284
+ return contentElement || null;
61285
+ }
61286
+ createElement() {
61287
+ const element = document.createElement("span");
61288
+ element.classList.add(structuredContentClass$1);
61289
+ element.setAttribute("data-structured-content", "");
61290
+ const contentElement = document.createElement("span");
61291
+ contentElement.classList.add(structuredContentInnerClass$1);
61292
+ element.append(contentElement);
61293
+ const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
61294
+ updateDOMAttributes(element, { ...domAttrs });
61295
+ return { element, contentElement };
61296
+ }
61297
+ buildView() {
61298
+ const { element } = this.createElement();
61299
+ const dragHandle = this.createDragHandle();
61300
+ element.prepend(dragHandle);
61301
+ element.addEventListener("dragstart", (e) => this.onDragStart(e));
61302
+ this.root = element;
61303
+ }
61304
+ updateView() {
61305
+ const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
61306
+ updateDOMAttributes(this.dom, { ...domAttrs });
61307
+ }
61308
+ update(node, decorations, innerDecorations) {
61309
+ const result = super.update(node, decorations, innerDecorations);
61310
+ if (!result) return false;
61311
+ this.updateView();
61312
+ return true;
61313
+ }
61314
+ }
61315
+ const structuredContentClass$1 = "sd-structured-content";
61316
+ const structuredContentInnerClass$1 = "sd-structured-content__content";
61317
+ const StructuredContent = Node$1.create({
61318
+ name: "structuredContent",
61319
+ group: "inline structuredContent",
61320
+ inline: true,
61321
+ content: "inline*",
61322
+ isolating: true,
61323
+ atom: false,
61324
+ // false - has editable content.
61325
+ draggable: true,
61326
+ addOptions() {
61327
+ return {
61328
+ htmlAttributes: {
61329
+ class: structuredContentClass$1,
61330
+ "aria-label": "Structured content node"
61331
+ }
61332
+ };
61333
+ },
61334
+ addAttributes() {
61335
+ return {
61336
+ id: {
61337
+ default: null,
61338
+ parseDOM: (elem) => elem.getAttribute("data-id"),
61339
+ renderDOM: (attrs) => {
61340
+ if (!attrs.id) return {};
61341
+ return { "data-id": attrs.id };
61342
+ }
61343
+ },
61344
+ tag: {
61345
+ default: null,
61346
+ parseDOM: (elem) => elem.getAttribute("data-tag"),
61347
+ renderDOM: (attrs) => {
61348
+ if (!attrs.tag) return {};
61349
+ return { "data-tag": attrs.tag };
61350
+ }
61351
+ },
61352
+ alias: {
61353
+ default: null,
61354
+ parseDOM: (elem) => elem.getAttribute("data-alias"),
61355
+ renderDOM: (attrs) => {
61356
+ if (!attrs.alias) return {};
61357
+ return { "data-alias": attrs.alias };
61358
+ }
61359
+ },
61360
+ sdtPr: {
61361
+ rendered: false
61362
+ }
61363
+ };
61364
+ },
61365
+ parseDOM() {
61366
+ return [{ tag: "span[data-structured-content]" }];
61367
+ },
61368
+ renderDOM({ htmlAttributes }) {
61369
+ return [
61370
+ "span",
61371
+ Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
61372
+ "data-structured-content": ""
61373
+ }),
61374
+ 0
61375
+ ];
61376
+ },
61377
+ addNodeView() {
61378
+ return (props) => {
61379
+ return new StructuredContentInlineView({ ...props });
61380
+ };
61381
+ }
61382
+ });
61383
+ class StructuredContentBlockView extends StructuredContentViewBase {
61384
+ constructor(props) {
61385
+ super(props);
61386
+ }
61387
+ mount() {
61388
+ this.buildView();
61389
+ }
61390
+ get contentDOM() {
61391
+ const contentElement = this.dom?.querySelector(`.${structuredContentInnerClass}`);
61392
+ return contentElement || null;
61393
+ }
61394
+ createElement() {
61395
+ const element = document.createElement("div");
61396
+ element.classList.add(structuredContentClass);
61397
+ element.setAttribute("data-structured-content-block", "");
61398
+ const contentElement = document.createElement("div");
61399
+ contentElement.classList.add(structuredContentInnerClass);
61400
+ element.append(contentElement);
61401
+ const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
61402
+ updateDOMAttributes(element, { ...domAttrs });
61403
+ return { element, contentElement };
61404
+ }
61405
+ buildView() {
61406
+ const { element } = this.createElement();
61407
+ const dragHandle = this.createDragHandle();
61408
+ element.prepend(dragHandle);
61409
+ element.addEventListener("dragstart", (e) => this.onDragStart(e));
61410
+ this.root = element;
61411
+ }
61412
+ updateView() {
61413
+ const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
61414
+ updateDOMAttributes(this.dom, { ...domAttrs });
61415
+ }
61416
+ update(node, decorations, innerDecorations) {
61417
+ const result = super.update(node, decorations, innerDecorations);
61418
+ if (!result) return false;
61419
+ this.updateView();
61420
+ return true;
61421
+ }
61422
+ }
61423
+ const structuredContentClass = "sd-structured-content-block";
61424
+ const structuredContentInnerClass = "sd-structured-content-block__content";
61425
+ const StructuredContentBlock = Node$1.create({
61426
+ name: "structuredContentBlock",
61427
+ group: "block structuredContent",
61428
+ content: "block*",
61429
+ isolating: true,
61430
+ atom: false,
61431
+ // false - has editable content.
61432
+ draggable: true,
61433
+ addOptions() {
61434
+ return {
61435
+ htmlAttributes: {
61436
+ class: structuredContentClass,
61437
+ "aria-label": "Structured content block node"
61438
+ }
61439
+ };
61440
+ },
61441
+ addAttributes() {
61442
+ return {
61443
+ id: {
61444
+ default: null,
61445
+ parseDOM: (elem) => elem.getAttribute("data-id"),
61446
+ renderDOM: (attrs) => {
61447
+ if (!attrs.id) return {};
61448
+ return { "data-id": attrs.id };
61449
+ }
61450
+ },
61451
+ tag: {
61452
+ default: null,
61453
+ parseDOM: (elem) => elem.getAttribute("data-tag"),
61454
+ renderDOM: (attrs) => {
61455
+ if (!attrs.tag) return {};
61456
+ return { "data-tag": attrs.tag };
61457
+ }
61458
+ },
61459
+ alias: {
61460
+ default: null,
61461
+ parseDOM: (elem) => elem.getAttribute("data-alias"),
61462
+ renderDOM: (attrs) => {
61463
+ if (!attrs.alias) return {};
61464
+ return { "data-alias": attrs.alias };
61465
+ }
61466
+ },
61467
+ sdtPr: {
61468
+ rendered: false
61469
+ }
61470
+ };
61471
+ },
61472
+ parseDOM() {
61473
+ return [{ tag: "div[data-structured-content-block]" }];
61474
+ },
61475
+ renderDOM({ htmlAttributes }) {
61476
+ return [
61477
+ "div",
61478
+ Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
61479
+ "data-structured-content-block": ""
61480
+ }),
61481
+ 0
61482
+ ];
61483
+ },
61484
+ addNodeView() {
61485
+ return (props) => {
61486
+ return new StructuredContentBlockView({ ...props });
61487
+ };
61488
+ }
61489
+ });
61490
+ function getStructuredContentTagsById(idOrIds, state2) {
61491
+ const result = findChildren$5(state2.doc, (node) => {
61492
+ const isStructuredContent = ["structuredContent", "structuredContentBlock"].includes(node.type.name);
61493
+ if (Array.isArray(idOrIds)) {
61494
+ return isStructuredContent && idOrIds.includes(node.attrs.id);
61495
+ } else {
61496
+ return isStructuredContent && node.attrs.id === idOrIds;
61497
+ }
61498
+ });
61499
+ return result;
61500
+ }
61501
+ function getStructuredContentTags(state2) {
61502
+ const result = findChildren$5(state2.doc, (node) => {
61503
+ return node.type.name === "structuredContent" || node.type.name === "structuredContentBlock";
61504
+ });
61505
+ return result;
61506
+ }
61507
+ function getStructuredContentInlineTags(state2) {
61508
+ const result = findChildren$5(state2.doc, (node) => node.type.name === "structuredContent");
61509
+ return result;
61510
+ }
61511
+ function getStructuredContentBlockTags(state2) {
61512
+ const result = findChildren$5(state2.doc, (node) => node.type.name === "structuredContentBlock");
61513
+ return result;
61514
+ }
61515
+ const structuredContentHelpers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
61516
+ __proto__: null,
61517
+ getStructuredContentBlockTags,
61518
+ getStructuredContentInlineTags,
61519
+ getStructuredContentTags,
61520
+ getStructuredContentTagsById
61521
+ }, Symbol.toStringTag, { value: "Module" }));
61522
+ const STRUCTURED_CONTENT_NAMES = ["structuredContent", "structuredContentBlock"];
61523
+ const StructuredContentCommands = Extension.create({
61524
+ name: "structuredContentCommands",
61525
+ addCommands() {
61526
+ return {
61527
+ /**
61528
+ * Inserts a structured content inline at selection.
61529
+ * @category Command
61530
+ * @param {StructuredContentInlineInsert} options
61531
+ */
61532
+ insertStructuredContentInline: (options = {}) => ({ editor, dispatch, state: state2, tr }) => {
61533
+ const { schema } = editor;
61534
+ let { from: from2, to } = state2.selection;
61535
+ if (dispatch) {
61536
+ const selectionText = state2.doc.textBetween(from2, to);
61537
+ let content = null;
61538
+ if (selectionText) {
61539
+ content = schema.text(selectionText);
61540
+ }
61541
+ if (options.text) {
61542
+ content = schema.text(options.text);
61543
+ }
61544
+ if (options.json) {
61545
+ content = schema.nodeFromJSON(options.json);
61546
+ }
61547
+ if (!content) {
61548
+ content = schema.text(" ");
61549
+ }
61550
+ const attrs = {
61551
+ ...options.attrs,
61552
+ id: options.attrs?.id || randomId(),
61553
+ tag: "inline_text_sdt",
61554
+ alias: options.attrs?.alias || "Structured content"
61555
+ };
61556
+ const node = schema.nodes.structuredContent.create(attrs, content, null);
61557
+ const parent = findParentNode((node2) => node2.type.name === "structuredContent")(state2.selection);
61558
+ if (parent) {
61559
+ const insertPos = parent.pos + parent.node.nodeSize;
61560
+ from2 = to = insertPos;
61561
+ }
61562
+ tr.replaceWith(from2, to, node);
61563
+ }
61564
+ return true;
61565
+ },
61566
+ /**
61567
+ * Inserts a structured content block at selection.
61568
+ * @category Command
61569
+ * @param {StructuredContentBlockInsert} options
61570
+ */
61571
+ insertStructuredContentBlock: (options = {}) => ({ editor, dispatch, state: state2, tr }) => {
61572
+ const { schema } = editor;
61573
+ let { from: from2, to } = state2.selection;
61574
+ if (dispatch) {
61575
+ const selectionContent = state2.selection.content();
61576
+ let content = null;
61577
+ if (selectionContent.size) {
61578
+ content = selectionContent.content;
61579
+ }
61580
+ if (options.html) {
61581
+ const html = htmlHandler(options.html, editor);
61582
+ const doc2 = DOMParser$1.fromSchema(schema).parse(html);
61583
+ content = doc2.content;
61584
+ }
61585
+ if (options.json) {
61586
+ content = schema.nodeFromJSON(options.json);
61587
+ }
61588
+ if (!content) {
61589
+ content = schema.nodeFromJSON({ type: "paragraph", content: [] });
61590
+ }
61591
+ const attrs = {
61592
+ ...options.attrs,
61593
+ id: options.attrs?.id || randomId(),
61594
+ tag: "block_table_sdt",
61595
+ alias: options.attrs?.alias || "Structured content"
61596
+ };
61597
+ const node = schema.nodes.structuredContentBlock.create(attrs, content, null);
61598
+ const parent = findParentNode((node2) => node2.type.name === "structuredContentBlock")(state2.selection);
61599
+ if (parent) {
61600
+ const insertPos = parent.pos + parent.node.nodeSize;
61601
+ from2 = to = insertPos;
61602
+ }
61603
+ tr.replaceRangeWith(from2, to, node);
61604
+ }
61605
+ return true;
61606
+ },
61607
+ /**
61608
+ * Updates a structured content attributes or content.
61609
+ * If the updated node does not match the schema, it will not be updated.
61610
+ * @category Command
61611
+ * @param {string} id
61612
+ * @param {StructuredContentUpdate} options
61613
+ */
61614
+ updateStructuredContentById: (id, options = {}) => ({ editor, dispatch, state: state2, tr }) => {
61615
+ const structuredContentTags = getStructuredContentTagsById(id, state2);
61616
+ if (!structuredContentTags.length) {
61617
+ return true;
61618
+ }
61619
+ const { schema } = editor;
61620
+ if (dispatch) {
61621
+ const structuredContent = structuredContentTags[0];
61622
+ const { pos, node } = structuredContent;
61623
+ const posFrom = pos;
61624
+ const posTo = pos + node.nodeSize;
61625
+ let content = null;
61626
+ if (options.text) {
61627
+ content = schema.text(options.text);
61628
+ }
61629
+ if (options.html) {
61630
+ const html = htmlHandler(options.html, editor);
61631
+ const doc2 = DOMParser$1.fromSchema(schema).parse(html);
61632
+ content = doc2.content;
61633
+ }
61634
+ if (options.json) {
61635
+ content = schema.nodeFromJSON(options.json);
61636
+ }
61637
+ if (!content) {
61638
+ content = node.content;
61639
+ }
61640
+ const updatedNode = node.type.create({ ...node.attrs, ...options.attrs }, content, node.marks);
61641
+ try {
61642
+ updatedNode.check();
61643
+ } catch {
61644
+ console.error("Updated node does not conform to the schema");
61645
+ return false;
61646
+ }
61647
+ tr.replaceWith(posFrom, posTo, updatedNode);
61648
+ }
61649
+ return true;
61650
+ },
61651
+ /**
61652
+ * Removes a structured content.
61653
+ * @category Command
61654
+ * @param {Array<{ node: Node, pos: number }>} structuredContentTags
61655
+ */
61656
+ deleteStructuredContent: (structuredContentTags) => ({ dispatch, tr }) => {
61657
+ if (!structuredContentTags.length) {
61658
+ return true;
61659
+ }
61660
+ if (dispatch) {
61661
+ structuredContentTags.forEach((structuredContent) => {
61662
+ const { pos, node } = structuredContent;
61663
+ const posFrom = tr.mapping.map(pos);
61664
+ const posTo = tr.mapping.map(pos + node.nodeSize);
61665
+ const currentNode = tr.doc.nodeAt(posFrom);
61666
+ if (currentNode && node.eq(currentNode)) {
61667
+ tr.delete(posFrom, posTo);
61668
+ }
61669
+ });
61670
+ }
61671
+ return true;
61672
+ },
61673
+ /**
61674
+ * Removes a structured content by ID.
61675
+ * @category Command
61676
+ * @param {string | string[]} idOrIds
61677
+ */
61678
+ deleteStructuredContentById: (idOrIds) => ({ dispatch, state: state2, tr }) => {
61679
+ const structuredContentTags = getStructuredContentTagsById(idOrIds, state2);
61680
+ if (!structuredContentTags.length) {
61681
+ return true;
61682
+ }
61683
+ if (dispatch) {
61684
+ structuredContentTags.forEach((structuredContent) => {
61685
+ const { pos, node } = structuredContent;
61686
+ const posFrom = tr.mapping.map(pos);
61687
+ const posTo = tr.mapping.map(pos + node.nodeSize);
61688
+ const currentNode = tr.doc.nodeAt(posFrom);
61689
+ if (currentNode && node.eq(currentNode)) {
61690
+ tr.delete(posFrom, posTo);
61691
+ }
61692
+ });
61693
+ }
61694
+ return true;
61695
+ },
61696
+ /**
61697
+ * Removes a structured content at cursor, preserving its content.
61698
+ * @category Command
61699
+ */
61700
+ deleteStructuredContentAtSelection: () => ({ editor, dispatch, state: state2, tr }) => {
61701
+ const predicate = (node) => STRUCTURED_CONTENT_NAMES.includes(node.type.name);
61702
+ const structuredContent = findParentNode(predicate)(state2.selection);
61703
+ if (!structuredContent) {
61704
+ return true;
61705
+ }
61706
+ if (dispatch) {
61707
+ const { node, pos } = structuredContent;
61708
+ const posFrom = pos;
61709
+ const posTo = posFrom + node.nodeSize;
61710
+ const content = node.content;
61711
+ tr.replaceWith(posFrom, posTo, content);
61712
+ }
61713
+ return true;
61714
+ }
61715
+ };
61716
+ },
61717
+ addHelpers() {
61718
+ return {
61719
+ ...structuredContentHelpers
61720
+ };
61721
+ }
61722
+ });
61723
+ const randomId = () => {
61724
+ return Math.floor(Math.random() * 4294967295).toString();
61725
+ };
61726
+ class DocumentSectionView {
61727
+ constructor(node, getPos, decorations, editor) {
61728
+ __privateAdd$1(this, _DocumentSectionView_instances);
61729
+ this.node = node;
61730
+ this.editor = editor;
61731
+ this.decorations = decorations;
61732
+ this.view = editor.view;
61733
+ this.getPos = getPos;
61734
+ __privateMethod$1(this, _DocumentSectionView_instances, init_fn2).call(this);
61735
+ }
61736
+ }
61737
+ _DocumentSectionView_instances = /* @__PURE__ */ new WeakSet();
61738
+ init_fn2 = function() {
61739
+ const { attrs } = this.node;
61740
+ const { id, title, description } = attrs;
61741
+ this.dom = document.createElement("div");
61742
+ this.dom.className = "sd-document-section-block";
61743
+ this.dom.setAttribute("data-id", id);
61744
+ this.dom.setAttribute("data-title", title);
61745
+ this.dom.setAttribute("data-description", description);
61746
+ this.dom.setAttribute("aria-label", "Document section");
61747
+ __privateMethod$1(this, _DocumentSectionView_instances, addToolTip_fn).call(this);
61748
+ this.contentDOM = document.createElement("div");
61749
+ this.contentDOM.className = "sd-document-section-block-content";
61750
+ this.contentDOM.setAttribute("contenteditable", "true");
61751
+ this.dom.appendChild(this.contentDOM);
61752
+ };
61753
+ addToolTip_fn = function() {
61754
+ const { title } = this.node.attrs;
61755
+ this.infoDiv = document.createElement("div");
61756
+ this.infoDiv.className = "sd-document-section-block-info";
61757
+ const textSpan = document.createElement("span");
61758
+ textSpan.textContent = title || "Document section";
61759
+ this.infoDiv.appendChild(textSpan);
61760
+ this.infoDiv.setAttribute("contenteditable", "false");
61761
+ this.dom.appendChild(this.infoDiv);
61762
+ };
61763
+ const getAllSections = (editor) => {
61764
+ if (!editor) return [];
61765
+ const type2 = editor.schema.nodes.documentSection;
61766
+ if (!type2) return [];
61767
+ const sections = [];
61768
+ const { state: state2 } = editor;
61769
+ state2.doc.descendants((node, pos) => {
61770
+ if (node.type.name === type2.name) {
61771
+ sections.push({ node, pos });
61772
+ }
61773
+ });
61774
+ return sections;
61775
+ };
61776
+ const exportSectionsToHTML = (editor) => {
61777
+ const sections = getAllSections(editor);
61778
+ const processedSections = /* @__PURE__ */ new Set();
61779
+ const result = [];
61780
+ sections.forEach(({ node }) => {
61781
+ const { attrs } = node;
61782
+ const { id, title, description } = attrs;
61783
+ if (processedSections.has(id)) return;
61784
+ processedSections.add(id);
61785
+ const html = getHTMLFromNode(node, editor);
61786
+ result.push({
61787
+ id,
61788
+ title,
61789
+ description,
61790
+ html
61791
+ });
61792
+ });
61793
+ return result;
61794
+ };
61795
+ const getHTMLFromNode = (node, editor) => {
61796
+ const tempDocument = document.implementation.createHTMLDocument();
61797
+ const container = tempDocument.createElement("div");
61798
+ const fragment = DOMSerializer.fromSchema(editor.schema).serializeFragment(node.content);
61799
+ container.appendChild(fragment);
61800
+ let html = container.innerHTML;
61801
+ return html;
61802
+ };
61803
+ const exportSectionsToJSON = (editor) => {
61804
+ const sections = getAllSections(editor);
61805
+ const processedSections = /* @__PURE__ */ new Set();
61806
+ const result = [];
61807
+ sections.forEach(({ node }) => {
61808
+ const { attrs } = node;
61809
+ const { id, title, description } = attrs;
61810
+ if (processedSections.has(id)) return;
61811
+ processedSections.add(id);
61812
+ result.push({
61813
+ id,
61814
+ title,
61815
+ description,
61816
+ content: node.toJSON()
61817
+ });
61818
+ });
61819
+ return result;
61820
+ };
61821
+ const getLinkedSectionEditor = (id, options, editor) => {
61822
+ const sections = getAllSections(editor);
61823
+ const section = sections.find((s) => s.node.attrs.id === id);
61824
+ if (!section) return null;
61825
+ const child = editor.createChildEditor({
61826
+ ...options,
61827
+ onUpdate: ({ editor: childEditor, transaction }) => {
61828
+ const isFromtLinkedParent = transaction.getMeta("fromLinkedParent");
61829
+ if (isFromtLinkedParent) return;
61830
+ const updatedContent = childEditor.state.doc.content;
61831
+ const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
61832
+ if (!sectionNode) return;
61833
+ const { pos, node } = sectionNode;
61834
+ const newNode = node.type.create(node.attrs, updatedContent, node.marks);
61835
+ const tr = editor.state.tr.replaceWith(pos, pos + node.nodeSize, newNode);
61836
+ tr.setMeta("fromLinkedChild", true);
61837
+ editor.view.dispatch(tr);
61838
+ }
61839
+ });
61840
+ editor.on("update", ({ transaction }) => {
61841
+ const isFromLinkedChild = transaction.getMeta("fromLinkedChild");
61842
+ if (isFromLinkedChild) return;
61843
+ const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
61844
+ if (!sectionNode) return;
61845
+ const sectionContent = sectionNode.node.content;
61846
+ const json = {
61847
+ type: "doc",
61848
+ content: sectionContent.content.map((node) => node.toJSON())
61849
+ };
61850
+ const childTr = child.state.tr;
61851
+ childTr.setMeta("fromLinkedParent", true);
61852
+ childTr.replaceWith(0, child.state.doc.content.size, child.schema.nodeFromJSON(json));
61853
+ child.view.dispatch(childTr);
61854
+ });
61855
+ return child;
61856
+ };
61857
+ const SectionHelpers = {
61858
+ getAllSections,
61859
+ exportSectionsToHTML,
61860
+ exportSectionsToJSON,
61861
+ getLinkedSectionEditor
61862
+ };
61863
+ const DocumentSection = Node$1.create({
61864
+ name: "documentSection",
61865
+ group: "block",
61866
+ content: "block*",
61867
+ atom: true,
61868
+ isolating: true,
61869
+ addOptions() {
61870
+ return {
61871
+ htmlAttributes: {
61872
+ class: "sd-document-section-block",
61873
+ "aria-label": "Structured content block"
61874
+ }
61875
+ };
61876
+ },
61877
+ parseDOM() {
61878
+ return [
61879
+ {
61880
+ tag: "div.sd-document-section-block",
61881
+ priority: 60
61882
+ }
61883
+ ];
61884
+ },
61885
+ renderDOM({ htmlAttributes }) {
61886
+ return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
61887
+ },
61888
+ addAttributes() {
61889
+ return {
61890
+ id: {},
61891
+ sdBlockId: {
61892
+ default: null,
61893
+ keepOnSplit: false,
61894
+ parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
61895
+ renderDOM: (attrs) => {
61896
+ return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
61897
+ }
61898
+ },
61899
+ title: {},
61900
+ description: {},
61901
+ sectionType: {},
61902
+ isLocked: { default: false }
61903
+ };
61904
+ },
61905
+ addNodeView() {
61906
+ return ({ node, editor, getPos, decorations }) => {
61907
+ return new DocumentSectionView(node, getPos, decorations, editor);
61908
+ };
61909
+ },
61910
+ addCommands() {
61911
+ return {
61912
+ /**
61913
+ * Create a lockable content section
61914
+ * @category Command
61915
+ * @param {SectionCreate} [options={}] - Section configuration
61916
+ * @example
61917
+ * editor.commands.createDocumentSection({
61918
+ * id: 1,
61919
+ * title: 'Terms & Conditions',
61920
+ * isLocked: true,
61921
+ * html: '<p>Legal content...</p>'
61922
+ * })
61923
+ */
61924
+ createDocumentSection: (options = {}) => ({ tr, state: state2, dispatch, editor }) => {
61925
+ const { selection } = state2;
61926
+ let { from: from2, to } = selection;
61927
+ let content = selection.content().content;
61928
+ const { html: optionsHTML, json: optionsJSON } = options;
61929
+ if (optionsHTML) {
61930
+ const html = htmlHandler(optionsHTML, this.editor);
61931
+ const doc2 = DOMParser$1.fromSchema(this.editor.schema).parse(html);
61932
+ content = doc2.content;
61933
+ }
61934
+ if (optionsJSON) {
61935
+ content = this.editor.schema.nodeFromJSON(optionsJSON);
61936
+ }
61937
+ if (!content?.content?.length) {
61938
+ content = this.editor.schema.nodeFromJSON({ type: "paragraph", content: [] });
61939
+ }
61940
+ if (!options.id) {
61941
+ const allSections = SectionHelpers.getAllSections(editor);
61942
+ options.id = allSections.length + 1;
61943
+ }
61944
+ if (!options.title) {
61945
+ options.title = "Document section";
61946
+ }
61947
+ const node = this.type.createAndFill(options, content);
61948
+ if (!node) return false;
61949
+ const isAlreadyInSdtBlock = findParentNode((node2) => node2.type.name === "documentSection")(selection);
61950
+ if (isAlreadyInSdtBlock && isAlreadyInSdtBlock.node) {
61951
+ const insertPos2 = isAlreadyInSdtBlock.pos + isAlreadyInSdtBlock.node.nodeSize;
61952
+ from2 = insertPos2;
61953
+ to = insertPos2;
61954
+ }
61955
+ tr.replaceRangeWith(from2, to, node);
61956
+ const nodeEnd = from2 + node.nodeSize;
61957
+ let shouldInsertParagraph = true;
61958
+ let insertPos = nodeEnd;
61959
+ if (nodeEnd >= tr.doc.content.size) {
61960
+ insertPos = tr.doc.content.size;
61961
+ if (insertPos > 0) {
61962
+ const $endPos = tr.doc.resolve(insertPos);
61963
+ if ($endPos.nodeBefore && $endPos.nodeBefore.type.name === "paragraph") {
61964
+ shouldInsertParagraph = false;
61965
+ }
61966
+ }
61967
+ }
61968
+ if (shouldInsertParagraph) {
61969
+ const emptyParagraph = tr.doc.type.schema.nodes.paragraph.create();
61970
+ tr.insert(insertPos, emptyParagraph);
61971
+ }
61972
+ if (dispatch) {
61973
+ tr.setMeta("documentSection", { action: "create" });
61974
+ dispatch(tr);
61975
+ setTimeout(() => {
61976
+ try {
61977
+ const currentState = editor.state;
61978
+ const docSize = currentState.doc.content.size;
61979
+ let targetPos = from2 + node.nodeSize;
61980
+ if (shouldInsertParagraph) {
61981
+ targetPos += 1;
61982
+ }
61983
+ targetPos = Math.min(targetPos, docSize);
61984
+ if (targetPos < docSize && targetPos > 0) {
61985
+ const newSelection = Selection.near(currentState.doc.resolve(targetPos));
61986
+ const newTr = currentState.tr.setSelection(newSelection);
61987
+ editor.view.dispatch(newTr);
61988
+ }
61989
+ } catch (e) {
61990
+ console.warn("Could not set delayed selection:", e);
61991
+ }
61992
+ }, 0);
61993
+ }
61994
+ return true;
61995
+ },
61996
+ /**
61997
+ * Remove section wrapper at cursor, preserving its content
61998
+ * @category Command
61999
+ * @example
62000
+ * editor.commands.removeSectionAtSelection()
62001
+ * @note Content stays in document, only section wrapper is removed
62002
+ */
62003
+ removeSectionAtSelection: () => ({ tr, dispatch }) => {
62004
+ const sdtNode = findParentNode((node2) => node2.type.name === "documentSection")(tr.selection);
62005
+ if (!sdtNode) return false;
62006
+ const { node, pos } = sdtNode;
62007
+ const nodeStart = pos;
62008
+ const nodeEnd = nodeStart + node.nodeSize;
62009
+ const contentToPreserve = node.content;
62010
+ tr.delete(nodeStart, nodeEnd);
62011
+ if (contentToPreserve.size > 0) {
62012
+ tr.insert(nodeStart, contentToPreserve);
62013
+ }
62014
+ const newPos = Math.min(nodeStart, tr.doc.content.size);
62015
+ tr.setSelection(Selection.near(tr.doc.resolve(newPos)));
62016
+ if (dispatch) {
62017
+ tr.setMeta("documentSection", { action: "delete" });
62018
+ dispatch(tr);
62019
+ }
62020
+ return true;
62021
+ },
62022
+ /**
62023
+ * Delete section and all its content
62024
+ * @category Command
62025
+ * @param {number} id - Section to delete
62026
+ * @example
62027
+ * editor.commands.removeSectionById(123)
62028
+ */
62029
+ removeSectionById: (id) => ({ tr, dispatch }) => {
62030
+ const sections = SectionHelpers.getAllSections(this.editor);
62031
+ const sectionToRemove = sections.find(({ node: node2 }) => node2.attrs.id === id);
62032
+ if (!sectionToRemove) return false;
62033
+ const { pos, node } = sectionToRemove;
62034
+ const nodeStart = pos;
62035
+ const nodeEnd = nodeStart + node.nodeSize;
62036
+ tr.delete(nodeStart, nodeEnd);
62037
+ if (dispatch) {
62038
+ tr.setMeta("documentSection", { action: "delete", id });
62039
+ dispatch(tr);
62040
+ }
62041
+ return true;
62042
+ },
62043
+ /**
62044
+ * Lock section against edits
62045
+ * @category Command
62046
+ * @param {number} id - Section to lock
62047
+ * @example
62048
+ * editor.commands.lockSectionById(123)
62049
+ */
62050
+ lockSectionById: (id) => ({ tr, dispatch }) => {
62051
+ const sections = SectionHelpers.getAllSections(this.editor);
62052
+ const sectionToLock = sections.find(({ node }) => node.attrs.id === id);
62053
+ if (!sectionToLock) return false;
62054
+ tr.setNodeMarkup(sectionToLock.pos, null, { ...sectionToLock.node.attrs, isLocked: true });
62055
+ if (dispatch) {
62056
+ tr.setMeta("documentSection", { action: "lock", id });
62057
+ dispatch(tr);
62058
+ }
62059
+ return true;
62060
+ },
62061
+ /**
62062
+ * Modify section attributes or content
62063
+ * @category Command
62064
+ * @param {SectionUpdate} options - Changes to apply
62065
+ * @example
62066
+ * editor.commands.updateSectionById({ id: 123, attrs: { isLocked: false } })
62067
+ * editor.commands.updateSectionById({ id: 123, html: '<p>New content</p>' })
62068
+ * editor.commands.updateSectionById({
62069
+ * id: 123,
62070
+ * html: '<p>Updated</p>',
62071
+ * attrs: { title: 'New Title' }
62072
+ * })
62073
+ */
62074
+ updateSectionById: ({ id, html, json, attrs }) => ({ tr, dispatch, editor }) => {
62075
+ const sections = SectionHelpers.getAllSections(editor || this.editor);
62076
+ const sectionToUpdate = sections.find(({ node: node2 }) => node2.attrs.id === id);
62077
+ if (!sectionToUpdate) return false;
62078
+ const { pos, node } = sectionToUpdate;
62079
+ let newContent = null;
62080
+ if (html) {
62081
+ const htmlDoc = htmlHandler(html, editor || this.editor);
62082
+ const doc2 = DOMParser$1.fromSchema((editor || this.editor).schema).parse(htmlDoc);
62083
+ newContent = doc2.content;
62084
+ }
62085
+ if (json) {
62086
+ newContent = (editor || this.editor).schema.nodeFromJSON(json);
62087
+ }
62088
+ if (!newContent) {
62089
+ newContent = node.content;
62090
+ }
62091
+ const updatedNode = node.type.create({ ...node.attrs, ...attrs }, newContent, node.marks);
62092
+ tr.replaceWith(pos, pos + node.nodeSize, updatedNode);
62093
+ if (dispatch) {
62094
+ tr.setMeta("documentSection", { action: "update", id, attrs });
62095
+ dispatch(tr);
62096
+ }
62097
+ return true;
62098
+ }
62099
+ };
62100
+ },
62101
+ addHelpers() {
62102
+ return {
62103
+ ...SectionHelpers
62104
+ };
62105
+ }
62106
+ });
60785
62107
  const Document = Node$1.create({
60786
62108
  name: "doc",
60787
62109
  topNode: true,
@@ -61289,15 +62611,31 @@ Please report this to https://github.com/markedjs/marked.`, e) {
61289
62611
  }
61290
62612
  return result;
61291
62613
  };
61292
- const CustomSelectionPluginKey = new PluginKey("CustomSelection");
61293
- const shouldAllowNativeContextMenu = (event) => {
62614
+ const isKeyboardInvocation = (event) => {
62615
+ return event.type === "contextmenu" && typeof event.detail === "number" && event.detail === 0 && (event.button === 0 || event.button === void 0) && event.clientX === 0 && event.clientY === 0;
62616
+ };
62617
+ const prefersNativeMenu = (event) => {
61294
62618
  if (!event) return false;
61295
62619
  if (event.ctrlKey || event.metaKey) {
61296
62620
  return true;
61297
62621
  }
61298
- const isKeyboardInvocation = event.type === "contextmenu" && typeof event.detail === "number" && event.detail === 0 && (event.button === 0 || event.button === void 0) && event.clientX === 0 && event.clientY === 0;
61299
- return Boolean(isKeyboardInvocation);
62622
+ return isKeyboardInvocation(event);
61300
62623
  };
62624
+ const shouldAllowNativeContextMenu = (event) => {
62625
+ return prefersNativeMenu(event);
62626
+ };
62627
+ const shouldBypassContextMenu = shouldAllowNativeContextMenu;
62628
+ const DEFAULT_SELECTION_STATE = Object.freeze({
62629
+ focused: false,
62630
+ preservedSelection: null,
62631
+ showVisualSelection: false,
62632
+ skipFocusReset: false
62633
+ });
62634
+ const normalizeSelectionState = (state2 = {}) => ({
62635
+ ...DEFAULT_SELECTION_STATE,
62636
+ ...state2
62637
+ });
62638
+ const CustomSelectionPluginKey = new PluginKey("CustomSelection");
61301
62639
  const handleClickOutside = (event, editor) => {
61302
62640
  const editorElem = editor?.options?.element;
61303
62641
  if (!editorElem) return;
@@ -61334,11 +62672,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
61334
62672
  const customSelectionPlugin = new Plugin({
61335
62673
  key: CustomSelectionPluginKey,
61336
62674
  state: {
61337
- init: () => ({
61338
- focused: false,
61339
- preservedSelection: null,
61340
- showVisualSelection: false
61341
- }),
62675
+ init: () => ({ ...DEFAULT_SELECTION_STATE }),
61342
62676
  apply: (tr, value) => {
61343
62677
  const meta = getFocusMeta(tr);
61344
62678
  if (meta !== void 0) {
@@ -61369,7 +62703,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
61369
62703
  setFocusMeta(view.state.tr, {
61370
62704
  focused: true,
61371
62705
  preservedSelection: selection,
61372
- showVisualSelection: true
62706
+ showVisualSelection: true,
62707
+ skipFocusReset: true
61373
62708
  })
61374
62709
  );
61375
62710
  }
@@ -61390,7 +62725,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
61390
62725
  setFocusMeta(view.state.tr, {
61391
62726
  focused: true,
61392
62727
  preservedSelection: selection2,
61393
- showVisualSelection: true
62728
+ showVisualSelection: true,
62729
+ skipFocusReset: true
61394
62730
  })
61395
62731
  );
61396
62732
  this.editor.setOptions({
@@ -61413,7 +62749,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
61413
62749
  setFocusMeta(view.state.tr, {
61414
62750
  focused: true,
61415
62751
  preservedSelection: selection,
61416
- showVisualSelection: true
62752
+ showVisualSelection: true,
62753
+ skipFocusReset: false
61417
62754
  })
61418
62755
  );
61419
62756
  this.editor.setOptions({
@@ -61431,7 +62768,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
61431
62768
  setFocusMeta(view.state.tr, {
61432
62769
  focused: true,
61433
62770
  preservedSelection: selection,
61434
- showVisualSelection: true
62771
+ showVisualSelection: true,
62772
+ skipFocusReset: false
61435
62773
  })
61436
62774
  );
61437
62775
  }
@@ -61442,7 +62780,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
61442
62780
  setFocusMeta(view.state.tr, {
61443
62781
  focused: false,
61444
62782
  preservedSelection: null,
61445
- showVisualSelection: false
62783
+ showVisualSelection: false,
62784
+ skipFocusReset: false
61446
62785
  })
61447
62786
  );
61448
62787
  if (!selection.empty && !this.editor.options.element?.contains(target)) {
@@ -61459,12 +62798,20 @@ Please report this to https://github.com/markedjs/marked.`, e) {
61459
62798
  const isElement2 = target instanceof Element;
61460
62799
  const isToolbarBtn = isElement2 && isToolbarButton(target);
61461
62800
  const isToolbarInp = isElement2 && isToolbarInput(target);
62801
+ const focusState = getFocusState(view.state);
62802
+ if (focusState?.skipFocusReset) {
62803
+ view.dispatch(
62804
+ setFocusMeta(view.state.tr, normalizeSelectionState({ ...focusState, skipFocusReset: false }))
62805
+ );
62806
+ return false;
62807
+ }
61462
62808
  if (!isToolbarBtn && !isToolbarInp) {
61463
62809
  view.dispatch(
61464
62810
  setFocusMeta(view.state.tr, {
61465
62811
  focused: false,
61466
62812
  preservedSelection: null,
61467
- showVisualSelection: false
62813
+ showVisualSelection: false,
62814
+ skipFocusReset: false
61468
62815
  })
61469
62816
  );
61470
62817
  }
@@ -61475,12 +62822,16 @@ Please report this to https://github.com/markedjs/marked.`, e) {
61475
62822
  const isToolbarBtn = isElement2 && isToolbarButton(target);
61476
62823
  const isToolbarInp = isElement2 && isToolbarInput(target);
61477
62824
  const state2 = getFocusState(view.state);
62825
+ if (state2?.skipFocusReset) {
62826
+ return false;
62827
+ }
61478
62828
  if (isToolbarBtn || isToolbarInp) {
61479
62829
  view.dispatch(
61480
62830
  setFocusMeta(view.state.tr, {
61481
62831
  focused: true,
61482
62832
  preservedSelection: state2.preservedSelection || view.state.selection,
61483
- showVisualSelection: true
62833
+ showVisualSelection: true,
62834
+ skipFocusReset: false
61484
62835
  })
61485
62836
  );
61486
62837
  } else {
@@ -61488,7 +62839,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
61488
62839
  setFocusMeta(view.state.tr, {
61489
62840
  focused: false,
61490
62841
  preservedSelection: null,
61491
- showVisualSelection: false
62842
+ showVisualSelection: false,
62843
+ skipFocusReset: false
61492
62844
  })
61493
62845
  );
61494
62846
  }
@@ -62334,7 +63686,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
62334
63686
  this.decorations = decorations;
62335
63687
  this.view = editor.view;
62336
63688
  this.getPos = getPos;
62337
- __privateMethod$1(this, _ListItemNodeView_instances, init_fn2).call(this);
63689
+ __privateMethod$1(this, _ListItemNodeView_instances, init_fn3).call(this);
62338
63690
  activeListItemNodeViews.add(this);
62339
63691
  }
62340
63692
  refreshIndentStyling() {
@@ -62395,7 +63747,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
62395
63747
  }
62396
63748
  }
62397
63749
  _ListItemNodeView_instances = /* @__PURE__ */ new WeakSet();
62398
- init_fn2 = function() {
63750
+ init_fn3 = function() {
62399
63751
  const { attrs } = this.node;
62400
63752
  const { listLevel, listNumberingType, lvlText, numId, level, customFormat } = attrs;
62401
63753
  let orderMarker = "";
@@ -69794,908 +71146,178 @@ Please report this to https://github.com/markedjs/marked.`, e) {
69794
71146
  style: attrs.style
69795
71147
  };
69796
71148
  }
69797
- },
69798
- wrapAttributes: {
69799
- rendered: false
69800
- },
69801
- attributes: {
69802
- rendered: false
69803
- }
69804
- };
69805
- },
69806
- parseDOM() {
69807
- return [
69808
- {
69809
- tag: `div[data-type="${this.name}"]`
69810
- }
69811
- ];
69812
- },
69813
- renderDOM({ htmlAttributes }) {
69814
- return [
69815
- "div",
69816
- Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
69817
- 0
69818
- ];
69819
- }
69820
- });
69821
- const ShapeTextbox = Node$1.create({
69822
- name: "shapeTextbox",
69823
- group: "block",
69824
- content: "paragraph* block*",
69825
- isolating: true,
69826
- addOptions() {
69827
- return {
69828
- htmlAttributes: {
69829
- class: "sd-editor-shape-textbox",
69830
- "aria-label": "Shape textbox node"
69831
- }
69832
- };
69833
- },
69834
- addAttributes() {
69835
- return {
69836
- sdBlockId: {
69837
- default: null,
69838
- keepOnSplit: false,
69839
- parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
69840
- renderDOM: (attrs) => {
69841
- return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
69842
- }
69843
- },
69844
- attributes: {
69845
- rendered: false
69846
- }
69847
- };
69848
- },
69849
- parseDOM() {
69850
- return [
69851
- {
69852
- tag: `div[data-type="${this.name}"]`
69853
- }
69854
- ];
69855
- },
69856
- renderDOM({ htmlAttributes }) {
69857
- return [
69858
- "div",
69859
- Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
69860
- 0
69861
- ];
69862
- }
69863
- });
69864
- const ContentBlock = Node$1.create({
69865
- name: "contentBlock",
69866
- group: "inline",
69867
- content: "",
69868
- isolating: true,
69869
- atom: true,
69870
- inline: true,
69871
- addOptions() {
69872
- return {
69873
- htmlAttributes: {
69874
- contenteditable: false
69875
- }
69876
- };
69877
- },
69878
- addAttributes() {
69879
- return {
69880
- horizontalRule: {
69881
- default: false,
69882
- renderDOM: ({ horizontalRule }) => {
69883
- if (!horizontalRule) return {};
69884
- return { "data-horizontal-rule": "true" };
69885
- }
69886
- },
69887
- size: {
69888
- default: null,
69889
- renderDOM: ({ size: size2 }) => {
69890
- if (!size2) return {};
69891
- let style2 = "";
69892
- if (size2.top) style2 += `top: ${size2.top}px; `;
69893
- if (size2.left) style2 += `left: ${size2.left}px; `;
69894
- if (size2.width) style2 += `width: ${size2.width.toString().endsWith("%") ? size2.width : `${size2.width}px`}; `;
69895
- if (size2.height)
69896
- style2 += `height: ${size2.height.toString().endsWith("%") ? size2.height : `${size2.height}px`}; `;
69897
- return { style: style2 };
69898
- }
69899
- },
69900
- background: {
69901
- default: null,
69902
- renderDOM: (attrs) => {
69903
- if (!attrs.background) return {};
69904
- return {
69905
- style: `background-color: ${attrs.background}`
69906
- };
69907
- }
69908
- },
69909
- drawingContent: {
69910
- rendered: false
69911
- },
69912
- attributes: {
69913
- rendered: false
69914
- }
69915
- };
69916
- },
69917
- parseDOM() {
69918
- return [
69919
- {
69920
- tag: `div[data-type="${this.name}"]`
69921
- }
69922
- ];
69923
- },
69924
- renderDOM({ htmlAttributes }) {
69925
- return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name })];
69926
- },
69927
- addCommands() {
69928
- return {
69929
- /**
69930
- * Insert a horizontal rule
69931
- * @category Command
69932
- * @example
69933
- * editor.commands.insertHorizontalRule()
69934
- * @note Creates a visual separator between content sections
69935
- */
69936
- insertHorizontalRule: () => ({ commands: commands2 }) => {
69937
- return commands2.insertContent({
69938
- type: this.name,
69939
- attrs: {
69940
- horizontalRule: true,
69941
- size: { width: "100%", height: 2 },
69942
- background: "#e5e7eb"
69943
- }
69944
- });
69945
- },
69946
- /**
69947
- * Insert a content block
69948
- * @category Command
69949
- * @param {ContentBlockConfig} config - Block configuration
69950
- * @example
69951
- * // Insert a spacer block
69952
- * editor.commands.insertContentBlock({ size: { height: 20 } })
69953
- *
69954
- * @example
69955
- * // Insert a colored divider
69956
- * editor.commands.insertContentBlock({
69957
- * size: { width: '50%', height: 3 },
69958
- * background: '#3b82f6'
69959
- * })
69960
- * @note Used for spacing, dividers, and special inline content
69961
- */
69962
- insertContentBlock: (config2) => ({ commands: commands2 }) => {
69963
- return commands2.insertContent({
69964
- type: this.name,
69965
- attrs: config2
69966
- });
69967
- }
69968
- };
69969
- }
69970
- });
69971
- class StructuredContentViewBase {
69972
- constructor(props) {
69973
- __publicField$1(this, "node");
69974
- __publicField$1(this, "view");
69975
- __publicField$1(this, "getPos");
69976
- __publicField$1(this, "decorations");
69977
- __publicField$1(this, "innerDecorations");
69978
- __publicField$1(this, "editor");
69979
- __publicField$1(this, "extension");
69980
- __publicField$1(this, "htmlAttributes");
69981
- __publicField$1(this, "root");
69982
- __publicField$1(this, "isDragging", false);
69983
- this.node = props.node;
69984
- this.view = props.editor.view;
69985
- this.getPos = props.getPos;
69986
- this.decorations = props.decorations;
69987
- this.innerDecorations = props.innerDecorations;
69988
- this.editor = props.editor;
69989
- this.extension = props.extension;
69990
- this.htmlAttributes = props.htmlAttributes;
69991
- this.mount(props);
69992
- }
69993
- mount() {
69994
- return;
69995
- }
69996
- get dom() {
69997
- return this.root;
69998
- }
69999
- get contentDOM() {
70000
- return null;
70001
- }
70002
- update(node, decorations, innerDecorations) {
70003
- if (node.type !== this.node.type) {
70004
- return false;
70005
- }
70006
- this.node = node;
70007
- this.decorations = decorations;
70008
- this.innerDecorations = innerDecorations;
70009
- this.updateHTMLAttributes();
70010
- return true;
70011
- }
70012
- stopEvent(event) {
70013
- if (!this.dom) return false;
70014
- const target = event.target;
70015
- const isInElement = this.dom.contains(target) && !this.contentDOM?.contains(target);
70016
- if (!isInElement) return false;
70017
- const isDragEvent = event.type.startsWith("drag");
70018
- const isDropEvent = event.type === "drop";
70019
- const isInput = ["INPUT", "BUTTON", "SELECT", "TEXTAREA"].includes(target.tagName) || target.isContentEditable;
70020
- if (isInput && !isDropEvent && !isDragEvent) return true;
70021
- const { isEditable } = this.editor;
70022
- const { isDragging } = this;
70023
- const isDraggable = !!this.node.type.spec.draggable;
70024
- const isSelectable = NodeSelection.isSelectable(this.node);
70025
- const isCopyEvent = event.type === "copy";
70026
- const isPasteEvent = event.type === "paste";
70027
- const isCutEvent = event.type === "cut";
70028
- const isClickEvent = event.type === "mousedown";
70029
- if (!isDraggable && isSelectable && isDragEvent && event.target === this.dom) {
70030
- event.preventDefault();
70031
- }
70032
- if (isDraggable && isDragEvent && !isDragging && event.target === this.dom) {
70033
- event.preventDefault();
70034
- return false;
70035
- }
70036
- if (isDraggable && isEditable && !isDragging && isClickEvent) {
70037
- const dragHandle = target.closest("[data-drag-handle]");
70038
- const isValidDragHandle = dragHandle && (this.dom === dragHandle || this.dom.contains(dragHandle));
70039
- if (isValidDragHandle) {
70040
- this.isDragging = true;
70041
- document.addEventListener(
70042
- "dragend",
70043
- () => {
70044
- this.isDragging = false;
70045
- },
70046
- { once: true }
70047
- );
70048
- document.addEventListener(
70049
- "drop",
70050
- () => {
70051
- this.isDragging = false;
70052
- },
70053
- { once: true }
70054
- );
70055
- document.addEventListener(
70056
- "mouseup",
70057
- () => {
70058
- this.isDragging = false;
70059
- },
70060
- { once: true }
70061
- );
70062
- }
70063
- }
70064
- if (isDragging || isDropEvent || isCopyEvent || isPasteEvent || isCutEvent || isClickEvent && isSelectable) {
70065
- return false;
70066
- }
70067
- return true;
70068
- }
70069
- ignoreMutation(mutation) {
70070
- if (!this.dom || !this.contentDOM) return true;
70071
- if (this.node.isLeaf || this.node.isAtom) return true;
70072
- if (mutation.type === "selection") return false;
70073
- if (this.contentDOM === mutation.target && mutation.type === "attributes") return true;
70074
- if (this.contentDOM.contains(mutation.target)) return false;
70075
- return true;
70076
- }
70077
- destroy() {
70078
- this.dom.remove();
70079
- this.contentDOM?.remove();
70080
- }
70081
- updateAttributes(attrs) {
70082
- const pos = this.getPos();
70083
- if (typeof pos !== "number") {
70084
- return;
70085
- }
70086
- return this.view.dispatch(
70087
- this.view.state.tr.setNodeMarkup(pos, void 0, {
70088
- ...this.node.attrs,
70089
- ...attrs
70090
- })
70091
- );
70092
- }
70093
- updateHTMLAttributes() {
70094
- const { extensionService } = this.editor;
70095
- const { attributes } = extensionService;
70096
- const extensionAttrs = attributes.filter((i2) => i2.type === this.node.type.name);
70097
- this.htmlAttributes = Attribute.getAttributesToRender(this.node, extensionAttrs);
70098
- }
70099
- createDragHandle() {
70100
- const dragHandle = document.createElement("span");
70101
- dragHandle.classList.add("sd-structured-content-draggable");
70102
- dragHandle.draggable = true;
70103
- dragHandle.contentEditable = "false";
70104
- dragHandle.dataset.dragHandle = "";
70105
- const textElement = document.createElement("span");
70106
- textElement.textContent = "Structured content";
70107
- dragHandle.append(textElement);
70108
- return dragHandle;
70109
- }
70110
- onDragStart(event) {
70111
- const { view } = this.editor;
70112
- const target = event.target;
70113
- const dragHandle = target.nodeType === 3 ? target.parentElement?.closest("[data-drag-handle]") : target.closest("[data-drag-handle]");
70114
- if (!this.dom || this.contentDOM?.contains(target) || !dragHandle) {
70115
- return;
70116
- }
70117
- let x = 0;
70118
- let y2 = 0;
70119
- if (this.dom !== dragHandle) {
70120
- const domBox = this.dom.getBoundingClientRect();
70121
- const handleBox = dragHandle.getBoundingClientRect();
70122
- const offsetX = event.offsetX ?? event.nativeEvent?.offsetX;
70123
- const offsetY = event.offsetY ?? event.nativeEvent?.offsetY;
70124
- x = handleBox.x - domBox.x + offsetX;
70125
- y2 = handleBox.y - domBox.y + offsetY;
70126
- }
70127
- event.dataTransfer?.setDragImage(this.dom, x, y2);
70128
- const pos = this.getPos();
70129
- if (typeof pos !== "number") {
70130
- return;
70131
- }
70132
- const selection = NodeSelection.create(view.state.doc, pos);
70133
- const transaction = view.state.tr.setSelection(selection);
70134
- view.dispatch(transaction);
70135
- }
70136
- }
70137
- class StructuredContentInlineView extends StructuredContentViewBase {
70138
- constructor(props) {
70139
- super(props);
70140
- }
70141
- mount() {
70142
- this.buildView();
70143
- }
70144
- get contentDOM() {
70145
- const contentElement = this.dom?.querySelector(`.${structuredContentInnerClass$1}`);
70146
- return contentElement || null;
70147
- }
70148
- createElement() {
70149
- const element = document.createElement("span");
70150
- element.classList.add(structuredContentClass$1);
70151
- element.setAttribute("data-structured-content", "");
70152
- const contentElement = document.createElement("span");
70153
- contentElement.classList.add(structuredContentInnerClass$1);
70154
- element.append(contentElement);
70155
- const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
70156
- updateDOMAttributes(element, { ...domAttrs });
70157
- return { element, contentElement };
70158
- }
70159
- buildView() {
70160
- const { element } = this.createElement();
70161
- const dragHandle = this.createDragHandle();
70162
- element.prepend(dragHandle);
70163
- element.addEventListener("dragstart", (e) => this.onDragStart(e));
70164
- this.root = element;
70165
- }
70166
- updateView() {
70167
- const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
70168
- updateDOMAttributes(this.dom, { ...domAttrs });
70169
- }
70170
- update(node, decorations, innerDecorations) {
70171
- const result = super.update(node, decorations, innerDecorations);
70172
- if (!result) return false;
70173
- this.updateView();
70174
- return true;
70175
- }
70176
- }
70177
- const structuredContentClass$1 = "sd-structured-content";
70178
- const structuredContentInnerClass$1 = "sd-structured-content__content";
70179
- const StructuredContent = Node$1.create({
70180
- name: "structuredContent",
70181
- group: "inline structuredContent",
70182
- inline: true,
70183
- content: "inline*",
70184
- isolating: true,
70185
- atom: false,
70186
- // false - has editable content.
70187
- draggable: true,
70188
- addOptions() {
70189
- return {
70190
- htmlAttributes: {
70191
- class: structuredContentClass$1,
70192
- "aria-label": "Structured content node"
70193
- }
70194
- };
70195
- },
70196
- addAttributes() {
70197
- return {
70198
- id: {
70199
- default: null,
70200
- parseDOM: (elem) => elem.getAttribute("data-id"),
70201
- renderDOM: (attrs) => {
70202
- if (!attrs.id) return {};
70203
- return { "data-id": attrs.id };
70204
- }
70205
- },
70206
- sdtPr: {
70207
- rendered: false
70208
- }
70209
- };
70210
- },
70211
- parseDOM() {
70212
- return [{ tag: "span[data-structured-content]" }];
70213
- },
70214
- renderDOM({ htmlAttributes }) {
70215
- return [
70216
- "span",
70217
- Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
70218
- "data-structured-content": ""
70219
- }),
70220
- 0
70221
- ];
70222
- },
70223
- addNodeView() {
70224
- return (props) => {
70225
- return new StructuredContentInlineView({ ...props });
70226
- };
70227
- }
70228
- });
70229
- class StructuredContentBlockView extends StructuredContentViewBase {
70230
- constructor(props) {
70231
- super(props);
70232
- }
70233
- mount() {
70234
- this.buildView();
70235
- }
70236
- get contentDOM() {
70237
- const contentElement = this.dom?.querySelector(`.${structuredContentInnerClass}`);
70238
- return contentElement || null;
70239
- }
70240
- createElement() {
70241
- const element = document.createElement("div");
70242
- element.classList.add(structuredContentClass);
70243
- element.setAttribute("data-structured-content-block", "");
70244
- const contentElement = document.createElement("div");
70245
- contentElement.classList.add(structuredContentInnerClass);
70246
- element.append(contentElement);
70247
- const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
70248
- updateDOMAttributes(element, { ...domAttrs });
70249
- return { element, contentElement };
70250
- }
70251
- buildView() {
70252
- const { element } = this.createElement();
70253
- const dragHandle = this.createDragHandle();
70254
- element.prepend(dragHandle);
70255
- element.addEventListener("dragstart", (e) => this.onDragStart(e));
70256
- this.root = element;
70257
- }
70258
- updateView() {
70259
- const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
70260
- updateDOMAttributes(this.dom, { ...domAttrs });
70261
- }
70262
- update(node, decorations, innerDecorations) {
70263
- const result = super.update(node, decorations, innerDecorations);
70264
- if (!result) return false;
70265
- this.updateView();
70266
- return true;
71149
+ },
71150
+ wrapAttributes: {
71151
+ rendered: false
71152
+ },
71153
+ attributes: {
71154
+ rendered: false
71155
+ }
71156
+ };
71157
+ },
71158
+ parseDOM() {
71159
+ return [
71160
+ {
71161
+ tag: `div[data-type="${this.name}"]`
71162
+ }
71163
+ ];
71164
+ },
71165
+ renderDOM({ htmlAttributes }) {
71166
+ return [
71167
+ "div",
71168
+ Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
71169
+ 0
71170
+ ];
70267
71171
  }
70268
- }
70269
- const structuredContentClass = "sd-structured-content-block";
70270
- const structuredContentInnerClass = "sd-structured-content-block__content";
70271
- const StructuredContentBlock = Node$1.create({
70272
- name: "structuredContentBlock",
70273
- group: "block structuredContent",
70274
- content: "block*",
71172
+ });
71173
+ const ShapeTextbox = Node$1.create({
71174
+ name: "shapeTextbox",
71175
+ group: "block",
71176
+ content: "paragraph* block*",
70275
71177
  isolating: true,
70276
- atom: false,
70277
- // false - has editable content.
70278
- draggable: true,
70279
71178
  addOptions() {
70280
71179
  return {
70281
71180
  htmlAttributes: {
70282
- class: structuredContentClass,
70283
- "aria-label": "Structured content block node"
71181
+ class: "sd-editor-shape-textbox",
71182
+ "aria-label": "Shape textbox node"
70284
71183
  }
70285
71184
  };
70286
71185
  },
70287
71186
  addAttributes() {
70288
71187
  return {
70289
- id: {
71188
+ sdBlockId: {
70290
71189
  default: null,
70291
- parseDOM: (elem) => elem.getAttribute("data-id"),
71190
+ keepOnSplit: false,
71191
+ parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
70292
71192
  renderDOM: (attrs) => {
70293
- if (!attrs.id) return {};
70294
- return { "data-id": attrs.id };
71193
+ return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
70295
71194
  }
70296
71195
  },
70297
- sdtPr: {
71196
+ attributes: {
70298
71197
  rendered: false
70299
71198
  }
70300
71199
  };
70301
71200
  },
70302
71201
  parseDOM() {
70303
- return [{ tag: "div[data-structured-content-block]" }];
71202
+ return [
71203
+ {
71204
+ tag: `div[data-type="${this.name}"]`
71205
+ }
71206
+ ];
70304
71207
  },
70305
71208
  renderDOM({ htmlAttributes }) {
70306
71209
  return [
70307
71210
  "div",
70308
- Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
70309
- "data-structured-content-block": ""
70310
- }),
71211
+ Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
70311
71212
  0
70312
71213
  ];
70313
- },
70314
- addNodeView() {
70315
- return (props) => {
70316
- return new StructuredContentBlockView({ ...props });
70317
- };
70318
71214
  }
70319
71215
  });
70320
- class DocumentSectionView {
70321
- constructor(node, getPos, decorations, editor) {
70322
- __privateAdd$1(this, _DocumentSectionView_instances);
70323
- this.node = node;
70324
- this.editor = editor;
70325
- this.decorations = decorations;
70326
- this.view = editor.view;
70327
- this.getPos = getPos;
70328
- __privateMethod$1(this, _DocumentSectionView_instances, init_fn3).call(this);
70329
- }
70330
- }
70331
- _DocumentSectionView_instances = /* @__PURE__ */ new WeakSet();
70332
- init_fn3 = function() {
70333
- const { attrs } = this.node;
70334
- const { id, title, description } = attrs;
70335
- this.dom = document.createElement("div");
70336
- this.dom.className = "sd-document-section-block";
70337
- this.dom.setAttribute("data-id", id);
70338
- this.dom.setAttribute("data-title", title);
70339
- this.dom.setAttribute("data-description", description);
70340
- this.dom.setAttribute("aria-label", "Document section");
70341
- __privateMethod$1(this, _DocumentSectionView_instances, addToolTip_fn).call(this);
70342
- this.contentDOM = document.createElement("div");
70343
- this.contentDOM.className = "sd-document-section-block-content";
70344
- this.contentDOM.setAttribute("contenteditable", "true");
70345
- this.dom.appendChild(this.contentDOM);
70346
- };
70347
- addToolTip_fn = function() {
70348
- const { title } = this.node.attrs;
70349
- this.infoDiv = document.createElement("div");
70350
- this.infoDiv.className = "sd-document-section-block-info";
70351
- const textSpan = document.createElement("span");
70352
- textSpan.textContent = title || "Document section";
70353
- this.infoDiv.appendChild(textSpan);
70354
- this.infoDiv.setAttribute("contenteditable", "false");
70355
- this.dom.appendChild(this.infoDiv);
70356
- };
70357
- const getAllSections = (editor) => {
70358
- if (!editor) return [];
70359
- const type2 = editor.schema.nodes.documentSection;
70360
- if (!type2) return [];
70361
- const sections = [];
70362
- const { state: state2 } = editor;
70363
- state2.doc.descendants((node, pos) => {
70364
- if (node.type.name === type2.name) {
70365
- sections.push({ node, pos });
70366
- }
70367
- });
70368
- return sections;
70369
- };
70370
- const exportSectionsToHTML = (editor) => {
70371
- const sections = getAllSections(editor);
70372
- const processedSections = /* @__PURE__ */ new Set();
70373
- const result = [];
70374
- sections.forEach(({ node }) => {
70375
- const { attrs } = node;
70376
- const { id, title, description } = attrs;
70377
- if (processedSections.has(id)) return;
70378
- processedSections.add(id);
70379
- const html = getHTMLFromNode(node, editor);
70380
- result.push({
70381
- id,
70382
- title,
70383
- description,
70384
- html
70385
- });
70386
- });
70387
- return result;
70388
- };
70389
- const getHTMLFromNode = (node, editor) => {
70390
- const tempDocument = document.implementation.createHTMLDocument();
70391
- const container = tempDocument.createElement("div");
70392
- const fragment = DOMSerializer.fromSchema(editor.schema).serializeFragment(node.content);
70393
- container.appendChild(fragment);
70394
- let html = container.innerHTML;
70395
- return html;
70396
- };
70397
- const exportSectionsToJSON = (editor) => {
70398
- const sections = getAllSections(editor);
70399
- const processedSections = /* @__PURE__ */ new Set();
70400
- const result = [];
70401
- sections.forEach(({ node }) => {
70402
- const { attrs } = node;
70403
- const { id, title, description } = attrs;
70404
- if (processedSections.has(id)) return;
70405
- processedSections.add(id);
70406
- result.push({
70407
- id,
70408
- title,
70409
- description,
70410
- content: node.toJSON()
70411
- });
70412
- });
70413
- return result;
70414
- };
70415
- const getLinkedSectionEditor = (id, options, editor) => {
70416
- const sections = getAllSections(editor);
70417
- const section = sections.find((s) => s.node.attrs.id === id);
70418
- if (!section) return null;
70419
- const child = editor.createChildEditor({
70420
- ...options,
70421
- onUpdate: ({ editor: childEditor, transaction }) => {
70422
- const isFromtLinkedParent = transaction.getMeta("fromLinkedParent");
70423
- if (isFromtLinkedParent) return;
70424
- const updatedContent = childEditor.state.doc.content;
70425
- const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
70426
- if (!sectionNode) return;
70427
- const { pos, node } = sectionNode;
70428
- const newNode = node.type.create(node.attrs, updatedContent, node.marks);
70429
- const tr = editor.state.tr.replaceWith(pos, pos + node.nodeSize, newNode);
70430
- tr.setMeta("fromLinkedChild", true);
70431
- editor.view.dispatch(tr);
70432
- }
70433
- });
70434
- editor.on("update", ({ transaction }) => {
70435
- const isFromLinkedChild = transaction.getMeta("fromLinkedChild");
70436
- if (isFromLinkedChild) return;
70437
- const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
70438
- if (!sectionNode) return;
70439
- const sectionContent = sectionNode.node.content;
70440
- const json = {
70441
- type: "doc",
70442
- content: sectionContent.content.map((node) => node.toJSON())
70443
- };
70444
- const childTr = child.state.tr;
70445
- childTr.setMeta("fromLinkedParent", true);
70446
- childTr.replaceWith(0, child.state.doc.content.size, child.schema.nodeFromJSON(json));
70447
- child.view.dispatch(childTr);
70448
- });
70449
- return child;
70450
- };
70451
- const SectionHelpers = {
70452
- getAllSections,
70453
- exportSectionsToHTML,
70454
- exportSectionsToJSON,
70455
- getLinkedSectionEditor
70456
- };
70457
- const DocumentSection = Node$1.create({
70458
- name: "documentSection",
70459
- group: "block",
70460
- content: "block*",
70461
- atom: true,
71216
+ const ContentBlock = Node$1.create({
71217
+ name: "contentBlock",
71218
+ group: "inline",
71219
+ content: "",
70462
71220
  isolating: true,
71221
+ atom: true,
71222
+ inline: true,
70463
71223
  addOptions() {
70464
71224
  return {
70465
71225
  htmlAttributes: {
70466
- class: "sd-document-section-block",
70467
- "aria-label": "Structured content block"
71226
+ contenteditable: false
70468
71227
  }
70469
71228
  };
70470
71229
  },
70471
- parseDOM() {
70472
- return [
70473
- {
70474
- tag: "div.sd-document-section-block",
70475
- priority: 60
70476
- }
70477
- ];
70478
- },
70479
- renderDOM({ htmlAttributes }) {
70480
- return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
70481
- },
70482
71230
  addAttributes() {
70483
71231
  return {
70484
- id: {},
70485
- sdBlockId: {
71232
+ horizontalRule: {
71233
+ default: false,
71234
+ renderDOM: ({ horizontalRule }) => {
71235
+ if (!horizontalRule) return {};
71236
+ return { "data-horizontal-rule": "true" };
71237
+ }
71238
+ },
71239
+ size: {
71240
+ default: null,
71241
+ renderDOM: ({ size: size2 }) => {
71242
+ if (!size2) return {};
71243
+ let style2 = "";
71244
+ if (size2.top) style2 += `top: ${size2.top}px; `;
71245
+ if (size2.left) style2 += `left: ${size2.left}px; `;
71246
+ if (size2.width) style2 += `width: ${size2.width.toString().endsWith("%") ? size2.width : `${size2.width}px`}; `;
71247
+ if (size2.height)
71248
+ style2 += `height: ${size2.height.toString().endsWith("%") ? size2.height : `${size2.height}px`}; `;
71249
+ return { style: style2 };
71250
+ }
71251
+ },
71252
+ background: {
70486
71253
  default: null,
70487
- keepOnSplit: false,
70488
- parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
70489
71254
  renderDOM: (attrs) => {
70490
- return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
71255
+ if (!attrs.background) return {};
71256
+ return {
71257
+ style: `background-color: ${attrs.background}`
71258
+ };
70491
71259
  }
70492
71260
  },
70493
- title: {},
70494
- description: {},
70495
- sectionType: {},
70496
- isLocked: { default: false }
71261
+ drawingContent: {
71262
+ rendered: false
71263
+ },
71264
+ attributes: {
71265
+ rendered: false
71266
+ }
70497
71267
  };
70498
71268
  },
70499
- addNodeView() {
70500
- return ({ node, editor, getPos, decorations }) => {
70501
- return new DocumentSectionView(node, getPos, decorations, editor);
70502
- };
71269
+ parseDOM() {
71270
+ return [
71271
+ {
71272
+ tag: `div[data-type="${this.name}"]`
71273
+ }
71274
+ ];
71275
+ },
71276
+ renderDOM({ htmlAttributes }) {
71277
+ return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name })];
70503
71278
  },
70504
71279
  addCommands() {
70505
71280
  return {
70506
71281
  /**
70507
- * Create a lockable content section
71282
+ * Insert a horizontal rule
70508
71283
  * @category Command
70509
- * @param {SectionCreate} [options={}] - Section configuration
70510
71284
  * @example
70511
- * editor.commands.createDocumentSection({
70512
- * id: 1,
70513
- * title: 'Terms & Conditions',
70514
- * isLocked: true,
70515
- * html: '<p>Legal content...</p>'
70516
- * })
71285
+ * editor.commands.insertHorizontalRule()
71286
+ * @note Creates a visual separator between content sections
70517
71287
  */
70518
- createDocumentSection: (options = {}) => ({ tr, state: state2, dispatch, editor }) => {
70519
- const { selection } = state2;
70520
- let { from: from2, to } = selection;
70521
- let content = selection.content().content;
70522
- const { html: optionsHTML, json: optionsJSON } = options;
70523
- if (optionsHTML) {
70524
- const html = htmlHandler(optionsHTML, this.editor);
70525
- const doc2 = DOMParser$1.fromSchema(this.editor.schema).parse(html);
70526
- content = doc2.content;
70527
- }
70528
- if (optionsJSON) {
70529
- content = this.editor.schema.nodeFromJSON(optionsJSON);
70530
- }
70531
- if (!content?.content?.length) {
70532
- content = this.editor.schema.nodeFromJSON({ type: "paragraph", content: [] });
70533
- }
70534
- if (!options.id) {
70535
- const allSections = SectionHelpers.getAllSections(editor);
70536
- options.id = allSections.length + 1;
70537
- }
70538
- if (!options.title) {
70539
- options.title = "Document section";
70540
- }
70541
- const node = this.type.createAndFill(options, content);
70542
- if (!node) return false;
70543
- const isAlreadyInSdtBlock = findParentNode((node2) => node2.type.name === "documentSection")(selection);
70544
- if (isAlreadyInSdtBlock && isAlreadyInSdtBlock.node) {
70545
- const insertPos2 = isAlreadyInSdtBlock.pos + isAlreadyInSdtBlock.node.nodeSize;
70546
- from2 = insertPos2;
70547
- to = insertPos2;
70548
- }
70549
- tr.replaceRangeWith(from2, to, node);
70550
- const nodeEnd = from2 + node.nodeSize;
70551
- let shouldInsertParagraph = true;
70552
- let insertPos = nodeEnd;
70553
- if (nodeEnd >= tr.doc.content.size) {
70554
- insertPos = tr.doc.content.size;
70555
- if (insertPos > 0) {
70556
- const $endPos = tr.doc.resolve(insertPos);
70557
- if ($endPos.nodeBefore && $endPos.nodeBefore.type.name === "paragraph") {
70558
- shouldInsertParagraph = false;
70559
- }
71288
+ insertHorizontalRule: () => ({ commands: commands2 }) => {
71289
+ return commands2.insertContent({
71290
+ type: this.name,
71291
+ attrs: {
71292
+ horizontalRule: true,
71293
+ size: { width: "100%", height: 2 },
71294
+ background: "#e5e7eb"
70560
71295
  }
70561
- }
70562
- if (shouldInsertParagraph) {
70563
- const emptyParagraph = tr.doc.type.schema.nodes.paragraph.create();
70564
- tr.insert(insertPos, emptyParagraph);
70565
- }
70566
- if (dispatch) {
70567
- tr.setMeta("documentSection", { action: "create" });
70568
- dispatch(tr);
70569
- setTimeout(() => {
70570
- try {
70571
- const currentState = editor.state;
70572
- const docSize = currentState.doc.content.size;
70573
- let targetPos = from2 + node.nodeSize;
70574
- if (shouldInsertParagraph) {
70575
- targetPos += 1;
70576
- }
70577
- targetPos = Math.min(targetPos, docSize);
70578
- if (targetPos < docSize && targetPos > 0) {
70579
- const newSelection = Selection.near(currentState.doc.resolve(targetPos));
70580
- const newTr = currentState.tr.setSelection(newSelection);
70581
- editor.view.dispatch(newTr);
70582
- }
70583
- } catch (e) {
70584
- console.warn("Could not set delayed selection:", e);
70585
- }
70586
- }, 0);
70587
- }
70588
- return true;
70589
- },
70590
- /**
70591
- * Remove section wrapper at cursor, preserving its content
70592
- * @category Command
70593
- * @example
70594
- * editor.commands.removeSectionAtSelection()
70595
- * @note Content stays in document, only section wrapper is removed
70596
- */
70597
- removeSectionAtSelection: () => ({ tr, dispatch }) => {
70598
- const sdtNode = findParentNode((node2) => node2.type.name === "documentSection")(tr.selection);
70599
- if (!sdtNode) return false;
70600
- const { node, pos } = sdtNode;
70601
- const nodeStart = pos;
70602
- const nodeEnd = nodeStart + node.nodeSize;
70603
- const contentToPreserve = node.content;
70604
- tr.delete(nodeStart, nodeEnd);
70605
- if (contentToPreserve.size > 0) {
70606
- tr.insert(nodeStart, contentToPreserve);
70607
- }
70608
- const newPos = Math.min(nodeStart, tr.doc.content.size);
70609
- tr.setSelection(Selection.near(tr.doc.resolve(newPos)));
70610
- if (dispatch) {
70611
- tr.setMeta("documentSection", { action: "delete" });
70612
- dispatch(tr);
70613
- }
70614
- return true;
70615
- },
70616
- /**
70617
- * Delete section and all its content
70618
- * @category Command
70619
- * @param {number} id - Section to delete
70620
- * @example
70621
- * editor.commands.removeSectionById(123)
70622
- */
70623
- removeSectionById: (id) => ({ tr, dispatch }) => {
70624
- const sections = SectionHelpers.getAllSections(this.editor);
70625
- const sectionToRemove = sections.find(({ node: node2 }) => node2.attrs.id === id);
70626
- if (!sectionToRemove) return false;
70627
- const { pos, node } = sectionToRemove;
70628
- const nodeStart = pos;
70629
- const nodeEnd = nodeStart + node.nodeSize;
70630
- tr.delete(nodeStart, nodeEnd);
70631
- if (dispatch) {
70632
- tr.setMeta("documentSection", { action: "delete", id });
70633
- dispatch(tr);
70634
- }
70635
- return true;
71296
+ });
70636
71297
  },
70637
71298
  /**
70638
- * Lock section against edits
71299
+ * Insert a content block
70639
71300
  * @category Command
70640
- * @param {number} id - Section to lock
71301
+ * @param {ContentBlockConfig} config - Block configuration
70641
71302
  * @example
70642
- * editor.commands.lockSectionById(123)
70643
- */
70644
- lockSectionById: (id) => ({ tr, dispatch }) => {
70645
- const sections = SectionHelpers.getAllSections(this.editor);
70646
- const sectionToLock = sections.find(({ node }) => node.attrs.id === id);
70647
- if (!sectionToLock) return false;
70648
- tr.setNodeMarkup(sectionToLock.pos, null, { ...sectionToLock.node.attrs, isLocked: true });
70649
- if (dispatch) {
70650
- tr.setMeta("documentSection", { action: "lock", id });
70651
- dispatch(tr);
70652
- }
70653
- return true;
70654
- },
70655
- /**
70656
- * Modify section attributes or content
70657
- * @category Command
70658
- * @param {SectionUpdate} options - Changes to apply
71303
+ * // Insert a spacer block
71304
+ * editor.commands.insertContentBlock({ size: { height: 20 } })
71305
+ *
70659
71306
  * @example
70660
- * editor.commands.updateSectionById({ id: 123, attrs: { isLocked: false } })
70661
- * editor.commands.updateSectionById({ id: 123, html: '<p>New content</p>' })
70662
- * editor.commands.updateSectionById({
70663
- * id: 123,
70664
- * html: '<p>Updated</p>',
70665
- * attrs: { title: 'New Title' }
71307
+ * // Insert a colored divider
71308
+ * editor.commands.insertContentBlock({
71309
+ * size: { width: '50%', height: 3 },
71310
+ * background: '#3b82f6'
70666
71311
  * })
71312
+ * @note Used for spacing, dividers, and special inline content
70667
71313
  */
70668
- updateSectionById: ({ id, html, json, attrs }) => ({ tr, dispatch, editor }) => {
70669
- const sections = SectionHelpers.getAllSections(editor || this.editor);
70670
- const sectionToUpdate = sections.find(({ node: node2 }) => node2.attrs.id === id);
70671
- if (!sectionToUpdate) return false;
70672
- const { pos, node } = sectionToUpdate;
70673
- let newContent = null;
70674
- if (html) {
70675
- const htmlDoc = htmlHandler(html, editor || this.editor);
70676
- const doc2 = DOMParser$1.fromSchema((editor || this.editor).schema).parse(htmlDoc);
70677
- newContent = doc2.content;
70678
- }
70679
- if (json) {
70680
- newContent = (editor || this.editor).schema.nodeFromJSON(json);
70681
- }
70682
- if (!newContent) {
70683
- newContent = node.content;
70684
- }
70685
- const updatedNode = node.type.create({ ...node.attrs, ...attrs }, newContent, node.marks);
70686
- tr.replaceWith(pos, pos + node.nodeSize, updatedNode);
70687
- if (dispatch) {
70688
- tr.setMeta("documentSection", { action: "update", id, attrs });
70689
- dispatch(tr);
70690
- }
70691
- return true;
71314
+ insertContentBlock: (config2) => ({ commands: commands2 }) => {
71315
+ return commands2.insertContent({
71316
+ type: this.name,
71317
+ attrs: config2
71318
+ });
70692
71319
  }
70693
71320
  };
70694
- },
70695
- addHelpers() {
70696
- return {
70697
- ...SectionHelpers
70698
- };
70699
71321
  }
70700
71322
  });
70701
71323
  const { findChildren } = helpers;
@@ -77263,7 +77885,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
77263
77885
  const prevSelection = prevState.selection;
77264
77886
  if (selection.from !== prevSelection.from || selection.to !== prevSelection.to) {
77265
77887
  setTimeout(() => {
77266
- const selectedResizableWrapper = document.querySelector(".sd-editor-resizable-wrapper");
77888
+ const searchRoot = editorView?.dom;
77889
+ const selectedResizableWrapper = searchRoot?.querySelector(".sd-editor-resizable-wrapper");
77267
77890
  if (selectedResizableWrapper) {
77268
77891
  showResizeHandles(view2, selectedResizableWrapper);
77269
77892
  } else {
@@ -77544,6 +78167,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
77544
78167
  Search,
77545
78168
  StructuredContent,
77546
78169
  StructuredContentBlock,
78170
+ StructuredContentCommands,
77547
78171
  DocumentSection,
77548
78172
  NodeResizer,
77549
78173
  CustomSelection,
@@ -90799,7 +91423,7 @@ ${style2}
90799
91423
  if (!argument) return;
90800
91424
  item.onActivate({ zoom: argument });
90801
91425
  this.emit("superdoc-command", { item, argument });
90802
- const layers = document.querySelector(this.superdoc.config.selector)?.querySelector(".layers");
91426
+ const layers = this.superdoc.element?.querySelector(".layers");
90803
91427
  if (!layers) return;
90804
91428
  const isMobileDevice = typeof screen.orientation !== "undefined";
90805
91429
  const isSmallScreen = window.matchMedia("(max-width: 834px)").matches;
@@ -91861,14 +92485,6 @@ ${style2}
91861
92485
  return null;
91862
92486
  }
91863
92487
  }
91864
- const shouldBypassContextMenu = (event) => {
91865
- if (!event) return false;
91866
- if (event.ctrlKey || event.metaKey) {
91867
- return true;
91868
- }
91869
- const isKeyboardInvocation = event.type === "contextmenu" && typeof event.detail === "number" && event.detail === 0 && (event.button === 0 || event.button === void 0) && event.clientX === 0 && event.clientY === 0;
91870
- return Boolean(isKeyboardInvocation);
91871
- };
91872
92488
  const isModuleEnabled = (editorOptions, moduleName) => {
91873
92489
  switch (moduleName) {
91874
92490
  case "ai":
@@ -96417,7 +97033,7 @@ ${reason}`);
96417
97033
  const c1 = changes[i2];
96418
97034
  const c2 = changes[i2 + 1];
96419
97035
  const c1Key = markMetaKeys[c1.mark.type.name];
96420
- if (c1 && c2 && c1.to === c2.from) {
97036
+ if (c1 && c2 && c1.to === c2.from && c1.mark.attrs.id === c2.mark.attrs.id) {
96421
97037
  const c2Key = markMetaKeys[c2.mark.type.name];
96422
97038
  grouped.push({
96423
97039
  from: c1.from,
@@ -96462,6 +97078,7 @@ ${reason}`);
96462
97078
  const isCommentsListVisible = ref$1(false);
96463
97079
  const editorCommentIds = ref$1([]);
96464
97080
  const editorCommentPositions = ref$1({});
97081
+ const isCommentHighlighted = ref$1(false);
96465
97082
  const floatingCommentsOffset = ref$1(0);
96466
97083
  const sortedConversations = ref$1([]);
96467
97084
  const visibleConversations = ref$1([]);
@@ -96740,8 +97357,8 @@ ${reason}`);
96740
97357
  tr.setMeta(CommentsPluginKey, { type: "forceTrackChanges" });
96741
97358
  tr.setMeta(TrackChangesBasePluginKey, trackChangesPayload);
96742
97359
  }
97360
+ dispatch(tr);
96743
97361
  });
96744
- dispatch(tr);
96745
97362
  };
96746
97363
  const translateCommentsForExport = () => {
96747
97364
  const processedComments = [];
@@ -96811,6 +97428,7 @@ ${reason}`);
96811
97428
  try {
96812
97429
  const normalizedContent = normalizeCommentForEditor(commentTextJson);
96813
97430
  const schemaContent = Array.isArray(normalizedContent) ? normalizedContent[0] : normalizedContent;
97431
+ if (!schemaContent.content.length) return null;
96814
97432
  const editor = new Editor({
96815
97433
  mode: "text",
96816
97434
  isHeadless: true,
@@ -96844,6 +97462,7 @@ ${reason}`);
96844
97462
  commentsParentElement,
96845
97463
  editorCommentPositions,
96846
97464
  hasInitializedLocations,
97465
+ isCommentHighlighted,
96847
97466
  // Floating comments
96848
97467
  floatingCommentsOffset,
96849
97468
  sortedConversations,
@@ -108538,7 +109157,8 @@ ${style2}
108538
109157
  currentCommentText,
108539
109158
  isDebugging: isDebugging2,
108540
109159
  editingCommentId,
108541
- editorCommentPositions
109160
+ editorCommentPositions,
109161
+ isCommentHighlighted
108542
109162
  } = storeToRefs(commentsStore);
108543
109163
  const { activeZoom } = storeToRefs(superdocStore);
108544
109164
  const isInternal = ref$1(true);
@@ -108600,13 +109220,14 @@ ${style2}
108600
109220
  "track-format",
108601
109221
  "track-format-dec"
108602
109222
  ];
108603
- if (excludedClasses.some((className) => e.target.classList.contains(className))) return;
109223
+ if (excludedClasses.some((className) => e.target.classList.contains(className)) || isCommentHighlighted.value) return;
108604
109224
  if (activeComment.value === props.comment.commentId) {
108605
109225
  floatingCommentsOffset.value = 0;
108606
109226
  emit2("dialog-exit");
108607
109227
  }
108608
109228
  activeComment.value = null;
108609
109229
  commentsStore.setActiveComment(proxy.$superdoc, activeComment.value);
109230
+ isCommentHighlighted.value = false;
108610
109231
  };
108611
109232
  const handleAddComment = () => {
108612
109233
  const options = {
@@ -108819,7 +109440,7 @@ ${style2}
108819
109440
  };
108820
109441
  }
108821
109442
  };
108822
- const CommentDialog = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["__scopeId", "data-v-dc5e6675"]]);
109443
+ const CommentDialog = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["__scopeId", "data-v-e07f3426"]]);
108823
109444
  const _hoisted_1$b = { class: "comments-list" };
108824
109445
  const _hoisted_2$5 = { key: 0 };
108825
109446
  const _hoisted_3$3 = { class: "comment-item" };
@@ -109842,7 +110463,8 @@ ${style2}
109842
110463
  getFloatingComments,
109843
110464
  hasSyncedCollaborationComments,
109844
110465
  editorCommentPositions,
109845
- hasInitializedLocations
110466
+ hasInitializedLocations,
110467
+ isCommentHighlighted
109846
110468
  } = storeToRefs(commentsStore);
109847
110469
  const { showAddComment, handleEditorLocationsUpdate, handleTrackedChangeUpdate } = commentsStore;
109848
110470
  const { proxy } = getCurrentInstance();
@@ -110037,6 +110659,7 @@ ${style2}
110037
110659
  nextTick(() => {
110038
110660
  if (pendingComment.value) return;
110039
110661
  commentsStore.setActiveComment(proxy.$superdoc, activeCommentId);
110662
+ isCommentHighlighted.value = true;
110040
110663
  });
110041
110664
  if (typeof proxy.$superdoc.config.onCommentsUpdate === "function") {
110042
110665
  proxy.$superdoc.config.onCommentsUpdate(params2);
@@ -110359,7 +110982,7 @@ ${style2}
110359
110982
  };
110360
110983
  }
110361
110984
  };
110362
- const App = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-dbfba5b9"]]);
110985
+ const App = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-3f71b1bf"]]);
110363
110986
  const createSuperdocVueApp = () => {
110364
110987
  const app = createApp(App);
110365
110988
  const pinia = createPinia();
@@ -110476,6 +111099,9 @@ ${style2}
110476
111099
  this.isDev = this.config.isDev || false;
110477
111100
  this.activeEditor = null;
110478
111101
  this.comments = [];
111102
+ if (!this.config.selector) {
111103
+ throw new Error("SuperDoc: selector is required");
111104
+ }
110479
111105
  this.app.mount(this.config.selector);
110480
111106
  this.readyEditors = 0;
110481
111107
  this.isLocked = this.config.isLocked || false;
@@ -110495,6 +111121,16 @@ ${style2}
110495
111121
  users: this.users
110496
111122
  };
110497
111123
  }
111124
+ /**
111125
+ * Get the SuperDoc container element
111126
+ * @returns {HTMLElement | null}
111127
+ */
111128
+ get element() {
111129
+ if (typeof this.config.selector === "string") {
111130
+ return document.querySelector(this.config.selector);
111131
+ }
111132
+ return this.config.selector;
111133
+ }
110498
111134
  #patchNaiveUIStyles() {
110499
111135
  const cspNonce = this.config.cspNonce;
110500
111136
  const originalCreateElement = document.createElement;
@@ -110518,10 +111154,16 @@ ${style2}
110518
111154
  }
110519
111155
  if (hasDocumentConfig) {
110520
111156
  const normalized = normalizeDocumentEntry(this.config.document);
110521
- this.config.documents = [normalized];
111157
+ this.config.documents = [
111158
+ {
111159
+ id: v4(),
111160
+ ...normalized
111161
+ }
111162
+ ];
110522
111163
  } else if (hasDocumentUrl) {
110523
111164
  this.config.documents = [
110524
111165
  {
111166
+ id: v4(),
110525
111167
  type: DOCX,
110526
111168
  url: this.config.document,
110527
111169
  name: "document.docx",
@@ -110529,33 +111171,34 @@ ${style2}
110529
111171
  }
110530
111172
  ];
110531
111173
  } else if (hasDocumentFile) {
111174
+ const normalized = normalizeDocumentEntry(this.config.document);
110532
111175
  this.config.documents = [
110533
111176
  {
110534
- type: this.config.document.type,
110535
- data: this.config.document,
110536
- name: this.config.document.name,
110537
- isNewFile: true
111177
+ id: v4(),
111178
+ ...normalized
110538
111179
  }
110539
111180
  ];
110540
111181
  } else if (hasDocumentBlob) {
110541
- const docType = this.config.document.type || DOCX;
110542
- let extension = ".docx";
110543
- if (docType === PDF) {
110544
- extension = ".pdf";
110545
- } else if (docType === HTML) {
110546
- extension = ".html";
110547
- }
111182
+ const normalized = normalizeDocumentEntry(this.config.document);
110548
111183
  this.config.documents = [
110549
111184
  {
110550
- type: docType,
110551
- data: this.config.document,
110552
- name: `document${extension}`,
110553
- isNewFile: true
111185
+ id: v4(),
111186
+ ...normalized
110554
111187
  }
110555
111188
  ];
110556
111189
  }
110557
111190
  if (Array.isArray(this.config.documents) && this.config.documents.length > 0) {
110558
- this.config.documents = this.config.documents.map((d2) => normalizeDocumentEntry(d2));
111191
+ this.config.documents = this.config.documents.map((d2) => {
111192
+ const normalized = normalizeDocumentEntry(d2);
111193
+ if (!normalized || typeof normalized !== "object") {
111194
+ return normalized;
111195
+ }
111196
+ const existingId = typeof normalized === "object" && "id" in normalized && normalized.id || d2 && typeof d2 === "object" && "id" in d2 && d2.id;
111197
+ return {
111198
+ ...normalized,
111199
+ id: existingId || v4()
111200
+ };
111201
+ });
110559
111202
  }
110560
111203
  }
110561
111204
  #initVueApp() {