@mdaemon/html-editor 1.0.6 → 1.0.8

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.js CHANGED
@@ -12430,7 +12430,6 @@ function isMarkInSet(marks, type, attributes = {}) {
12430
12430
  return !!findMarkInSet(marks, type, attributes);
12431
12431
  }
12432
12432
  function getMarkRange($pos, type, attributes) {
12433
- var _a;
12434
12433
  if (!$pos || !type) {
12435
12434
  return;
12436
12435
  }
@@ -12441,7 +12440,12 @@ function getMarkRange($pos, type, attributes) {
12441
12440
  if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) {
12442
12441
  return;
12443
12442
  }
12444
- attributes = attributes || ((_a = start.node.marks[0]) == null ? void 0 : _a.attrs);
12443
+ if (!attributes) {
12444
+ const firstMark = start.node.marks.find((mark2) => mark2.type === type);
12445
+ if (firstMark) {
12446
+ attributes = firstMark.attrs;
12447
+ }
12448
+ }
12445
12449
  const mark = findMarkInSet([...start.node.marks], type, attributes);
12446
12450
  if (!mark) {
12447
12451
  return;
@@ -12472,7 +12476,7 @@ function getMarkType(nameOrType, schema) {
12472
12476
  }
12473
12477
  return nameOrType;
12474
12478
  }
12475
- var extendMarkRange = (typeOrName, attributes = {}) => ({ tr: tr2, state, dispatch }) => {
12479
+ var extendMarkRange = (typeOrName, attributes) => ({ tr: tr2, state, dispatch }) => {
12476
12480
  const type = getMarkType(typeOrName, state.schema);
12477
12481
  const { doc: doc2, selection } = tr2;
12478
12482
  const { $from, from: from2, to } = selection;
@@ -12783,7 +12787,7 @@ var insertContentAt = (position, value, options) => ({ tr: tr2, dispatch, editor
12783
12787
  const fromSelectionAtStart = $from.parentOffset === 0;
12784
12788
  const isTextSelection2 = $fromNode.isText || $fromNode.isTextblock;
12785
12789
  const hasContent = $fromNode.content.size > 0;
12786
- if (fromSelectionAtStart && isTextSelection2 && hasContent) {
12790
+ if (fromSelectionAtStart && isTextSelection2 && hasContent && isOnlyBlockContent) {
12787
12791
  from2 = Math.max(0, from2 - 1);
12788
12792
  }
12789
12793
  tr2.replaceWith(from2, to, newContent);
@@ -13226,6 +13230,9 @@ function getAttributesFromExtensions(extensions) {
13226
13230
  keepOnSplit: true,
13227
13231
  isRequired: false
13228
13232
  };
13233
+ const nodeExtensionTypes = nodeExtensions.filter((ext) => ext.name !== "text").map((ext) => ext.name);
13234
+ const markExtensionTypes = markExtensions.map((ext) => ext.name);
13235
+ const allExtensionTypes = [...nodeExtensionTypes, ...markExtensionTypes];
13229
13236
  extensions.forEach((extension) => {
13230
13237
  const context = {
13231
13238
  name: extension.name,
@@ -13243,7 +13250,19 @@ function getAttributesFromExtensions(extensions) {
13243
13250
  }
13244
13251
  const globalAttributes = addGlobalAttributes();
13245
13252
  globalAttributes.forEach((globalAttribute) => {
13246
- globalAttribute.types.forEach((type) => {
13253
+ let resolvedTypes;
13254
+ if (Array.isArray(globalAttribute.types)) {
13255
+ resolvedTypes = globalAttribute.types;
13256
+ } else if (globalAttribute.types === "*") {
13257
+ resolvedTypes = allExtensionTypes;
13258
+ } else if (globalAttribute.types === "nodes") {
13259
+ resolvedTypes = nodeExtensionTypes;
13260
+ } else if (globalAttribute.types === "marks") {
13261
+ resolvedTypes = markExtensionTypes;
13262
+ } else {
13263
+ resolvedTypes = [];
13264
+ }
13265
+ resolvedTypes.forEach((type) => {
13247
13266
  Object.entries(globalAttribute.attributes).forEach(([name, attribute]) => {
13248
13267
  extensionAttributes.push({
13249
13268
  type,
@@ -13292,6 +13311,67 @@ function getAttributesFromExtensions(extensions) {
13292
13311
  });
13293
13312
  return extensionAttributes;
13294
13313
  }
13314
+ function splitStyleDeclarations(styles) {
13315
+ const result = [];
13316
+ let current = "";
13317
+ let inSingleQuote = false;
13318
+ let inDoubleQuote = false;
13319
+ let parenDepth = 0;
13320
+ const length = styles.length;
13321
+ for (let i = 0; i < length; i += 1) {
13322
+ const char = styles[i];
13323
+ if (char === "'" && !inDoubleQuote) {
13324
+ inSingleQuote = !inSingleQuote;
13325
+ current += char;
13326
+ continue;
13327
+ }
13328
+ if (char === '"' && !inSingleQuote) {
13329
+ inDoubleQuote = !inDoubleQuote;
13330
+ current += char;
13331
+ continue;
13332
+ }
13333
+ if (!inSingleQuote && !inDoubleQuote) {
13334
+ if (char === "(") {
13335
+ parenDepth += 1;
13336
+ current += char;
13337
+ continue;
13338
+ }
13339
+ if (char === ")" && parenDepth > 0) {
13340
+ parenDepth -= 1;
13341
+ current += char;
13342
+ continue;
13343
+ }
13344
+ if (char === ";" && parenDepth === 0) {
13345
+ result.push(current);
13346
+ current = "";
13347
+ continue;
13348
+ }
13349
+ }
13350
+ current += char;
13351
+ }
13352
+ if (current) {
13353
+ result.push(current);
13354
+ }
13355
+ return result;
13356
+ }
13357
+ function parseStyleEntries(styles) {
13358
+ const pairs = [];
13359
+ const declarations = splitStyleDeclarations(styles || "");
13360
+ const numDeclarations = declarations.length;
13361
+ for (let i = 0; i < numDeclarations; i += 1) {
13362
+ const declaration = declarations[i];
13363
+ const firstColonIndex = declaration.indexOf(":");
13364
+ if (firstColonIndex === -1) {
13365
+ continue;
13366
+ }
13367
+ const property = declaration.slice(0, firstColonIndex).trim();
13368
+ const value = declaration.slice(firstColonIndex + 1).trim();
13369
+ if (property && value) {
13370
+ pairs.push([property, value]);
13371
+ }
13372
+ }
13373
+ return pairs;
13374
+ }
13295
13375
  function mergeAttributes(...objects) {
13296
13376
  return objects.filter((item) => !!item).reduce((items, item) => {
13297
13377
  const mergedAttributes = { ...items };
@@ -13307,17 +13387,7 @@ function mergeAttributes(...objects) {
13307
13387
  const insertClasses = valueClasses.filter((valueClass) => !existingClasses.includes(valueClass));
13308
13388
  mergedAttributes[key] = [...existingClasses, ...insertClasses].join(" ");
13309
13389
  } else if (key === "style") {
13310
- const newStyles = value ? value.split(";").map((style2) => style2.trim()).filter(Boolean) : [];
13311
- const existingStyles = mergedAttributes[key] ? mergedAttributes[key].split(";").map((style2) => style2.trim()).filter(Boolean) : [];
13312
- const styleMap = /* @__PURE__ */ new Map();
13313
- existingStyles.forEach((style2) => {
13314
- const [property, val] = style2.split(":").map((part) => part.trim());
13315
- styleMap.set(property, val);
13316
- });
13317
- newStyles.forEach((style2) => {
13318
- const [property, val] = style2.split(":").map((part) => part.trim());
13319
- styleMap.set(property, val);
13320
- });
13390
+ const styleMap = new Map([...parseStyleEntries(mergedAttributes[key]), ...parseStyleEntries(value)]);
13321
13391
  mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join("; ");
13322
13392
  } else {
13323
13393
  mergedAttributes[key] = value;
@@ -13741,6 +13811,9 @@ function isMarkActive(state, typeOrName, attributes = {}) {
13741
13811
  const from2 = $from.pos;
13742
13812
  const to = $to.pos;
13743
13813
  state.doc.nodesBetween(from2, to, (node, pos) => {
13814
+ if (type && node.inlineContent && !node.type.allowsMarkType(type)) {
13815
+ return false;
13816
+ }
13744
13817
  if (!node.isText && !node.marks.length) {
13745
13818
  return;
13746
13819
  }
@@ -13849,7 +13922,7 @@ function isNodeEmpty(node, {
13849
13922
  return true;
13850
13923
  }
13851
13924
  if (node.isText) {
13852
- return /^\s*$/m.test((_a = node.text) != null ? _a : "");
13925
+ return !/\S/.test((_a = node.text) != null ? _a : "");
13853
13926
  }
13854
13927
  }
13855
13928
  if (node.isText) {
@@ -14237,6 +14310,16 @@ var joinListForwards = (tr2, listType) => {
14237
14310
  tr2.join(after);
14238
14311
  return true;
14239
14312
  };
14313
+ function createInnerSelectionForWholeDocList(tr2) {
14314
+ const doc2 = tr2.doc;
14315
+ const list = doc2.firstChild;
14316
+ if (!list) {
14317
+ return null;
14318
+ }
14319
+ const from2 = 1;
14320
+ const to = list.nodeSize - 1;
14321
+ return TextSelection.create(doc2, from2, to);
14322
+ }
14240
14323
  var toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) => ({ editor, tr: tr2, state, dispatch, chain, commands, can }) => {
14241
14324
  const { extensions, splittableMarks } = editor.extensionManager;
14242
14325
  const listType = getNodeType(listTypeOrName, state.schema);
@@ -14249,13 +14332,36 @@ var toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) =>
14249
14332
  return false;
14250
14333
  }
14251
14334
  const parentList = findParentNode((node) => isList(node.type.name, extensions))(selection);
14252
- if (range.depth >= 1 && parentList && range.depth - parentList.depth <= 1) {
14253
- if (parentList.node.type === listType) {
14335
+ const isAllSelection = selection.from === 0 && selection.to === state.doc.content.size;
14336
+ const topLevelNodes = state.doc.content.content;
14337
+ const soleTopLevelNode = topLevelNodes.length === 1 ? topLevelNodes[0] : null;
14338
+ const allSelectionList = isAllSelection && soleTopLevelNode && isList(soleTopLevelNode.type.name, extensions) ? {
14339
+ node: soleTopLevelNode,
14340
+ pos: 0
14341
+ } : null;
14342
+ const currentList = parentList != null ? parentList : allSelectionList;
14343
+ const isInsideExistingList = !!parentList && range.depth >= 1 && range.depth - parentList.depth <= 1;
14344
+ const hasWholeDocSelectedList = !!allSelectionList;
14345
+ if ((isInsideExistingList || hasWholeDocSelectedList) && currentList) {
14346
+ if (currentList.node.type === listType) {
14347
+ if (isAllSelection && hasWholeDocSelectedList) {
14348
+ return chain().command(({ tr: trx, dispatch: disp }) => {
14349
+ const nextSelection = createInnerSelectionForWholeDocList(trx);
14350
+ if (!nextSelection) {
14351
+ return false;
14352
+ }
14353
+ trx.setSelection(nextSelection);
14354
+ if (disp) {
14355
+ disp(trx);
14356
+ }
14357
+ return true;
14358
+ }).liftListItem(itemType).run();
14359
+ }
14254
14360
  return commands.liftListItem(itemType);
14255
14361
  }
14256
- if (isList(parentList.node.type.name, extensions) && listType.validContent(parentList.node.content) && dispatch) {
14362
+ if (isList(currentList.node.type.name, extensions) && listType.validContent(currentList.node.content)) {
14257
14363
  return chain().command(() => {
14258
- tr2.setNodeMarkup(parentList.pos, listType);
14364
+ tr2.setNodeMarkup(currentList.pos, listType);
14259
14365
  return true;
14260
14366
  }).command(() => joinListBackwards(tr2, listType)).command(() => joinListForwards(tr2, listType)).run();
14261
14367
  }
@@ -15249,6 +15355,39 @@ var ExtensionManager = class {
15249
15355
  };
15250
15356
  }, baseDispatch);
15251
15357
  }
15358
+ /**
15359
+ * Get the composed transformPastedHTML function from all extensions.
15360
+ * @param baseTransform The base transform function (e.g. from the editor props)
15361
+ * @returns A composed transform function that chains all extension transforms
15362
+ */
15363
+ transformPastedHTML(baseTransform) {
15364
+ const { editor } = this;
15365
+ const extensions = sortExtensions([...this.extensions]);
15366
+ return extensions.reduce(
15367
+ (transform, extension) => {
15368
+ const context = {
15369
+ name: extension.name,
15370
+ options: extension.options,
15371
+ storage: this.editor.extensionStorage[extension.name],
15372
+ editor,
15373
+ type: getSchemaTypeByName(extension.name, this.schema)
15374
+ };
15375
+ const extensionTransform = getExtensionField(
15376
+ extension,
15377
+ "transformPastedHTML",
15378
+ context
15379
+ );
15380
+ if (!extensionTransform) {
15381
+ return transform;
15382
+ }
15383
+ return (html, view) => {
15384
+ const transformedHtml = transform(html, view);
15385
+ return extensionTransform.call(context, transformedHtml);
15386
+ };
15387
+ },
15388
+ baseTransform || ((html) => html)
15389
+ );
15390
+ }
15252
15391
  get markViews() {
15253
15392
  const { editor } = this;
15254
15393
  const { markExtensions } = splitExtensions(this.extensions);
@@ -15467,7 +15606,7 @@ var Delete = Extension.create({
15467
15606
  const newEnd = mapping.slice(index).map(step.to);
15468
15607
  const oldStart = mapping.invert().map(newStart, -1);
15469
15608
  const oldEnd = mapping.invert().map(newEnd);
15470
- const foundBeforeMark = (_a3 = nextTransaction.doc.nodeAt(newStart - 1)) == null ? void 0 : _a3.marks.some((mark) => mark.eq(step.mark));
15609
+ const foundBeforeMark = newStart > 0 ? (_a3 = nextTransaction.doc.nodeAt(newStart - 1)) == null ? void 0 : _a3.marks.some((mark) => mark.eq(step.mark)) : false;
15471
15610
  const foundAfterMark = (_b3 = nextTransaction.doc.nodeAt(newEnd)) == null ? void 0 : _b3.marks.some((mark) => mark.eq(step.mark));
15472
15611
  this.editor.emit("delete", {
15473
15612
  type: "mark",
@@ -16219,7 +16358,7 @@ var Editor = class extends EventEmitter {
16219
16358
  return this.options.editable && this.view && this.view.editable;
16220
16359
  }
16221
16360
  /**
16222
- * Returns the editor state.
16361
+ * Returns the editor view.
16223
16362
  */
16224
16363
  get view() {
16225
16364
  if (this.editorView) {
@@ -16387,6 +16526,8 @@ var Editor = class extends EventEmitter {
16387
16526
  const { editorProps, enableExtensionDispatchTransaction } = this.options;
16388
16527
  const baseDispatch = editorProps.dispatchTransaction || this.dispatchTransaction.bind(this);
16389
16528
  const dispatch = enableExtensionDispatchTransaction ? this.extensionManager.dispatchTransaction(baseDispatch) : baseDispatch;
16529
+ const baseTransformPastedHTML = editorProps.transformPastedHTML;
16530
+ const transformPastedHTML = this.extensionManager.transformPastedHTML(baseTransformPastedHTML);
16390
16531
  this.editorView = new EditorView(element, {
16391
16532
  ...editorProps,
16392
16533
  attributes: {
@@ -16395,6 +16536,7 @@ var Editor = class extends EventEmitter {
16395
16536
  ...editorProps == null ? void 0 : editorProps.attributes
16396
16537
  },
16397
16538
  dispatchTransaction: dispatch,
16539
+ transformPastedHTML,
16398
16540
  state: this.editorState,
16399
16541
  markViews: this.extensionManager.markViews,
16400
16542
  nodeViews: this.extensionManager.nodeViews
@@ -16902,7 +17044,7 @@ var ResizableNodeView = class {
16902
17044
  const element = document.createElement("div");
16903
17045
  element.dataset.resizeContainer = "";
16904
17046
  element.dataset.node = this.node.type.name;
16905
- element.style.display = "flex";
17047
+ element.style.display = this.node.type.isInline ? "inline-flex" : "flex";
16906
17048
  if (this.classNames.container) {
16907
17049
  element.className = this.classNames.container;
16908
17050
  }
@@ -17704,17 +17846,21 @@ function renderNestedMarkdownContent(node, h2, prefixOrGenerator, ctx) {
17704
17846
  const prefix = typeof prefixOrGenerator === "function" ? prefixOrGenerator(ctx) : prefixOrGenerator;
17705
17847
  const [content, ...children] = node.content;
17706
17848
  const mainContent = h2.renderChildren([content]);
17707
- const output = [`${prefix}${mainContent}`];
17849
+ let output = `${prefix}${mainContent}`;
17708
17850
  if (children && children.length > 0) {
17709
- children.forEach((child) => {
17710
- const childContent = h2.renderChildren([child]);
17711
- if (childContent) {
17712
- const indentedChild = childContent.split("\n").map((line) => line ? h2.indent(line) : "").join("\n");
17713
- output.push(indentedChild);
17851
+ children.forEach((child, index) => {
17852
+ var _a, _b;
17853
+ const childContent = (_b = (_a = h2.renderChild) == null ? void 0 : _a.call(h2, child, index + 1)) != null ? _b : h2.renderChildren([child]);
17854
+ if (childContent !== void 0 && childContent !== null) {
17855
+ const indentedChild = childContent.split("\n").map((line) => line ? h2.indent(line) : h2.indent("")).join("\n");
17856
+ output += child.type === "paragraph" ? `
17857
+
17858
+ ${indentedChild}` : `
17859
+ ${indentedChild}`;
17714
17860
  }
17715
17861
  });
17716
17862
  }
17717
- return output.join("\n");
17863
+ return output;
17718
17864
  }
17719
17865
  function updateMarkViewAttributes(checkMark, editor, attrs = {}) {
17720
17866
  const { state } = editor;
@@ -17804,7 +17950,10 @@ function markPasteRule(config) {
17804
17950
  }
17805
17951
  markEnd = range.from + startSpaces + captureGroup.length;
17806
17952
  tr2.addMark(range.from + startSpaces, markEnd, config.type.create(attributes || {}));
17807
- tr2.removeStoredMark(config.type);
17953
+ const isMatchAtEndOfText = match.index !== void 0 && match.input !== void 0 && match.index + match[0].length >= match.input.length;
17954
+ if (!isMatchAtEndOfText) {
17955
+ tr2.removeStoredMark(config.type);
17956
+ }
17808
17957
  }
17809
17958
  }
17810
17959
  });
@@ -17840,7 +17989,9 @@ var Blockquote = Node3.create({
17840
17989
  return /* @__PURE__ */ h("blockquote", { ...mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), children: /* @__PURE__ */ h("slot", {}) });
17841
17990
  },
17842
17991
  parseMarkdown: (token, helpers) => {
17843
- return helpers.createNode("blockquote", void 0, helpers.parseChildren(token.tokens || []));
17992
+ var _a;
17993
+ const parseBlockChildren = (_a = helpers.parseBlockChildren) != null ? _a : helpers.parseChildren;
17994
+ return helpers.createNode("blockquote", void 0, parseBlockChildren(token.tokens || []));
17844
17995
  },
17845
17996
  renderMarkdown: (node, h2) => {
17846
17997
  if (!node.content) {
@@ -17848,8 +17999,9 @@ var Blockquote = Node3.create({
17848
17999
  }
17849
18000
  const prefix = ">";
17850
18001
  const result = [];
17851
- node.content.forEach((child) => {
17852
- const childContent = h2.renderChildren([child]);
18002
+ node.content.forEach((child, index) => {
18003
+ var _a, _b;
18004
+ const childContent = (_b = (_a = h2.renderChild) == null ? void 0 : _a.call(h2, child, index)) != null ? _b : h2.renderChildren([child]);
17853
18005
  const lines = childContent.split("\n");
17854
18006
  const linesWithPrefix = lines.map((line) => {
17855
18007
  if (line.trim() === "") {
@@ -17927,6 +18079,12 @@ var Bold = Mark2.create({
17927
18079
  parseMarkdown: (token, helpers) => {
17928
18080
  return helpers.applyMark("bold", helpers.parseInline(token.tokens || []));
17929
18081
  },
18082
+ markdownOptions: {
18083
+ htmlReopen: {
18084
+ open: "<strong>",
18085
+ close: "</strong>"
18086
+ }
18087
+ },
17930
18088
  renderMarkdown: (node, h2) => {
17931
18089
  return `**${h2.renderChildren(node)}**`;
17932
18090
  },
@@ -18103,8 +18261,8 @@ var CodeBlock = Node3.create({
18103
18261
  },
18104
18262
  markdownTokenName: "code",
18105
18263
  parseMarkdown: (token, helpers) => {
18106
- var _a;
18107
- if (((_a = token.raw) == null ? void 0 : _a.startsWith("```")) === false && token.codeBlockStyle !== "indented") {
18264
+ var _a, _b;
18265
+ if (((_a = token.raw) == null ? void 0 : _a.startsWith("```")) === false && ((_b = token.raw) == null ? void 0 : _b.startsWith("~~~")) === false && token.codeBlockStyle !== "indented") {
18108
18266
  return [];
18109
18267
  }
18110
18268
  return helpers.createNode(
@@ -18346,7 +18504,6 @@ var CodeBlock = Node3.create({
18346
18504
  ];
18347
18505
  }
18348
18506
  });
18349
- var index_default = CodeBlock;
18350
18507
  var Document = Node3.create({
18351
18508
  name: "doc",
18352
18509
  topNode: true,
@@ -18623,6 +18780,12 @@ var Italic = Mark2.create({
18623
18780
  parseMarkdown: (token, helpers) => {
18624
18781
  return helpers.applyMark("italic", helpers.parseInline(token.tokens || []));
18625
18782
  },
18783
+ markdownOptions: {
18784
+ htmlReopen: {
18785
+ open: "<em>",
18786
+ close: "</em>"
18787
+ }
18788
+ },
18626
18789
  renderMarkdown: (node, h2) => {
18627
18790
  return `*${h2.renderChildren(node)}*`;
18628
18791
  },
@@ -20321,14 +20484,16 @@ var ListItem = Node3.create({
20321
20484
  },
20322
20485
  markdownTokenName: "list_item",
20323
20486
  parseMarkdown: (token, helpers) => {
20487
+ var _a;
20324
20488
  if (token.type !== "list_item") {
20325
20489
  return [];
20326
20490
  }
20491
+ const parseBlockChildren = (_a = helpers.parseBlockChildren) != null ? _a : helpers.parseChildren;
20327
20492
  let content = [];
20328
20493
  if (token.tokens && token.tokens.length > 0) {
20329
20494
  const hasParagraphTokens = token.tokens.some((t) => t.type === "paragraph");
20330
20495
  if (hasParagraphTokens) {
20331
- content = helpers.parseChildren(token.tokens);
20496
+ content = parseBlockChildren(token.tokens);
20332
20497
  } else {
20333
20498
  const firstToken = token.tokens[0];
20334
20499
  if (firstToken && firstToken.type === "text" && firstToken.tokens && firstToken.tokens.length > 0) {
@@ -20341,11 +20506,11 @@ var ListItem = Node3.create({
20341
20506
  ];
20342
20507
  if (token.tokens.length > 1) {
20343
20508
  const remainingTokens = token.tokens.slice(1);
20344
- const additionalContent = helpers.parseChildren(remainingTokens);
20509
+ const additionalContent = parseBlockChildren(remainingTokens);
20345
20510
  content.push(...additionalContent);
20346
20511
  }
20347
20512
  } else {
20348
- content = helpers.parseChildren(token.tokens);
20513
+ content = parseBlockChildren(token.tokens);
20349
20514
  }
20350
20515
  }
20351
20516
  }
@@ -21263,18 +21428,22 @@ var Paragraph = Node3.create({
21263
21428
  return helpers.parseChildren([tokens[0]]);
21264
21429
  }
21265
21430
  const content = helpers.parseInline(tokens);
21266
- if (content.length === 1 && content[0].type === "text" && (content[0].text === EMPTY_PARAGRAPH_MARKDOWN || content[0].text === NBSP_CHAR)) {
21431
+ 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);
21432
+ if (hasExplicitEmptyParagraphMarker && content.length === 1 && content[0].type === "text" && (content[0].text === EMPTY_PARAGRAPH_MARKDOWN || content[0].text === NBSP_CHAR)) {
21267
21433
  return helpers.createNode("paragraph", void 0, []);
21268
21434
  }
21269
21435
  return helpers.createNode("paragraph", void 0, content);
21270
21436
  },
21271
- renderMarkdown: (node, h2) => {
21437
+ renderMarkdown: (node, h2, ctx) => {
21438
+ var _a, _b;
21272
21439
  if (!node) {
21273
21440
  return "";
21274
21441
  }
21275
21442
  const content = Array.isArray(node.content) ? node.content : [];
21276
21443
  if (content.length === 0) {
21277
- return EMPTY_PARAGRAPH_MARKDOWN;
21444
+ const previousContent = Array.isArray((_a = ctx == null ? void 0 : ctx.previousNode) == null ? void 0 : _a.content) ? ctx.previousNode.content : [];
21445
+ const previousNodeIsEmptyParagraph = ((_b = ctx == null ? void 0 : ctx.previousNode) == null ? void 0 : _b.type) === "paragraph" && previousContent.length === 0;
21446
+ return previousNodeIsEmptyParagraph ? EMPTY_PARAGRAPH_MARKDOWN : "";
21278
21447
  }
21279
21448
  return h2.renderChildren(content);
21280
21449
  },
@@ -22533,6 +22702,9 @@ var Placeholder = Extension.create({
22533
22702
  doc2.descendants((node, pos) => {
22534
22703
  const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
22535
22704
  const isEmpty2 = !node.isLeaf && isNodeEmpty(node);
22705
+ if (!node.type.isTextblock) {
22706
+ return this.options.includeChildren;
22707
+ }
22536
22708
  if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty2) {
22537
22709
  const classes = [this.options.emptyNodeClass];
22538
22710
  if (isEmptyDoc) {
@@ -22586,6 +22758,7 @@ Extension.create({
22586
22758
  ];
22587
22759
  }
22588
22760
  });
22761
+ var skipTrailingNodeMeta = "skipTrailingNode";
22589
22762
  function nodeEqualsType({ types, node }) {
22590
22763
  return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
22591
22764
  }
@@ -22605,11 +22778,14 @@ var TrailingNode = Extension.create({
22605
22778
  return [
22606
22779
  new Plugin({
22607
22780
  key: plugin,
22608
- appendTransaction: (_, __, state) => {
22781
+ appendTransaction: (transactions, __, state) => {
22609
22782
  const { doc: doc2, tr: tr2, schema } = state;
22610
22783
  const shouldInsertNodeAtEnd = plugin.getState(state);
22611
22784
  const endPosition = doc2.content.size;
22612
22785
  const type = schema.nodes[defaultNode];
22786
+ if (transactions.some((transaction) => transaction.getMeta(skipTrailingNodeMeta))) {
22787
+ return;
22788
+ }
22613
22789
  if (!shouldInsertNodeAtEnd) {
22614
22790
  return;
22615
22791
  }
@@ -25107,6 +25283,35 @@ function tableEditing({ allowTableNodeSelection = false } = {}) {
25107
25283
  }
25108
25284
  });
25109
25285
  }
25286
+ function normalizeTableCellAlign(value) {
25287
+ if (value === "left" || value === "right" || value === "center") {
25288
+ return value;
25289
+ }
25290
+ return null;
25291
+ }
25292
+ function parseAlign(element) {
25293
+ const styleAlign = (element.style.textAlign || "").trim().toLowerCase();
25294
+ const attrAlign = (element.getAttribute("align") || "").trim().toLowerCase();
25295
+ const align = styleAlign || attrAlign;
25296
+ return normalizeTableCellAlign(align);
25297
+ }
25298
+ function normalizeTableCellAlignFromAttributes(attributes) {
25299
+ return normalizeTableCellAlign(attributes == null ? void 0 : attributes.align);
25300
+ }
25301
+ function createAlignAttribute() {
25302
+ return {
25303
+ default: null,
25304
+ parseHTML: (element) => parseAlign(element),
25305
+ renderHTML: (attributes) => {
25306
+ if (!attributes.align) {
25307
+ return {};
25308
+ }
25309
+ return {
25310
+ style: `text-align: ${attributes.align}`
25311
+ };
25312
+ }
25313
+ };
25314
+ }
25110
25315
  var TableCell = Node3.create({
25111
25316
  name: "tableCell",
25112
25317
  addOptions() {
@@ -25139,7 +25344,8 @@ var TableCell = Node3.create({
25139
25344
  }
25140
25345
  return value;
25141
25346
  }
25142
- }
25347
+ },
25348
+ align: createAlignAttribute()
25143
25349
  };
25144
25350
  },
25145
25351
  tableRole: "cell",
@@ -25174,7 +25380,8 @@ var TableHeader = Node3.create({
25174
25380
  const value = colwidth ? colwidth.split(",").map((width) => parseInt(width, 10)) : null;
25175
25381
  return value;
25176
25382
  }
25177
- }
25383
+ },
25384
+ align: createAlignAttribute()
25178
25385
  };
25179
25386
  },
25180
25387
  tableRole: "header_cell",
@@ -25402,7 +25609,8 @@ function renderTableToMarkdown(node, h2, options = {}) {
25402
25609
  }
25403
25610
  const text = collapseWhitespace(raw);
25404
25611
  const isHeader = cellNode.type === "tableHeader";
25405
- cells.push({ text, isHeader });
25612
+ const align = normalizeTableCellAlignFromAttributes(cellNode.attrs);
25613
+ cells.push({ text, isHeader, align });
25406
25614
  });
25407
25615
  }
25408
25616
  rows.push(cells);
@@ -25428,11 +25636,33 @@ function renderTableToMarkdown(node, h2, options = {}) {
25428
25636
  const pad = (s, width) => s + " ".repeat(Math.max(0, width - s.length));
25429
25637
  const headerRow = rows[0];
25430
25638
  const hasHeader = headerRow.some((c2) => c2.isHeader);
25639
+ const colAlignments = new Array(columnCount).fill(null);
25640
+ rows.forEach((r2) => {
25641
+ var _a2;
25642
+ for (let i = 0; i < columnCount; i += 1) {
25643
+ if (!colAlignments[i] && ((_a2 = r2[i]) == null ? void 0 : _a2.align)) {
25644
+ colAlignments[i] = r2[i].align;
25645
+ }
25646
+ }
25647
+ });
25431
25648
  let out = "\n";
25432
25649
  const headerTexts = new Array(columnCount).fill(0).map((_, i) => hasHeader ? headerRow[i] && headerRow[i].text || "" : "");
25433
25650
  out += `| ${headerTexts.map((t, i) => pad(t, colWidths[i])).join(" | ")} |
25434
25651
  `;
25435
- out += `| ${colWidths.map((w) => "-".repeat(Math.max(3, w))).join(" | ")} |
25652
+ out += `| ${colWidths.map((w, index) => {
25653
+ const dashCount = Math.max(3, w);
25654
+ const alignment = colAlignments[index];
25655
+ if (alignment === "left") {
25656
+ return `:${"-".repeat(dashCount)}`;
25657
+ }
25658
+ if (alignment === "right") {
25659
+ return `${"-".repeat(dashCount)}:`;
25660
+ }
25661
+ if (alignment === "center") {
25662
+ return `:${"-".repeat(dashCount)}:`;
25663
+ }
25664
+ return "-".repeat(dashCount);
25665
+ }).join(" | ")} |
25436
25666
  `;
25437
25667
  const body = hasHeader ? rows.slice(1) : rows;
25438
25668
  body.forEach((r2) => {
@@ -25486,18 +25716,27 @@ var Table = Node3.create({
25486
25716
  },
25487
25717
  parseMarkdown: (token, h2) => {
25488
25718
  const rows = [];
25719
+ const alignments = Array.isArray(token.align) ? token.align : [];
25489
25720
  if (token.header) {
25490
25721
  const headerCells = [];
25491
- token.header.forEach((cell) => {
25492
- headerCells.push(h2.createNode("tableHeader", {}, [{ type: "paragraph", content: h2.parseInline(cell.tokens) }]));
25722
+ token.header.forEach((cell, index) => {
25723
+ var _a;
25724
+ const align = normalizeTableCellAlign((_a = alignments[index]) != null ? _a : cell.align);
25725
+ const attrs = align ? { align } : {};
25726
+ headerCells.push(
25727
+ h2.createNode("tableHeader", attrs, [{ type: "paragraph", content: h2.parseInline(cell.tokens) }])
25728
+ );
25493
25729
  });
25494
25730
  rows.push(h2.createNode("tableRow", {}, headerCells));
25495
25731
  }
25496
25732
  if (token.rows) {
25497
25733
  token.rows.forEach((row) => {
25498
25734
  const bodyCells = [];
25499
- row.forEach((cell) => {
25500
- bodyCells.push(h2.createNode("tableCell", {}, [{ type: "paragraph", content: h2.parseInline(cell.tokens) }]));
25735
+ row.forEach((cell, index) => {
25736
+ var _a;
25737
+ const align = normalizeTableCellAlign((_a = alignments[index]) != null ? _a : cell.align);
25738
+ const attrs = align ? { align } : {};
25739
+ bodyCells.push(h2.createNode("tableCell", attrs, [{ type: "paragraph", content: h2.parseInline(cell.tokens) }]));
25501
25740
  });
25502
25741
  rows.push(h2.createNode("tableRow", {}, bodyCells));
25503
25742
  });
@@ -27298,7 +27537,7 @@ function LowlightPlugin({
27298
27537
  });
27299
27538
  return lowlightPlugin;
27300
27539
  }
27301
- var CodeBlockLowlight = index_default.extend({
27540
+ var CodeBlockLowlight = CodeBlock.extend({
27302
27541
  addOptions() {
27303
27542
  var _a;
27304
27543
  return {
@@ -42225,6 +42464,284 @@ class SearchReplace {
42225
42464
  }
42226
42465
  }
42227
42466
  }
42467
+ class SourceEditor {
42468
+ options;
42469
+ overlay = null;
42470
+ dialog = null;
42471
+ textarea = null;
42472
+ constructor(options) {
42473
+ this.options = options;
42474
+ }
42475
+ get tiptap() {
42476
+ return this.options.editor.getTipTap();
42477
+ }
42478
+ open() {
42479
+ if (this.overlay) {
42480
+ if (this.textarea) {
42481
+ this.textarea.value = this.tiptap?.getHTML() ?? "";
42482
+ }
42483
+ this.overlay.style.display = "flex";
42484
+ this.textarea?.focus();
42485
+ return;
42486
+ }
42487
+ this.createDialog();
42488
+ }
42489
+ close() {
42490
+ if (this.overlay) {
42491
+ this.overlay.style.display = "none";
42492
+ }
42493
+ }
42494
+ save() {
42495
+ if (this.textarea) {
42496
+ this.tiptap?.commands.setContent(this.textarea.value);
42497
+ }
42498
+ this.close();
42499
+ }
42500
+ createDialog() {
42501
+ const trans = this.options.trans;
42502
+ const skin = this.options.editor.getConfig().skin ?? "oxide";
42503
+ this.overlay = document.createElement("div");
42504
+ this.overlay.className = "md-dialog-overlay";
42505
+ this.overlay.addEventListener("click", (e) => {
42506
+ if (e.target === this.overlay) {
42507
+ this.close();
42508
+ }
42509
+ });
42510
+ const themeWrapper = document.createElement("div");
42511
+ themeWrapper.className = `md-editor-${skin}`;
42512
+ themeWrapper.style.display = "contents";
42513
+ this.dialog = document.createElement("div");
42514
+ this.dialog.className = "md-dialog md-source-editor-dialog";
42515
+ const header = document.createElement("div");
42516
+ header.className = "md-dialog-header";
42517
+ header.innerHTML = `
42518
+ <h3>${trans("Source code")}</h3>
42519
+ <button type="button" class="md-dialog-close">×</button>
42520
+ `;
42521
+ header.querySelector(".md-dialog-close")?.addEventListener("click", () => this.close());
42522
+ const body = document.createElement("div");
42523
+ body.className = "md-dialog-body";
42524
+ this.textarea = document.createElement("textarea");
42525
+ this.textarea.className = "md-source-editor-textarea";
42526
+ this.textarea.value = this.tiptap?.getHTML() ?? "";
42527
+ this.textarea.spellcheck = false;
42528
+ this.textarea.addEventListener("keydown", (e) => {
42529
+ if (e.key === "Tab") {
42530
+ e.preventDefault();
42531
+ const start = this.textarea.selectionStart;
42532
+ const end = this.textarea.selectionEnd;
42533
+ this.textarea.value = this.textarea.value.substring(0, start) + " " + this.textarea.value.substring(end);
42534
+ this.textarea.selectionStart = this.textarea.selectionEnd = start + 2;
42535
+ }
42536
+ });
42537
+ body.appendChild(this.textarea);
42538
+ const footer = document.createElement("div");
42539
+ footer.className = "md-source-editor-footer";
42540
+ footer.innerHTML = `
42541
+ <button type="button" class="md-btn md-source-editor-cancel">${trans("Cancel")}</button>
42542
+ <button type="button" class="md-btn md-btn-primary md-source-editor-save">${trans("Save")}</button>
42543
+ `;
42544
+ footer.querySelector(".md-source-editor-cancel")?.addEventListener("click", () => this.close());
42545
+ footer.querySelector(".md-source-editor-save")?.addEventListener("click", () => this.save());
42546
+ body.appendChild(footer);
42547
+ this.dialog.appendChild(header);
42548
+ this.dialog.appendChild(body);
42549
+ themeWrapper.appendChild(this.dialog);
42550
+ this.overlay.appendChild(themeWrapper);
42551
+ this.overlay.addEventListener("keydown", (e) => {
42552
+ if (e.key === "Escape") {
42553
+ this.close();
42554
+ }
42555
+ });
42556
+ document.body.appendChild(this.overlay);
42557
+ this.textarea.focus();
42558
+ }
42559
+ destroy() {
42560
+ if (this.overlay) {
42561
+ this.overlay.remove();
42562
+ this.overlay = null;
42563
+ this.dialog = null;
42564
+ this.textarea = null;
42565
+ }
42566
+ }
42567
+ }
42568
+ class LinkEditor {
42569
+ options;
42570
+ overlay = null;
42571
+ dialog = null;
42572
+ urlInput = null;
42573
+ textInput = null;
42574
+ titleInput = null;
42575
+ targetSelect = null;
42576
+ constructor(options) {
42577
+ this.options = options;
42578
+ }
42579
+ get tiptap() {
42580
+ return this.options.editor.getTipTap();
42581
+ }
42582
+ open() {
42583
+ if (!this.overlay) {
42584
+ this.createDialog();
42585
+ }
42586
+ this.populateFromSelection();
42587
+ this.overlay.style.display = "flex";
42588
+ this.urlInput?.focus();
42589
+ }
42590
+ close() {
42591
+ if (this.overlay) {
42592
+ this.overlay.style.display = "none";
42593
+ }
42594
+ }
42595
+ populateFromSelection() {
42596
+ const tiptap = this.tiptap;
42597
+ if (!tiptap) return;
42598
+ const attrs = tiptap.getAttributes("link");
42599
+ const { from: from2, to } = tiptap.state.selection;
42600
+ const selectedText = tiptap.state.doc.textBetween(from2, to, "");
42601
+ if (this.urlInput) this.urlInput.value = attrs.href ?? "";
42602
+ if (this.textInput) this.textInput.value = selectedText;
42603
+ if (this.titleInput) this.titleInput.value = attrs.title ?? "";
42604
+ if (this.targetSelect) this.targetSelect.value = attrs.target ?? "";
42605
+ }
42606
+ save() {
42607
+ const tiptap = this.tiptap;
42608
+ if (!tiptap) return;
42609
+ const url = this.urlInput?.value.trim() ?? "";
42610
+ const text = this.textInput?.value ?? "";
42611
+ const title = this.titleInput?.value.trim() ?? "";
42612
+ const target = this.targetSelect?.value ?? "";
42613
+ if (!url) {
42614
+ tiptap.chain().focus().unsetLink().run();
42615
+ this.close();
42616
+ return;
42617
+ }
42618
+ const linkAttrs = { href: url };
42619
+ if (target) {
42620
+ linkAttrs.target = target;
42621
+ } else {
42622
+ linkAttrs.target = null;
42623
+ }
42624
+ if (title) {
42625
+ linkAttrs.title = title;
42626
+ } else {
42627
+ linkAttrs.title = null;
42628
+ }
42629
+ const { from: from2, to } = tiptap.state.selection;
42630
+ const currentText = tiptap.state.doc.textBetween(from2, to, "");
42631
+ if (text && text !== currentText) {
42632
+ tiptap.chain().focus().deleteSelection().insertContent({
42633
+ type: "text",
42634
+ text,
42635
+ marks: [{ type: "link", attrs: linkAttrs }]
42636
+ }).run();
42637
+ } else if (from2 === to && text) {
42638
+ tiptap.chain().focus().insertContent({
42639
+ type: "text",
42640
+ text,
42641
+ marks: [{ type: "link", attrs: linkAttrs }]
42642
+ }).run();
42643
+ } else if (from2 === to && !text) {
42644
+ tiptap.chain().focus().insertContent({
42645
+ type: "text",
42646
+ text: url,
42647
+ marks: [{ type: "link", attrs: linkAttrs }]
42648
+ }).run();
42649
+ } else {
42650
+ tiptap.chain().focus().setLink(linkAttrs).run();
42651
+ }
42652
+ this.close();
42653
+ }
42654
+ createDialog() {
42655
+ const trans = this.options.trans;
42656
+ const skin = this.options.editor.getConfig().skin ?? "oxide";
42657
+ this.overlay = document.createElement("div");
42658
+ this.overlay.className = "md-dialog-overlay";
42659
+ this.overlay.addEventListener("click", (e) => {
42660
+ if (e.target === this.overlay) {
42661
+ this.close();
42662
+ }
42663
+ });
42664
+ const themeWrapper = document.createElement("div");
42665
+ themeWrapper.className = `md-editor-${skin}`;
42666
+ themeWrapper.style.display = "contents";
42667
+ this.dialog = document.createElement("div");
42668
+ this.dialog.className = "md-dialog md-link-editor-dialog";
42669
+ const header = document.createElement("div");
42670
+ header.className = "md-dialog-header";
42671
+ header.innerHTML = `
42672
+ <h3>${trans("Insert/Edit Link")}</h3>
42673
+ <button type="button" class="md-dialog-close">×</button>
42674
+ `;
42675
+ header.querySelector(".md-dialog-close")?.addEventListener("click", () => this.close());
42676
+ const body = document.createElement("div");
42677
+ body.className = "md-dialog-body";
42678
+ const urlRow = document.createElement("div");
42679
+ urlRow.className = "md-link-editor-row";
42680
+ urlRow.innerHTML = `<label>${trans("URL")}</label>`;
42681
+ this.urlInput = document.createElement("input");
42682
+ this.urlInput.type = "text";
42683
+ this.urlInput.className = "md-link-editor-input";
42684
+ urlRow.appendChild(this.urlInput);
42685
+ const textRow = document.createElement("div");
42686
+ textRow.className = "md-link-editor-row";
42687
+ textRow.innerHTML = `<label>${trans("Text to display")}</label>`;
42688
+ this.textInput = document.createElement("input");
42689
+ this.textInput.type = "text";
42690
+ this.textInput.className = "md-link-editor-input";
42691
+ textRow.appendChild(this.textInput);
42692
+ const titleRow = document.createElement("div");
42693
+ titleRow.className = "md-link-editor-row";
42694
+ titleRow.innerHTML = `<label>${trans("Title")}</label>`;
42695
+ this.titleInput = document.createElement("input");
42696
+ this.titleInput.type = "text";
42697
+ this.titleInput.className = "md-link-editor-input";
42698
+ titleRow.appendChild(this.titleInput);
42699
+ const targetRow = document.createElement("div");
42700
+ targetRow.className = "md-link-editor-row";
42701
+ targetRow.innerHTML = `<label>${trans("Open link in...")}</label>`;
42702
+ this.targetSelect = document.createElement("select");
42703
+ this.targetSelect.className = "md-link-editor-select";
42704
+ this.targetSelect.innerHTML = `
42705
+ <option value="">${trans("Current window")}</option>
42706
+ <option value="_blank">${trans("New window")}</option>
42707
+ `;
42708
+ targetRow.appendChild(this.targetSelect);
42709
+ body.appendChild(urlRow);
42710
+ body.appendChild(textRow);
42711
+ body.appendChild(titleRow);
42712
+ body.appendChild(targetRow);
42713
+ const footer = document.createElement("div");
42714
+ footer.className = "md-link-editor-footer";
42715
+ footer.innerHTML = `
42716
+ <button type="button" class="md-btn md-link-editor-cancel">${trans("Cancel")}</button>
42717
+ <button type="button" class="md-btn md-btn-primary md-link-editor-save">${trans("Save")}</button>
42718
+ `;
42719
+ footer.querySelector(".md-link-editor-cancel")?.addEventListener("click", () => this.close());
42720
+ footer.querySelector(".md-link-editor-save")?.addEventListener("click", () => this.save());
42721
+ body.appendChild(footer);
42722
+ this.dialog.appendChild(header);
42723
+ this.dialog.appendChild(body);
42724
+ themeWrapper.appendChild(this.dialog);
42725
+ this.overlay.appendChild(themeWrapper);
42726
+ this.overlay.addEventListener("keydown", (e) => {
42727
+ if (e.key === "Escape") {
42728
+ this.close();
42729
+ }
42730
+ });
42731
+ document.body.appendChild(this.overlay);
42732
+ }
42733
+ destroy() {
42734
+ if (this.overlay) {
42735
+ this.overlay.remove();
42736
+ this.overlay = null;
42737
+ this.dialog = null;
42738
+ this.urlInput = null;
42739
+ this.textInput = null;
42740
+ this.titleInput = null;
42741
+ this.targetSelect = null;
42742
+ }
42743
+ }
42744
+ }
42228
42745
  const DEFAULT_COLORS = [
42229
42746
  { value: "#000000", label: "Black" },
42230
42747
  { value: "#434343", label: "Dark Gray 4" },
@@ -42275,6 +42792,8 @@ class Toolbar {
42275
42792
  emojiPicker = null;
42276
42793
  imageUpload = null;
42277
42794
  searchReplace = null;
42795
+ sourceEditor = null;
42796
+ linkEditor = null;
42278
42797
  updateInterval = null;
42279
42798
  boundClickHandler = null;
42280
42799
  boundKeydownHandler = null;
@@ -42297,6 +42816,9 @@ class Toolbar {
42297
42816
  get trans() {
42298
42817
  return getTranslate();
42299
42818
  }
42819
+ icon(name) {
42820
+ return this.options.iconSet[name] ?? name;
42821
+ }
42300
42822
  render() {
42301
42823
  this.container.innerHTML = "";
42302
42824
  this.container.className = `md-toolbar md-toolbar-${this.options.mode}${this.options.sticky ? " md-toolbar-sticky" : ""}`;
@@ -42349,7 +42871,7 @@ class Toolbar {
42349
42871
  button.className = "md-toolbar-btn md-toolbar-toggle-btn";
42350
42872
  button.setAttribute("data-button", "togglemore");
42351
42873
  button.title = this.trans("More");
42352
- button.innerHTML = '<span class="md-toolbar-btn-icon">…</span>';
42874
+ button.innerHTML = `<span class="md-toolbar-btn-icon">${this.icon("togglemore")}</span>`;
42353
42875
  button.addEventListener("click", (e) => {
42354
42876
  e.preventDefault();
42355
42877
  this.toggleOverflow();
@@ -42372,43 +42894,43 @@ class Toolbar {
42372
42894
  }
42373
42895
  switch (name.toLowerCase()) {
42374
42896
  case "bold":
42375
- return this.createActionButton("bold", "B", this.trans("Bold"), () => {
42897
+ return this.createActionButton("bold", this.icon("bold"), this.trans("Bold"), () => {
42376
42898
  this.tiptap?.chain().focus().toggleBold().run();
42377
42899
  }, () => this.tiptap?.isActive("bold") ?? false);
42378
42900
  case "italic":
42379
- return this.createActionButton("italic", "I", this.trans("Italic"), () => {
42901
+ return this.createActionButton("italic", this.icon("italic"), this.trans("Italic"), () => {
42380
42902
  this.tiptap?.chain().focus().toggleItalic().run();
42381
42903
  }, () => this.tiptap?.isActive("italic") ?? false);
42382
42904
  case "underline":
42383
- return this.createActionButton("underline", "U", this.trans("Underline"), () => {
42905
+ return this.createActionButton("underline", this.icon("underline"), this.trans("Underline"), () => {
42384
42906
  this.tiptap?.chain().focus().toggleUnderline().run();
42385
42907
  }, () => this.tiptap?.isActive("underline") ?? false);
42386
42908
  case "strikethrough":
42387
- return this.createActionButton("strikethrough", "S", this.trans("Strikethrough"), () => {
42909
+ return this.createActionButton("strikethrough", this.icon("strikethrough"), this.trans("Strikethrough"), () => {
42388
42910
  this.tiptap?.chain().focus().toggleStrike().run();
42389
42911
  }, () => this.tiptap?.isActive("strike") ?? false);
42390
42912
  case "bullist":
42391
- return this.createActionButton("bullist", "", this.trans("Bullet list"), () => {
42913
+ return this.createActionButton("bullist", this.icon("bullist"), this.trans("Bullet list"), () => {
42392
42914
  this.tiptap?.chain().focus().toggleBulletList().run();
42393
42915
  }, () => this.tiptap?.isActive("bulletList") ?? false);
42394
42916
  case "numlist":
42395
- return this.createActionButton("numlist", "1.", this.trans("Numbered list"), () => {
42917
+ return this.createActionButton("numlist", this.icon("numlist"), this.trans("Numbered list"), () => {
42396
42918
  this.tiptap?.chain().focus().toggleOrderedList().run();
42397
42919
  }, () => this.tiptap?.isActive("orderedList") ?? false);
42398
42920
  case "outdent":
42399
- return this.createActionButton("outdent", "", this.trans("Decrease indent"), () => {
42921
+ return this.createActionButton("outdent", this.icon("outdent"), this.trans("Decrease indent"), () => {
42400
42922
  if (this.tiptap?.isActive("listItem")) {
42401
42923
  this.tiptap?.chain().focus().liftListItem("listItem").run();
42402
42924
  }
42403
42925
  });
42404
42926
  case "indent":
42405
- return this.createActionButton("indent", "", this.trans("Increase indent"), () => {
42927
+ return this.createActionButton("indent", this.icon("indent"), this.trans("Increase indent"), () => {
42406
42928
  if (this.tiptap?.isActive("listItem")) {
42407
42929
  this.tiptap?.chain().focus().sinkListItem("listItem").run();
42408
42930
  }
42409
42931
  });
42410
42932
  case "blockquote":
42411
- return this.createActionButton("blockquote", '"', this.trans("Blockquote"), () => {
42933
+ return this.createActionButton("blockquote", this.icon("blockquote"), this.trans("Blockquote"), () => {
42412
42934
  this.tiptap?.chain().focus().toggleBlockquote().run();
42413
42935
  }, () => this.tiptap?.isActive("blockquote") ?? false);
42414
42936
  case "fontfamily":
@@ -42418,19 +42940,19 @@ class Toolbar {
42418
42940
  case "lineheight":
42419
42941
  return this.createLineHeightDropdown();
42420
42942
  case "alignleft":
42421
- 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"), () => {
42943
+ return this.createActionButton("alignleft", this.icon("alignleft"), this.trans("Align left"), () => {
42422
42944
  this.tiptap?.chain().focus().setTextAlign("left").run();
42423
42945
  }, () => this.tiptap?.isActive({ textAlign: "left" }) ?? false);
42424
42946
  case "aligncenter":
42425
- 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"), () => {
42947
+ return this.createActionButton("aligncenter", this.icon("aligncenter"), this.trans("Align center"), () => {
42426
42948
  this.tiptap?.chain().focus().setTextAlign("center").run();
42427
42949
  }, () => this.tiptap?.isActive({ textAlign: "center" }) ?? false);
42428
42950
  case "alignright":
42429
- 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"), () => {
42951
+ return this.createActionButton("alignright", this.icon("alignright"), this.trans("Align right"), () => {
42430
42952
  this.tiptap?.chain().focus().setTextAlign("right").run();
42431
42953
  }, () => this.tiptap?.isActive({ textAlign: "right" }) ?? false);
42432
42954
  case "alignjustify":
42433
- 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"), () => {
42955
+ return this.createActionButton("alignjustify", this.icon("alignjustify"), this.trans("Justify"), () => {
42434
42956
  this.tiptap?.chain().focus().setTextAlign("justify").run();
42435
42957
  }, () => this.tiptap?.isActive({ textAlign: "justify" }) ?? false);
42436
42958
  case "forecolor":
@@ -42442,71 +42964,71 @@ class Toolbar {
42442
42964
  this.tiptap?.chain().focus().setHighlight({ color }).run();
42443
42965
  });
42444
42966
  case "removeformat":
42445
- return this.createActionButton("removeformat", "", this.trans("Remove formatting"), () => {
42967
+ return this.createActionButton("removeformat", this.icon("removeformat"), this.trans("Remove formatting"), () => {
42446
42968
  this.tiptap?.chain().focus().unsetAllMarks().clearNodes().run();
42447
42969
  });
42448
42970
  case "copy":
42449
- return this.createActionButton("copy", "📋", this.trans("Copy"), () => {
42971
+ return this.createActionButton("copy", this.icon("copy"), this.trans("Copy"), () => {
42450
42972
  document.execCommand("copy");
42451
42973
  });
42452
42974
  case "cut":
42453
- return this.createActionButton("cut", "", this.trans("Cut"), () => {
42975
+ return this.createActionButton("cut", this.icon("cut"), this.trans("Cut"), () => {
42454
42976
  document.execCommand("cut");
42455
42977
  });
42456
42978
  case "paste":
42457
- return this.createActionButton("paste", "📄", this.trans("Paste"), () => {
42979
+ return this.createActionButton("paste", this.icon("paste"), this.trans("Paste"), () => {
42458
42980
  document.execCommand("paste");
42459
42981
  });
42460
42982
  case "undo":
42461
- return this.createActionButton("undo", "", this.trans("Undo"), () => {
42983
+ return this.createActionButton("undo", this.icon("undo"), this.trans("Undo"), () => {
42462
42984
  this.tiptap?.chain().focus().undo().run();
42463
42985
  });
42464
42986
  case "redo":
42465
- return this.createActionButton("redo", "", this.trans("Redo"), () => {
42987
+ return this.createActionButton("redo", this.icon("redo"), this.trans("Redo"), () => {
42466
42988
  this.tiptap?.chain().focus().redo().run();
42467
42989
  });
42468
42990
  case "image":
42469
- 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"), () => {
42991
+ return this.createActionButton("image", this.icon("image"), this.trans("Insert image"), () => {
42470
42992
  this.openImageDialog();
42471
42993
  });
42472
42994
  case "charmap":
42473
- return this.createActionButton("charmap", "Ω", this.trans("Special character"), () => {
42995
+ return this.createActionButton("charmap", this.icon("charmap"), this.trans("Special character"), () => {
42474
42996
  this.openCharMap();
42475
42997
  });
42476
42998
  case "emoticons":
42477
- return this.createActionButton("emoticons", "😀", this.trans("Emoticons"), () => {
42999
+ return this.createActionButton("emoticons", this.icon("emoticons"), this.trans("Emoticons"), () => {
42478
43000
  this.openEmojiPicker();
42479
43001
  });
42480
43002
  case "fullscreen":
42481
- return this.createActionButton("fullscreen", "", this.trans("Fullscreen"), () => {
43003
+ return this.createActionButton("fullscreen", this.icon("fullscreen"), this.trans("Fullscreen"), () => {
42482
43004
  this.toggleFullscreen();
42483
43005
  }, () => this.state.isFullscreen);
42484
43006
  case "preview":
42485
- return this.createActionButton("preview", "👁", this.trans("Preview"), () => {
43007
+ return this.createActionButton("preview", this.icon("preview"), this.trans("Preview"), () => {
42486
43008
  this.openPreview();
42487
43009
  });
42488
43010
  case "code":
42489
- 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"), () => {
43011
+ return this.createActionButton("code", this.icon("code"), this.trans("Source code"), () => {
42490
43012
  this.openSourceCode();
42491
43013
  });
42492
43014
  case "link":
42493
- return this.createActionButton("link", "🔗", this.trans("Insert link"), () => {
43015
+ return this.createActionButton("link", this.icon("link"), this.trans("Insert link"), () => {
42494
43016
  this.openLinkDialog();
42495
43017
  }, () => this.tiptap?.isActive("link") ?? false);
42496
43018
  case "codesample":
42497
- return this.createActionButton("codesample", "{}", this.trans("Code sample"), () => {
43019
+ return this.createActionButton("codesample", this.icon("codesample"), this.trans("Code sample"), () => {
42498
43020
  this.tiptap?.chain().focus().toggleCodeBlock().run();
42499
43021
  }, () => this.tiptap?.isActive("codeBlock") ?? false);
42500
43022
  case "ltr":
42501
- return this.createActionButton("ltr", "", this.trans("Left to right"), () => {
43023
+ return this.createActionButton("ltr", this.icon("ltr"), this.trans("Left to right"), () => {
42502
43024
  this.tiptap?.chain().focus().setTextDirection("ltr").run();
42503
43025
  });
42504
43026
  case "rtl":
42505
- return this.createActionButton("rtl", "", this.trans("Right to left"), () => {
43027
+ return this.createActionButton("rtl", this.icon("rtl"), this.trans("Right to left"), () => {
42506
43028
  this.tiptap?.chain().focus().setTextDirection("rtl").run();
42507
43029
  });
42508
43030
  case "searchreplace":
42509
- return this.createActionButton("searchreplace", "🔍", this.trans("Find and replace"), () => {
43031
+ return this.createActionButton("searchreplace", this.icon("searchreplace"), this.trans("Find and replace"), () => {
42510
43032
  this.openSearchReplace();
42511
43033
  });
42512
43034
  case "template":
@@ -42875,14 +43397,13 @@ class Toolbar {
42875
43397
  this.imageUpload.open();
42876
43398
  }
42877
43399
  openLinkDialog() {
42878
- const previousUrl = this.tiptap?.getAttributes("link").href ?? "";
42879
- const url = prompt(this.trans("Enter URL:"), previousUrl);
42880
- if (url === null) return;
42881
- if (url === "") {
42882
- this.tiptap?.chain().focus().unsetLink().run();
42883
- } else {
42884
- this.tiptap?.chain().focus().setLink({ href: url }).run();
43400
+ if (!this.linkEditor) {
43401
+ this.linkEditor = new LinkEditor({
43402
+ editor: this.options.editor,
43403
+ trans: this.trans
43404
+ });
42885
43405
  }
43406
+ this.linkEditor.open();
42886
43407
  }
42887
43408
  openCharMap() {
42888
43409
  if (!this.charMap) {
@@ -42916,11 +43437,13 @@ class Toolbar {
42916
43437
  this.searchReplace.open();
42917
43438
  }
42918
43439
  openSourceCode() {
42919
- const html = this.tiptap?.getHTML() ?? "";
42920
- const newHtml = prompt(this.trans("Edit HTML source:"), html);
42921
- if (newHtml !== null) {
42922
- this.tiptap?.commands.setContent(newHtml);
43440
+ if (!this.sourceEditor) {
43441
+ this.sourceEditor = new SourceEditor({
43442
+ editor: this.options.editor,
43443
+ trans: this.trans
43444
+ });
42923
43445
  }
43446
+ this.sourceEditor.open();
42924
43447
  }
42925
43448
  openPreview() {
42926
43449
  const html = this.tiptap?.getHTML() ?? "";
@@ -42982,6 +43505,78 @@ class Toolbar {
42982
43505
  this.container.innerHTML = "";
42983
43506
  }
42984
43507
  }
43508
+ 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>';
43509
+ 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>';
43510
+ 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>';
43511
+ 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>';
43512
+ 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>';
43513
+ 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>';
43514
+ const DEFAULT_ICONS = {
43515
+ bold: "B",
43516
+ italic: "I",
43517
+ underline: "U",
43518
+ strikethrough: "S",
43519
+ bullist: "•",
43520
+ numlist: "1.",
43521
+ outdent: "←",
43522
+ indent: "→",
43523
+ blockquote: '"',
43524
+ alignleft: SVG_ALIGN_LEFT,
43525
+ aligncenter: SVG_ALIGN_CENTER,
43526
+ alignright: SVG_ALIGN_RIGHT,
43527
+ alignjustify: SVG_ALIGN_JUSTIFY,
43528
+ removeformat: "✕",
43529
+ copy: "📋",
43530
+ cut: "✂",
43531
+ paste: "📄",
43532
+ undo: "↩",
43533
+ redo: "↪",
43534
+ image: SVG_IMAGE,
43535
+ charmap: "Ω",
43536
+ emoticons: "😀",
43537
+ fullscreen: "⛶",
43538
+ preview: "👁",
43539
+ code: SVG_CODE,
43540
+ link: "🔗",
43541
+ codesample: "{}",
43542
+ ltr: "⇐",
43543
+ rtl: "⇒",
43544
+ searchreplace: "🔍",
43545
+ togglemore: "…"
43546
+ };
43547
+ const CONFAB_ICONS = {
43548
+ 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>',
43549
+ 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>',
43550
+ 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>',
43551
+ 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>',
43552
+ 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>',
43553
+ 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>',
43554
+ 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>',
43555
+ 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>',
43556
+ 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>',
43557
+ alignleft: SVG_ALIGN_LEFT,
43558
+ aligncenter: SVG_ALIGN_CENTER,
43559
+ alignright: SVG_ALIGN_RIGHT,
43560
+ alignjustify: SVG_ALIGN_JUSTIFY,
43561
+ 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>',
43562
+ 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>',
43563
+ 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>',
43564
+ 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>',
43565
+ 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>',
43566
+ 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>',
43567
+ image: SVG_IMAGE,
43568
+ charmap: "Ω",
43569
+ emoticons: "😀",
43570
+ 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>',
43571
+ 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>',
43572
+ code: SVG_CODE,
43573
+ 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>',
43574
+ 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>',
43575
+ 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>',
43576
+ 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>',
43577
+ 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>',
43578
+ 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>'
43579
+ };
42985
43580
  const FontSize = Extension.create({
42986
43581
  name: "fontSize",
42987
43582
  addOptions() {
@@ -43109,6 +43704,30 @@ const TextDirection = Extension.create({
43109
43704
  };
43110
43705
  }
43111
43706
  });
43707
+ const SignatureBlock = Node3.create({
43708
+ name: "signatureBlock",
43709
+ group: "block",
43710
+ content: "block+",
43711
+ defining: true,
43712
+ isolating: true,
43713
+ addAttributes() {
43714
+ return {
43715
+ id: {
43716
+ default: "signature"
43717
+ }
43718
+ };
43719
+ },
43720
+ parseHTML() {
43721
+ return [
43722
+ {
43723
+ tag: 'div[id="signature"]'
43724
+ }
43725
+ ];
43726
+ },
43727
+ renderHTML({ HTMLAttributes }) {
43728
+ return ["div", mergeAttributes(HTMLAttributes), 0];
43729
+ }
43730
+ });
43112
43731
  const en = {
43113
43732
  "Bold": "Bold",
43114
43733
  "Italic": "Italic",
@@ -43172,7 +43791,14 @@ const en = {
43172
43791
  "Invalid image URL": "Invalid image URL",
43173
43792
  "File too large": "File too large",
43174
43793
  "Invalid file type": "Invalid file type",
43175
- "More": "More"
43794
+ "More": "More",
43795
+ "Save": "Save",
43796
+ "Insert/Edit Link": "Insert/Edit Link",
43797
+ "Text to display": "Text to display",
43798
+ "Title": "Title",
43799
+ "Open link in...": "Open link in...",
43800
+ "Current window": "Current window",
43801
+ "New window": "New window"
43176
43802
  };
43177
43803
  const ar = {
43178
43804
  "Bold": "غامق",
@@ -43237,7 +43863,14 @@ const ar = {
43237
43863
  "Invalid image URL": "رابط صورة غير صالح",
43238
43864
  "File too large": "الملف كبير جداً",
43239
43865
  "Invalid file type": "نوع ملف غير صالح",
43240
- "More": "المزيد"
43866
+ "More": "المزيد",
43867
+ "Save": "Save",
43868
+ "Insert/Edit Link": "Insert/Edit Link",
43869
+ "Text to display": "Text to display",
43870
+ "Title": "Title",
43871
+ "Open link in...": "Open link in...",
43872
+ "Current window": "Current window",
43873
+ "New window": "New window"
43241
43874
  };
43242
43875
  const ca = {
43243
43876
  "Bold": "Negreta",
@@ -43302,7 +43935,14 @@ const ca = {
43302
43935
  "Invalid image URL": "URL d'imatge no vàlida",
43303
43936
  "File too large": "Fitxer massa gran",
43304
43937
  "Invalid file type": "Tipus de fitxer no vàlid",
43305
- "More": "Més"
43938
+ "More": "Més",
43939
+ "Save": "Save",
43940
+ "Insert/Edit Link": "Insert/Edit Link",
43941
+ "Text to display": "Text to display",
43942
+ "Title": "Title",
43943
+ "Open link in...": "Open link in...",
43944
+ "Current window": "Current window",
43945
+ "New window": "New window"
43306
43946
  };
43307
43947
  const zh = {
43308
43948
  "Bold": "粗体",
@@ -43367,7 +44007,14 @@ const zh = {
43367
44007
  "Invalid image URL": "无效的图片 URL",
43368
44008
  "File too large": "文件过大",
43369
44009
  "Invalid file type": "无效的文件类型",
43370
- "More": "更多"
44010
+ "More": "更多",
44011
+ "Save": "Save",
44012
+ "Insert/Edit Link": "Insert/Edit Link",
44013
+ "Text to display": "Text to display",
44014
+ "Title": "Title",
44015
+ "Open link in...": "Open link in...",
44016
+ "Current window": "Current window",
44017
+ "New window": "New window"
43371
44018
  };
43372
44019
  const cs = {
43373
44020
  "Bold": "Tučné",
@@ -43432,7 +44079,14 @@ const cs = {
43432
44079
  "Invalid image URL": "Neplatná URL obrázku",
43433
44080
  "File too large": "Soubor je příliš velký",
43434
44081
  "Invalid file type": "Neplatný typ souboru",
43435
- "More": "Více"
44082
+ "More": "Více",
44083
+ "Save": "Save",
44084
+ "Insert/Edit Link": "Insert/Edit Link",
44085
+ "Text to display": "Text to display",
44086
+ "Title": "Title",
44087
+ "Open link in...": "Open link in...",
44088
+ "Current window": "Current window",
44089
+ "New window": "New window"
43436
44090
  };
43437
44091
  const da = {
43438
44092
  "Bold": "Fed",
@@ -43497,7 +44151,14 @@ const da = {
43497
44151
  "Invalid image URL": "Ugyldig billed-URL",
43498
44152
  "File too large": "Filen er for stor",
43499
44153
  "Invalid file type": "Ugyldig filtype",
43500
- "More": "Mere"
44154
+ "More": "Mere",
44155
+ "Save": "Save",
44156
+ "Insert/Edit Link": "Insert/Edit Link",
44157
+ "Text to display": "Text to display",
44158
+ "Title": "Title",
44159
+ "Open link in...": "Open link in...",
44160
+ "Current window": "Current window",
44161
+ "New window": "New window"
43501
44162
  };
43502
44163
  const enGb = {
43503
44164
  "Bold": "Bold",
@@ -43562,7 +44223,14 @@ const enGb = {
43562
44223
  "Invalid image URL": "Invalid image URL",
43563
44224
  "File too large": "File too large",
43564
44225
  "Invalid file type": "Invalid file type",
43565
- "More": "More"
44226
+ "More": "More",
44227
+ "Save": "Save",
44228
+ "Insert/Edit Link": "Insert/Edit Link",
44229
+ "Text to display": "Text to display",
44230
+ "Title": "Title",
44231
+ "Open link in...": "Open link in...",
44232
+ "Current window": "Current window",
44233
+ "New window": "New window"
43566
44234
  };
43567
44235
  const fi = {
43568
44236
  "Bold": "Lihavoitu",
@@ -43627,7 +44295,14 @@ const fi = {
43627
44295
  "Invalid image URL": "Virheellinen kuvan URL",
43628
44296
  "File too large": "Tiedosto on liian suuri",
43629
44297
  "Invalid file type": "Virheellinen tiedostotyyppi",
43630
- "More": "Lisää"
44298
+ "More": "Lisää",
44299
+ "Save": "Save",
44300
+ "Insert/Edit Link": "Insert/Edit Link",
44301
+ "Text to display": "Text to display",
44302
+ "Title": "Title",
44303
+ "Open link in...": "Open link in...",
44304
+ "Current window": "Current window",
44305
+ "New window": "New window"
43631
44306
  };
43632
44307
  const fr = {
43633
44308
  "Bold": "Gras",
@@ -43692,7 +44367,14 @@ const fr = {
43692
44367
  "Invalid image URL": "URL d'image invalide",
43693
44368
  "File too large": "Fichier trop volumineux",
43694
44369
  "Invalid file type": "Type de fichier invalide",
43695
- "More": "Plus"
44370
+ "More": "Plus",
44371
+ "Save": "Save",
44372
+ "Insert/Edit Link": "Insert/Edit Link",
44373
+ "Text to display": "Text to display",
44374
+ "Title": "Title",
44375
+ "Open link in...": "Open link in...",
44376
+ "Current window": "Current window",
44377
+ "New window": "New window"
43696
44378
  };
43697
44379
  const frCa = {
43698
44380
  "Bold": "Gras",
@@ -43757,7 +44439,14 @@ const frCa = {
43757
44439
  "Invalid image URL": "URL d'image invalide",
43758
44440
  "File too large": "Fichier trop volumineux",
43759
44441
  "Invalid file type": "Type de fichier invalide",
43760
- "More": "Plus"
44442
+ "More": "Plus",
44443
+ "Save": "Save",
44444
+ "Insert/Edit Link": "Insert/Edit Link",
44445
+ "Text to display": "Text to display",
44446
+ "Title": "Title",
44447
+ "Open link in...": "Open link in...",
44448
+ "Current window": "Current window",
44449
+ "New window": "New window"
43761
44450
  };
43762
44451
  const de = {
43763
44452
  "Bold": "Fett",
@@ -43822,7 +44511,14 @@ const de = {
43822
44511
  "Invalid image URL": "Ungültige Bild-URL",
43823
44512
  "File too large": "Datei zu groß",
43824
44513
  "Invalid file type": "Ungültiger Dateityp",
43825
- "More": "Mehr"
44514
+ "More": "Mehr",
44515
+ "Save": "Save",
44516
+ "Insert/Edit Link": "Insert/Edit Link",
44517
+ "Text to display": "Text to display",
44518
+ "Title": "Title",
44519
+ "Open link in...": "Open link in...",
44520
+ "Current window": "Current window",
44521
+ "New window": "New window"
43826
44522
  };
43827
44523
  const el = {
43828
44524
  "Bold": "Έντονα",
@@ -43887,7 +44583,14 @@ const el = {
43887
44583
  "Invalid image URL": "Μη έγκυρο URL εικόνας",
43888
44584
  "File too large": "Το αρχείο είναι πολύ μεγάλο",
43889
44585
  "Invalid file type": "Μη έγκυρος τύπος αρχείου",
43890
- "More": "Περισσότερα"
44586
+ "More": "Περισσότερα",
44587
+ "Save": "Save",
44588
+ "Insert/Edit Link": "Insert/Edit Link",
44589
+ "Text to display": "Text to display",
44590
+ "Title": "Title",
44591
+ "Open link in...": "Open link in...",
44592
+ "Current window": "Current window",
44593
+ "New window": "New window"
43891
44594
  };
43892
44595
  const hu = {
43893
44596
  "Bold": "Félkövér",
@@ -43952,7 +44655,14 @@ const hu = {
43952
44655
  "Invalid image URL": "Érvénytelen kép URL",
43953
44656
  "File too large": "A fájl túl nagy",
43954
44657
  "Invalid file type": "Érvénytelen fájltípus",
43955
- "More": "Több"
44658
+ "More": "Több",
44659
+ "Save": "Save",
44660
+ "Insert/Edit Link": "Insert/Edit Link",
44661
+ "Text to display": "Text to display",
44662
+ "Title": "Title",
44663
+ "Open link in...": "Open link in...",
44664
+ "Current window": "Current window",
44665
+ "New window": "New window"
43956
44666
  };
43957
44667
  const id = {
43958
44668
  "Bold": "Tebal",
@@ -44017,7 +44727,14 @@ const id = {
44017
44727
  "Invalid image URL": "URL gambar tidak valid",
44018
44728
  "File too large": "File terlalu besar",
44019
44729
  "Invalid file type": "Jenis file tidak valid",
44020
- "More": "Lainnya"
44730
+ "More": "Lainnya",
44731
+ "Save": "Save",
44732
+ "Insert/Edit Link": "Insert/Edit Link",
44733
+ "Text to display": "Text to display",
44734
+ "Title": "Title",
44735
+ "Open link in...": "Open link in...",
44736
+ "Current window": "Current window",
44737
+ "New window": "New window"
44021
44738
  };
44022
44739
  const it = {
44023
44740
  "Bold": "Grassetto",
@@ -44082,7 +44799,14 @@ const it = {
44082
44799
  "Invalid image URL": "URL immagine non valido",
44083
44800
  "File too large": "File troppo grande",
44084
44801
  "Invalid file type": "Tipo di file non valido",
44085
- "More": "Altro"
44802
+ "More": "Altro",
44803
+ "Save": "Save",
44804
+ "Insert/Edit Link": "Insert/Edit Link",
44805
+ "Text to display": "Text to display",
44806
+ "Title": "Title",
44807
+ "Open link in...": "Open link in...",
44808
+ "Current window": "Current window",
44809
+ "New window": "New window"
44086
44810
  };
44087
44811
  const ja = {
44088
44812
  "Bold": "太字",
@@ -44147,7 +44871,14 @@ const ja = {
44147
44871
  "Invalid image URL": "無効な画像URL",
44148
44872
  "File too large": "ファイルが大きすぎます",
44149
44873
  "Invalid file type": "無効なファイル形式",
44150
- "More": "もっと見る"
44874
+ "More": "もっと見る",
44875
+ "Save": "Save",
44876
+ "Insert/Edit Link": "Insert/Edit Link",
44877
+ "Text to display": "Text to display",
44878
+ "Title": "Title",
44879
+ "Open link in...": "Open link in...",
44880
+ "Current window": "Current window",
44881
+ "New window": "New window"
44151
44882
  };
44152
44883
  const ko = {
44153
44884
  "Bold": "굵게",
@@ -44212,7 +44943,14 @@ const ko = {
44212
44943
  "Invalid image URL": "잘못된 이미지 URL",
44213
44944
  "File too large": "파일이 너무 큽니다",
44214
44945
  "Invalid file type": "잘못된 파일 형식",
44215
- "More": "더 보기"
44946
+ "More": "더 보기",
44947
+ "Save": "Save",
44948
+ "Insert/Edit Link": "Insert/Edit Link",
44949
+ "Text to display": "Text to display",
44950
+ "Title": "Title",
44951
+ "Open link in...": "Open link in...",
44952
+ "Current window": "Current window",
44953
+ "New window": "New window"
44216
44954
  };
44217
44955
  const nl = {
44218
44956
  "Bold": "Vet",
@@ -44277,7 +45015,14 @@ const nl = {
44277
45015
  "Invalid image URL": "Ongeldige afbeeldings-URL",
44278
45016
  "File too large": "Bestand te groot",
44279
45017
  "Invalid file type": "Ongeldig bestandstype",
44280
- "More": "Meer"
45018
+ "More": "Meer",
45019
+ "Save": "Save",
45020
+ "Insert/Edit Link": "Insert/Edit Link",
45021
+ "Text to display": "Text to display",
45022
+ "Title": "Title",
45023
+ "Open link in...": "Open link in...",
45024
+ "Current window": "Current window",
45025
+ "New window": "New window"
44281
45026
  };
44282
45027
  const nb = {
44283
45028
  "Bold": "Fet",
@@ -44342,7 +45087,14 @@ const nb = {
44342
45087
  "Invalid image URL": "Ugyldig bilde-URL",
44343
45088
  "File too large": "Filen er for stor",
44344
45089
  "Invalid file type": "Ugyldig filtype",
44345
- "More": "Mer"
45090
+ "More": "Mer",
45091
+ "Save": "Save",
45092
+ "Insert/Edit Link": "Insert/Edit Link",
45093
+ "Text to display": "Text to display",
45094
+ "Title": "Title",
45095
+ "Open link in...": "Open link in...",
45096
+ "Current window": "Current window",
45097
+ "New window": "New window"
44346
45098
  };
44347
45099
  const pl = {
44348
45100
  "Bold": "Pogrubienie",
@@ -44407,7 +45159,14 @@ const pl = {
44407
45159
  "Invalid image URL": "Nieprawidłowy URL obrazu",
44408
45160
  "File too large": "Plik jest za duży",
44409
45161
  "Invalid file type": "Nieprawidłowy typ pliku",
44410
- "More": "Więcej"
45162
+ "More": "Więcej",
45163
+ "Save": "Save",
45164
+ "Insert/Edit Link": "Insert/Edit Link",
45165
+ "Text to display": "Text to display",
45166
+ "Title": "Title",
45167
+ "Open link in...": "Open link in...",
45168
+ "Current window": "Current window",
45169
+ "New window": "New window"
44411
45170
  };
44412
45171
  const pt = {
44413
45172
  "Bold": "Negrito",
@@ -44472,7 +45231,14 @@ const pt = {
44472
45231
  "Invalid image URL": "URL de imagem inválido",
44473
45232
  "File too large": "Arquivo muito grande",
44474
45233
  "Invalid file type": "Tipo de arquivo inválido",
44475
- "More": "Mais"
45234
+ "More": "Mais",
45235
+ "Save": "Save",
45236
+ "Insert/Edit Link": "Insert/Edit Link",
45237
+ "Text to display": "Text to display",
45238
+ "Title": "Title",
45239
+ "Open link in...": "Open link in...",
45240
+ "Current window": "Current window",
45241
+ "New window": "New window"
44476
45242
  };
44477
45243
  const ro = {
44478
45244
  "Bold": "Îngroșat",
@@ -44537,7 +45303,14 @@ const ro = {
44537
45303
  "Invalid image URL": "URL imagine invalid",
44538
45304
  "File too large": "Fișierul este prea mare",
44539
45305
  "Invalid file type": "Tip de fișier invalid",
44540
- "More": "Mai mult"
45306
+ "More": "Mai mult",
45307
+ "Save": "Save",
45308
+ "Insert/Edit Link": "Insert/Edit Link",
45309
+ "Text to display": "Text to display",
45310
+ "Title": "Title",
45311
+ "Open link in...": "Open link in...",
45312
+ "Current window": "Current window",
45313
+ "New window": "New window"
44541
45314
  };
44542
45315
  const ru = {
44543
45316
  "Bold": "Полужирный",
@@ -44602,7 +45375,14 @@ const ru = {
44602
45375
  "Invalid image URL": "Недопустимый URL изображения",
44603
45376
  "File too large": "Файл слишком большой",
44604
45377
  "Invalid file type": "Недопустимый тип файла",
44605
- "More": "Ещё"
45378
+ "More": "Ещё",
45379
+ "Save": "Save",
45380
+ "Insert/Edit Link": "Insert/Edit Link",
45381
+ "Text to display": "Text to display",
45382
+ "Title": "Title",
45383
+ "Open link in...": "Open link in...",
45384
+ "Current window": "Current window",
45385
+ "New window": "New window"
44606
45386
  };
44607
45387
  const sr = {
44608
45388
  "Bold": "Подебљано",
@@ -44667,7 +45447,14 @@ const sr = {
44667
45447
  "Invalid image URL": "Неважећи URL слике",
44668
45448
  "File too large": "Датотека је превелика",
44669
45449
  "Invalid file type": "Неважећи тип датотеке",
44670
- "More": "Још"
45450
+ "More": "Још",
45451
+ "Save": "Save",
45452
+ "Insert/Edit Link": "Insert/Edit Link",
45453
+ "Text to display": "Text to display",
45454
+ "Title": "Title",
45455
+ "Open link in...": "Open link in...",
45456
+ "Current window": "Current window",
45457
+ "New window": "New window"
44671
45458
  };
44672
45459
  const sl = {
44673
45460
  "Bold": "Krepko",
@@ -44732,7 +45519,14 @@ const sl = {
44732
45519
  "Invalid image URL": "Neveljaven URL slike",
44733
45520
  "File too large": "Datoteka je prevelika",
44734
45521
  "Invalid file type": "Neveljavna vrsta datoteke",
44735
- "More": "Več"
45522
+ "More": "Več",
45523
+ "Save": "Save",
45524
+ "Insert/Edit Link": "Insert/Edit Link",
45525
+ "Text to display": "Text to display",
45526
+ "Title": "Title",
45527
+ "Open link in...": "Open link in...",
45528
+ "Current window": "Current window",
45529
+ "New window": "New window"
44736
45530
  };
44737
45531
  const es = {
44738
45532
  "Bold": "Negrita",
@@ -44797,7 +45591,14 @@ const es = {
44797
45591
  "Invalid image URL": "URL de imagen no válida",
44798
45592
  "File too large": "Archivo demasiado grande",
44799
45593
  "Invalid file type": "Tipo de archivo no válido",
44800
- "More": "Más"
45594
+ "More": "Más",
45595
+ "Save": "Save",
45596
+ "Insert/Edit Link": "Insert/Edit Link",
45597
+ "Text to display": "Text to display",
45598
+ "Title": "Title",
45599
+ "Open link in...": "Open link in...",
45600
+ "Current window": "Current window",
45601
+ "New window": "New window"
44801
45602
  };
44802
45603
  const sv = {
44803
45604
  "Bold": "Fet",
@@ -44862,7 +45663,14 @@ const sv = {
44862
45663
  "Invalid image URL": "Ogiltig bild-URL",
44863
45664
  "File too large": "Filen är för stor",
44864
45665
  "Invalid file type": "Ogiltig filtyp",
44865
- "More": "Mer"
45666
+ "More": "Mer",
45667
+ "Save": "Save",
45668
+ "Insert/Edit Link": "Insert/Edit Link",
45669
+ "Text to display": "Text to display",
45670
+ "Title": "Title",
45671
+ "Open link in...": "Open link in...",
45672
+ "Current window": "Current window",
45673
+ "New window": "New window"
44866
45674
  };
44867
45675
  const zhTw = {
44868
45676
  "Bold": "粗體",
@@ -44927,7 +45735,14 @@ const zhTw = {
44927
45735
  "Invalid image URL": "無效的圖片 URL",
44928
45736
  "File too large": "檔案過大",
44929
45737
  "Invalid file type": "無效的檔案類型",
44930
- "More": "更多"
45738
+ "More": "更多",
45739
+ "Save": "Save",
45740
+ "Insert/Edit Link": "Insert/Edit Link",
45741
+ "Text to display": "Text to display",
45742
+ "Title": "Title",
45743
+ "Open link in...": "Open link in...",
45744
+ "Current window": "Current window",
45745
+ "New window": "New window"
44931
45746
  };
44932
45747
  const th = {
44933
45748
  "Bold": "ตัวหนา",
@@ -44992,7 +45807,14 @@ const th = {
44992
45807
  "Invalid image URL": "URL รูปภาพไม่ถูกต้อง",
44993
45808
  "File too large": "ไฟล์ใหญ่เกินไป",
44994
45809
  "Invalid file type": "ประเภทไฟล์ไม่ถูกต้อง",
44995
- "More": "เพิ่มเติม"
45810
+ "More": "เพิ่มเติม",
45811
+ "Save": "Save",
45812
+ "Insert/Edit Link": "Insert/Edit Link",
45813
+ "Text to display": "Text to display",
45814
+ "Title": "Title",
45815
+ "Open link in...": "Open link in...",
45816
+ "Current window": "Current window",
45817
+ "New window": "New window"
44996
45818
  };
44997
45819
  const tr = {
44998
45820
  "Bold": "Kalın",
@@ -45057,7 +45879,14 @@ const tr = {
45057
45879
  "Invalid image URL": "Geçersiz resim URL'si",
45058
45880
  "File too large": "Dosya çok büyük",
45059
45881
  "Invalid file type": "Geçersiz dosya türü",
45060
- "More": "Daha fazla"
45882
+ "More": "Daha fazla",
45883
+ "Save": "Save",
45884
+ "Insert/Edit Link": "Insert/Edit Link",
45885
+ "Text to display": "Text to display",
45886
+ "Title": "Title",
45887
+ "Open link in...": "Open link in...",
45888
+ "Current window": "Current window",
45889
+ "New window": "New window"
45061
45890
  };
45062
45891
  const vi = {
45063
45892
  "Bold": "In đậm",
@@ -45122,7 +45951,14 @@ const vi = {
45122
45951
  "Invalid image URL": "URL hình ảnh không hợp lệ",
45123
45952
  "File too large": "Tệp quá lớn",
45124
45953
  "Invalid file type": "Loại tệp không hợp lệ",
45125
- "More": "Thêm"
45954
+ "More": "Thêm",
45955
+ "Save": "Save",
45956
+ "Insert/Edit Link": "Insert/Edit Link",
45957
+ "Text to display": "Text to display",
45958
+ "Title": "Title",
45959
+ "Open link in...": "Open link in...",
45960
+ "Current window": "Current window",
45961
+ "New window": "New window"
45126
45962
  };
45127
45963
  const locales = {
45128
45964
  en,
@@ -45240,6 +46076,8 @@ class HTMLEditor {
45240
46076
  directionality: config.directionality ?? "ltr",
45241
46077
  language: config.language ?? "en",
45242
46078
  height: config.height ?? 300,
46079
+ min_height: config.min_height,
46080
+ max_height: config.max_height,
45243
46081
  auto_focus: config.auto_focus,
45244
46082
  setFocus: config.setFocus,
45245
46083
  skin: config.skin ?? "oxide",
@@ -45276,6 +46114,20 @@ class HTMLEditor {
45276
46114
  this.editorWrapper.style.height = this.config.height;
45277
46115
  }
45278
46116
  }
46117
+ if (this.config.min_height) {
46118
+ if (typeof this.config.min_height === "number") {
46119
+ this.editorWrapper.style.minHeight = `${this.config.min_height}px`;
46120
+ } else {
46121
+ this.editorWrapper.style.minHeight = this.config.min_height;
46122
+ }
46123
+ }
46124
+ if (this.config.max_height) {
46125
+ if (typeof this.config.max_height === "number") {
46126
+ this.editorWrapper.style.maxHeight = `${this.config.max_height}px`;
46127
+ } else {
46128
+ this.editorWrapper.style.maxHeight = this.config.max_height;
46129
+ }
46130
+ }
45279
46131
  const toolbarContainer = document.createElement("div");
45280
46132
  toolbarContainer.className = "md-editor-toolbar";
45281
46133
  this.editorWrapper.appendChild(toolbarContainer);
@@ -45314,13 +46166,15 @@ class HTMLEditor {
45314
46166
  }
45315
46167
  };
45316
46168
  this.tiptap = new Editor(editorOptions);
46169
+ const iconSet = this.config.skin?.startsWith("confab") ? CONFAB_ICONS : DEFAULT_ICONS;
45317
46170
  this.toolbar = new Toolbar(toolbarContainer, {
45318
46171
  editor: this,
45319
46172
  buttons: this.config.toolbar ?? BASIC_TOOLBAR,
45320
46173
  mode: this.config.toolbar_mode ?? "sliding",
45321
46174
  sticky: this.config.toolbar_sticky ?? true,
45322
46175
  customButtons: this.customButtons,
45323
- config: this.config
46176
+ config: this.config,
46177
+ iconSet
45324
46178
  });
45325
46179
  if (this.config.auto_focus) {
45326
46180
  setTimeout(() => this.focus(), 10);
@@ -45403,6 +46257,7 @@ class HTMLEditor {
45403
46257
  codeBlock: false
45404
46258
  // We use CodeBlockLowlight instead
45405
46259
  }),
46260
+ SignatureBlock,
45406
46261
  Underline,
45407
46262
  TextStyle,
45408
46263
  FontFamily,
@@ -45415,7 +46270,21 @@ class HTMLEditor {
45415
46270
  TextAlign.configure({
45416
46271
  types: ["heading", "paragraph"]
45417
46272
  }),
45418
- Link.configure({
46273
+ Link.extend({
46274
+ addAttributes() {
46275
+ return {
46276
+ ...this.parent?.(),
46277
+ title: {
46278
+ default: null,
46279
+ parseHTML: (element) => element.getAttribute("title"),
46280
+ renderHTML: (attributes) => {
46281
+ if (!attributes.title) return {};
46282
+ return { title: attributes.title };
46283
+ }
46284
+ }
46285
+ };
46286
+ }
46287
+ }).configure({
45419
46288
  openOnClick: false,
45420
46289
  HTMLAttributes: {
45421
46290
  rel: "noopener noreferrer"
@@ -45641,13 +46510,18 @@ class HTMLEditor {
45641
46510
  }
45642
46511
  }
45643
46512
  exports.CHAR_MAP = CHAR_MAP;
46513
+ exports.CONFAB_ICONS = CONFAB_ICONS;
45644
46514
  exports.CharacterMap = CharacterMap;
46515
+ exports.DEFAULT_ICONS = DEFAULT_ICONS;
45645
46516
  exports.EMOJI_CATEGORIES = EMOJI_CATEGORIES;
45646
46517
  exports.EmojiPicker = EmojiPicker;
45647
46518
  exports.FontSize = FontSize;
45648
46519
  exports.HTMLEditor = HTMLEditor;
45649
46520
  exports.LineHeight = LineHeight;
46521
+ exports.LinkEditor = LinkEditor;
45650
46522
  exports.SearchReplace = SearchReplace;
46523
+ exports.SignatureBlock = SignatureBlock;
46524
+ exports.SourceEditor = SourceEditor;
45651
46525
  exports.TRANSLATION_KEYS = TRANSLATION_KEYS;
45652
46526
  exports.TextDirection = TextDirection;
45653
46527
  exports.Toolbar = Toolbar;
@@ -45660,4 +46534,3 @@ exports.getTranslate = getTranslate;
45660
46534
  exports.resetTranslate = resetTranslate;
45661
46535
  exports.setGetFileSrc = setGetFileSrc;
45662
46536
  exports.setTranslate = setTranslate;
45663
- //# sourceMappingURL=index.js.map