@zipify/wysiwyg 3.1.0-0 → 3.1.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 (81) hide show
  1. package/.eslintrc.js +17 -235
  2. package/.github/actions/setup/action.yaml +1 -1
  3. package/README.md +2 -0
  4. package/config/build/cli.config.js +7 -7
  5. package/config/build/lib.config.js +6 -4
  6. package/config/svgo.js +6 -3
  7. package/dist/cli.js +5 -4
  8. package/dist/wysiwyg.css +36 -33
  9. package/dist/wysiwyg.mjs +12403 -11604
  10. package/example/ExampleApp.vue +1 -1
  11. package/example/presets.js +7 -7
  12. package/example/tooltip/Tooltip.js +94 -69
  13. package/example/tooltip/tooltip.css +8 -31
  14. package/lib/Wysiwyg.vue +3 -0
  15. package/lib/__tests__/utils/buildTestExtensions.js +24 -2
  16. package/lib/cli/commands/ToJsonCommand.js +6 -6
  17. package/lib/components/base/__tests__/Button.test.js +1 -1
  18. package/lib/components/base/composables/__tests__/useDeselectionLock.test.js +2 -2
  19. package/lib/components/base/composables/__tests__/useElementRef.test.js +1 -1
  20. package/lib/components/base/composables/__tests__/useModalToggler.test.js +0 -2
  21. package/lib/components/base/composables/__tests__/useValidator.test.js +2 -2
  22. package/lib/components/base/composables/useModalToggler.js +30 -21
  23. package/lib/components/base/dropdown/DropdownActivator.vue +4 -0
  24. package/lib/components/toolbar/Toolbar.vue +1 -1
  25. package/lib/components/toolbar/base/__tests__/ToolbarDivider.test.js +1 -1
  26. package/lib/components/toolbar/controls/StylePresetControl.vue +2 -2
  27. package/lib/components/toolbar/controls/__tests__/LineHeightControl.test.js +0 -2
  28. package/lib/components/toolbar/controls/composables/__tests__/useRecentFonts.test.js +1 -1
  29. package/lib/components/toolbar/controls/link/composables/__tests__/useLink.test.js +2 -2
  30. package/lib/composables/useToolbar.js +24 -19
  31. package/lib/{entry-cli.js → entryCli.js} +0 -0
  32. package/lib/{entry-lib.js → entryLib.js} +0 -0
  33. package/lib/extensions/Alignment.js +6 -6
  34. package/lib/extensions/FontSize.js +1 -2
  35. package/lib/extensions/Link.js +2 -0
  36. package/lib/extensions/StylePreset.js +8 -46
  37. package/lib/extensions/__tests__/Alignment.test.js +1 -1
  38. package/lib/extensions/__tests__/BackgroundColor.test.js +2 -2
  39. package/lib/extensions/__tests__/FontColor.test.js +3 -3
  40. package/lib/extensions/__tests__/FontFamily.test.js +3 -3
  41. package/lib/extensions/__tests__/FontSize.test.js +3 -3
  42. package/lib/extensions/__tests__/FontWeight.test.js +4 -4
  43. package/lib/extensions/__tests__/LineHeight.test.js +2 -2
  44. package/lib/extensions/__tests__/Link.test.js +33 -5
  45. package/lib/extensions/__tests__/StylePreset.test.js +90 -119
  46. package/lib/extensions/__tests__/__snapshots__/Alignment.test.js.snap +2 -2
  47. package/lib/extensions/__tests__/__snapshots__/Link.test.js.snap +27 -0
  48. package/lib/extensions/__tests__/__snapshots__/StylePreset.test.js.snap +0 -2
  49. package/lib/extensions/core/NodeProcessor.js +9 -6
  50. package/lib/extensions/core/__tests__/NodeProcessor.test.js +6 -8
  51. package/lib/extensions/core/__tests__/TextProcessor.test.js +1 -1
  52. package/lib/extensions/core/index.js +0 -2
  53. package/lib/extensions/core/plugins/PlaceholderPlugin.js +2 -2
  54. package/lib/extensions/index.js +7 -3
  55. package/lib/extensions/list/List.js +4 -5
  56. package/lib/extensions/list/ListItem.js +1 -2
  57. package/lib/extensions/list/__tests__/List.test.js +7 -2
  58. package/lib/models/Font.js +2 -2
  59. package/lib/models/__tests__/Font.test.js +3 -9
  60. package/lib/services/ContentSerializer.js +9 -9
  61. package/lib/services/{ContextWidnow.js → ContextWindow.js} +0 -0
  62. package/lib/services/HtmlToJsonParser.js +3 -3
  63. package/lib/services/NodeFactory.js +6 -6
  64. package/lib/services/StylePresetRenderer.js +73 -0
  65. package/lib/services/__tests__/JsonSerializer.test.js +1 -1
  66. package/lib/services/__tests__/Storage.test.js +1 -1
  67. package/lib/services/__tests__/StylePresetRenderer.test.js +98 -0
  68. package/lib/services/__tests__/__snapshots__/StylePresetRenderer.test.js.snap +5 -0
  69. package/lib/services/index.js +2 -1
  70. package/lib/services/normalizer/BrowserDomParser.js +2 -2
  71. package/lib/services/normalizer/ContentNormalizer.js +3 -3
  72. package/lib/services/normalizer/HtmlNormalizer.js +52 -52
  73. package/lib/services/normalizer/JsonNormalizer.js +21 -21
  74. package/lib/styles/content.css +10 -10
  75. package/lib/utils/__tests__/convertAlignment.test.js +1 -1
  76. package/lib/utils/__tests__/renderInlineSetting.test.js +2 -2
  77. package/package.json +48 -46
  78. package/lib/extensions/core/steps/AddNodeMarkStep.js +0 -66
  79. package/lib/extensions/core/steps/AttrStep.js +0 -60
  80. package/lib/extensions/core/steps/RemoveNodeMarkStep.js +0 -56
  81. package/lib/extensions/core/steps/index.js +0 -3
