@zipify/wysiwyg 1.2.5 → 2.0.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/cli.js +2 -2
  2. package/dist/wysiwyg.mjs +421 -274
  3. package/lib/__tests__/utils/buildTestExtensions.js +14 -0
  4. package/lib/__tests__/utils/index.js +1 -0
  5. package/lib/components/toolbar/controls/SuperscriptControl.vue +2 -2
  6. package/lib/components/toolbar/controls/__tests__/SuperscriptControl.test.js +2 -2
  7. package/lib/composables/__tests__/useEditor.test.js +2 -2
  8. package/lib/extensions/BackgroundColor.js +4 -4
  9. package/lib/extensions/FontColor.js +4 -5
  10. package/lib/extensions/FontFamily.js +4 -5
  11. package/lib/extensions/FontSize.js +5 -7
  12. package/lib/extensions/FontStyle.js +13 -11
  13. package/lib/extensions/FontWeight.js +6 -9
  14. package/lib/extensions/StylePreset.js +0 -8
  15. package/lib/extensions/Superscript.js +23 -1
  16. package/lib/extensions/TextDecoration.js +33 -13
  17. package/lib/extensions/__tests__/Alignment.test.js +10 -7
  18. package/lib/extensions/__tests__/BackgroundColor.test.js +6 -3
  19. package/lib/extensions/__tests__/CaseStyle.test.js +11 -7
  20. package/lib/extensions/__tests__/FontColor.test.js +6 -3
  21. package/lib/extensions/__tests__/FontFamily.test.js +29 -22
  22. package/lib/extensions/__tests__/FontSize.test.js +24 -17
  23. package/lib/extensions/__tests__/FontStyle.test.js +22 -16
  24. package/lib/extensions/__tests__/FontWeight.test.js +26 -19
  25. package/lib/extensions/__tests__/LineHeight.test.js +14 -11
  26. package/lib/extensions/__tests__/Link.test.js +14 -10
  27. package/lib/extensions/__tests__/Margin.test.js +2 -2
  28. package/lib/extensions/__tests__/StylePreset.test.js +49 -49
  29. package/lib/extensions/__tests__/TextDecoration.test.js +72 -26
  30. package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +24 -24
  31. package/lib/extensions/__tests__/__snapshots__/FontColor.test.js.snap +24 -24
  32. package/lib/extensions/__tests__/__snapshots__/FontFamily.test.js.snap +86 -82
  33. package/lib/extensions/__tests__/__snapshots__/FontSize.test.js.snap +70 -70
  34. package/lib/extensions/__tests__/__snapshots__/FontStyle.test.js.snap +53 -45
  35. package/lib/extensions/__tests__/__snapshots__/FontWeight.test.js.snap +64 -60
  36. package/lib/extensions/__tests__/__snapshots__/TextDecoration.test.js.snap +148 -83
  37. package/lib/extensions/core/Document.js +5 -0
  38. package/lib/extensions/core/Heading.js +10 -0
  39. package/lib/extensions/core/NodeProcessor.js +84 -4
  40. package/lib/extensions/core/Paragraph.js +9 -0
  41. package/lib/extensions/core/TextProcessor.js +10 -12
  42. package/lib/extensions/core/__tests__/NodeProcessor.test.js +82 -10
  43. package/lib/extensions/core/__tests__/SelectionProcessor.test.js +2 -2
  44. package/lib/extensions/core/__tests__/TextProcessor.test.js +18 -20
  45. package/lib/extensions/core/__tests__/__snapshots__/NodeProcessor.test.js.snap +132 -0
  46. package/lib/extensions/core/index.js +5 -5
  47. package/lib/extensions/core/steps/AddNodeMarkStep.js +60 -0
  48. package/lib/extensions/core/steps/RemoveNodeMarkStep.js +50 -0
  49. package/lib/extensions/core/steps/index.js +2 -0
  50. package/lib/extensions/list/List.js +1 -0
  51. package/lib/extensions/list/ListItem.js +5 -0
  52. package/lib/extensions/list/__tests__/List.test.js +30 -25
  53. package/lib/services/ContentNormalizer.js +1 -100
  54. package/lib/services/NodeFactory.js +16 -6
  55. package/lib/services/__tests__/ContentNormalizer.test.js +0 -64
  56. package/lib/utils/findMarkByType.js +5 -0
  57. package/lib/utils/index.js +5 -0
  58. package/lib/utils/isMarkAppliedToParent.js +15 -0
  59. package/lib/utils/isNodeFullySelected.js +10 -0
  60. package/lib/utils/resolveNodePosition.js +6 -0
  61. package/lib/utils/resolveTextPosition.js +6 -0
  62. package/package.json +1 -1
package/dist/wysiwyg.mjs CHANGED
@@ -17,7 +17,11 @@ var __privateAdd = (obj, member, value) => {
17
17
  throw TypeError("Cannot add the same private member more than once");
18
18
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
19
19
  };
20
- var _domParser;
20
+ var __privateMethod = (obj, member, method) => {
21
+ __accessCheck(obj, member, "access private method");
22
+ return method;
23
+ };
24
+ var _domParser, _textBlock, textBlock_fn, _normalizeTextBlockArgs, normalizeTextBlockArgs_fn;
21
25
  import { computed, ref, watch, inject, onUnmounted, nextTick, provide, onMounted, toRef, unref, reactive } from "vue";
22
26
  import { ColorModel, ZipifyColorPicker } from "@zipify/colorpicker";
