@zipify/wysiwyg 1.0.0-dev.16 → 1.0.0-dev.19

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 (100) hide show
  1. package/.github/dependabot.yaml +1 -0
  2. package/dist/wysiwyg.css +293 -12
  3. package/dist/wysiwyg.js +1 -1
  4. package/example/ExampleApp.vue +6 -2
  5. package/example/pageBlocks.js +31 -0
  6. package/example/presets.js +2 -2
  7. package/lib/Wysiwyg.vue +16 -6
  8. package/lib/assets/icons/link.svg +3 -0
  9. package/lib/assets/icons/unlink.svg +3 -0
  10. package/lib/components/base/Button.vue +21 -1
  11. package/lib/components/base/Checkbox.vue +89 -0
  12. package/lib/components/base/FieldLabel.vue +2 -1
  13. package/lib/components/base/Icon.vue +2 -2
  14. package/lib/components/base/Modal.vue +0 -1
  15. package/lib/components/base/TextField.vue +106 -0
  16. package/lib/components/base/__tests__/TextField.test.js +57 -0
  17. package/lib/components/base/__tests__/__snapshots__/TextField.test.js.snap +9 -0
  18. package/lib/components/base/composables/index.js +1 -0
  19. package/lib/components/base/composables/useValidator.js +19 -0
  20. package/lib/components/base/dropdown/Dropdown.vue +15 -3
  21. package/lib/components/base/dropdown/DropdownActivator.vue +19 -3
  22. package/lib/components/base/index.js +3 -1
  23. package/lib/components/toolbar/Toolbar.vue +48 -8
  24. package/lib/components/toolbar/ToolbarFull.vue +10 -2
  25. package/lib/components/toolbar/__tests__/Toolbar.test.js +6 -0
  26. package/lib/components/toolbar/controls/FontSizeControl.vue +7 -0
  27. package/lib/components/toolbar/controls/UnderlineControl.vue +2 -2
  28. package/lib/components/toolbar/controls/__tests__/UnderlineControl.test.js +4 -0
  29. package/lib/components/toolbar/controls/index.js +1 -0
  30. package/lib/components/toolbar/controls/link/LinkControl.vue +152 -0
  31. package/lib/components/toolbar/controls/link/LinkControlApply.vue +35 -0
  32. package/lib/components/toolbar/controls/link/LinkControlHeader.vue +67 -0
  33. package/lib/components/toolbar/controls/link/composables/index.js +1 -0
  34. package/lib/components/toolbar/controls/link/composables/useLink.js +61 -0
  35. package/lib/components/toolbar/controls/link/destination/LinkControlDestination.vue +103 -0
  36. package/lib/components/toolbar/controls/link/destination/LinkControlPageBlock.vue +54 -0
  37. package/lib/components/toolbar/controls/link/destination/LinkControlUrl.vue +52 -0
  38. package/lib/components/toolbar/controls/link/destination/index.js +1 -0
  39. package/lib/components/toolbar/controls/link/index.js +1 -0
  40. package/lib/composables/__tests__/useEditor.test.js +2 -2
  41. package/lib/composables/useEditor.js +4 -5
  42. package/lib/composables/useToolbar.js +15 -19
  43. package/lib/enums/LinkDestinations.js +4 -0
  44. package/lib/enums/LinkTargets.js +4 -0
  45. package/lib/enums/TextSettings.js +3 -1
  46. package/lib/enums/index.js +2 -0
  47. package/lib/extensions/Alignment.js +18 -6
  48. package/lib/extensions/BackgroundColor.js +14 -6
  49. package/lib/extensions/FontColor.js +14 -6
  50. package/lib/extensions/FontFamily.js +25 -8
  51. package/lib/extensions/FontSize.js +26 -13
  52. package/lib/extensions/FontStyle.js +23 -13
  53. package/lib/extensions/FontWeight.js +22 -14
  54. package/lib/extensions/LineHeight.js +11 -3
  55. package/lib/extensions/Link.js +101 -0
  56. package/lib/extensions/StylePreset.js +4 -2
  57. package/lib/extensions/TextDecoration.js +27 -12
  58. package/lib/extensions/__tests__/Alignment.test.js +11 -5
  59. package/lib/extensions/__tests__/BackgroundColor.test.js +11 -5
  60. package/lib/extensions/__tests__/CaseStyle.test.js +3 -5
  61. package/lib/extensions/__tests__/FontColor.test.js +11 -5
  62. package/lib/extensions/__tests__/FontFamily.test.js +32 -7
  63. package/lib/extensions/__tests__/FontSize.test.js +11 -5
  64. package/lib/extensions/__tests__/FontStyle.test.js +11 -5
  65. package/lib/extensions/__tests__/FontWeight.test.js +11 -5
  66. package/lib/extensions/__tests__/LineHeight.test.js +11 -5
  67. package/lib/extensions/__tests__/StylePreset.test.js +70 -6
  68. package/lib/extensions/__tests__/TextDecoration.test.js +27 -5
  69. package/lib/extensions/__tests__/__snapshots__/Alignment.test.js.snap +26 -2
  70. package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +30 -1
  71. package/lib/extensions/__tests__/__snapshots__/FontColor.test.js.snap +18 -1
  72. package/lib/extensions/__tests__/__snapshots__/FontFamily.test.js.snap +88 -1
  73. package/lib/extensions/__tests__/__snapshots__/FontSize.test.js.snap +33 -2
  74. package/lib/extensions/__tests__/__snapshots__/FontStyle.test.js.snap +25 -4
  75. package/lib/extensions/__tests__/__snapshots__/FontWeight.test.js.snap +30 -1
  76. package/lib/extensions/__tests__/__snapshots__/LineHeight.test.js.snap +26 -2
  77. package/lib/extensions/__tests__/__snapshots__/StylePreset.test.js.snap +6 -2
  78. package/lib/extensions/__tests__/__snapshots__/TextDecoration.test.js.snap +93 -3
  79. package/lib/extensions/core/CopyPasteProcessor.js +10 -0
  80. package/lib/extensions/core/TextProcessor.js +10 -0
  81. package/lib/extensions/core/__tests__/NodeProcessor.test.js +3 -5
  82. package/lib/extensions/core/__tests__/SelectionProcessor.test.js +3 -5
  83. package/lib/extensions/core/__tests__/TextProcessor.test.js +138 -12
  84. package/lib/extensions/core/__tests__/__snapshots__/TextProcessor.test.js.snap +26 -0
  85. package/lib/extensions/core/index.js +11 -2
  86. package/lib/extensions/core/plugins/PastePlugin.js +48 -0
  87. package/lib/extensions/core/plugins/ProseMirrorPlugin.js +20 -0
  88. package/lib/extensions/core/plugins/index.js +1 -0
  89. package/lib/extensions/index.js +41 -34
  90. package/lib/extensions/list/__tests__/List.test.js +3 -5
  91. package/lib/extensions/list/__tests__/__snapshots__/List.test.js.snap +45 -15
  92. package/lib/injectionTokens.js +2 -1
  93. package/lib/services/ContentNormalizer.js +62 -20
  94. package/lib/services/__tests__/ContentNormalizer.test.js +40 -7
  95. package/lib/styles/content.css +96 -9
  96. package/lib/styles/helpers/offsets.css +16 -0
  97. package/lib/styles/variables.css +6 -0
  98. package/lib/utils/__tests__/__snapshots__/renderInlineSetting.test.js.snap +4 -4
  99. package/lib/utils/renderInlineSetting.js +1 -1
  100. package/package.json +11 -9
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <div>
3
+ <TextField
4
+ class="zw-margin-bottom--xs"
5
+ label="To what URL should this link go?"
6
+ placeholder="https://"
7
+ :value="href"
8
+ :error="validator.error.value"
9
+ @input="updateLink"
10
+ />
11
+
12
+ <Checkbox
13
+ label="Open in new tab"
14
+ :value="isTargetBlank"
15
+ @input="updateTarget"
16
+ />
17
+ </div>
18
+ </template>
19
+
20
+ <script>
21
+ import { TextField, Checkbox } from '../../../../base';
22
+
23
+ export default {
24
+ name: 'LinkControlUrl',
25
+
26
+ components: { TextField, Checkbox },
27
+
28
+ props: {
29
+ href: {
30
+ type: String,
31
+ required: true
32
+ },
33
+
34
+ isTargetBlank: {
35
+ type: Boolean,
36
+ required: true
37
+ },
38
+
39
+ validator: {
40
+ type: Object,
41
+ required: true
42
+ }
43
+ },
44
+
45
+ setup(props, { emit }) {
46
+ const updateLink = (value) => emit('updateLink', value);
47
+ const updateTarget = (value) => emit('updateTarget', value);
48
+
49
+ return { updateLink, updateTarget };
50
+ }
51
+ };
52
+ </script>
@@ -0,0 +1 @@
1
+ export { default as LinkControlDestination } from './LinkControlDestination';
@@ -0,0 +1 @@
1
+ export { default as LinkControl } from './LinkControl';
@@ -1,9 +1,9 @@
1
1
  import { h, toRef } from '@vue/composition-api';