@@ -1,32 +1,38 @@
1
- import { inject, nextTick, ref } from 'vue';
2
- import { autoUpdate, computePosition, limitShift, offset, shift } from '@floating-ui/dom';
1
+ import { createPopper } from '@popperjs/core';
2
+ import { inject, nextTick, ref, onUnmounted } from 'vue';
3
3
  import { InjectionTokens } from '../../../injectionTokens';
4
4
  import { useElementRef } from './useElementRef';
5
5
 
6
6
  export function useModalToggler({ onBeforeOpened, onClosed, wrapperRef, modalRef } = {}) {
7
7
  const editor = inject(InjectionTokens.EDITOR);
8
8
  const isOpened = ref(false);
9
- let floatingInstance;
9
+ let popper;
10
10
 
11
- function initModal() {
11
+ function initPopper() {
12
12
  const wrapperEl = useElementRef(wrapperRef);
13
13
  const modalEl = useElementRef(modalRef);
14
14
 
15
- floatingInstance = autoUpdate(wrapperEl.value, modalEl.value, async () => {
16
- const positioning = await computePosition(wrapperEl.value, modalEl.value, {
17
- placement: 'bottom',
18
- strategy: 'fixed',
19
- middleware: [
20
- shift({ padding: 16, crossAxis: true, limiter: limitShift() }),
21
- offset({ mainAxis: 4 })]
22
- });
23
-
24
- const { x, y } = positioning;
25
-
26
- Object.assign(modalEl.value, {
27
- left: `${x}px`,
28
- top: `${y}px`
29
- });
15
+ popper = createPopper(wrapperEl.value, modalEl.value, {
16
+ placement: 'bottom',
17
+ strategy: 'fixed',
18
+ modifiers: [
19
+ {
20
+ name: 'offset',
21
+ options: {
22
+ offset: [0, 4]
23
+ }
24
+ },
25
+ {
26
+ name: 'preventOverflow',
27
+ options: {
28
+ padding: 16
29
+ }
30
+ },
31
+ {
32
+ name: 'flip',
33
+ enabled: false
34
+ }
35
+ ]
30
36
  });
31
37
  }
32
38
 
@@ -37,16 +43,19 @@ export function useModalToggler({ onBeforeOpened, onClosed, wrapperRef, modalRef
37
43
 
38
44
  await nextTick();
39
45
 
40
- initModal();
46
+ initPopper();
41
47
  }
42
48
 
43
49
  function close() {
44
50
  isOpened.value = false;
45
- floatingInstance?.();
46
51
  editor.commands.restoreSelection();
47
52
  onClosed?.();
48
53
  }
49
54
 
55
+ onUnmounted(() => {
56
+ popper?.destroy();
57
+ });
58
+
50
59
  const toggle = (toOpen) => toOpen ? open() : close();
51
60
 
52
61
  return { isOpened, open, close, toggle };
@@ -82,6 +82,10 @@ export default {
82
82
  width: 100%;
83
83
  }
84
84
 
85
+ .zw-dropdown__activator-title {
86
+ margin-right: var(--zw-offset-xxs);
87
+ }
88
+
85
89
  .zw-dropdown__activator-arrow {
86
90
  margin-left: auto;
87
91
  }
@@ -68,7 +68,7 @@ export default {
68
68
  color: rgb(var(--zw-color-n70));
69
69
  z-index: 999999;
70
70
  text-align: left;
71
- position: fixed;
71
+ position: absolute;
72
72
  }
73
73
 
74
74
  .zw-toolbar::before,
@@ -18,7 +18,7 @@ describe('rendering', () => {
18
18
  });
19
19
 
20
20
 
21
- test('should render vertical divider', () => {
21
+ test('should render horizontal divider', () => {
22
22
  const wrapper = createComponent({ isHorizontal: true });
23
23
 
24
24
  expect(wrapper.classes('zw-toolbar__divider--horizontal')).toBeTruthy();
@@ -73,7 +73,7 @@ export default {
73
73
  .run();
74
74
  };
75
75
 
76
- const tooltip = computed(() => isCustomized.value ? 'Reset Styles to the Page Styles' : '');
76
+ const tooltip = computed(() => isCustomized.value ? 'Reset Styles to Page Styles' : '');
77
77
 
78
78
  const removeCustomization = () => editor.chain().focus().removePresetCustomization().run();
79
79
 
@@ -96,7 +96,7 @@ export default {
96
96
  }
97
97
 
98
98
  .zw-style-preset-control__dropdown {
99
- width: 96px;
99
+ width: 120px;
100
100
  }
101
101
 
102
102
  .zw-style-preset-control__reset {
@@ -4,8 +4,6 @@ import { InjectionTokens } from '../../../../injectionTokens';
4
4
  import { Button, Modal, NumberField, Range } from '../../../base';
5
5
  import LineHeightControl from '../LineHeightControl';
6
6
 
7
- jest.mock('@floating-ui/dom');
8
-
9
7
  const createEditor = ({ height } = {}) => {
10
8
  const heightRef = ref(height ?? '1.2');
11
9
 
@@ -57,7 +57,7 @@ describe('list of fonts', () => {
57
57
  expect(recentFonts.fonts.value).toEqual(['Lato', 'Roboto', 'Source Sans']);
58
58
  });
59
59
 
60
- test('should move up font in list', () => {
60
+ test('should move up font in list new font', () => {
61
61
  const recentFonts = createWrapper({
62
62
  initial: ['Roboto', 'Source Sans', 'Times New Roman']
63
63
  });
@@ -97,7 +97,7 @@ describe('actions with link', () => {
97
97
  });
98
98
  });
99
99
 
100
- test('should apply link target', () => {
100
+ test('should apply link target to new window', () => {
101
101
  const link = useComposable();
102
102
 
103
103
  link.updateTarget(false);
@@ -105,7 +105,7 @@ describe('actions with link', () => {
105
105
  expect(link.linkData.value.target).toBe(LinkTargets.SELF);
106
106
  });
107
107
 
108
- test('should apply link target', () => {
108
+ test('should apply link target to current window', () => {
109
109
  const link = useComposable();
110
110
 
111
111
  link.updateTarget(true);
@@ -1,33 +1,38 @@
1
- import { onUnmounted } from 'vue';
2
- import { autoUpdate, computePosition, limitShift, offset, shift } from '@floating-ui/dom';
1
+ import { createPopper } from '@popperjs/core';
3
2
  import { useElementRef } from '../components/base';
4
3
 
5
4
  export function useToolbar({ wrapperRef, offsets, isActiveRef, placementRef }) {
6
5
  const wrapperEl = useElementRef(wrapperRef);
7
- let floatingInstance;
6
+ let popper;
8
7
 
9
8
  function mount(element) {
10
- floatingInstance = autoUpdate(wrapperEl.value, element, async () => {
11
- const positioning = await computePosition(wrapperEl.value, element, {
12
- placement: placementRef.value,
13
- strategy: 'fixed',
14
- middleware: [
15
- shift({ padding: 16, crossAxis: true, limiter: limitShift() }),
16
- offset({ crossAxis: offsets[0], mainAxis: offsets[1] })]
17
- });
18
-
19
- const { x, y } = positioning;
20
-
21
- Object.assign(element.style, {
22
- left: `${x}px`,
23
- top: `${y}px`
24
- });
9
+ popper = createPopper(wrapperEl.value, element, {
10
+ placement: placementRef.value,
11
+ strategy: 'fixed',
12
+ modifiers: [
13
+ {
14
+ name: 'offset',
15
+ options: { offset: offsets }
16
+ },
17
+ {
18
+ name: 'preventOverflow',
19
+ options: {
20
+ altAxis: true,
21
+ padding: 2
22
+ }
23
+ },
24
+ {
25
+ name: 'flip',
26
+ enabled: false
27
+ }
28
+ ]
25
29
  });
26
30
  }
27
31
 
28
- onUnmounted(() => floatingInstance?.());
32
+ const update = () => popper?.update();
29
33
 
30
34
  return {
35
+ update,
31
36
  mount,
32
37
  isActiveRef,
33
38
  offsets
File without changes
File without changes
@@ -26,9 +26,9 @@ export const Alignment = Extension.create({
26
26
  return { desktop: textAlign, tablet: textAlign, mobile: textAlign };
27
27
  }
28
28
 
29
- const mobile = style.getPropertyValue('--zw-text-align-mobile') || null;
30
- const tablet = style.getPropertyValue('--zw-text-align-tablet') || null;
31
- const desktop = style.getPropertyValue('--zw-text-align-desktop') || null;
29
+ const mobile = style.getPropertyValue('--zw-alignment-mobile') || null;
30
+ const tablet = style.getPropertyValue('--zw-alignment-tablet') || null;
31
+ const desktop = style.getPropertyValue('--zw-alignment-desktop') || null;
32
32
 
33
33
  if (!mobile && !tablet && !desktop) return null;
34
34
 
@@ -39,9 +39,9 @@ export const Alignment = Extension.create({
39
39
  if (!attrs.alignment) return null;
40
40
 
41
41
  return renderInlineSetting({
42
- text_align_mobile: attrs.alignment.mobile,
43
- text_align_tablet: attrs.alignment.tablet,
44
- text_align_desktop: attrs.alignment.desktop
42
+ alignment_mobile: attrs.alignment.mobile,
43
+ alignment_tablet: attrs.alignment.tablet,
44
+ alignment_desktop: attrs.alignment.desktop
45
45
  });
46
46
  }
47
47
  }
@@ -2,7 +2,6 @@ import { Mark } from '@tiptap/vue-2';
2
2
  import { computed, unref } from 'vue';
3
3
  import { convertFontSize, createCommand, createKeyboardShortcut, renderMark } from '../utils';
4
4
  import { MarkGroups, TextSettings } from '../enums';
5
- import { AddNodeMarkStep } from './core';
6
5
 
7
6
  export const FontSize = Mark.create({
8
7
  name: TextSettings.FONT_SIZE,
@@ -57,7 +56,7 @@ export const FontSize = Mark.create({
57
56
  return;
58
57
  }
59
58
 
60
- tr.step(new AddNodeMarkStep(position, updated));
59
+ tr.addNodeMark(position, updated);
61
60
  }
62
61
  });
63
62
  }),
@@ -55,6 +55,8 @@ export const Link = Base.extend({
55
55
  ...this.parent?.(),
56
56
 
57
57
  applyLink: createCommand(({ commands, chain }, attributes) => {
58
+ commands.setMeta('preventAutolink', true);
59
+
58
60
  if (!commands.getSelectedText()) {
59
61
  return commands.insertContent(NodeFactory.text(attributes.text, [
60
62
  NodeFactory.mark(TextSettings.LINK, attributes)
@@ -1,22 +1,12 @@
1
1
  import { Extension } from '@tiptap/vue-2';
2
2
  import { computed, toRef, unref } from 'vue';
3
3
  import { createCommand } from '../utils';
4
- import { Devices, NodeTypes, TextSettings } from '../enums';
4
+ import { NodeTypes, TextSettings } from '../enums';
5
5
  import { ContextWindow } from '../services';
6
6
 
7
- function makePresetClass(base, preset) {
8
- const baseClass = base.split(' ').map((part) => `.${part}`).join('');
9
-
10
- return baseClass + preset.id;
11
- }
12
-
13
7
  export const StylePreset = Extension.create({
14
8
  name: TextSettings.STYLE_PRESET,
15
9
 
16
- addStorage: () => ({
17
- presetStyleEl: null
18
- }),
19
-
20
10
  addGlobalAttributes() {
21
11
  return [
22
12
  {
@@ -32,13 +22,13 @@ export const StylePreset = Extension.create({
32
22
  if (element.parentElement.tagName === 'LI') return null;
33
23
 
34
24
  for (const { id, node, fallbackClass } of presets) {
35
- const isFallback = fallbackClass && element.classList.contains(fallbackClass);
36
-
37
- if (isFallback) return { id };
25
+ if (fallbackClass && element.classList.contains(fallbackClass)) {
26
+ return { id };
27
+ }
38
28
 
39
- const className = makePresetClass(this.options.baseClass, { id });
29
+ const presetSelector = this.options.styleRenderer.makePresetCssClass({ id });
40
30
 
41
- if (element.matches(className)) return { id };
31
+ if (element.matches(presetSelector)) return { id };
42
32
  if (element.tagName === `H${node?.level}`) return { id };
43
33
  }
44
34
 
@@ -49,7 +39,7 @@ export const StylePreset = Extension.create({
49
39
  renderHTML: (attrs) => {
50
40
  if (!attrs.preset) return null;
51
41
 
52
- return { class: this.options.baseClass + attrs.preset.id };
42
+ return { class: this.options.styleRenderer.makePresetHtmlClass(attrs.preset) };
53
43
  }
54
44
  }
55
45
  }
@@ -208,34 +198,6 @@ export const StylePreset = Extension.create({
208
198
  },
209
199
 
210
200
  onCreate() {
211
- const existingStyleEl = ContextWindow.document.querySelector('[data-zw-styles]');
212
-
213
- if (existingStyleEl) {
214
- this.storage.presetStyleEl = existingStyleEl;
215
- return;
216
- }
217
-
218
- this.storage.presetStyleEl = ContextWindow.document.createElement('style');
219
- this.storage.presetStyleEl.dataset.zwStyles = '';
220
-
221
- for (const preset of this.options.presets) {
222
- const className = makePresetClass(this.options.baseClass, preset);
223
- const css = [` ${className} {`];
224
-
225
- for (const device of Devices.values) {
226
- for (const setting of Object.keys(preset[device])) {
227
- const variable = this.options.makeVariable({ device, preset, property: setting });
228
- const property = setting.replace(/_/i, '-');
229
- const prefix = device === Devices.COMMON ? 'preset' : `preset-${device}`;
230
-
231
- css.push(`--zw-${prefix}-${property}: var(${variable}, inherit);`);
232
- }
233
- }
234
-
235
- css.push('}');
236
- this.storage.presetStyleEl.innerHTML += css.join(' ');
237
- }
238
-
239
- ContextWindow.head.append(this.storage.presetStyleEl);
201
+ this.options.styleRenderer.inject(ContextWindow.head, this.options.presets);
240
202
  }
241
203
  });
@@ -144,7 +144,7 @@ describe('parsing html', () => {
144
144
 
145
145
  test('should get alignment from rendered view', () => {
146
146
  const editor = createEditor({
147
- content: '<p style="--zw-text-align-mobile:center;--zw-text-align-desktop:right">test</p>'
147
+ content: '<p style="--zw-alignment-mobile:center;--zw-alignment-desktop:right">test</p>'
148
148
  });
149
149
 
150
150
  expect(editor.getJSON()).toMatchSnapshot();
@@ -41,7 +41,7 @@ describe('get background color', () => {
41
41
 
42
42
  editor.commands.selectAll();
43
43
 
44
- expect(editor.commands.getBackgroundColor().value).toEqual('green');
44
+ expect(editor.commands.getBackgroundColor().value).toBe('green');
45
45
  });
46
46
 
47
47
  test('should get default background color', () => {
@@ -49,7 +49,7 @@ describe('get background color', () => {
49
49
  content: createContent(NodeFactory.text('hello world'))
50
50
  });
51
51
 
52
- expect(editor.commands.getBackgroundColor().value).toEqual('rgba(255, 255, 255, 0%)');
52
+ expect(editor.commands.getBackgroundColor().value).toBe('rgba(255, 255, 255, 0%)');
53
53
  });
54
54
  });
55
55
 
@@ -41,7 +41,7 @@ describe('get font color', () => {
41
41
 
42
42
  editor.commands.selectAll();
43
43
 
44
- expect(editor.commands.getFontColor().value).toEqual('green');
44
+ expect(editor.commands.getFontColor().value).toBe('green');
45
45
  });
46
46
 
47
47
  test('should get default font color', () => {
@@ -49,7 +49,7 @@ describe('get font color', () => {
49
49
  content: createContent(NodeFactory.text('hello world'))
50
50
  });
51
51
 
52
- expect(editor.commands.getDefaultFontColor().value).toEqual('red');
52
+ expect(editor.commands.getDefaultFontColor().value).toBe('red');
53
53
  });
54
54
 
55
55
  test('should get from preset', () => {
@@ -59,7 +59,7 @@ describe('get font color', () => {
59
59
 
60
60
  editor.commands.selectAll();
61
61
 
62
- expect(editor.commands.getFontColor().value).toEqual('red');
62
+ expect(editor.commands.getFontColor().value).toBe('red');
63
63
  });
64
64
  });
65
65
 
@@ -62,7 +62,7 @@ describe('get font family', () => {
62
62
 
63
63
  editor.commands.selectAll();
64
64
 
65
- expect(editor.commands.getFontFamily().value).toEqual('Bungee');
65
+ expect(editor.commands.getFontFamily().value).toBe('Bungee');
66
66
  });
67
67
 
68
68
  test('should get default font family', () => {
@@ -70,7 +70,7 @@ describe('get font family', () => {
70
70
  content: createContent(NodeFactory.text('hello world'))
71
71
  });
72
72
 
73
- expect(editor.commands.getDefaultFontFamily().value).toEqual('Lato');
73
+ expect(editor.commands.getDefaultFontFamily().value).toBe('Lato');
74
74
  });
75
75
 
76
76
  test('should get from preset', () => {
@@ -80,7 +80,7 @@ describe('get font family', () => {
80
80
 
81
81
  editor.commands.selectAll();
82
82
 
83
- expect(editor.commands.getFontFamily().value).toEqual('Lato');
83
+ expect(editor.commands.getFontFamily().value).toBe('Lato');
84
84
  });
85
85
 
86
86
  test('should find font model by name', () => {
@@ -58,7 +58,7 @@ describe('get font size', () => {
58
58
 
59
59
  editor.commands.selectAll();
60
60
 
61
- expect(editor.commands.getFontSize().value).toEqual('14');
61
+ expect(editor.commands.getFontSize().value).toBe('14');
62
62
  });
63
63
 
64
64
  test('should default value', () => {
@@ -66,7 +66,7 @@ describe('get font size', () => {
66
66
  content: createContent(NodeFactory.text('hello world'))
67
67
  });
68
68
 
69
- expect(editor.commands.getDefaultFontSize().value).toEqual('14');
69
+ expect(editor.commands.getDefaultFontSize().value).toBe('14');
70
70
  });
71
71
 
72
72
  test('should get from preset', () => {
@@ -76,7 +76,7 @@ describe('get font size', () => {
76
76
 
77
77
  editor.commands.selectAll();
78
78
 
79
- expect(editor.commands.getFontSize().value).toEqual('14');
79
+ expect(editor.commands.getFontSize().value).toBe('14');
80
80
  });
81
81
  });
82
82
 
@@ -60,7 +60,7 @@ describe('get font weight', () => {
60
60
 
61
61
  editor.commands.selectAll();
62
62
 
63
- expect(editor.commands.getFontWeight().value).toEqual('700');
63
+ expect(editor.commands.getFontWeight().value).toBe('700');
64
64
  });
65
65
 
66
66
  test('should default value', () => {
@@ -68,7 +68,7 @@ describe('get font weight', () => {
68
68
  content: createContent(NodeFactory.text('hello world'))
69
69
  });
70
70
 
71
- expect(editor.commands.getDefaultFontWeight().value).toEqual('400');
71
+ expect(editor.commands.getDefaultFontWeight().value).toBe('400');
72
72
  });
73
73
 
74
74
  test('should get from preset', () => {
@@ -78,7 +78,7 @@ describe('get font weight', () => {
78
78
 
79
79
  editor.commands.selectAll();
80
80
 
81
- expect(editor.commands.getFontWeight().value).toEqual('400');
81
+ expect(editor.commands.getFontWeight().value).toBe('400');
82
82
  });
83
83
 
84
84
  test('should get closest available font weight', () => {
@@ -90,7 +90,7 @@ describe('get font weight', () => {
90
90
 
91
91
  editor.commands.selectAll();
92
92
 
93
- expect(editor.commands.getFontWeight().value).toEqual('700');
93
+ expect(editor.commands.getFontWeight().value).toBe('700');
94
94
  });
95
95
  });
96
96
 
@@ -62,7 +62,7 @@ describe('get value', () => {
62
62
  content: createContent({ line_height: null })
63
63
  });
64
64
 
65
- expect(editor.commands.getDefaultLineHeight().value).toEqual('1.2');
65
+ expect(editor.commands.getDefaultLineHeight().value).toBe('1.2');
66
66
  });
67
67
 
68
68
  test('should get from preset', () => {
@@ -70,7 +70,7 @@ describe('get value', () => {
70
70
  content: createContent({ line_height: null })
71
71
  });
72
72
 
73
- expect(editor.commands.getLineHeight().value).toEqual('1.2');
73
+ expect(editor.commands.getLineHeight().value).toBe('1.2');
74
74
  });
75
75
  });
76
76
 
@@ -3,7 +3,7 @@ import { Editor, Mark } from '@tiptap/vue-2';
3
3
  import { buildTestExtensions } from '../../__tests__/utils';
4
4
  import { ContentNormalizer, NodeFactory } from '../../services';
5
5
  import { Link } from '../Link';
6
- import { TextSettings } from '../../enums';
6
+ import { LinkDestinations, LinkTargets, TextSettings } from '../../enums';
7
7
 
8
8
  const MockFontWeight = Mark.create({
9
9
  name: TextSettings.FONT_WEIGHT,
@@ -27,11 +27,12 @@ function createEditor({ content }) {
27
27
  });
28
28
  }
29
29
 
30
- const createLink = (href) => ({
31
- href: href ?? '/test',
30
+ const createLink = (attrs = {}) => ({
31
+ href: '/test',
32
32
  text: 'Hello world link',
33
- target: '_self',
34
- destination: 'url'
33
+ target: LinkTargets.SELF,
34
+ destination: LinkDestinations.URL,
35
+ ...attrs
35
36
  });
36
37
 
37
38
  describe('get link', () => {
@@ -108,6 +109,33 @@ describe('apply link', () => {
108
109
 
109
110
  expect(editor.getJSON()).toMatchSnapshot();
110
111
  });
112
+
113
+ test('should apply link to text with link', () => {
114
+ const editor = createEditor({
115
+ content: NodeFactory.doc([
116
+ NodeFactory.paragraph([
117
+ NodeFactory.text('https://google.com', [
118
+ NodeFactory.mark(TextSettings.LINK, {
119
+ href: 'https://google.com',
120
+ destination: LinkDestinations.URL,
121
+ target: LinkTargets.SELF
122
+ })
123
+ ])
124
+ ])
125
+ ])
126
+ });
127
+
128
+ editor.commands.selectAll();
129
+
130
+ editor.commands.applyLink({
131
+ text: 'https://google.com',
132
+ href: 'https://google.com',
133
+ destination: LinkDestinations.URL,
134
+ target: LinkTargets.BLANK
135
+ });
136
+
137
+ expect(editor.getJSON()).toMatchSnapshot();
138
+ });
111
139
  });
112
140
 
113
141
  describe('parse html', () => {