23
27
  function OrderedMap(content) {
@@ -14443,6 +14447,41 @@ function unmarkWysiwygContent({ __wswg__, ...content }) {
14443
14447
  function markWysiwygContent(content) {
14444
14448
  return { ...content, __wswg__: true };
14445
14449
  }
14450
+ function resolveNodePosition({ path, pos }, node, modifier) {
14451
+ const index = path.indexOf(node);
14452
+ const slice2 = path.slice(index).reverse().filter((step) => typeof step === "object");
14453
+ return pos + modifier * slice2.length;
14454
+ }
14455
+ function resolveTextPosition($from, $to, node, position) {
14456
+ return {
14457
+ from: Math.max(position, $from.pos),
14458
+ to: Math.min(position + node.nodeSize, $to.pos)
14459
+ };
14460
+ }
14461
+ function isNodeFullySelected($from, $to, node, position) {
14462
+ const fromPosition = resolveNodePosition($from, node, -1);
14463
+ const toPosition = resolveNodePosition($to, node, 1);
14464
+ const isFromMatch = fromPosition <= position;
14465
+ const isToMatch = toPosition >= node.nodeSize + position;
14466
+ return isFromMatch && isToMatch;
14467
+ }
14468
+ const DEFAULT_COMPARATOR = (parent, child) => child.eq(parent);
14469
+ function isMarkAppliedToParent({ doc: doc2 }, position, checkingMark, comparator = DEFAULT_COMPARATOR) {
14470
+ const steps = doc2.resolve(position).path.reverse();
14471
+ for (const step of steps) {
14472
+ if (typeof step === "number")
14473
+ continue;
14474
+ for (const mark of step.marks) {
14475
+ if (comparator(mark, checkingMark))
14476
+ return true;
14477
+ }
14478
+ }
14479
+ return false;
14480
+ }
14481
+ function findMarkByType(list, typeOrName) {
14482
+ const name = typeof typeOrName === "string" ? typeOrName : typeOrName.name;
14483
+ return list.find((mark) => mark.type.name === name);
14484
+ }
14446
14485
  var render$D = function __render__6() {
14447
14486
  var _vm = this;
14448
14487
  var _h = _vm.$createElement;
@@ -19518,8 +19557,6 @@ const _ContentNormalizer = class {
19518
19557
  this.iterateNodes(this._normalizeBreakLines, (node) => node.tagName === "BR");
19519
19558
  this.iterateNodes(this._removeEmptyNodes, this._isBlockNode);
19520
19559
  this.iterateNodes(this._normalizeListItems, (node) => node.tagName === "LI");
19521
- this.iterateNodes(this._normalizeSettingsStructure, (node) => node.tagName === "SPAN");
19522
- this.iterateNodes(this._normalizeStyles, (node) => node.tagName !== "SPAN");
19523
19560
  }
19524
19561
  get normalizedHTML() {
19525
19562
  return this.dom.body.innerHTML;
@@ -19527,9 +19564,6 @@ const _ContentNormalizer = class {
19527
19564
  get _NodeFilter() {
19528
19565
  return this._parser.types.NodeFilter;
19529
19566
  }
19530
- get _Node() {
19531
- return this._parser.types.Node;
19532
- }
19533
19567
  _removeComments() {
19534
19568
  const iterator = this.createNodeIterator(this._NodeFilter.SHOW_COMMENT);
19535
19569
  this.runIterator(iterator, (node) => node.remove());
@@ -19595,78 +19629,17 @@ const _ContentNormalizer = class {
19595
19629
  itemEl.append(fragment);
19596
19630
  this._removeStyleProperties(itemEl, _ContentNormalizer.BLOCK_STYLES);
19597
19631
  }
19598
- _normalizeSettingsStructure(element) {
19599
- if (this._isOnlyTextContent(element))
19600
- return;
19601
- const cloned = element.cloneNode(true);
19602
- const migratingStyles = this._getMigratingStyles(element, { customProperties: true });
19603
- const content = [];
19604
- for (const node of cloned.childNodes) {
19605
- let child = node;
19606
- if (migratingStyles.length) {
19607
- child = this._wrapTextNode(cloned, node);
19608
- this._assignElementProperties(child, cloned, migratingStyles);
19609
- }
19610
- content.push(child);
19611
- }
19612
- element.replaceWith(...content);
19613
- }
19614
- _normalizeStyles(element) {
19615
- if (!this._isBlockNode(element) && this._isOnlyTextContent(element))
19616
- return;
19617
- const properties = this._getMigratingStyles(element);
19618
- if (!properties.length)
19619
- return;
19620
- for (const node of element.childNodes) {
19621
- const child = this._wrapTextNode(element, node);
19622
- this._assignElementProperties(child, element, properties);
19623
- }
19624
- this._removeStyleProperties(element, properties);
19625
- }
19626
- _isOnlyTextContent(node) {
19627
- return Array.from(node.childNodes).every((node2) => node2.nodeType === this._Node.TEXT_NODE);
19628
- }
19629
19632
  _isBlockNode(node) {
19630
19633
  return _ContentNormalizer.BLOCK_NODE_NAMES.includes(node.tagName);
19631
19634
  }
19632
- _getMigratingStyles(element, { customProperties } = {}) {
19633
- const blacklist = _ContentNormalizer.BLOCK_STYLES;
19634
- const properties = [];
19635
- for (let index = 0; index < element.style.length; index++) {
19636
- const property = element.style.item(index);
19637
- if (blacklist.includes(property))
19638
- continue;
19639
- if (!customProperties && property.startsWith("--"))
19640
- continue;
19641
- properties.push(property);
19642
- }
19643
- return properties;
19644
- }
19645
- _wrapTextNode(parent, node) {
19646
- if (node.nodeType !== this._Node.TEXT_NODE)
19647
- return node;
19648
- const span = this.dom.createElement("span");
19649
- span.append(node.cloneNode());
19650
- parent.replaceChild(span, node);
19651
- return span;
19652
- }
19653
19635
  _assignElementProperties(target, source, properties) {
19654
19636
  for (const property of properties) {
19655
19637
  const value = source.style.getPropertyValue(property);
19656
- if (value && this._canAssignElementProperty(target, source, property)) {
19638
+ if (value && !target.style.getPropertyValue(property)) {
19657
19639
  target.style.setProperty(property, value);
19658
19640
  }
19659
19641
  }
19660
19642
  }
19661
- _canAssignElementProperty(target, source, property) {
19662
- if (target.style.getPropertyValue(property))
19663
- return false;
19664
- return _ContentNormalizer.ASSIGN_STYLE_RULES.every((rule) => {
19665
- if (!rule.tag.test(target.tagName.toLowerCase()))
19666
- return true;
19667
- return !rule.ignore.test(property);
19668
- });
19669
- }
19670
19643
  _removeStyleProperties(element, properties) {
19671
19644
  for (const property of properties) {
19672
19645
  element.style.removeProperty(property);
@@ -19712,20 +19685,6 @@ __publicField(ContentNormalizer, "BLOCK_STYLES", [
19712
19685
  "margin-left",
19713
19686
  "margin-right"
19714
19687
  ]);
19715
- __publicField(ContentNormalizer, "ASSIGN_STYLE_RULES", [
19716
- {
19717
- tag: /^(b|strong)$/,
19718
- ignore: /font-weight/
19719
- },
19720
- {
19721
- tag: /^i$/,
19722
- ignore: /font-style/
19723
- },
19724
- {
19725
- tag: /^s$/,
19726
- ignore: /text-decoration(.+)?/
19727
- }
19728
- ]);
19729
19688
  class ContextWindow {
19730
19689
  static use(window2) {
19731
19690
  this.window = window2;
@@ -19766,7 +19725,7 @@ class NodeFactory {
19766
19725
  }
19767
19726
  static heading(level, ...args) {
19768
19727
  var _a;
19769
- const config = this._textBlock(args);
19728
+ const config = __privateMethod(this, _textBlock, textBlock_fn).call(this, args);
19770
19729
  (_a = config.attrs) != null ? _a : config.attrs = {};
19771
19730
  config.attrs.level = level;
19772
19731
  return {
@@ -19777,16 +19736,7 @@ class NodeFactory {
19777
19736
  static paragraph(...args) {
19778
19737
  return {
19779
19738
  type: NodeTypes.PARAGRAPH,
19780
- ...this._textBlock(args)
19781
- };
19782
- }
19783
- static _textBlock(args) {
19784
- const attrs = args.length === 1 ? null : args[0];
19785
- const content = args.length === 1 ? args[0] : args[1];
19786
- const children = typeof content === "string" ? [this.text(content)] : content;
19787
- return {
19788
- content: children,
19789
- ...attrs ? { attrs } : {}
19739
+ ...__privateMethod(this, _textBlock, textBlock_fn).call(this, args)
19790
19740
  };
19791
19741
  }
19792
19742
  static text(text2, marks) {
@@ -19803,6 +19753,28 @@ class NodeFactory {
19803
19753
  return { mobile: null, tablet: value, desktop: value };
19804
19754
  }
19805
19755
  }
19756
+ _textBlock = new WeakSet();
19757
+ textBlock_fn = function(args) {
19758
+ const { attrs, content, marks } = __privateMethod(this, _normalizeTextBlockArgs, normalizeTextBlockArgs_fn).call(this, args);
19759
+ const children = typeof content === "string" ? [this.text(content)] : content;
19760
+ return {
19761
+ content: children,
19762
+ ...attrs ? { attrs } : {},
19763
+ ...marks ? { marks } : {}
19764
+ };
19765
+ };
19766
+ _normalizeTextBlockArgs = new WeakSet();
19767
+ normalizeTextBlockArgs_fn = function(args) {
19768
+ if (args.length === 1) {
19769
+ return { attrs: null, marks: null, content: args[0] };
19770
+ }
19771
+ if (args.length === 2) {
19772
+ return { attrs: args[0], marks: null, content: args[1] };
19773
+ }
19774
+ return { attrs: args[0], marks: args[1], content: args[2] };
19775
+ };
19776
+ __privateAdd(NodeFactory, _textBlock);
19777
+ __privateAdd(NodeFactory, _normalizeTextBlockArgs);
19806
19778
  const dataStorage = /* @__PURE__ */ new WeakMap();
19807
19779
  function toggleListener(toEnable, onClick) {
19808
19780
  const args = ["click", onClick, { capture: true }];
@@ -21502,7 +21474,7 @@ const __vue2_script$f = {
21502
21474
  },
21503
21475
  setup() {
21504
21476
  const editor = inject(InjectionTokens$1.EDITOR);
21505
- const currentValue = computed(() => editor.isActive("superscript"));
21477
+ const currentValue = editor.commands.isSuperscript();
21506
21478
  const apply2 = () => editor.chain().focus().toggleSuperscript().run();
21507
21479
  return {
21508
21480
  currentValue,
@@ -22957,6 +22929,7 @@ function useToolbar({ wrapperRef, offsets, isActiveRef, placementRef }) {
22957
22929
  }
22958
22930
  const FontFamily = Mark.create({
22959
22931
  name: TextSettings.FONT_FAMILY,
22932
+ group: "settings",
22960
22933
  addOptions: () => ({
22961
22934
  fonts: []
22962
22935
  }),
@@ -22966,7 +22939,7 @@ const FontFamily = Mark.create({
22966
22939
  addCommands() {
22967
22940
  return {
22968
22941
  applyFontFamily: createCommand(({ commands: commands2 }, value) => {
22969
- commands2.setMark(this.name, { value });
22942
+ commands2.applyMark(this.name, { value });
22970
22943
  const font = commands2.findFontByName(value);
22971
22944
  let fontWeight = unref(commands2.getFontWeight());
22972
22945
  if (!font.isWeightSupported(fontWeight)) {
@@ -22987,12 +22960,8 @@ const FontFamily = Mark.create({
22987
22960
  findFontByName: createCommand((_, name) => {
22988
22961
  return this.options.fonts.find((font) => font.name === name);
22989
22962
  }),
22990
- getFontFamily: createCommand(({ editor, commands: commands2 }) => {
22991
- const defaultValue = commands2.getDefaultFontFamily();
22992
- return computed(() => {
22993
- var _a, _b;
22994
- return (_b = (_a = editor.getAttributes(this.name)) == null ? void 0 : _a.value) != null ? _b : unref(defaultValue);
22995
- });
22963
+ getFontFamily: createCommand(({ commands: commands2 }) => {
22964
+ return commands2.getCommonSettingMark(this.name, commands2.getDefaultFontFamily());
22996
22965
  }),
22997
22966
  getDefaultFontFamily: createCommand(({ commands: commands2 }) => {
22998
22967
  const preset = commands2.getPreset();
@@ -23023,84 +22992,12 @@ const FontFamily = Mark.create({
23023
22992
  return renderMark({ font_family });
23024
22993
  }
23025
22994
  });
23026
- const Heading = Node.create({
23027
- name: "heading",
23028
- addOptions() {
23029
- return {
23030
- levels: [1, 2, 3, 4, 5, 6],
23031
- HTMLAttributes: {}
23032
- };
23033
- },
23034
- content: "inline*",
23035
- group: "block",
23036
- defining: true,
23037
- addAttributes() {
23038
- return {
23039
- level: {
23040
- default: 1,
23041
- rendered: false
23042
- }
23043
- };
23044
- },
23045
- parseHTML() {
23046
- return this.options.levels.map((level) => ({
23047
- tag: `h${level}`,
23048
- attrs: { level }
23049
- }));
23050
- },
23051
- renderHTML({ node, HTMLAttributes }) {
23052
- const hasLevel = this.options.levels.includes(node.attrs.level);
23053
- const level = hasLevel ? node.attrs.level : this.options.levels[0];
23054
- return [`h${level}`, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
23055
- },
23056
- addCommands() {
23057
- return {
23058
- setHeading: (attributes) => ({ commands: commands2 }) => {
23059
- if (!this.options.levels.includes(attributes.level)) {
23060
- return false;
23061
- }
23062
- return commands2.setNode(this.name, attributes);
23063
- },
23064
- toggleHeading: (attributes) => ({ commands: commands2 }) => {
23065
- if (!this.options.levels.includes(attributes.level)) {
23066
- return false;
23067
- }
23068
- return commands2.toggleNode(this.name, "paragraph", attributes);
23069
- }
23070
- };
23071
- },
23072
- addKeyboardShortcuts() {
23073
- return this.options.levels.reduce((items, level) => ({
23074
- ...items,
23075
- ...{
23076
- [`Mod-Alt-${level}`]: () => this.editor.commands.toggleHeading({ level })
23077
- }
23078
- }), {});
23079
- },
23080
- addInputRules() {
23081
- return this.options.levels.map((level) => {
23082
- return textblockTypeInputRule({
23083
- find: new RegExp(`^(#{1,${level}})\\s$`),
23084
- type: this.type,
23085
- getAttributes: {
23086
- level
23087
- }
23088
- });
23089
- });
23090
- }
23091
- });
23092
22995
  function makePresetClass(base2, preset) {
23093
22996
  const baseClass = base2.split(" ").map((part) => `.${part}`).join("");
23094
22997
  return baseClass + preset.id;
23095
22998
  }
23096
22999
  const StylePreset = Extension.create({
23097
23000
  name: "style_preset",
23098
- addExtensions: () => [
23099
- Heading.configure({
23100
- levels: [1, 2, 3, 4],
23101
- HTMLAttributes: { class: "zw-style" }
23102
- })
23103
- ],
23104
23001
  addStorage: () => ({
23105
23002
  presetStyleEl: null
23106
23003
  }),
@@ -23256,13 +23153,14 @@ const StylePreset = Extension.create({
23256
23153
  });
23257
23154
  const FontWeight = Mark.create({
23258
23155
  name: TextSettings.FONT_WEIGHT,
23156
+ group: "settings",
23259
23157
  addAttributes: () => ({
23260
23158
  value: { required: true }
23261
23159
  }),
23262
23160
  addCommands() {
23263
23161
  return {
23264
23162
  applyFontWeight: createCommand(({ commands: commands2 }, value) => {
23265
- commands2.setMark(this.name, { value });
23163
+ commands2.applyMark(this.name, { value });
23266
23164
  const font = unref(commands2.getFont());
23267
23165
  if (!font.isItalicSupported(value)) {
23268
23166
  commands2.removeItalic();
@@ -23276,17 +23174,13 @@ const FontWeight = Mark.create({
23276
23174
  const nextWeight = currentFont.findClosestWeight(wantedWeight);
23277
23175
  commands2.applyFontWeight(nextWeight);
23278
23176
  }),
23279
- getFontWeight: createCommand(({ editor, commands: commands2 }) => {
23280
- const defaultValue = commands2.getDefaultFontWeight();
23177
+ getFontWeight: createCommand(({ commands: commands2 }) => {
23178
+ const selectionRef = commands2.getCommonSettingMark(this.name, commands2.getDefaultFontWeight());
23281
23179
  const fontRef = commands2.getFont();
23282
23180
  return computed(() => {
23283
- var _a, _b;
23284
- const weight = (_b = (_a = editor.getAttributes(this.name)) == null ? void 0 : _a.value) != null ? _b : unref(defaultValue);
23181
+ const weight = unref(selectionRef);
23285
23182
  const font = unref(fontRef);
23286
- if (font.isWeightSupported(weight)) {
23287
- return weight;
23288
- }
23289
- return font.findClosestWeight(weight);
23183
+ return font.isWeightSupported(weight) ? weight : font.findClosestWeight(weight);
23290
23184
  });
23291
23185
  }),
23292
23186
  getDefaultFontWeight: createCommand(({ commands: commands2 }) => {
@@ -23330,6 +23224,7 @@ const FontWeight = Mark.create({
23330
23224
  });
23331
23225
  const FontSize = Mark.create({
23332
23226
  name: TextSettings.FONT_SIZE,
23227
+ group: "settings",
23333
23228
  addOptions: () => ({
23334
23229
  minSize: 1,
23335
23230
  maxSize: 100
@@ -23343,13 +23238,8 @@ const FontSize = Mark.create({
23343
23238
  },
23344
23239
  addCommands() {
23345
23240
  return {
23346
- getFontSize: createCommand(({ editor, commands: commands2 }) => {
23347
- const device = commands2.getDevice();
23348
- const defaultValue = commands2.getDefaultFontSize();
23349
- return computed(() => {
23350
- var _a, _b;
23351
- return (_b = (_a = editor.getAttributes(this.name)) == null ? void 0 : _a[unref(device)]) != null ? _b : unref(defaultValue);
23352
- });
23241
+ getFontSize: createCommand(({ commands: commands2 }) => {
23242
+ return commands2.getDeviceSettingMark(this.name, commands2.getDefaultFontSize());
23353
23243
  }),
23354
23244
  getDefaultFontSize: createCommand(({ commands: commands2 }) => {
23355
23245
  const device = commands2.getDevice();
@@ -23357,7 +23247,7 @@ const FontSize = Mark.create({
23357
23247
  return computed(() => unref(preset)[unref(device)].font_size.replace("px", ""));
23358
23248
  }),
23359
23249
  applyFontSize: createCommand(({ commands: commands2 }, value) => {
23360
- commands2.setMark(this.name, { desktop: value, tablet: value, mobile: null });
23250
+ commands2.applyMark(this.name, { desktop: value, tablet: value, mobile: null });
23361
23251
  }),
23362
23252
  increaseFontSize: createCommand(({ commands: commands2 }) => {
23363
23253
  const size2 = Number(unref(commands2.getFontSize()));
@@ -23412,24 +23302,21 @@ const FontSize = Mark.create({
23412
23302
  });
23413
23303
  const FontColor = Mark.create({
23414
23304
  name: TextSettings.FONT_COLOR,
23305
+ group: "settings",
23415
23306
  addAttributes: () => ({
23416
23307
  value: { required: true }
23417
23308
  }),
23418
23309
  addCommands() {
23419
23310
  return {
23420
- getFontColor: createCommand(({ commands: commands2, editor }) => {
23421
- const defaultValue = commands2.getDefaultFontColor();
23422
- return computed(() => {
23423
- var _a, _b;
23424
- return (_b = (_a = editor.getAttributes(this.name)) == null ? void 0 : _a.value) != null ? _b : unref(defaultValue);
23425
- });
23311
+ getFontColor: createCommand(({ commands: commands2 }) => {
23312
+ return commands2.getCommonSettingMark(this.name, commands2.getDefaultFontColor());
23426
23313
  }),
23427
23314
  getDefaultFontColor: createCommand(({ commands: commands2 }) => {
23428
23315
  const preset = commands2.getPreset();
23429
23316
  return computed(() => unref(preset).common.color);
23430
23317
  }),
23431
23318
  applyFontColor: createCommand(({ commands: commands2 }, value) => {
23432
- commands2.setMark(this.name, { value });
23319
+ commands2.applyMark(this.name, { value });
23433
23320
  })
23434
23321
  };
23435
23322
  },
@@ -23452,19 +23339,17 @@ const FontColor = Mark.create({
23452
23339
  });
23453
23340
  const BackgroundColor = Mark.create({
23454
23341
  name: TextSettings.BACKGROUND_COLOR,
23342
+ group: "settings",
23455
23343
  addAttributes: () => ({
23456
23344
  value: { required: true }
23457
23345
  }),
23458
23346
  addCommands() {
23459
23347
  return {
23460
- getBackgroundColor: createCommand(({ editor }) => {
23461
- return computed(() => {
23462
- var _a, _b;
23463
- return (_b = (_a = editor.getAttributes(this.name)) == null ? void 0 : _a.value) != null ? _b : "rgba(255, 255, 255, 0%)";
23464
- });
23348
+ getBackgroundColor: createCommand(({ commands: commands2 }) => {
23349
+ return commands2.getCommonSettingMark(this.name, "rgba(255, 255, 255, 0%)");
23465
23350
  }),
23466
23351
  applyBackgroundColor: createCommand(({ commands: commands2 }, value) => {
23467
- commands2.setMark(this.name, { value });
23352
+ commands2.applyMark(this.name, { value });
23468
23353
  })
23469
23354
  };
23470
23355
  },
@@ -23495,16 +23380,18 @@ const DeviceManager = Extension.create({
23495
23380
  });
23496
23381
  const FontStyle = Mark.create({
23497
23382
  name: TextSettings.FONT_STYLE,
23383
+ group: "settings",
23498
23384
  addAttributes: () => ({
23499
23385
  italic: { required: true }
23500
23386
  }),
23501
23387
  addCommands() {
23502
23388
  return {
23503
- isItalic: createCommand(({ editor, commands: commands2 }) => {
23504
- const defaultValue = commands2.getDefaultFontStyle();
23389
+ isItalic: createCommand(({ commands: commands2 }) => {
23390
+ const selectionRef = commands2.getMark(this.name);
23391
+ const defaultValueRef = commands2.getDefaultFontStyle();
23505
23392
  return computed(() => {
23506
23393
  var _a, _b;
23507
- return (_b = (_a = editor.getAttributes(this.name)) == null ? void 0 : _a.italic) != null ? _b : unref(defaultValue).italic;
23394
+ return (_b = (_a = unref(selectionRef)) == null ? void 0 : _a.italic) != null ? _b : unref(defaultValueRef).italic;
23508
23395
  });
23509
23396
  }),
23510
23397
  isItalicAvailable: createCommand(({ commands: commands2 }) => {
@@ -23519,16 +23406,16 @@ const FontStyle = Mark.create({
23519
23406
  }));
23520
23407
  }),
23521
23408
  toggleItalic: createCommand(({ commands: commands2 }) => {
23522
- const isItalicAvailable = unref(this.editor.commands.isItalicAvailable());
23409
+ const isItalicAvailable = unref(commands2.isItalicAvailable());
23523
23410
  if (!isItalicAvailable)
23524
23411
  return;
23525
23412
  unref(commands2.isItalic()) ? commands2.removeItalic() : commands2.applyItalic();
23526
23413
  }),
23527
23414
  applyItalic: createCommand(({ commands: commands2 }) => {
23528
- commands2.setMark(this.name, { italic: true });
23415
+ commands2.applyMark(this.name, { italic: true });
23529
23416
  }),
23530
23417
  removeItalic: createCommand(({ commands: commands2 }) => {
23531
- commands2.setMark(this.name, { italic: false });
23418
+ commands2.applyMark(this.name, { italic: false });
23532
23419
  })
23533
23420
  };
23534
23421
  },
@@ -23537,8 +23424,12 @@ const FontStyle = Mark.create({
23537
23424
  "Mod-I": createKeyboardShortcut("toggleItalic")
23538
23425
  }),
23539
23426
  parseHTML() {
23540
- const getAttrs = (value) => value.includes("italic") && { italic: true };
23427
+ const getAttrs = (value) => ({ italic: value.includes("italic") });
23541
23428
  return [
23429
+ {
23430
+ tag: "i",
23431
+ attrs: { italic: true }
23432
+ },
23542
23433
  {
23543
23434
  style: "--zw-font-style",
23544
23435
  getAttrs
@@ -23546,10 +23437,6 @@ const FontStyle = Mark.create({
23546
23437
  {
23547
23438
  style: "font-style",
23548
23439
  getAttrs
23549
- },
23550
- {
23551
- tag: "i",
23552
- attrs: { italic: true }
23553
23440
  }
23554
23441
  ];
23555
23442
  },
@@ -23561,6 +23448,7 @@ const FontStyle = Mark.create({
23561
23448
  const TextDecoration = Mark.create({
23562
23449
  name: TextSettings.TEXT_DECORATION,
23563
23450
  priority: 1e3,
23451
+ group: "settings",
23564
23452
  addAttributes: () => ({
23565
23453
  underline: { default: false },
23566
23454
  strike_through: { default: false }
@@ -23575,15 +23463,14 @@ const TextDecoration = Mark.create({
23575
23463
  const decoration = commands2.getTextDecoration();
23576
23464
  return computed(() => unref(decoration).strike_through);
23577
23465
  }),
23578
- getTextDecoration: createCommand(({ editor, commands: commands2 }) => {
23579
- const defaultValue = commands2.getDefaultTextDecoration();
23466
+ getTextDecoration: createCommand(({ commands: commands2 }) => {
23467
+ const selectionRef = commands2.getMarks(this.name);
23468
+ const defaultValueRef = commands2.getDefaultTextDecoration();
23580
23469
  return computed(() => {
23581
- var _a, _b, _c;
23582
- const attrs = (_a = editor.getAttributes(this.name)) != null ? _a : {};
23583
- return {
23584
- underline: (_b = attrs.underline) != null ? _b : unref(defaultValue).underline,
23585
- strike_through: (_c = attrs.strike_through) != null ? _c : unref(defaultValue).strike_through
23586
- };
23470
+ return unref(selectionRef).reduceRight((collector, mark) => ({
23471
+ underline: collector.underline || mark.underline,
23472
+ strike_through: collector.strike_through || mark.strike_through
23473
+ }), unref(defaultValueRef));
23587
23474
  });
23588
23475
  }),
23589
23476
  getDefaultTextDecoration: createCommand(({ commands: commands2 }) => {
@@ -23602,15 +23489,32 @@ const TextDecoration = Mark.create({
23602
23489
  toggleStrikeThrough: createCommand(({ commands: commands2 }) => {
23603
23490
  commands2.toggleTextDecoration("strike_through");
23604
23491
  }),
23605
- toggleTextDecoration: createCommand(({ commands: commands2 }, name) => {
23606
- const isEnabled = unref(commands2.getTextDecoration())[name];
23607
- isEnabled ? commands2.removeTextDecoration(name) : commands2.applyTextDecoration(name);
23492
+ toggleTextDecoration: createCommand(({ commands: commands2 }, name, toEnable = null) => {
23493
+ const value = unref(commands2.getTextDecoration());
23494
+ const isEnabled = toEnable != null ? toEnable : !value[name];
23495
+ commands2.applyMark(this.name, { [name]: isEnabled }, {
23496
+ compareParentMark: (parent, child) => {
23497
+ if (parent.type.name !== child.type.name)
23498
+ return false;
23499
+ return parent.attrs[name] || parent.eq(child);
23500
+ },
23501
+ onAppliedToParent: ({ tr, textPosition, initialMark, applyingMark }) => {
23502
+ if (!initialMark)
23503
+ return;
23504
+ if (initialMark.eq(applyingMark)) {
23505
+ tr.removeMark(textPosition.from, textPosition.to, applyingMark.type);
23506
+ return;
23507
+ }
23508
+ const mark = applyingMark.type.create({ ...initialMark.attrs, [name]: isEnabled });
23509
+ tr.addMark(textPosition.from, textPosition.to, mark);
23510
+ }
23511
+ });
23608
23512
  }),
23609
23513
  applyTextDecoration: createCommand(({ commands: commands2 }, name) => {
23610
- commands2.setMark(this.name, { [name]: true });
23514
+ commands2.toggleTextDecoration(name, true);
23611
23515
  }),
23612
23516
  removeTextDecoration: createCommand(({ commands: commands2 }, name) => {
23613
- commands2.setMark(this.name, { ...unref(commands2.getTextDecoration()), [name]: false });
23517
+ commands2.toggleTextDecoration(name, false);
23614
23518
  })
23615
23519
  };
23616
23520
  },
@@ -23852,6 +23756,10 @@ const ListItem$1 = Node.create({
23852
23756
  });
23853
23757
  const ListItem = ListItem$1.extend({
23854
23758
  name: NodeTypes.LIST_ITEM,
23759
+ marks: "settings",
23760
+ addOptions: () => ({
23761
+ HTMLAttributes: { class: "zw-style" }
23762
+ }),
23855
23763
  addKeyboardShortcuts() {
23856
23764
  const { Enter } = this.parent();
23857
23765
  return { Enter };
@@ -23861,6 +23769,7 @@ const List = Node.create({
23861
23769
  name: NodeTypes.LIST,
23862
23770
  content: `${NodeTypes.LIST_ITEM}+`,
23863
23771
  group: "block list",
23772
+ marks: "settings",
23864
23773
  addExtensions: () => [
23865
23774
  ListItem
23866
23775
  ],
@@ -25032,44 +24941,22 @@ const Superscript$1 = Mark.create({
25032
24941
  }
25033
24942
  });
25034
24943
  const Superscript = Superscript$1.extend({
24944
+ name: TextSettings.SUPERSCRIPT,
25035
24945
  addKeyboardShortcuts: null,
25036
24946
  addOptions: () => ({
25037
24947
  HTMLAttributes: { class: "zw-superscript" }
25038
- })
25039
- });
25040
- const Document = Node.create({
25041
- name: "doc",
25042
- topNode: true,
25043
- content: "block+"
25044
- });
25045
- const Paragraph = Node.create({
25046
- name: "paragraph",
25047
- priority: 1e3,
25048
- addOptions() {
25049
- return {
25050
- HTMLAttributes: {}
25051
- };
25052
- },
25053
- group: "block",
25054
- content: "inline*",
25055
- parseHTML() {
25056
- return [
25057
- { tag: "p" }
25058
- ];
25059
- },
25060
- renderHTML({ HTMLAttributes }) {
25061
- return ["p", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
25062
- },
24948
+ }),
25063
24949
  addCommands() {
25064
24950
  return {
25065
- setParagraph: () => ({ commands: commands2 }) => {
25066
- return commands2.setNode(this.name);
25067
- }
25068
- };
25069
- },
25070
- addKeyboardShortcuts() {
25071
- return {
25072
- "Mod-Alt-0": () => this.editor.commands.setParagraph()
24951
+ ...this.parent(),
24952
+ toggleSuperscript: createCommand(({ commands: commands2 }) => {
24953
+ const isActive2 = unref(commands2.isSuperscript());
24954
+ isActive2 ? commands2.unsetSuperscript() : commands2.setSuperscript();
24955
+ }),
24956
+ isSuperscript: createCommand(({ commands: commands2 }) => {
24957
+ const selectionRef = commands2.getMark(this.name);
24958
+ return computed(() => !!unref(selectionRef));
24959
+ })
25073
24960
  };
25074
24961
  }
25075
24962
  });
@@ -25683,6 +25570,85 @@ const History = Extension.create({
25683
25570
  };
25684
25571
  }
25685
25572
  });
25573
+ class RemoveNodeMarkStep extends Step {
25574
+ static fromJSON(schema, json) {
25575
+ if (typeof json.pos != "number") {
25576
+ throw new RangeError("Invalid input for RemoveNodeMarkStep.fromJSON");
25577
+ }
25578
+ return new RemoveNodeMarkStep(json.pos, schema.markFromJSON(json.mark));
25579
+ }
25580
+ constructor(pos, mark) {
25581
+ super();
25582
+ this.pos = pos;
25583
+ this.mark = mark;
25584
+ }
25585
+ apply(doc2) {
25586
+ const node = doc2.nodeAt(this.pos);
25587
+ if (!node)
25588
+ return StepResult.fail("No node at mark step's position");
25589
+ const updated = node.type.create(node.attrs, null, this.mark.removeFromSet(node.marks));
25590
+ const slice2 = new Slice(Fragment.from(updated), 0, node.isLeaf ? 0 : 1);
25591
+ return StepResult.fromReplace(doc2, this.pos, this.pos + 1, slice2);
25592
+ }
25593
+ invert(doc2) {
25594
+ const node = doc2.nodeAt(this.pos);
25595
+ if (!node || !this.mark.isInSet(node.marks))
25596
+ return this;
25597
+ return new AddNodeMarkStep(this.pos, this.mark);
25598
+ }
25599
+ map(mapping) {
25600
+ const pos = mapping.mapResult(this.pos, 1);
25601
+ return pos.deletedAfter ? null : new RemoveNodeMarkStep(pos.pos, this.mark);
25602
+ }
25603
+ toJSON() {
25604
+ return { stepType: "removeNodeMark", pos: this.pos, mark: this.mark.toJSON() };
25605
+ }
25606
+ }
25607
+ Step.jsonID("removeNodeMark", RemoveNodeMarkStep);
25608
+ class AddNodeMarkStep extends Step {
25609
+ static fromJSON(schema, json) {
25610
+ if (typeof json.pos != "number") {
25611
+ throw new RangeError("Invalid input for AddNodeMarkStep.fromJSON");
25612
+ }
25613
+ return new AddNodeMarkStep(json.pos, schema.markFromJSON(json.mark));
25614
+ }
25615
+ constructor(pos, mark) {
25616
+ super();
25617
+ this.pos = pos;
25618
+ this.mark = mark;
25619
+ }
25620
+ apply(doc2) {
25621
+ const node = doc2.nodeAt(this.pos);
25622
+ if (!node)
25623
+ return StepResult.fail("No node at mark step's position");
25624
+ const updated = node.type.create(node.attrs, null, this.mark.addToSet(node.marks));
25625
+ const slice2 = new Slice(Fragment.from(updated), 0, node.isLeaf ? 0 : 1);
25626
+ return StepResult.fromReplace(doc2, this.pos, this.pos + 1, slice2);
25627
+ }
25628
+ invert(doc2) {
25629
+ const node = doc2.nodeAt(this.pos);
25630
+ if (node) {
25631
+ const newSet = this.mark.addToSet(node.marks);
25632
+ if (newSet.length === node.marks.length) {
25633
+ for (const mark of node.marks) {
25634
+ if (!mark.isInSet(newSet)) {
25635
+ return new AddNodeMarkStep(this.pos, mark);
25636
+ }
25637
+ }
25638
+ return new AddNodeMarkStep(this.pos, this.mark);
25639
+ }
25640
+ }
25641
+ return new RemoveNodeMarkStep(this.pos, this.mark);
25642
+ }
25643
+ map(mapping) {
25644
+ const pos = mapping.mapResult(this.pos, 1);
25645
+ return pos.deletedAfter ? null : new AddNodeMarkStep(pos.pos, this.mark);
25646
+ }
25647
+ toJSON() {
25648
+ return { stepType: "addNodeMark", pos: this.pos, mark: this.mark.toJSON() };
25649
+ }
25650
+ }
25651
+ Step.jsonID("addNodeMark", AddNodeMarkStep);
25686
25652
  const NodeProcessor = Extension.create({
25687
25653
  name: "node_processor",
25688
25654
  addCommands() {
@@ -25703,7 +25669,73 @@ const NodeProcessor = Extension.create({
25703
25669
  Object.assign(attrs, ((_a = editor.getAttributes(type)) == null ? void 0 : _a[name]) || {});
25704
25670
  }
25705
25671
  return Object.keys(attrs).length ? attrs : null;
25706
- }))
25672
+ })),
25673
+ applyMark: createCommand(({ state }, name, value, customizer = {}) => {
25674
+ const { tr, doc: doc2, schema } = state;
25675
+ const { $from, $to } = tr.selection;
25676
+ const markType = getMarkType(name, schema);
25677
+ const onAppliedToParent = customizer.onAppliedToParent || ((context) => {
25678
+ const { tr: tr2, textPosition, applyingMark } = context;
25679
+ tr2.removeMark(textPosition.from, textPosition.to, applyingMark.type);
25680
+ });
25681
+ if ($from.pos === $to.pos)
25682
+ return;
25683
+ doc2.nodesBetween($from.pos, $to.pos, (node, position) => {
25684
+ if (node.type.name === NodeTypes.LIST)
25685
+ return;
25686
+ const initialMark = findMarkByType(node.marks, name);
25687
+ const applyingMark = markType.create({ ...(initialMark == null ? void 0 : initialMark.attrs) || {}, ...value });
25688
+ const textPosition = resolveTextPosition($from, $to, node, position);
25689
+ if (isMarkAppliedToParent(tr, position, applyingMark, customizer.compareParentMark)) {
25690
+ onAppliedToParent({ tr, textPosition, applyingMark, initialMark, node });
25691
+ return;
25692
+ }
25693
+ if (node.isText) {
25694
+ tr.addMark(textPosition.from, textPosition.to, applyingMark);
25695
+ return;
25696
+ }
25697
+ if (isNodeFullySelected($from, $to, node, position)) {
25698
+ tr.step(new AddNodeMarkStep(position, applyingMark));
25699
+ }
25700
+ });
25701
+ }),
25702
+ getMarks: createCommand(({ editor }, name) => {
25703
+ const stateRef = toRef(editor, "state");
25704
+ return computed(() => {
25705
+ const { selection, doc: doc2 } = unref(stateRef);
25706
+ const { from: from2, to } = unref(selection);
25707
+ const marks = [];
25708
+ doc2.nodesBetween(from2, to, (node) => {
25709
+ for (const mark of node.marks) {
25710
+ if (mark.type.name === name)
25711
+ marks.unshift(mark.attrs);
25712
+ }
25713
+ });
25714
+ return marks;
25715
+ });
25716
+ }),
25717
+ getMark: createCommand(({ commands: commands2 }, name) => {
25718
+ const marksRef = commands2.getMarks(name);
25719
+ return computed(() => {
25720
+ var _a;
25721
+ return (_a = unref(marksRef)[0]) != null ? _a : null;
25722
+ });
25723
+ }),
25724
+ getCommonSettingMark: createCommand(({ commands: commands2 }, name, defaultRef) => {
25725
+ const selectionRef = commands2.getMark(name);
25726
+ return computed(() => {
25727
+ var _a, _b;
25728
+ return (_b = (_a = unref(selectionRef)) == null ? void 0 : _a.value) != null ? _b : unref(defaultRef);
25729
+ });
25730
+ }),
25731
+ getDeviceSettingMark: createCommand(({ commands: commands2 }, name, defaultRef) => {
25732
+ const selectionRef = commands2.getMark(name);
25733
+ const deviceRef = commands2.getDevice();
25734
+ return computed(() => {
25735
+ var _a, _b;
25736
+ return (_b = (_a = unref(selectionRef)) == null ? void 0 : _a[unref(deviceRef)]) != null ? _b : unref(defaultRef);
25737
+ });
25738
+ })
25707
25739
  };
25708
25740
  }
25709
25741
  });
@@ -25719,22 +25751,20 @@ const TextProcessor = Extension.create({
25719
25751
  marks.forEach((mark) => commands2.unsetMark(mark));
25720
25752
  }),
25721
25753
  transformText: createCommand(({ state }, transform) => {
25722
- const { selection } = state.tr;
25723
- if (selection.from === selection.to)
25754
+ const { $from, $to } = state.tr.selection;
25755
+ if ($from.pos === $to.pos)
25724
25756
  return;
25725
- state.doc.nodesBetween(selection.from, selection.to, (node, position) => {
25757
+ state.doc.nodesBetween($from.pos, $to.pos, (node, position) => {
25726
25758
  if (!node.isText)
25727
25759
  return;
25728
- const startPosition = Math.max(position, selection.from);
25729
- const endPosition = Math.min(position + node.nodeSize, selection.to);
25730
- const substringFrom = Math.max(0, selection.from - position);
25731
- const substringTo = Math.max(0, selection.to - position);
25760
+ const textPosition = resolveTextPosition($from, $to, node, position);
25761
+ const substringFrom = Math.max(0, $from.pos - position);
25762
+ const substringTo = Math.max(0, $to.pos - position);
25732
25763
  const updatedText = transform({
25733
- text: node.textContent.substring(substringFrom, substringTo),
25734
- position: { start: startPosition, end: endPosition }
25764
+ text: node.textContent.substring(substringFrom, substringTo)
25735
25765
  });
25736
25766
  const updatedNode = state.schema.text(updatedText, node.marks);
25737
- state.tr.replaceWith(startPosition, endPosition, updatedNode);
25767
+ state.tr.replaceWith(textPosition.from, textPosition.to, updatedNode);
25738
25768
  });
25739
25769
  })
25740
25770
  };
@@ -25843,15 +25873,132 @@ const CopyPasteProcessor = Extension.create({
25843
25873
  return [PastePlugin.create()];
25844
25874
  }
25845
25875
  });
25876
+ const Document$1 = Node.create({
25877
+ name: "doc",
25878
+ topNode: true,
25879
+ content: "block+"
25880
+ });
25881
+ const Document = Document$1.extend({
25882
+ marks: "settings"
25883
+ });
25884
+ const Paragraph$1 = Node.create({
25885
+ name: "paragraph",
25886
+ priority: 1e3,
25887
+ addOptions() {
25888
+ return {
25889
+ HTMLAttributes: {}
25890
+ };
25891
+ },
25892
+ group: "block",
25893
+ content: "inline*",
25894
+ parseHTML() {
25895
+ return [
25896
+ { tag: "p" }
25897
+ ];
25898
+ },
25899
+ renderHTML({ HTMLAttributes }) {
25900
+ return ["p", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
25901
+ },
25902
+ addCommands() {
25903
+ return {
25904
+ setParagraph: () => ({ commands: commands2 }) => {
25905
+ return commands2.setNode(this.name);
25906
+ }
25907
+ };
25908
+ },
25909
+ addKeyboardShortcuts() {
25910
+ return {
25911
+ "Mod-Alt-0": () => this.editor.commands.setParagraph()
25912
+ };
25913
+ }
25914
+ });
25915
+ const Paragraph = Paragraph$1.extend({
25916
+ marks: "_",
25917
+ addOptions: () => ({
25918
+ HTMLAttributes: { class: "zw-style" }
25919
+ })
25920
+ });
25921
+ const Heading$1 = Node.create({
25922
+ name: "heading",
25923
+ addOptions() {
25924
+ return {
25925
+ levels: [1, 2, 3, 4, 5, 6],
25926
+ HTMLAttributes: {}
25927
+ };
25928
+ },
25929
+ content: "inline*",
25930
+ group: "block",
25931
+ defining: true,
25932
+ addAttributes() {
25933
+ return {
25934
+ level: {
25935
+ default: 1,
25936
+ rendered: false
25937
+ }
25938
+ };
25939
+ },
25940
+ parseHTML() {
25941
+ return this.options.levels.map((level) => ({
25942
+ tag: `h${level}`,
25943
+ attrs: { level }
25944
+ }));
25945
+ },
25946
+ renderHTML({ node, HTMLAttributes }) {
25947
+ const hasLevel = this.options.levels.includes(node.attrs.level);
25948
+ const level = hasLevel ? node.attrs.level : this.options.levels[0];
25949
+ return [`h${level}`, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
25950
+ },
25951
+ addCommands() {
25952
+ return {
25953
+ setHeading: (attributes) => ({ commands: commands2 }) => {
25954
+ if (!this.options.levels.includes(attributes.level)) {
25955
+ return false;
25956
+ }
25957
+ return commands2.setNode(this.name, attributes);
25958
+ },
25959
+ toggleHeading: (attributes) => ({ commands: commands2 }) => {
25960
+ if (!this.options.levels.includes(attributes.level)) {
25961
+ return false;
25962
+ }
25963
+ return commands2.toggleNode(this.name, "paragraph", attributes);
25964
+ }
25965
+ };
25966
+ },
25967
+ addKeyboardShortcuts() {
25968
+ return this.options.levels.reduce((items, level) => ({
25969
+ ...items,
25970
+ ...{
25971
+ [`Mod-Alt-${level}`]: () => this.editor.commands.toggleHeading({ level })
25972
+ }
25973
+ }), {});
25974
+ },
25975
+ addInputRules() {
25976
+ return this.options.levels.map((level) => {
25977
+ return textblockTypeInputRule({
25978
+ find: new RegExp(`^(#{1,${level}})\\s$`),
25979
+ type: this.type,
25980
+ getAttributes: {
25981
+ level
25982
+ }
25983
+ });
25984
+ });
25985
+ }
25986
+ });
25987
+ const Heading = Heading$1.extend({
25988
+ marks: "_",
25989
+ addOptions: () => ({
25990
+ levels: [1, 2, 3, 4],
25991
+ HTMLAttributes: { class: "zw-style" }
25992
+ })
25993
+ });
25846
25994
  const buildCoreExtensions = () => [
25847
25995
  Document,
25848
- Paragraph.configure({
25849
- HTMLAttributes: { class: "zw-style" }
25850
- }),
25851
25996
  Placeholder.configure({
25852
25997
  placeholder: "Type your text here...",
25853
25998
  emptyNodeClass: "zw-wysiwyg__placeholder"
25854
25999
  }),
26000
+ Paragraph,
26001
+ Heading,
25855
26002
  Text,
25856
26003
  History,
25857
26004
  NodeProcessor,