2
2
  import { EditorContent } from '@tiptap/vue-2';
3
3
  import { shallowMount } from '@vue/test-utils';
4
- import { CORE_EXTENSIONS } from '../../extensions';
5
4
  import { useEditor } from '../useEditor';
6
5
  import { NodeFactory } from '../../__tests__/utils';
6
+ import { buildCoreExtensions } from '../../extensions/core';
7
7
 
8
8
  const TestComponent = {
9
9
  name: 'Test',
@@ -19,7 +19,7 @@ const TestComponent = {
19
19
  setup(props, { emit }) {
20
20
  const editor = useEditor({
21
21
  content: toRef(props, 'value'),
22
- extensions: CORE_EXTENSIONS,
22
+ extensions: buildCoreExtensions(),
23
23
  onChange: (content) => emit('input', content),
24
24
  onFocus: () => emit('focus')
25
25
  });
@@ -3,12 +3,11 @@ import { onUnmounted, watch, reactive } from '@vue/composition-api';
3
3
  import { ContentNormalizer } from '../services';
4
4
 
5
5
  export function useEditor({ content, onChange, extensions }) {
6
- const normalizer = new ContentNormalizer();
7
-
8
6
  const editor = reactive(new Editor({
9
- content: normalizer.normalize(content.value),
7
+ content: ContentNormalizer.normalize(content.value),
10
8
  onUpdate: () => onChange(editor.getJSON()),
11
- extensions
9
+ extensions,
10
+ injectCSS: false
12
11
  }));
13
12
 
14
13
  onUnmounted(() => editor.destroy());
@@ -17,7 +16,7 @@ export function useEditor({ content, onChange, extensions }) {
17
16
  const isChanged = JSON.stringify(editor.getJSON()) !== JSON.stringify(value);
18
17
 
19
18
  if (isChanged) {
20
- const content = normalizer.normalize(value);
19
+ const content = ContentNormalizer.normalize(value);
21
20
 
22
21
  editor.commands.setContent(content, false);
23
22
  }
@@ -1,33 +1,29 @@
1
1
  import { createPopper } from '@popperjs/core';
2
- import { onUnmounted, onMounted, watch } from '@vue/composition-api';
3
- import { useElementRef } from '../components/base/composables';
2
+ import { useElementRef } from '../components/base';
4
3
 
5
- export function useToolbar({ wrapperRef, popperRef, offsets, isActiveRef }) {
4
+ export function useToolbar({ wrapperRef, offsets, isActiveRef }) {
5
+ const wrapperEl = useElementRef(wrapperRef);
6
6
  let toolbar;
7
7
 
8
- onMounted(() => {
9
- const wrapperEl = useElementRef(wrapperRef).value;
10
- const toolbarEl = useElementRef(popperRef).value;
11
-
12
- toolbar = createPopper(wrapperEl, toolbarEl, {
8
+ function mount(element) {
9
+ toolbar = createPopper(wrapperEl.value, element, {
13
10
  placement: 'top-start',
14
11
  modifiers: [
15
12
  {
16
13
  name: 'offset',
17
- options: {
18
- offset: offsets
19
- }
14
+ options: { offset: offsets }
20
15
  }
21
16
  ]
22
17
  });
23
- });
24
- const update = () => toolbar.update();
25
-
26
- watch(isActiveRef, () => {
27
- if (isActiveRef.value) update();
28
- });
18
+ }
29
19
 
30
- onUnmounted(() => toolbar.destroy());
20
+ const update = () => toolbar?.update();
31
21
 
32
- return { toolbar, update };
22
+ return {
23
+ toolbar,
24
+ update,
25
+ mount,
26
+ isActiveRef,
27
+ offsets
28
+ };
33
29
  }
@@ -0,0 +1,4 @@
1
+ export const LinkDestinations = Object.freeze({
2
+ URL: 'url',
3
+ BLOCK: 'block'
4
+ });
@@ -0,0 +1,4 @@
1
+ export const LinkTargets = Object.freeze({
2
+ BLANK: '_blank',
3
+ SELF: '_self'
4
+ });
@@ -8,6 +8,7 @@ export const TextSettings = Object.freeze({
8
8
  FONT_WEIGHT: 'font_weight',
9
9
  LINE_HEIGHT: 'line_height',
10
10
  TEXT_DECORATION: 'text_decoration',
11
+ SUPERSCRIPT: 'superscript',
11
12
 
12
13
  get attributes() {
13
14
  return [
@@ -24,7 +25,8 @@ export const TextSettings = Object.freeze({
24
25
  this.FONT_SIZE,
25
26
  this.FONT_STYLE,
26
27
  this.FONT_WEIGHT,
27
- this.TEXT_DECORATION
28
+ this.TEXT_DECORATION,
29
+ this.SUPERSCRIPT
28
30
  ];
29
31
  }
30
32
  });
@@ -4,3 +4,5 @@ export { Alignments } from './Alignments';
4
4
  export { NodeTypes } from './NodeTypes';
5
5
  export { ListTypes } from './ListTypes';
6
6
  export { TextSettings } from './TextSettings';
7
+ export { LinkTargets } from './LinkTargets';
8
+ export { LinkDestinations } from './LinkDestinations';
@@ -19,19 +19,31 @@ export const Alignment = Extension.create({
19
19
  [TextSettings.ALIGNMENT]: {
20
20
  isRequired: false,
21
21
 
22
- parseHTML(el) {
23
- const value = el.style.textAlign;
22
+ parseHTML({ style }) {
23
+ if (style.textAlign) {
24
+ return {
25
+ desktop: style.textAlign,
26
+ tablet: style.textAlign,
27
+ mobile: style.textAlign
28
+ };
29
+ }
24
30
 
25
- return value ? { desktop: value, tablet: value, mobile: value } : null;
31
+ const mobile = style.getPropertyValue('--zw-text-align-mobile') || null;
32
+ const tablet = style.getPropertyValue('--zw-text-align-tablet') || null;
33
+ const desktop = style.getPropertyValue('--zw-text-align-desktop') || null;
34
+
35
+ if (!mobile && !tablet && !desktop) return null;
36
+
37
+ return { desktop, tablet, mobile };
26
38
  },
27
39
 
28
40
  renderHTML(attrs) {
29
41
  if (!attrs.alignment) return null;
30
42
 
31
43
  return renderInlineSetting({
32
- mobile_text_align: attrs.alignment.mobile,
33
- tablet_text_align: attrs.alignment.tablet,
34
- desktop_text_align: attrs.alignment.desktop
44
+ text_align_mobile: attrs.alignment.mobile,
45
+ text_align_tablet: attrs.alignment.tablet,
46
+ text_align_desktop: attrs.alignment.desktop
35
47
  });
36
48
  }
37
49
  }
@@ -22,12 +22,20 @@ export const BackgroundColor = Mark.create({
22
22
  };
23
23
  },
24
24
 
25
- parseHTML: () => [
26
- {
27
- style: 'background-color',
28
- getAttrs: (value) => ({ value: convertColor(value) })
29
- }
30
- ],
25
+ parseHTML() {
26
+ const getAttrs = (value) => ({ value: convertColor(value) });
27
+
28
+ return [
29
+ {
30
+ style: '--zw-background-color',
31
+ getAttrs
32
+ },
33
+ {
34
+ style: 'background-color',
35
+ getAttrs
36
+ }
37
+ ];
38
+ },
31
39
 
32
40
  renderHTML({ HTMLAttributes: attrs }) {
33
41
  return renderMark({ background_color: attrs.value });
@@ -30,12 +30,20 @@ export const FontColor = Mark.create({
30
30
  };
31
31
  },
32
32
 
33
- parseHTML: () => [
34
- {
35
- style: 'color',
36
- getAttrs: (value) => ({ value: convertColor(value) })
37
- }
38
- ],
33
+ parseHTML() {
34
+ const getAttrs = (value) => ({ value: convertColor(value) });
35
+
36
+ return [
37
+ {
38
+ style: '--zw-font-color',
39
+ getAttrs
40
+ },
41
+ {
42
+ style: 'color',
43
+ getAttrs
44
+ }
45
+ ];
46
+ },
39
47
 
40
48
  renderHTML({ HTMLAttributes: attrs }) {
41
49
  return renderMark({ font_color: attrs.value });
@@ -7,7 +7,8 @@ export const FontFamily = Mark.create({
7
7
  name: TextSettings.FONT_FAMILY,
8
8
 
9
9
  addOptions: () => ({
10
- fonts: []
10
+ fonts: [],
11
+ defaultFont: ''
11
12
  }),
12
13
 
13
14
  addAttributes: () => ({
@@ -56,14 +57,30 @@ export const FontFamily = Mark.create({
56
57
  };
57
58
  },
58
59
 
59
- parseHTML: () => [
60
- {
61
- style: 'font-family',
62
- getAttrs: (value) => ({ value })
63
- }
64
- ],
60
+ parseHTML() {
61
+ const getAttrs = (input) => {
62
+ const parsed = input.replace(/"/g, '');
63
+ const isExists = this.options.fonts.some((font) => font.name === parsed);
64
+ const value = isExists ? parsed : this.options.defaultFont;
65
+
66
+ return { value };
67
+ };
68
+
69
+ return [
70
+ {
71
+ style: '--zw-font-family',
72
+ getAttrs
73
+ },
74
+ {
75
+ style: 'font-family',
76
+ getAttrs
77
+ }
78
+ ];
79
+ },
65
80
 
66
81
  renderHTML({ HTMLAttributes: attrs }) {
67
- return renderMark({ font_family: attrs.value });
82
+ const font_family = attrs.value ? `"${attrs.value}"` : null;
83
+
84
+ return renderMark({ font_family });
68
85
  }
69
86
  });
@@ -62,25 +62,38 @@ export const FontSize = Mark.create({
62
62
  'Mod-Shift--': createKeyboardShortcut('decreaseFontSize')
63
63
  }),
64
64
 
65
- parseHTML: () => [
66
- {
67
- style: 'font-size',
68
-
69
- getAttrs: (input) => {
70
- const value = String(parseInt(input));
71
-
72
- return { desktop: value, tablet: value, mobile: value };
65
+ parseHTML() {
66
+ const parseSize = (value) => value ? String(parseInt(value)) : null;
67
+
68
+ return [
69
+ {
70
+ tag: '[style*="--zw-font-size"]',
71
+
72
+ getAttrs: ({ style }) => ({
73
+ mobile: parseSize(style.getPropertyValue('--zw-font-size-mobile')),
74
+ tablet: parseSize(style.getPropertyValue('--zw-font-size-tablet')),
75
+ desktop: parseSize(style.getPropertyValue('--zw-font-size-desktop'))
76
+ })
77
+ },
78
+ {
79
+ style: 'font-size',
80
+
81
+ getAttrs: (input) => {
82
+ const value = parseSize(input);
83
+
84
+ return { desktop: value, tablet: value, mobile: value };
85
+ }
73
86
  }
74
- }
75
- ],
87
+ ];
88
+ },
76
89
 
77
90
  renderHTML({ HTMLAttributes: attrs }) {
78
91
  const addUnits = (value) => value ? `${value}px` : null;
79
92
 
80
93
  return renderMark({
81
- mobile_font_size: addUnits(attrs.mobile),
82
- tablet_font_size: addUnits(attrs.tablet),
83
- desktop_font_size: addUnits(attrs.desktop)
94
+ font_size_mobile: addUnits(attrs.mobile),
95
+ font_size_tablet: addUnits(attrs.tablet),
96
+ font_size_desktop: addUnits(attrs.desktop)
84
97
  });
85
98
  }
86
99
  });
@@ -56,18 +56,28 @@ export const FontStyle = Mark.create({
56
56
  'Mod-I': createKeyboardShortcut('toggleItalic')
57
57
  }),
58
58
 
59
- parseHTML: () => [
60
- {
61
- tag: 'i',
62
- attrs: { italic: true }
63
- },
64
- {
65
- style: 'font-style',
66
- getAttrs: (value) => ({ italic: value.includes('italic') })
67
- }
68
- ],
69
-
70
- renderHTML() {
71
- return renderMark({ font_style: 'italic' });
59
+ parseHTML() {
60
+ const getAttrs = (value) => value.includes('italic') && { italic: true };
61
+
62
+ return [
63
+ {
64
+ style: '--zw-font-style',
65
+ getAttrs
66
+ },
67
+ {
68
+ style: 'font-style',
69
+ getAttrs
70
+ },
71
+ {
72
+ tag: 'i',
73
+ attrs: { italic: true }
74
+ }
75
+ ];
76
+ },
77
+
78
+ renderHTML({ HTMLAttributes: attrs }) {
79
+ const font_style = attrs.italic ? 'italic' : null;
80
+
81
+ return renderMark({ font_style });
72
82
  }
73
83
  });
@@ -59,20 +59,28 @@ export const FontWeight = Mark.create({
59
59
  'Mod-B': createKeyboardShortcut('toggleBold')
60
60
  }),
61
61
 
62
- parseHTML: () => [
63
- {
64
- tag: 'b',
65
- attrs: { value: '700' }
66
- },
67
- {
68
- tag: 'strong',
69
- attrs: { value: '700' }
70
- },
71
- {
72
- style: 'font-weight',
73
- getAttrs: (value) => ({ value })
74
- }
75
- ],
62
+ parseHTML() {
63
+ const getAttrs = (value) => ({ value });
64
+
65
+ return [
66
+ {
67
+ style: '--zw-font-weight',
68
+ getAttrs
69
+ },
70
+ {
71
+ style: 'font-weight',
72
+ getAttrs
73
+ },
74
+ {
75
+ tag: 'b',
76
+ attrs: { value: '700' }
77
+ },
78
+ {
79
+ tag: 'strong',
80
+ attrs: { value: '700' }
81
+ }
82
+ ];
83
+ },
76
84
 
77
85
  renderHTML({ HTMLAttributes: attrs }) {
78
86
  return renderMark({ font_weight: attrs.value });
@@ -21,6 +21,14 @@ export const LineHeight = Extension.create({
21
21
  isRequired: false,
22
22
 
23
23
  parseHTML(element) {
24
+ if (element.matches('[style*="--zw-line-height"]')) {
25
+ const mobile = element.style.getPropertyValue('--zw-line-height-mobile') || null;
26
+ const tablet = element.style.getPropertyValue('--zw-line-height-tablet') || null;
27
+ const desktop = element.style.getPropertyValue('--zw-line-height-desktop') || null;
28
+
29
+ return { mobile, tablet, desktop };
30
+ }
31
+
24
32
  const value = element.style.lineHeight;
25
33
 
26
34
  if (!value) return null;
@@ -41,9 +49,9 @@ export const LineHeight = Extension.create({
41
49
  if (!attrs.line_height) return null;
42
50
 
43
51
  return renderInlineSetting({
44
- mobile_line_height: attrs.line_height.mobile,
45
- tablet_line_height: attrs.line_height.tablet,
46
- desktop_line_height: attrs.line_height.desktop
52
+ line_height_mobile: attrs.line_height.mobile,
53
+ line_height_tablet: attrs.line_height.tablet,
54
+ line_height_desktop: attrs.line_height.desktop
47
55
  });
48
56
  }
49
57
  }
@@ -0,0 +1,101 @@
1
+ import Base from '@tiptap/extension-link';
2
+ import { createCommand } from '../utils';
3
+ import { LinkDestinations, LinkTargets } from '../enums';
4
+
5
+ export const Link = Base.extend({
6
+ name: 'link',
7
+
8
+ addOptions() {
9
+ return {
10
+ ...this.parent?.(),
11
+ openOnClick: false,
12
+ HTMLAttributes: {
13
+ target: LinkTargets.SELF
14
+ },
15
+ preset: {},
16
+ basePresetClass: null,
17
+ pageBlocks: []
18
+ };
19
+ },
20
+
21
+ addAttributes() {
22
+ return {
23
+ href: {
24
+ default: null,
25
+ parseHTML: (element) => {
26
+ const href = element.getAttribute('href');
27
+
28
+ if (!href.startsWith('#')) return href;
29
+
30
+ return parseFloat(element.getAttribute('href').replace('#', ''));
31
+ }
32
+ },
33
+
34
+ target: {
35
+ default: this.options.target,
36
+ parseHTML: (element) => {
37
+ const target = element.getAttribute('target');
38
+
39
+ if (!target) return LinkTargets.SELF;
40
+
41
+ return target;
42
+ }
43
+ },
44
+
45
+ destination: {
46
+ default: LinkDestinations.URL,
47
+ parseHTML: (element) => {
48
+ const href = element.getAttribute('href');
49
+
50
+ if (!href.startsWith('#')) return LinkDestinations.URL;
51
+
52
+ const id = href.replace('#', '');
53
+ const block = this.options.pageBlocks.value.find((block) => block.id === parseInt(id));
54
+
55
+ return block ? LinkDestinations.BLOCK : LinkDestinations.URL;
56
+ }
57
+ }
58
+ };
59
+ },
60
+
61
+ addCommands() {
62
+ return {
63
+ ...this.parent?.(),
64
+ applyLink: createCommand(({ commands, chain }, attributes) => {
65
+ if (!commands.getSelectedText()) {
66
+ return commands.insertContent({
67
+ type: 'text',
68
+ marks: [
69
+ {
70
+ type: 'link',
71
+ attrs: { ...attributes }
72
+ }
73
+ ],
74
+ text: attributes.text
75
+ });
76
+ }
77
+
78
+ return chain()
79
+ .setMark(this.name, attributes)
80
+ .transformText(() => attributes.text)
81
+ .extendMarkRange('link')
82
+ .run();
83
+ })
84
+ };
85
+ },
86
+
87
+ renderHTML({ HTMLAttributes: attrs }) {
88
+ const href = attrs.destination === LinkDestinations.BLOCK ? `#${attrs.href}` : attrs.href;
89
+
90
+ const presetClass = this.options.basePresetClass + this.options.preset.id;
91
+ const classes = `${presetClass} zw-style`;
92
+
93
+ const linkAttrs = {
94
+ href,
95
+ target: attrs.target,
96
+ class: classes
97
+ };
98
+
99
+ return ['a', linkAttrs, 0];
100
+ }
101
+ });
@@ -39,11 +39,13 @@ export const StylePreset = Extension.create({
39
39
  attributes: {
40
40
  preset: {
41
41
  isRequired: false,
42
- default: null,
42
+ default: { id: this.options.defaultId },
43
43
 
44
44
  parseHTML: (element) => {
45
45
  const presets = this.options.presetsRef.value;
46
46
 
47
+ if (element.parentElement.tagName === 'LI') return null;
48
+
47
49
  for (const { id, node, fallbackClass } of presets) {
48
50
  const isFallback = fallbackClass && element.classList.contains(fallbackClass);
49
51
 
@@ -148,7 +150,7 @@ export const StylePreset = Extension.create({
148
150
  chain()
149
151
  .storeSelection()
150
152
  .expandSelectionToBlock()
151
- .unsetAllMarks()
153
+ .unsetMarks(TextSettings.marks)
152
154
  .resetAttributes(NodeTypes.PARAGRAPH, TextSettings.attributes)
153
155
  .resetAttributes(NodeTypes.HEADING, TextSettings.attributes)
154
156
  .restoreSelection()