@mdaemon/html-editor 1.0.6 → 1.0.7

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.
package/dist/index.mjs CHANGED
@@ -12428,7 +12428,6 @@ function isMarkInSet(marks, type, attributes = {}) {
12428
12428
  return !!findMarkInSet(marks, type, attributes);
12429
12429
  }
12430
12430
  function getMarkRange($pos, type, attributes) {
12431
- var _a;
12432
12431
  if (!$pos || !type) {
12433
12432
  return;
12434
12433
  }
@@ -12439,7 +12438,12 @@ function getMarkRange($pos, type, attributes) {
12439
12438
  if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) {
12440
12439
  return;
12441
12440
  }
12442
- attributes = attributes || ((_a = start.node.marks[0]) == null ? void 0 : _a.attrs);
12441
+ if (!attributes) {
12442
+ const firstMark = start.node.marks.find((mark2) => mark2.type === type);
12443
+ if (firstMark) {
12444
+ attributes = firstMark.attrs;
12445
+ }
12446
+ }
12443
12447
  const mark = findMarkInSet([...start.node.marks], type, attributes);
12444
12448
  if (!mark) {
12445
12449
  return;
@@ -12470,7 +12474,7 @@ function getMarkType(nameOrType, schema) {
12470
12474
  }
12471
12475
  return nameOrType;
12472
12476
  }
12473
- var extendMarkRange = (typeOrName, attributes = {}) => ({ tr: tr2, state, dispatch }) => {
12477
+ var extendMarkRange = (typeOrName, attributes) => ({ tr: tr2, state, dispatch }) => {
12474
12478
  const type = getMarkType(typeOrName, state.schema);
12475
12479
  const { doc: doc2, selection } = tr2;
12476
12480
  const { $from, from: from2, to } = selection;
@@ -12781,7 +12785,7 @@ var insertContentAt = (position, value, options) => ({ tr: tr2, dispatch, editor
12781
12785
  const fromSelectionAtStart = $from.parentOffset === 0;
12782
12786
  const isTextSelection2 = $fromNode.isText || $fromNode.isTextblock;
12783
12787
  const hasContent = $fromNode.content.size > 0;
12784
- if (fromSelectionAtStart && isTextSelection2 && hasContent) {
12788
+ if (fromSelectionAtStart && isTextSelection2 && hasContent && isOnlyBlockContent) {
12785
12789
  from2 = Math.max(0, from2 - 1);
12786
12790
  }
12787
12791
  tr2.replaceWith(from2, to, newContent);
@@ -13224,6 +13228,9 @@ function getAttributesFromExtensions(extensions) {
13224
13228
  keepOnSplit: true,
13225
13229
  isRequired: false
13226
13230
  };
13231
+ const nodeExtensionTypes = nodeExtensions.filter((ext) => ext.name !== "text").map((ext) => ext.name);
13232
+ const markExtensionTypes = markExtensions.map((ext) => ext.name);
13233
+ const allExtensionTypes = [...nodeExtensionTypes, ...markExtensionTypes];
13227
13234
  extensions.forEach((extension) => {
13228
13235
  const context = {
13229
13236
  name: extension.name,
@@ -13241,7 +13248,19 @@ function getAttributesFromExtensions(extensions) {
13241
13248
  }
13242
13249
  const globalAttributes = addGlobalAttributes();
13243
13250
  globalAttributes.forEach((globalAttribute) => {
13244
- globalAttribute.types.forEach((type) => {
13251
+ let resolvedTypes;
13252
+ if (Array.isArray(globalAttribute.types)) {
13253
+ resolvedTypes = globalAttribute.types;
13254
+ } else if (globalAttribute.types === "*") {
13255
+ resolvedTypes = allExtensionTypes;
13256
+ } else if (globalAttribute.types === "nodes") {
13257
+ resolvedTypes = nodeExtensionTypes;
13258
+ } else if (globalAttribute.types === "marks") {
13259
+ resolvedTypes = markExtensionTypes;
13260
+ } else {
13261
+ resolvedTypes = [];
13262
+ }
13263
+ resolvedTypes.forEach((type) => {
13245
13264
  Object.entries(globalAttribute.attributes).forEach(([name, attribute]) => {
13246
13265
  extensionAttributes.push({
13247
13266
  type,
@@ -13290,6 +13309,67 @@ function getAttributesFromExtensions(extensions) {
13290
13309
  });
13291
13310
  return extensionAttributes;
13292
13311
  }
13312
+ function splitStyleDeclarations(styles) {
13313
+ const result = [];
13314
+ let current = "";
13315
+ let inSingleQuote = false;
13316
+ let inDoubleQuote = false;
13317
+ let parenDepth = 0;
13318
+ const length = styles.length;
13319
+ for (let i = 0; i < length; i += 1) {
13320
+ const char = styles[i];
13321
+ if (char === "'" && !inDoubleQuote) {
13322
+ inSingleQuote = !inSingleQuote;
13323
+ current += char;
13324
+ continue;
13325
+ }
13326
+ if (char === '"' && !inSingleQuote) {
13327
+ inDoubleQuote = !inDoubleQuote;
13328
+ current += char;
13329
+ continue;
13330
+ }
13331
+ if (!inSingleQuote && !inDoubleQuote) {
13332
+ if (char === "(") {
13333
+ parenDepth += 1;
13334
+ current += char;
13335
+ continue;
13336
+ }
13337
+ if (char === ")" && parenDepth > 0) {
13338
+ parenDepth -= 1;
13339
+ current += char;
13340
+ continue;
13341
+ }
13342
+ if (char === ";" && parenDepth === 0) {
13343
+ result.push(current);
13344
+ current = "";
13345
+ continue;
13346
+ }
13347
+ }
13348
+ current += char;
13349
+ }
13350
+ if (current) {
13351
+ result.push(current);
13352
+ }
13353
+ return result;
13354
+ }
13355
+ function parseStyleEntries(styles) {
13356
+ const pairs = [];
13357
+ const declarations = splitStyleDeclarations(styles || "");
13358
+ const numDeclarations = declarations.length;
13359
+ for (let i = 0; i < numDeclarations; i += 1) {
13360
+ const declaration = declarations[i];
13361
+ const firstColonIndex = declaration.indexOf(":");
13362
+ if (firstColonIndex === -1) {
13363
+ continue;
13364
+ }
13365
+ const property = declaration.slice(0, firstColonIndex).trim();
13366
+ const value = declaration.slice(firstColonIndex + 1).trim();
13367
+ if (property && value) {
13368
+ pairs.push([property, value]);
13369
+ }
13370
+ }
13371
+ return pairs;
13372
+ }
13293
13373
  function mergeAttributes(...objects) {
13294
13374
  return objects.filter((item) => !!item).reduce((items, item) => {
13295
13375
  const mergedAttributes = { ...items };
@@ -13305,17 +13385,7 @@ function mergeAttributes(...objects) {
13305
13385
  const insertClasses = valueClasses.filter((valueClass) => !existingClasses.includes(valueClass));
13306
13386
  mergedAttributes[key] = [...existingClasses, ...insertClasses].join(" ");
13307
13387
  } else if (key === "style") {
13308
- const newStyles = value ? value.split(";").map((style2) => style2.trim()).filter(Boolean) : [];
13309
- const existingStyles = mergedAttributes[key] ? mergedAttributes[key].split(";").map((style2) => style2.trim()).filter(Boolean) : [];
13310
- const styleMap = /* @__PURE__ */ new Map();
13311
- existingStyles.forEach((style2) => {
13312
- const [property, val] = style2.split(":").map((part) => part.trim());
13313
- styleMap.set(property, val);
13314
- });
13315
- newStyles.forEach((style2) => {
13316
- const [property, val] = style2.split(":").map((part) => part.trim());
13317
- styleMap.set(property, val);
13318
- });
13388
+ const styleMap = new Map([...parseStyleEntries(mergedAttributes[key]), ...parseStyleEntries(value)]);
13319
13389
  mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join("; ");
13320
13390
  } else {
13321
13391
  mergedAttributes[key] = value;
@@ -13739,6 +13809,9 @@ function isMarkActive(state, typeOrName, attributes = {}) {
13739
13809
  const from2 = $from.pos;
13740
13810
  const to = $to.pos;
13741
13811
  state.doc.nodesBetween(from2, to, (node, pos) => {
13812
+ if (type && node.inlineContent && !node.type.allowsMarkType(type)) {
13813
+ return false;
13814
+ }
13742
13815
  if (!node.isText && !node.marks.length) {
13743
13816
  return;
13744
13817
  }
@@ -13847,7 +13920,7 @@ function isNodeEmpty(node, {
13847
13920
  return true;
13848
13921
  }
13849
13922
  if (node.isText) {
13850
- return /^\s*$/m.test((_a = node.text) != null ? _a : "");
13923
+ return !/\S/.test((_a = node.text) != null ? _a : "");
13851
13924
  }
13852
13925
  }
13853
13926
  if (node.isText) {
@@ -14235,6 +14308,16 @@ var joinListForwards = (tr2, listType) => {
14235
14308
  tr2.join(after);
14236
14309
  return true;
14237
14310
  };
14311
+ function createInnerSelectionForWholeDocList(tr2) {
14312
+ const doc2 = tr2.doc;
14313
+ const list = doc2.firstChild;
14314
+ if (!list) {
14315
+ return null;
14316
+ }
14317
+ const from2 = 1;
14318
+ const to = list.nodeSize - 1;
14319
+ return TextSelection.create(doc2, from2, to);
14320
+ }
14238
14321
  var toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) => ({ editor, tr: tr2, state, dispatch, chain, commands, can }) => {
14239
14322
  const { extensions, splittableMarks } = editor.extensionManager;
14240
14323
  const listType = getNodeType(listTypeOrName, state.schema);
@@ -14247,13 +14330,36 @@ var toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) =>
14247
14330
  return false;
14248
14331
  }
14249
14332
  const parentList = findParentNode((node) => isList(node.type.name, extensions))(selection);
14250
- if (range.depth >= 1 && parentList && range.depth - parentList.depth <= 1) {
14251
- if (parentList.node.type === listType) {
14333
+ const isAllSelection = selection.from === 0 && selection.to === state.doc.content.size;
14334
+ const topLevelNodes = state.doc.content.content;
14335
+ const soleTopLevelNode = topLevelNodes.length === 1 ? topLevelNodes[0] : null;
14336
+ const allSelectionList = isAllSelection && soleTopLevelNode && isList(soleTopLevelNode.type.name, extensions) ? {
14337
+ node: soleTopLevelNode,
14338
+ pos: 0
14339
+ } : null;
14340
+ const currentList = parentList != null ? parentList : allSelectionList;
14341
+ const isInsideExistingList = !!parentList && range.depth >= 1 && range.depth - parentList.depth <= 1;
14342
+ const hasWholeDocSelectedList = !!allSelectionList;
14343
+ if ((isInsideExistingList || hasWholeDocSelectedList) && currentList) {
14344
+ if (currentList.node.type === listType) {
14345
+ if (isAllSelection && hasWholeDocSelectedList) {
14346
+ return chain().command(({ tr: trx, dispatch: disp }) => {
14347
+ const nextSelection = createInnerSelectionForWholeDocList(trx);
14348
+ if (!nextSelection) {
14349
+ return false;
14350
+ }
14351
+ trx.setSelection(nextSelection);
14352
+ if (disp) {
14353
+ disp(trx);
14354
+ }
14355
+ return true;
14356
+ }).liftListItem(itemType).run();
14357
+ }
14252
14358
  return commands.liftListItem(itemType);
14253
14359
  }
14254
- if (isList(parentList.node.type.name, extensions) && listType.validContent(parentList.node.content) && dispatch) {
14360
+ if (isList(currentList.node.type.name, extensions) && listType.validContent(currentList.node.content)) {
14255
14361
  return chain().command(() => {
14256
- tr2.setNodeMarkup(parentList.pos, listType);
14362
+ tr2.setNodeMarkup(currentList.pos, listType);
14257
14363
  return true;
14258
14364
  }).command(() => joinListBackwards(tr2, listType)).command(() => joinListForwards(tr2, listType)).run();
14259
14365
  }
@@ -15247,6 +15353,39 @@ var ExtensionManager = class {
15247
15353
  };
15248
15354
  }, baseDispatch);
15249
15355
  }
15356
+ /**
15357
+ * Get the composed transformPastedHTML function from all extensions.
15358
+ * @param baseTransform The base transform function (e.g. from the editor props)
15359
+ * @returns A composed transform function that chains all extension transforms
15360
+ */
15361
+ transformPastedHTML(baseTransform) {
15362
+ const { editor } = this;
15363
+ const extensions = sortExtensions([...this.extensions]);
15364
+ return extensions.reduce(
15365
+ (transform, extension) => {
15366
+ const context = {
15367
+ name: extension.name,
15368
+ options: extension.options,
15369
+ storage: this.editor.extensionStorage[extension.name],
15370
+ editor,
15371
+ type: getSchemaTypeByName(extension.name, this.schema)
15372
+ };
15373
+ const extensionTransform = getExtensionField(
15374
+ extension,
15375
+ "transformPastedHTML",
15376
+ context
15377
+ );
15378
+ if (!extensionTransform) {
15379
+ return transform;
15380
+ }
15381
+ return (html, view) => {
15382
+ const transformedHtml = transform(html, view);
15383
+ return extensionTransform.call(context, transformedHtml);
15384
+ };
15385
+ },
15386
+ baseTransform || ((html) => html)
15387
+ );
15388
+ }
15250
15389
  get markViews() {
15251
15390
  const { editor } = this;
15252
15391
  const { markExtensions } = splitExtensions(this.extensions);
@@ -15465,7 +15604,7 @@ var Delete = Extension.create({
15465
15604
  const newEnd = mapping.slice(index).map(step.to);
15466
15605
  const oldStart = mapping.invert().map(newStart, -1);
15467
15606
  const oldEnd = mapping.invert().map(newEnd);
15468
- const foundBeforeMark = (_a3 = nextTransaction.doc.nodeAt(newStart - 1)) == null ? void 0 : _a3.marks.some((mark) => mark.eq(step.mark));
15607
+ const foundBeforeMark = newStart > 0 ? (_a3 = nextTransaction.doc.nodeAt(newStart - 1)) == null ? void 0 : _a3.marks.some((mark) => mark.eq(step.mark)) : false;
15469
15608
  const foundAfterMark = (_b3 = nextTransaction.doc.nodeAt(newEnd)) == null ? void 0 : _b3.marks.some((mark) => mark.eq(step.mark));
15470
15609
  this.editor.emit("delete", {
15471
15610
  type: "mark",
@@ -16217,7 +16356,7 @@ var Editor = class extends EventEmitter {
16217
16356
  return this.options.editable && this.view && this.view.editable;
16218
16357
  }
16219
16358
  /**
16220
- * Returns the editor state.
16359
+ * Returns the editor view.
16221
16360
  */
16222
16361
  get view() {
16223
16362
  if (this.editorView) {
@@ -16385,6 +16524,8 @@ var Editor = class extends EventEmitter {
16385
16524
  const { editorProps, enableExtensionDispatchTransaction } = this.options;
16386
16525
  const baseDispatch = editorProps.dispatchTransaction || this.dispatchTransaction.bind(this);
16387
16526
  const dispatch = enableExtensionDispatchTransaction ? this.extensionManager.dispatchTransaction(baseDispatch) : baseDispatch;
16527
+ const baseTransformPastedHTML = editorProps.transformPastedHTML;
16528
+ const transformPastedHTML = this.extensionManager.transformPastedHTML(baseTransformPastedHTML);
16388
16529
  this.editorView = new EditorView(element, {
16389
16530
  ...editorProps,
16390
16531
  attributes: {
@@ -16393,6 +16534,7 @@ var Editor = class extends EventEmitter {
16393
16534
  ...editorProps == null ? void 0 : editorProps.attributes
16394
16535
  },
16395
16536
  dispatchTransaction: dispatch,
16537
+ transformPastedHTML,
16396
16538
  state: this.editorState,
16397
16539
  markViews: this.extensionManager.markViews,
16398
16540
  nodeViews: this.extensionManager.nodeViews
@@ -16900,7 +17042,7 @@ var ResizableNodeView = class {
16900
17042
  const element = document.createElement("div");
16901
17043
  element.dataset.resizeContainer = "";
16902
17044
  element.dataset.node = this.node.type.name;
16903
- element.style.display = "flex";
17045
+ element.style.display = this.node.type.isInline ? "inline-flex" : "flex";
16904
17046
  if (this.classNames.container) {
16905
17047
  element.className = this.classNames.container;
16906
17048
  }
@@ -17702,17 +17844,21 @@ function renderNestedMarkdownContent(node, h2, prefixOrGenerator, ctx) {
17702
17844
  const prefix = typeof prefixOrGenerator === "function" ? prefixOrGenerator(ctx) : prefixOrGenerator;
17703
17845
  const [content, ...children] = node.content;
17704
17846
  const mainContent = h2.renderChildren([content]);
17705
- const output = [`${prefix}${mainContent}`];
17847
+ let output = `${prefix}${mainContent}`;
17706
17848
  if (children && children.length > 0) {
17707
- children.forEach((child) => {
17708
- const childContent = h2.renderChildren([child]);
17709
- if (childContent) {
17710
- const indentedChild = childContent.split("\n").map((line) => line ? h2.indent(line) : "").join("\n");
17711
- output.push(indentedChild);
17849
+ children.forEach((child, index) => {
17850
+ var _a, _b;
17851
+ const childContent = (_b = (_a = h2.renderChild) == null ? void 0 : _a.call(h2, child, index + 1)) != null ? _b : h2.renderChildren([child]);
17852
+ if (childContent !== void 0 && childContent !== null) {
17853
+ const indentedChild = childContent.split("\n").map((line) => line ? h2.indent(line) : h2.indent("")).join("\n");
17854
+ output += child.type === "paragraph" ? `
17855
+
17856
+ ${indentedChild}` : `
17857
+ ${indentedChild}`;
17712
17858
  }
17713
17859
  });
17714
17860
  }
17715
- return output.join("\n");
17861
+ return output;
17716
17862
  }
17717
17863
  function updateMarkViewAttributes(checkMark, editor, attrs = {}) {
17718
17864
  const { state } = editor;
@@ -17802,7 +17948,10 @@ function markPasteRule(config) {
17802
17948
  }
17803
17949
  markEnd = range.from + startSpaces + captureGroup.length;
17804
17950
  tr2.addMark(range.from + startSpaces, markEnd, config.type.create(attributes || {}));
17805
- tr2.removeStoredMark(config.type);
17951
+ const isMatchAtEndOfText = match.index !== void 0 && match.input !== void 0 && match.index + match[0].length >= match.input.length;
17952
+ if (!isMatchAtEndOfText) {
17953
+ tr2.removeStoredMark(config.type);
17954
+ }
17806
17955
  }
17807
17956
  }
17808
17957
  });
@@ -17838,7 +17987,9 @@ var Blockquote = Node3.create({
17838
17987
  return /* @__PURE__ */ h("blockquote", { ...mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), children: /* @__PURE__ */ h("slot", {}) });
17839
17988
  },
17840
17989
  parseMarkdown: (token, helpers) => {
17841
- return helpers.createNode("blockquote", void 0, helpers.parseChildren(token.tokens || []));
17990
+ var _a;
17991
+ const parseBlockChildren = (_a = helpers.parseBlockChildren) != null ? _a : helpers.parseChildren;
17992
+ return helpers.createNode("blockquote", void 0, parseBlockChildren(token.tokens || []));
17842
17993
  },
17843
17994
  renderMarkdown: (node, h2) => {
17844
17995
  if (!node.content) {
@@ -17846,8 +17997,9 @@ var Blockquote = Node3.create({
17846
17997
  }
17847
17998
  const prefix = ">";
17848
17999
  const result = [];
17849
- node.content.forEach((child) => {
17850
- const childContent = h2.renderChildren([child]);
18000
+ node.content.forEach((child, index) => {
18001
+ var _a, _b;
18002
+ const childContent = (_b = (_a = h2.renderChild) == null ? void 0 : _a.call(h2, child, index)) != null ? _b : h2.renderChildren([child]);
17851
18003
  const lines = childContent.split("\n");
17852
18004
  const linesWithPrefix = lines.map((line) => {
17853
18005
  if (line.trim() === "") {
@@ -17925,6 +18077,12 @@ var Bold = Mark2.create({
17925
18077
  parseMarkdown: (token, helpers) => {
17926
18078
  return helpers.applyMark("bold", helpers.parseInline(token.tokens || []));
17927
18079
  },
18080
+ markdownOptions: {
18081
+ htmlReopen: {
18082
+ open: "<strong>",
18083
+ close: "</strong>"
18084
+ }
18085
+ },
17928
18086
  renderMarkdown: (node, h2) => {
17929
18087
  return `**${h2.renderChildren(node)}**`;
17930
18088
  },
@@ -18101,8 +18259,8 @@ var CodeBlock = Node3.create({
18101
18259
  },
18102
18260
  markdownTokenName: "code",
18103
18261
  parseMarkdown: (token, helpers) => {
18104
- var _a;
18105
- if (((_a = token.raw) == null ? void 0 : _a.startsWith("```")) === false && token.codeBlockStyle !== "indented") {
18262
+ var _a, _b;
18263
+ if (((_a = token.raw) == null ? void 0 : _a.startsWith("```")) === false && ((_b = token.raw) == null ? void 0 : _b.startsWith("~~~")) === false && token.codeBlockStyle !== "indented") {
18106
18264
  return [];
18107
18265
  }
18108
18266
  return helpers.createNode(
@@ -18344,7 +18502,6 @@ var CodeBlock = Node3.create({
18344
18502
  ];
18345
18503
  }
18346
18504
  });
18347
- var index_default = CodeBlock;
18348
18505
  var Document = Node3.create({
18349
18506
  name: "doc",
18350
18507
  topNode: true,
@@ -18621,6 +18778,12 @@ var Italic = Mark2.create({
18621
18778
  parseMarkdown: (token, helpers) => {
18622
18779
  return helpers.applyMark("italic", helpers.parseInline(token.tokens || []));
18623
18780
  },
18781
+ markdownOptions: {
18782
+ htmlReopen: {
18783
+ open: "<em>",
18784
+ close: "</em>"
18785
+ }
18786
+ },
18624
18787
  renderMarkdown: (node, h2) => {
18625
18788
  return `*${h2.renderChildren(node)}*`;
18626
18789
  },
@@ -20319,14 +20482,16 @@ var ListItem = Node3.create({
20319
20482
  },
20320
20483
  markdownTokenName: "list_item",
20321
20484
  parseMarkdown: (token, helpers) => {
20485
+ var _a;
20322
20486
  if (token.type !== "list_item") {
20323
20487
  return [];
20324
20488
  }
20489
+ const parseBlockChildren = (_a = helpers.parseBlockChildren) != null ? _a : helpers.parseChildren;
20325
20490
  let content = [];
20326
20491
  if (token.tokens && token.tokens.length > 0) {
20327
20492
  const hasParagraphTokens = token.tokens.some((t) => t.type === "paragraph");
20328
20493
  if (hasParagraphTokens) {
20329
- content = helpers.parseChildren(token.tokens);
20494
+ content = parseBlockChildren(token.tokens);
20330
20495
  } else {
20331
20496
  const firstToken = token.tokens[0];
20332
20497
  if (firstToken && firstToken.type === "text" && firstToken.tokens && firstToken.tokens.length > 0) {
@@ -20339,11 +20504,11 @@ var ListItem = Node3.create({
20339
20504
  ];
20340
20505
  if (token.tokens.length > 1) {
20341
20506
  const remainingTokens = token.tokens.slice(1);
20342
- const additionalContent = helpers.parseChildren(remainingTokens);
20507
+ const additionalContent = parseBlockChildren(remainingTokens);
20343
20508
  content.push(...additionalContent);
20344
20509
  }
20345
20510
  } else {
20346
- content = helpers.parseChildren(token.tokens);
20511
+ content = parseBlockChildren(token.tokens);
20347
20512
  }
20348
20513
  }
20349
20514
  }
@@ -21261,18 +21426,22 @@ var Paragraph = Node3.create({
21261
21426
  return helpers.parseChildren([tokens[0]]);
21262
21427
  }
21263
21428
  const content = helpers.parseInline(tokens);
21264
- if (content.length === 1 && content[0].type === "text" && (content[0].text === EMPTY_PARAGRAPH_MARKDOWN || content[0].text === NBSP_CHAR)) {
21429
+ const hasExplicitEmptyParagraphMarker = tokens.length === 1 && tokens[0].type === "text" && (tokens[0].raw === EMPTY_PARAGRAPH_MARKDOWN || tokens[0].text === EMPTY_PARAGRAPH_MARKDOWN || tokens[0].raw === NBSP_CHAR || tokens[0].text === NBSP_CHAR);
21430
+ if (hasExplicitEmptyParagraphMarker && content.length === 1 && content[0].type === "text" && (content[0].text === EMPTY_PARAGRAPH_MARKDOWN || content[0].text === NBSP_CHAR)) {
21265
21431
  return helpers.createNode("paragraph", void 0, []);
21266
21432
  }
21267
21433
  return helpers.createNode("paragraph", void 0, content);
21268
21434
  },
21269
- renderMarkdown: (node, h2) => {
21435
+ renderMarkdown: (node, h2, ctx) => {
21436
+ var _a, _b;
21270
21437
  if (!node) {
21271
21438
  return "";
21272
21439
  }
21273
21440
  const content = Array.isArray(node.content) ? node.content : [];
21274
21441
  if (content.length === 0) {
21275
- return EMPTY_PARAGRAPH_MARKDOWN;
21442
+ const previousContent = Array.isArray((_a = ctx == null ? void 0 : ctx.previousNode) == null ? void 0 : _a.content) ? ctx.previousNode.content : [];
21443
+ const previousNodeIsEmptyParagraph = ((_b = ctx == null ? void 0 : ctx.previousNode) == null ? void 0 : _b.type) === "paragraph" && previousContent.length === 0;
21444
+ return previousNodeIsEmptyParagraph ? EMPTY_PARAGRAPH_MARKDOWN : "";
21276
21445
  }
21277
21446
  return h2.renderChildren(content);
21278
21447
  },
@@ -22531,6 +22700,9 @@ var Placeholder = Extension.create({
22531
22700
  doc2.descendants((node, pos) => {
22532
22701
  const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
22533
22702
  const isEmpty2 = !node.isLeaf && isNodeEmpty(node);
22703
+ if (!node.type.isTextblock) {
22704
+ return this.options.includeChildren;
22705
+ }
22534
22706
  if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty2) {
22535
22707
  const classes = [this.options.emptyNodeClass];
22536
22708
  if (isEmptyDoc) {
@@ -22584,6 +22756,7 @@ Extension.create({
22584
22756
  ];
22585
22757
  }
22586
22758
  });
22759
+ var skipTrailingNodeMeta = "skipTrailingNode";
22587
22760
  function nodeEqualsType({ types, node }) {
22588
22761
  return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
22589
22762
  }
@@ -22603,11 +22776,14 @@ var TrailingNode = Extension.create({
22603
22776
  return [
22604
22777
  new Plugin({
22605
22778
  key: plugin,
22606
- appendTransaction: (_, __, state) => {
22779
+ appendTransaction: (transactions, __, state) => {
22607
22780
  const { doc: doc2, tr: tr2, schema } = state;
22608
22781
  const shouldInsertNodeAtEnd = plugin.getState(state);
22609
22782
  const endPosition = doc2.content.size;
22610
22783
  const type = schema.nodes[defaultNode];
22784
+ if (transactions.some((transaction) => transaction.getMeta(skipTrailingNodeMeta))) {
22785
+ return;
22786
+ }
22611
22787
  if (!shouldInsertNodeAtEnd) {
22612
22788
  return;
22613
22789
  }
@@ -25105,6 +25281,35 @@ function tableEditing({ allowTableNodeSelection = false } = {}) {
25105
25281
  }
25106
25282
  });
25107
25283
  }
25284
+ function normalizeTableCellAlign(value) {
25285
+ if (value === "left" || value === "right" || value === "center") {
25286
+ return value;
25287
+ }
25288
+ return null;
25289
+ }
25290
+ function parseAlign(element) {
25291
+ const styleAlign = (element.style.textAlign || "").trim().toLowerCase();
25292
+ const attrAlign = (element.getAttribute("align") || "").trim().toLowerCase();
25293
+ const align = styleAlign || attrAlign;
25294
+ return normalizeTableCellAlign(align);
25295
+ }
25296
+ function normalizeTableCellAlignFromAttributes(attributes) {
25297
+ return normalizeTableCellAlign(attributes == null ? void 0 : attributes.align);
25298
+ }
25299
+ function createAlignAttribute() {
25300
+ return {
25301
+ default: null,
25302
+ parseHTML: (element) => parseAlign(element),
25303
+ renderHTML: (attributes) => {
25304
+ if (!attributes.align) {
25305
+ return {};
25306
+ }
25307
+ return {
25308
+ style: `text-align: ${attributes.align}`
25309
+ };
25310
+ }
25311
+ };
25312
+ }
25108
25313
  var TableCell = Node3.create({
25109
25314
  name: "tableCell",
25110
25315
  addOptions() {
@@ -25137,7 +25342,8 @@ var TableCell = Node3.create({
25137
25342
  }
25138
25343
  return value;
25139
25344
  }
25140
- }
25345
+ },
25346
+ align: createAlignAttribute()
25141
25347
  };
25142
25348
  },
25143
25349
  tableRole: "cell",
@@ -25172,7 +25378,8 @@ var TableHeader = Node3.create({
25172
25378
  const value = colwidth ? colwidth.split(",").map((width) => parseInt(width, 10)) : null;
25173
25379
  return value;
25174
25380
  }
25175
- }
25381
+ },
25382
+ align: createAlignAttribute()
25176
25383
  };
25177
25384
  },
25178
25385
  tableRole: "header_cell",
@@ -25400,7 +25607,8 @@ function renderTableToMarkdown(node, h2, options = {}) {
25400
25607
  }
25401
25608
  const text = collapseWhitespace(raw);
25402
25609
  const isHeader = cellNode.type === "tableHeader";
25403
- cells.push({ text, isHeader });
25610
+ const align = normalizeTableCellAlignFromAttributes(cellNode.attrs);
25611
+ cells.push({ text, isHeader, align });
25404
25612
  });
25405
25613
  }
25406
25614
  rows.push(cells);
@@ -25426,11 +25634,33 @@ function renderTableToMarkdown(node, h2, options = {}) {
25426
25634
  const pad = (s, width) => s + " ".repeat(Math.max(0, width - s.length));
25427
25635
  const headerRow = rows[0];
25428
25636
  const hasHeader = headerRow.some((c2) => c2.isHeader);
25637
+ const colAlignments = new Array(columnCount).fill(null);
25638
+ rows.forEach((r2) => {
25639
+ var _a2;
25640
+ for (let i = 0; i < columnCount; i += 1) {
25641
+ if (!colAlignments[i] && ((_a2 = r2[i]) == null ? void 0 : _a2.align)) {
25642
+ colAlignments[i] = r2[i].align;
25643
+ }
25644
+ }
25645
+ });
25429
25646
  let out = "\n";
25430
25647
  const headerTexts = new Array(columnCount).fill(0).map((_, i) => hasHeader ? headerRow[i] && headerRow[i].text || "" : "");
25431
25648
  out += `| ${headerTexts.map((t, i) => pad(t, colWidths[i])).join(" | ")} |
25432
25649
  `;
25433
- out += `| ${colWidths.map((w) => "-".repeat(Math.max(3, w))).join(" | ")} |
25650
+ out += `| ${colWidths.map((w, index) => {
25651
+ const dashCount = Math.max(3, w);
25652
+ const alignment = colAlignments[index];
25653
+ if (alignment === "left") {
25654
+ return `:${"-".repeat(dashCount)}`;
25655
+ }
25656
+ if (alignment === "right") {
25657
+ return `${"-".repeat(dashCount)}:`;
25658
+ }
25659
+ if (alignment === "center") {
25660
+ return `:${"-".repeat(dashCount)}:`;
25661
+ }
25662
+ return "-".repeat(dashCount);
25663
+ }).join(" | ")} |
25434
25664
  `;
25435
25665
  const body = hasHeader ? rows.slice(1) : rows;
25436
25666
  body.forEach((r2) => {
@@ -25484,18 +25714,27 @@ var Table = Node3.create({
25484
25714
  },
25485
25715
  parseMarkdown: (token, h2) => {
25486
25716
  const rows = [];
25717
+ const alignments = Array.isArray(token.align) ? token.align : [];
25487
25718
  if (token.header) {
25488
25719
  const headerCells = [];
25489
- token.header.forEach((cell) => {
25490
- headerCells.push(h2.createNode("tableHeader", {}, [{ type: "paragraph", content: h2.parseInline(cell.tokens) }]));
25720
+ token.header.forEach((cell, index) => {
25721
+ var _a;
25722
+ const align = normalizeTableCellAlign((_a = alignments[index]) != null ? _a : cell.align);
25723
+ const attrs = align ? { align } : {};
25724
+ headerCells.push(
25725
+ h2.createNode("tableHeader", attrs, [{ type: "paragraph", content: h2.parseInline(cell.tokens) }])
25726
+ );
25491
25727
  });
25492
25728
  rows.push(h2.createNode("tableRow", {}, headerCells));
25493
25729
  }
25494
25730
  if (token.rows) {
25495
25731
  token.rows.forEach((row) => {
25496
25732
  const bodyCells = [];
25497
- row.forEach((cell) => {
25498
- bodyCells.push(h2.createNode("tableCell", {}, [{ type: "paragraph", content: h2.parseInline(cell.tokens) }]));
25733
+ row.forEach((cell, index) => {
25734
+ var _a;
25735
+ const align = normalizeTableCellAlign((_a = alignments[index]) != null ? _a : cell.align);
25736
+ const attrs = align ? { align } : {};
25737
+ bodyCells.push(h2.createNode("tableCell", attrs, [{ type: "paragraph", content: h2.parseInline(cell.tokens) }]));
25499
25738
  });
25500
25739
  rows.push(h2.createNode("tableRow", {}, bodyCells));
25501
25740
  });
@@ -27296,7 +27535,7 @@ function LowlightPlugin({
27296
27535
  });
27297
27536
  return lowlightPlugin;
27298
27537
  }
27299
- var CodeBlockLowlight = index_default.extend({
27538
+ var CodeBlockLowlight = CodeBlock.extend({
27300
27539
  addOptions() {
27301
27540
  var _a;
27302
27541
  return {
@@ -42295,6 +42534,9 @@ class Toolbar {
42295
42534
  get trans() {
42296
42535
  return getTranslate();
42297
42536
  }
42537
+ icon(name) {
42538
+ return this.options.iconSet[name] ?? name;
42539
+ }
42298
42540
  render() {
42299
42541
  this.container.innerHTML = "";
42300
42542
  this.container.className = `md-toolbar md-toolbar-${this.options.mode}${this.options.sticky ? " md-toolbar-sticky" : ""}`;
@@ -42347,7 +42589,7 @@ class Toolbar {
42347
42589
  button.className = "md-toolbar-btn md-toolbar-toggle-btn";
42348
42590
  button.setAttribute("data-button", "togglemore");
42349
42591
  button.title = this.trans("More");
42350
- button.innerHTML = '<span class="md-toolbar-btn-icon">…</span>';
42592
+ button.innerHTML = `<span class="md-toolbar-btn-icon">${this.icon("togglemore")}</span>`;
42351
42593
  button.addEventListener("click", (e) => {
42352
42594
  e.preventDefault();
42353
42595
  this.toggleOverflow();
@@ -42370,43 +42612,43 @@ class Toolbar {
42370
42612
  }
42371
42613
  switch (name.toLowerCase()) {
42372
42614
  case "bold":
42373
- return this.createActionButton("bold", "B", this.trans("Bold"), () => {
42615
+ return this.createActionButton("bold", this.icon("bold"), this.trans("Bold"), () => {
42374
42616
  this.tiptap?.chain().focus().toggleBold().run();
42375
42617
  }, () => this.tiptap?.isActive("bold") ?? false);
42376
42618
  case "italic":
42377
- return this.createActionButton("italic", "I", this.trans("Italic"), () => {
42619
+ return this.createActionButton("italic", this.icon("italic"), this.trans("Italic"), () => {
42378
42620
  this.tiptap?.chain().focus().toggleItalic().run();
42379
42621
  }, () => this.tiptap?.isActive("italic") ?? false);
42380
42622
  case "underline":
42381
- return this.createActionButton("underline", "U", this.trans("Underline"), () => {
42623
+ return this.createActionButton("underline", this.icon("underline"), this.trans("Underline"), () => {
42382
42624
  this.tiptap?.chain().focus().toggleUnderline().run();
42383
42625
  }, () => this.tiptap?.isActive("underline") ?? false);
42384
42626
  case "strikethrough":
42385
- return this.createActionButton("strikethrough", "S", this.trans("Strikethrough"), () => {
42627
+ return this.createActionButton("strikethrough", this.icon("strikethrough"), this.trans("Strikethrough"), () => {
42386
42628
  this.tiptap?.chain().focus().toggleStrike().run();
42387
42629
  }, () => this.tiptap?.isActive("strike") ?? false);
42388
42630
  case "bullist":
42389
- return this.createActionButton("bullist", "", this.trans("Bullet list"), () => {
42631
+ return this.createActionButton("bullist", this.icon("bullist"), this.trans("Bullet list"), () => {
42390
42632
  this.tiptap?.chain().focus().toggleBulletList().run();
42391
42633
  }, () => this.tiptap?.isActive("bulletList") ?? false);
42392
42634
  case "numlist":
42393
- return this.createActionButton("numlist", "1.", this.trans("Numbered list"), () => {
42635
+ return this.createActionButton("numlist", this.icon("numlist"), this.trans("Numbered list"), () => {
42394
42636
  this.tiptap?.chain().focus().toggleOrderedList().run();
42395
42637
  }, () => this.tiptap?.isActive("orderedList") ?? false);
42396
42638
  case "outdent":
42397
- return this.createActionButton("outdent", "", this.trans("Decrease indent"), () => {
42639
+ return this.createActionButton("outdent", this.icon("outdent"), this.trans("Decrease indent"), () => {
42398
42640
  if (this.tiptap?.isActive("listItem")) {
42399
42641
  this.tiptap?.chain().focus().liftListItem("listItem").run();
42400
42642
  }
42401
42643
  });
42402
42644
  case "indent":
42403
- return this.createActionButton("indent", "", this.trans("Increase indent"), () => {
42645
+ return this.createActionButton("indent", this.icon("indent"), this.trans("Increase indent"), () => {
42404
42646
  if (this.tiptap?.isActive("listItem")) {
42405
42647
  this.tiptap?.chain().focus().sinkListItem("listItem").run();
42406
42648
  }
42407
42649
  });
42408
42650
  case "blockquote":
42409
- return this.createActionButton("blockquote", '"', this.trans("Blockquote"), () => {
42651
+ return this.createActionButton("blockquote", this.icon("blockquote"), this.trans("Blockquote"), () => {
42410
42652
  this.tiptap?.chain().focus().toggleBlockquote().run();
42411
42653
  }, () => this.tiptap?.isActive("blockquote") ?? false);
42412
42654
  case "fontfamily":
@@ -42416,19 +42658,19 @@ class Toolbar {
42416
42658
  case "lineheight":
42417
42659
  return this.createLineHeightDropdown();
42418
42660
  case "alignleft":
42419
- return this.createActionButton("alignleft", '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="15" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>', this.trans("Align left"), () => {
42661
+ return this.createActionButton("alignleft", this.icon("alignleft"), this.trans("Align left"), () => {
42420
42662
  this.tiptap?.chain().focus().setTextAlign("left").run();
42421
42663
  }, () => this.tiptap?.isActive({ textAlign: "left" }) ?? false);
42422
42664
  case "aligncenter":
42423
- return this.createActionButton("aligncenter", '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="6" y1="12" x2="18" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>', this.trans("Align center"), () => {
42665
+ return this.createActionButton("aligncenter", this.icon("aligncenter"), this.trans("Align center"), () => {
42424
42666
  this.tiptap?.chain().focus().setTextAlign("center").run();
42425
42667
  }, () => this.tiptap?.isActive({ textAlign: "center" }) ?? false);
42426
42668
  case "alignright":
42427
- return this.createActionButton("alignright", '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="9" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>', this.trans("Align right"), () => {
42669
+ return this.createActionButton("alignright", this.icon("alignright"), this.trans("Align right"), () => {
42428
42670
  this.tiptap?.chain().focus().setTextAlign("right").run();
42429
42671
  }, () => this.tiptap?.isActive({ textAlign: "right" }) ?? false);
42430
42672
  case "alignjustify":
42431
- return this.createActionButton("alignjustify", '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>', this.trans("Justify"), () => {
42673
+ return this.createActionButton("alignjustify", this.icon("alignjustify"), this.trans("Justify"), () => {
42432
42674
  this.tiptap?.chain().focus().setTextAlign("justify").run();
42433
42675
  }, () => this.tiptap?.isActive({ textAlign: "justify" }) ?? false);
42434
42676
  case "forecolor":
@@ -42440,71 +42682,71 @@ class Toolbar {
42440
42682
  this.tiptap?.chain().focus().setHighlight({ color }).run();
42441
42683
  });
42442
42684
  case "removeformat":
42443
- return this.createActionButton("removeformat", "", this.trans("Remove formatting"), () => {
42685
+ return this.createActionButton("removeformat", this.icon("removeformat"), this.trans("Remove formatting"), () => {
42444
42686
  this.tiptap?.chain().focus().unsetAllMarks().clearNodes().run();
42445
42687
  });
42446
42688
  case "copy":
42447
- return this.createActionButton("copy", "📋", this.trans("Copy"), () => {
42689
+ return this.createActionButton("copy", this.icon("copy"), this.trans("Copy"), () => {
42448
42690
  document.execCommand("copy");
42449
42691
  });
42450
42692
  case "cut":
42451
- return this.createActionButton("cut", "", this.trans("Cut"), () => {
42693
+ return this.createActionButton("cut", this.icon("cut"), this.trans("Cut"), () => {
42452
42694
  document.execCommand("cut");
42453
42695
  });
42454
42696
  case "paste":
42455
- return this.createActionButton("paste", "📄", this.trans("Paste"), () => {
42697
+ return this.createActionButton("paste", this.icon("paste"), this.trans("Paste"), () => {
42456
42698
  document.execCommand("paste");
42457
42699
  });
42458
42700
  case "undo":
42459
- return this.createActionButton("undo", "", this.trans("Undo"), () => {
42701
+ return this.createActionButton("undo", this.icon("undo"), this.trans("Undo"), () => {
42460
42702
  this.tiptap?.chain().focus().undo().run();
42461
42703
  });
42462
42704
  case "redo":
42463
- return this.createActionButton("redo", "", this.trans("Redo"), () => {
42705
+ return this.createActionButton("redo", this.icon("redo"), this.trans("Redo"), () => {
42464
42706
  this.tiptap?.chain().focus().redo().run();
42465
42707
  });
42466
42708
  case "image":
42467
- return this.createActionButton("image", '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>', this.trans("Insert image"), () => {
42709
+ return this.createActionButton("image", this.icon("image"), this.trans("Insert image"), () => {
42468
42710
  this.openImageDialog();
42469
42711
  });
42470
42712
  case "charmap":
42471
- return this.createActionButton("charmap", "Ω", this.trans("Special character"), () => {
42713
+ return this.createActionButton("charmap", this.icon("charmap"), this.trans("Special character"), () => {
42472
42714
  this.openCharMap();
42473
42715
  });
42474
42716
  case "emoticons":
42475
- return this.createActionButton("emoticons", "😀", this.trans("Emoticons"), () => {
42717
+ return this.createActionButton("emoticons", this.icon("emoticons"), this.trans("Emoticons"), () => {
42476
42718
  this.openEmojiPicker();
42477
42719
  });
42478
42720
  case "fullscreen":
42479
- return this.createActionButton("fullscreen", "", this.trans("Fullscreen"), () => {
42721
+ return this.createActionButton("fullscreen", this.icon("fullscreen"), this.trans("Fullscreen"), () => {
42480
42722
  this.toggleFullscreen();
42481
42723
  }, () => this.state.isFullscreen);
42482
42724
  case "preview":
42483
- return this.createActionButton("preview", "👁", this.trans("Preview"), () => {
42725
+ return this.createActionButton("preview", this.icon("preview"), this.trans("Preview"), () => {
42484
42726
  this.openPreview();
42485
42727
  });
42486
42728
  case "code":
42487
- return this.createActionButton("code", '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>', this.trans("Source code"), () => {
42729
+ return this.createActionButton("code", this.icon("code"), this.trans("Source code"), () => {
42488
42730
  this.openSourceCode();
42489
42731
  });
42490
42732
  case "link":
42491
- return this.createActionButton("link", "🔗", this.trans("Insert link"), () => {
42733
+ return this.createActionButton("link", this.icon("link"), this.trans("Insert link"), () => {
42492
42734
  this.openLinkDialog();
42493
42735
  }, () => this.tiptap?.isActive("link") ?? false);
42494
42736
  case "codesample":
42495
- return this.createActionButton("codesample", "{}", this.trans("Code sample"), () => {
42737
+ return this.createActionButton("codesample", this.icon("codesample"), this.trans("Code sample"), () => {
42496
42738
  this.tiptap?.chain().focus().toggleCodeBlock().run();
42497
42739
  }, () => this.tiptap?.isActive("codeBlock") ?? false);
42498
42740
  case "ltr":
42499
- return this.createActionButton("ltr", "", this.trans("Left to right"), () => {
42741
+ return this.createActionButton("ltr", this.icon("ltr"), this.trans("Left to right"), () => {
42500
42742
  this.tiptap?.chain().focus().setTextDirection("ltr").run();
42501
42743
  });
42502
42744
  case "rtl":
42503
- return this.createActionButton("rtl", "", this.trans("Right to left"), () => {
42745
+ return this.createActionButton("rtl", this.icon("rtl"), this.trans("Right to left"), () => {
42504
42746
  this.tiptap?.chain().focus().setTextDirection("rtl").run();
42505
42747
  });
42506
42748
  case "searchreplace":
42507
- return this.createActionButton("searchreplace", "🔍", this.trans("Find and replace"), () => {
42749
+ return this.createActionButton("searchreplace", this.icon("searchreplace"), this.trans("Find and replace"), () => {
42508
42750
  this.openSearchReplace();
42509
42751
  });
42510
42752
  case "template":
@@ -42980,6 +43222,78 @@ class Toolbar {
42980
43222
  this.container.innerHTML = "";
42981
43223
  }
42982
43224
  }
43225
+ const SVG_ALIGN_LEFT = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="15" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>';
43226
+ const SVG_ALIGN_CENTER = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="6" y1="12" x2="18" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>';
43227
+ const SVG_ALIGN_RIGHT = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="9" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>';
43228
+ const SVG_ALIGN_JUSTIFY = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>';
43229
+ const SVG_IMAGE = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>';
43230
+ const SVG_CODE = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>';
43231
+ const DEFAULT_ICONS = {
43232
+ bold: "B",
43233
+ italic: "I",
43234
+ underline: "U",
43235
+ strikethrough: "S",
43236
+ bullist: "•",
43237
+ numlist: "1.",
43238
+ outdent: "←",
43239
+ indent: "→",
43240
+ blockquote: '"',
43241
+ alignleft: SVG_ALIGN_LEFT,
43242
+ aligncenter: SVG_ALIGN_CENTER,
43243
+ alignright: SVG_ALIGN_RIGHT,
43244
+ alignjustify: SVG_ALIGN_JUSTIFY,
43245
+ removeformat: "✕",
43246
+ copy: "📋",
43247
+ cut: "✂",
43248
+ paste: "📄",
43249
+ undo: "↩",
43250
+ redo: "↪",
43251
+ image: SVG_IMAGE,
43252
+ charmap: "Ω",
43253
+ emoticons: "😀",
43254
+ fullscreen: "⛶",
43255
+ preview: "👁",
43256
+ code: SVG_CODE,
43257
+ link: "🔗",
43258
+ codesample: "{}",
43259
+ ltr: "⇐",
43260
+ rtl: "⇒",
43261
+ searchreplace: "🔍",
43262
+ togglemore: "…"
43263
+ };
43264
+ const CONFAB_ICONS = {
43265
+ bold: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/><path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/></svg>',
43266
+ italic: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/></svg>',
43267
+ underline: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3"/><line x1="4" y1="21" x2="20" y2="21"/></svg>',
43268
+ strikethrough: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 4c-1.5-1-3.2-1.5-5-1.5C7.7 2.5 5 4.6 5 7.5c0 1.5.7 2.7 1.8 3.5"/><path d="M8 20c1.5 1 3.2 1.5 5 1.5 3.3 0 6-2.1 6-5 0-1.5-.7-2.7-1.8-3.5"/><line x1="2" y1="12" x2="22" y2="12"/></svg>',
43269
+ bullist: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="9" y1="6" x2="20" y2="6"/><line x1="9" y1="12" x2="20" y2="12"/><line x1="9" y1="18" x2="20" y2="18"/><circle cx="5" cy="6" r="1" fill="currentColor" stroke="none"/><circle cx="5" cy="12" r="1" fill="currentColor" stroke="none"/><circle cx="5" cy="18" r="1" fill="currentColor" stroke="none"/></svg>',
43270
+ numlist: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><text x="3" y="8" font-size="7" fill="currentColor" stroke="none" font-family="sans-serif">1</text><text x="3" y="14" font-size="7" fill="currentColor" stroke="none" font-family="sans-serif">2</text><text x="3" y="20" font-size="7" fill="currentColor" stroke="none" font-family="sans-serif">3</text></svg>',
43271
+ outdent: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="4" x2="21" y2="4"/><line x1="3" y1="20" x2="21" y2="20"/><line x1="11" y1="9" x2="21" y2="9"/><line x1="11" y1="15" x2="21" y2="15"/><polyline points="7 9 3 12 7 15"/></svg>',
43272
+ indent: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="4" x2="21" y2="4"/><line x1="3" y1="20" x2="21" y2="20"/><line x1="11" y1="9" x2="21" y2="9"/><line x1="11" y1="15" x2="21" y2="15"/><polyline points="3 9 7 12 3 15"/></svg>',
43273
+ blockquote: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21c3 0 7-1 7-8V5c0-1.25-.76-2.02-2-2H4c-1.25 0-2 .76-2 2v6c0 1.25.76 2 2 2h4.5c-1 2-3.5 3.5-5.5 3.5"/><path d="M15 21c3 0 7-1 7-8V5c0-1.25-.76-2.02-2-2h-4c-1.25 0-2 .76-2 2v6c0 1.25.76 2 2 2h4.5c-1 2-3.5 3.5-5.5 3.5"/></svg>',
43274
+ alignleft: SVG_ALIGN_LEFT,
43275
+ aligncenter: SVG_ALIGN_CENTER,
43276
+ alignright: SVG_ALIGN_RIGHT,
43277
+ alignjustify: SVG_ALIGN_JUSTIFY,
43278
+ removeformat: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h11l-3 14"/><line x1="4" y1="7" x2="9" y2="3"/><line x1="18" y1="4" x2="22" y2="8"/><line x1="18" y1="8" x2="22" y2="4"/></svg>',
43279
+ copy: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>',
43280
+ cut: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><line x1="20" y1="4" x2="8.1" y2="15.9"/><line x1="14.5" y1="9.5" x2="20" y2="4"/><line x1="8.1" y1="8.1" x2="20" y2="20"/></svg>',
43281
+ paste: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><rect x="8" y="2" width="8" height="4" rx="1"/></svg>',
43282
+ undo: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"/><path d="M3.5 14a9 9 0 1 0 2.2-5.8L1 10"/></svg>',
43283
+ redo: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.5 14a9 9 0 1 1-2.2-5.8L23 10"/></svg>',
43284
+ image: SVG_IMAGE,
43285
+ charmap: "Ω",
43286
+ emoticons: "😀",
43287
+ fullscreen: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>',
43288
+ preview: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>',
43289
+ code: SVG_CODE,
43290
+ link: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.5.5l3-3a5 5 0 0 0-7.1-7.1l-1.7 1.7"/><path d="M14 11a5 5 0 0 0-7.5-.5l-3 3a5 5 0 0 0 7.1 7.1l1.7-1.7"/></svg>',
43291
+ codesample: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5a2 2 0 0 0 2 2h1"/><path d="M16 3h1a2 2 0 0 1 2 2v5a2 2 0 0 0 2 2 2 2 0 0 0-2 2v5a2 2 0 0 1-2 2h-1"/></svg>',
43292
+ ltr: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="18" y1="5" x2="18" y2="19"/><path d="M8 5a4 4 0 0 0 0 8h4"/><polyline points="4 17 8 21 12 17"/></svg>',
43293
+ rtl: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="6" y1="5" x2="6" y2="19"/><path d="M16 5a4 4 0 0 1 0 8h-4"/><polyline points="20 17 16 21 12 17"/></svg>',
43294
+ searchreplace: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.6" y2="16.6"/></svg>',
43295
+ togglemore: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1" fill="currentColor"/><circle cx="5" cy="12" r="1" fill="currentColor"/><circle cx="19" cy="12" r="1" fill="currentColor"/></svg>'
43296
+ };
42983
43297
  const FontSize = Extension.create({
42984
43298
  name: "fontSize",
42985
43299
  addOptions() {
@@ -43107,6 +43421,30 @@ const TextDirection = Extension.create({
43107
43421
  };
43108
43422
  }
43109
43423
  });
43424
+ const SignatureBlock = Node3.create({
43425
+ name: "signatureBlock",
43426
+ group: "block",
43427
+ content: "block+",
43428
+ defining: true,
43429
+ isolating: true,
43430
+ addAttributes() {
43431
+ return {
43432
+ id: {
43433
+ default: "signature"
43434
+ }
43435
+ };
43436
+ },
43437
+ parseHTML() {
43438
+ return [
43439
+ {
43440
+ tag: 'div[id="signature"]'
43441
+ }
43442
+ ];
43443
+ },
43444
+ renderHTML({ HTMLAttributes }) {
43445
+ return ["div", mergeAttributes(HTMLAttributes), 0];
43446
+ }
43447
+ });
43110
43448
  const en = {
43111
43449
  "Bold": "Bold",
43112
43450
  "Italic": "Italic",
@@ -45238,6 +45576,8 @@ class HTMLEditor {
45238
45576
  directionality: config.directionality ?? "ltr",
45239
45577
  language: config.language ?? "en",
45240
45578
  height: config.height ?? 300,
45579
+ min_height: config.min_height,
45580
+ max_height: config.max_height,
45241
45581
  auto_focus: config.auto_focus,
45242
45582
  setFocus: config.setFocus,
45243
45583
  skin: config.skin ?? "oxide",
@@ -45274,6 +45614,20 @@ class HTMLEditor {
45274
45614
  this.editorWrapper.style.height = this.config.height;
45275
45615
  }
45276
45616
  }
45617
+ if (this.config.min_height) {
45618
+ if (typeof this.config.min_height === "number") {
45619
+ this.editorWrapper.style.minHeight = `${this.config.min_height}px`;
45620
+ } else {
45621
+ this.editorWrapper.style.minHeight = this.config.min_height;
45622
+ }
45623
+ }
45624
+ if (this.config.max_height) {
45625
+ if (typeof this.config.max_height === "number") {
45626
+ this.editorWrapper.style.maxHeight = `${this.config.max_height}px`;
45627
+ } else {
45628
+ this.editorWrapper.style.maxHeight = this.config.max_height;
45629
+ }
45630
+ }
45277
45631
  const toolbarContainer = document.createElement("div");
45278
45632
  toolbarContainer.className = "md-editor-toolbar";
45279
45633
  this.editorWrapper.appendChild(toolbarContainer);
@@ -45312,13 +45666,15 @@ class HTMLEditor {
45312
45666
  }
45313
45667
  };
45314
45668
  this.tiptap = new Editor(editorOptions);
45669
+ const iconSet = this.config.skin?.startsWith("confab") ? CONFAB_ICONS : DEFAULT_ICONS;
45315
45670
  this.toolbar = new Toolbar(toolbarContainer, {
45316
45671
  editor: this,
45317
45672
  buttons: this.config.toolbar ?? BASIC_TOOLBAR,
45318
45673
  mode: this.config.toolbar_mode ?? "sliding",
45319
45674
  sticky: this.config.toolbar_sticky ?? true,
45320
45675
  customButtons: this.customButtons,
45321
- config: this.config
45676
+ config: this.config,
45677
+ iconSet
45322
45678
  });
45323
45679
  if (this.config.auto_focus) {
45324
45680
  setTimeout(() => this.focus(), 10);
@@ -45401,6 +45757,7 @@ class HTMLEditor {
45401
45757
  codeBlock: false
45402
45758
  // We use CodeBlockLowlight instead
45403
45759
  }),
45760
+ SignatureBlock,
45404
45761
  Underline,
45405
45762
  TextStyle,
45406
45763
  FontFamily,
@@ -45640,13 +45997,16 @@ class HTMLEditor {
45640
45997
  }
45641
45998
  export {
45642
45999
  CHAR_MAP,
46000
+ CONFAB_ICONS,
45643
46001
  CharacterMap,
46002
+ DEFAULT_ICONS,
45644
46003
  EMOJI_CATEGORIES,
45645
46004
  EmojiPicker,
45646
46005
  FontSize,
45647
46006
  HTMLEditor,
45648
46007
  LineHeight,
45649
46008
  SearchReplace,
46009
+ SignatureBlock,
45650
46010
  TRANSLATION_KEYS,
45651
46011
  TextDirection,
45652
46012
  Toolbar,