@zipify/wysiwyg 1.3.0-0 → 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 (84) hide show
  1. package/dist/cli.js +2 -2
  2. package/dist/wysiwyg.css +31 -42
  3. package/dist/wysiwyg.mjs +454 -399
  4. package/lib/__tests__/utils/buildTestExtensions.js +14 -0
  5. package/lib/__tests__/utils/index.js +1 -0
  6. package/lib/components/base/Button.vue +0 -7
  7. package/lib/components/base/dropdown/Dropdown.vue +1 -7
  8. package/lib/components/base/dropdown/DropdownActivator.vue +4 -19
  9. package/lib/components/base/dropdown/__tests__/DropdownActivator.test.js +1 -23
  10. package/lib/components/toolbar/controls/AlignmentControl.vue +1 -11
  11. package/lib/components/toolbar/controls/FontColorControl.vue +0 -13
  12. package/lib/components/toolbar/controls/FontFamilyControl.vue +0 -4
  13. package/lib/components/toolbar/controls/FontSizeControl.vue +1 -6
  14. package/lib/components/toolbar/controls/FontWeightControl.vue +0 -12
  15. package/lib/components/toolbar/controls/ItalicControl.vue +0 -13
  16. package/lib/components/toolbar/controls/LineHeightControl.vue +0 -14
  17. package/lib/components/toolbar/controls/SuperscriptControl.vue +2 -2
  18. package/lib/components/toolbar/controls/UnderlineControl.vue +0 -12
  19. package/lib/components/toolbar/controls/__tests__/AlignmentControl.test.js +5 -72
  20. package/lib/components/toolbar/controls/__tests__/FontColorControl.test.js +1 -22
  21. package/lib/components/toolbar/controls/__tests__/FontFamilyControl.test.js +0 -1
  22. package/lib/components/toolbar/controls/__tests__/FontSizeControl.test.js +0 -1
  23. package/lib/components/toolbar/controls/__tests__/FontWeightControl.test.js +0 -1
  24. package/lib/components/toolbar/controls/__tests__/ItalicControl.test.js +1 -23
  25. package/lib/components/toolbar/controls/__tests__/LineHeightControl.test.js +1 -23
  26. package/lib/components/toolbar/controls/__tests__/SuperscriptControl.test.js +2 -2
  27. package/lib/components/toolbar/controls/__tests__/UnderlineControl.test.js +1 -25
  28. package/lib/composables/__tests__/useEditor.test.js +2 -2
  29. package/lib/extensions/BackgroundColor.js +4 -4
  30. package/lib/extensions/FontColor.js +4 -5
  31. package/lib/extensions/FontFamily.js +4 -5
  32. package/lib/extensions/FontSize.js +5 -7
  33. package/lib/extensions/FontStyle.js +13 -11
  34. package/lib/extensions/FontWeight.js +6 -9
  35. package/lib/extensions/StylePreset.js +0 -14
  36. package/lib/extensions/Superscript.js +23 -1
  37. package/lib/extensions/TextDecoration.js +33 -20
  38. package/lib/extensions/__tests__/Alignment.test.js +10 -7
  39. package/lib/extensions/__tests__/BackgroundColor.test.js +6 -3
  40. package/lib/extensions/__tests__/CaseStyle.test.js +11 -7
  41. package/lib/extensions/__tests__/FontColor.test.js +6 -3
  42. package/lib/extensions/__tests__/FontFamily.test.js +29 -22
  43. package/lib/extensions/__tests__/FontSize.test.js +24 -17
  44. package/lib/extensions/__tests__/FontStyle.test.js +22 -16
  45. package/lib/extensions/__tests__/FontWeight.test.js +26 -19
  46. package/lib/extensions/__tests__/LineHeight.test.js +14 -11
  47. package/lib/extensions/__tests__/Link.test.js +14 -10
  48. package/lib/extensions/__tests__/Margin.test.js +2 -2
  49. package/lib/extensions/__tests__/StylePreset.test.js +49 -100
  50. package/lib/extensions/__tests__/TextDecoration.test.js +72 -46
  51. package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +24 -24
  52. package/lib/extensions/__tests__/__snapshots__/FontColor.test.js.snap +24 -24
  53. package/lib/extensions/__tests__/__snapshots__/FontFamily.test.js.snap +86 -82
  54. package/lib/extensions/__tests__/__snapshots__/FontSize.test.js.snap +70 -70
  55. package/lib/extensions/__tests__/__snapshots__/FontStyle.test.js.snap +53 -45
  56. package/lib/extensions/__tests__/__snapshots__/FontWeight.test.js.snap +64 -60
  57. package/lib/extensions/__tests__/__snapshots__/TextDecoration.test.js.snap +148 -83
  58. package/lib/extensions/core/Document.js +5 -0
  59. package/lib/extensions/core/Heading.js +10 -0
  60. package/lib/extensions/core/NodeProcessor.js +84 -4
  61. package/lib/extensions/core/Paragraph.js +9 -0
  62. package/lib/extensions/core/TextProcessor.js +10 -12
  63. package/lib/extensions/core/__tests__/NodeProcessor.test.js +82 -10
  64. package/lib/extensions/core/__tests__/SelectionProcessor.test.js +2 -2
  65. package/lib/extensions/core/__tests__/TextProcessor.test.js +18 -20
  66. package/lib/extensions/core/__tests__/__snapshots__/NodeProcessor.test.js.snap +132 -0
  67. package/lib/extensions/core/index.js +5 -5
  68. package/lib/extensions/core/steps/AddNodeMarkStep.js +60 -0
  69. package/lib/extensions/core/steps/RemoveNodeMarkStep.js +50 -0
  70. package/lib/extensions/core/steps/index.js +2 -0
  71. package/lib/extensions/list/List.js +1 -0
  72. package/lib/extensions/list/ListItem.js +5 -0
  73. package/lib/extensions/list/__tests__/List.test.js +30 -25
  74. package/lib/services/ContentNormalizer.js +1 -100
  75. package/lib/services/NodeFactory.js +16 -6
  76. package/lib/services/__tests__/ContentNormalizer.test.js +0 -64
  77. package/lib/utils/findMarkByType.js +5 -0
  78. package/lib/utils/index.js +5 -0
  79. package/lib/utils/isMarkAppliedToParent.js +15 -0
  80. package/lib/utils/isNodeFullySelected.js +10 -0
  81. package/lib/utils/resolveNodePosition.js +6 -0
  82. package/lib/utils/resolveTextPosition.js +6 -0
  83. package/package.json +1 -1
  84. package/lib/assets/icons/indicator.svg +0 -5
@@ -4,14 +4,9 @@ import { InjectionTokens } from '../../../../injectionTokens';
4
4
  import { Button } from '../../../base';
5
5
  import ItalicControl from '../ItalicControl';
6
6
 
7
- const SELECTORS = {
8
- INDICATOR: '[data-test-selector="customizedIndicator"]'
9
- };
10
-
11
- const createEditor = ({ isItalic, isItalicAvailable, isSettingCustomized } = {}) => ({
7
+ const createEditor = ({ isItalic, isItalicAvailable } = {}) => ({
12
8
  commands: {
13
9
  isItalic: () => ref(isItalic),
14
- isSettingCustomized: () => ref(isSettingCustomized ?? false),
15
10
  isItalicAvailable: () => ref(isItalicAvailable ?? true),
16
11
  focus: jest.fn().mockReturnThis(),
17
12
  toggleItalic: jest.fn().mockReturnThis(),
@@ -45,23 +40,6 @@ describe('rendering', () => {
45
40
 
46
41
  expect(buttonWrapper.props('disabled')).toBe(true);
47
42
  });
48
-
49
- test('should render indicator of customized styles', () => {
50
- const editor = createEditor({
51
- isItalic: true,
52
- isSettingCustomized: true
53
- });
54
- const wrapper = createComponent({ editor });
55
-
56
- expect(wrapper).toVueContainComponent(SELECTORS.INDICATOR);
57
- });
58
-
59
- test('should not render indicator of customized styles', () => {
60
- const editor = createEditor({ isItalic: false });
61
- const wrapper = createComponent({ editor });
62
-
63
- expect(wrapper).not.toVueContainComponent(SELECTORS.INDICATOR);
64
- });
65
43
  });
66
44
 
67
45
  describe('selection value', () => {
@@ -4,17 +4,12 @@ import { InjectionTokens } from '../../../../injectionTokens';
4
4
  import { Button, Modal, NumberField, Range } from '../../../base';
5
5
  import LineHeightControl from '../LineHeightControl';
6
6
 
7
- const SELECTORS = {
8
- INDICATOR: '[data-test-selector="customizedIndicator"]'
9
- };
10
-
11
- const createEditor = ({ height, isSettingCustomized } = {}) => {
7
+ const createEditor = ({ height } = {}) => {
12
8
  const heightRef = ref(height ?? '1.2');
13
9
 
14
10
  return {
15
11
  commands: {
16
12
  getLineHeight: () => heightRef,
17
- isSettingCustomized: () => ref(isSettingCustomized ?? false),
18
13
  applyLineHeight: jest.fn(function (value) {
19
14
  heightRef.value = value;
20
15
  return this;
@@ -122,21 +117,4 @@ describe('rendering', () => {
122
117
  expect(buttonWrapper.props('active')).toBe(true);
123
118
  expect(modalWrapper.props('toggler').isOpened.value).toBe(true);
124
119
  });
125
-
126
- test('should render indicator of customized styles', () => {
127
- const editor = createEditor({
128
- height: '1.8',
129
- isSettingCustomized: true
130
- });
131
- const wrapper = createComponent({ editor });
132
-
133
- expect(wrapper).toVueContainComponent(SELECTORS.INDICATOR);
134
- });
135
-
136
- test('should not render indicator of customized styles', () => {
137
- const editor = createEditor({ height: '1.2' });
138
- const wrapper = createComponent({ editor });
139
-
140
- expect(wrapper).not.toVueContainComponent(SELECTORS.INDICATOR);
141
- });
142
120
  });
@@ -1,13 +1,13 @@
1
+ import { ref } from 'vue';
1
2
  import { shallowMount } from '@vue/test-utils';
2
3
  import { InjectionTokens } from '../../../../injectionTokens';
3
4
  import { Button } from '../../../base';
4
5
  import SuperscriptControl from '../SuperscriptControl';
5
6
 
6
7
  const createEditor = ({ isSuperscript } = {}) => ({
7
- isActive: () => isSuperscript,
8
-
9
8
  commands: {
10
9
  focus: jest.fn().mockReturnThis(),
10
+ isSuperscript: () => ref(isSuperscript),
11
11
  toggleSuperscript: jest.fn().mockReturnThis(),
12
12
  run: jest.fn()
13
13
  },
@@ -4,14 +4,9 @@ import { InjectionTokens } from '../../../../injectionTokens';
4
4
  import { Button } from '../../../base';
5
5
  import UnderlineControl from '../UnderlineControl';
6
6
 
7
- const SELECTORS = {
8
- INDICATOR: '[data-test-selector="customizedIndicator"]'
9
- };
10
-
11
- const createEditor = ({ isUnderline, isSettingCustomized } = {}) => ({
7
+ const createEditor = ({ isUnderline } = {}) => ({
12
8
  commands: {
13
9
  isUnderline: () => ref(isUnderline),
14
- isUnderlineCustomized: () => ref(isSettingCustomized ?? false),
15
10
  focus: jest.fn().mockReturnThis(),
16
11
  toggleUnderline: jest.fn().mockReturnThis(),
17
12
  run: jest.fn()
@@ -51,22 +46,3 @@ describe('selection value', () => {
51
46
  expect(editor.commands.toggleUnderline).toHaveBeenCalled();
52
47
  });
53
48
  });
54
-
55
- describe('render indicator of customized styles', () => {
56
- test('should render indicator', () => {
57
- const editor = createEditor({
58
- isUnderline: true,
59
- isSettingCustomized: true
60
- });
61
- const wrapper = createComponent({ editor });
62
-
63
- expect(wrapper).toVueContainComponent(SELECTORS.INDICATOR);
64
- });
65
-
66
- test('should not render indicator', () => {
67
- const editor = createEditor({ isUnderline: false });
68
- const wrapper = createComponent({ editor });
69
-
70
- expect(wrapper).not.toVueContainComponent(SELECTORS.INDICATOR);
71
- });
72
- });
@@ -1,9 +1,9 @@
1
1
  import { h, ref, toRef } from 'vue';
2
2
  import { EditorContent } from '@tiptap/vue-2';
3
3
  import { shallowMount } from '@vue/test-utils';
4
+ import { buildTestExtensions } from '../../__tests__/utils';
4
5
  import { useEditor } from '../useEditor';
5
6
  import { NodeFactory } from '../../services';
6
- import { buildCoreExtensions } from '../../extensions/core';
7
7
 
8
8
  const TestComponent = {
9
9
  name: 'Test',
@@ -20,7 +20,7 @@ const TestComponent = {
20
20
  const editor = useEditor({
21
21
  isReadonlyRef: ref(false),
22
22
  content: toRef(props, 'value'),
23
- extensions: buildCoreExtensions(),
23
+ extensions: buildTestExtensions(),
24
24
  onChange: (content) => emit('input', content),
25
25
  onFocus: () => emit('focus')
26
26
  });
@@ -1,10 +1,10 @@
1
1
  import { Mark } from '@tiptap/vue-2';
2
- import { computed } from 'vue';
3
2
  import { convertColor, createCommand, renderMark } from '../utils';
4
3
  import { TextSettings } from '../enums';
5
4
 
6
5
  export const BackgroundColor = Mark.create({
7
6
  name: TextSettings.BACKGROUND_COLOR,
7
+ group: 'settings',
8
8
 
9
9
  addAttributes: () => ({
10
10
  value: { required: true }
@@ -12,12 +12,12 @@ export const BackgroundColor = Mark.create({
12
12
 
13
13
  addCommands() {
14
14
  return {
15
- getBackgroundColor: createCommand(({ editor }) => {
16
- return computed(() => editor.getAttributes(this.name)?.value ?? 'rgba(255, 255, 255, 0%)');
15
+ getBackgroundColor: createCommand(({ commands }) => {
16
+ return commands.getCommonSettingMark(this.name, 'rgba(255, 255, 255, 0%)');
17
17
  }),
18
18
 
19
19
  applyBackgroundColor: createCommand(({ commands }, value) => {
20
- commands.setMark(this.name, { value });
20
+ commands.applyMark(this.name, { value });
21
21
  })
22
22
  };
23
23
  },
@@ -5,6 +5,7 @@ import { TextSettings } from '../enums';
5
5
 
6
6
  export const FontColor = Mark.create({
7
7
  name: TextSettings.FONT_COLOR,
8
+ group: 'settings',
8
9
 
9
10
  addAttributes: () => ({
10
11
  value: { required: true }
@@ -12,10 +13,8 @@ export const FontColor = Mark.create({
12
13
 
13
14
  addCommands() {
14
15
  return {
15
- getFontColor: createCommand(({ commands, editor }) => {
16
- const defaultValue = commands.getDefaultFontColor();
17
-
18
- return computed(() => editor.getAttributes(this.name)?.value ?? unref(defaultValue));
16
+ getFontColor: createCommand(({ commands }) => {
17
+ return commands.getCommonSettingMark(this.name, commands.getDefaultFontColor());
19
18
  }),
20
19
 
21
20
  getDefaultFontColor: createCommand(({ commands }) => {
@@ -25,7 +24,7 @@ export const FontColor = Mark.create({
25
24
  }),
26
25
 
27
26
  applyFontColor: createCommand(({ commands }, value) => {
28
- commands.setMark(this.name, { value });
27
+ commands.applyMark(this.name, { value });
29
28
  })
30
29
  };
31
30
  },
@@ -5,6 +5,7 @@ import { TextSettings } from '../enums';
5
5
 
6
6
  export const FontFamily = Mark.create({
7
7
  name: TextSettings.FONT_FAMILY,
8
+ group: 'settings',
8
9
 
9
10
  addOptions: () => ({
10
11
  fonts: []
@@ -17,7 +18,7 @@ export const FontFamily = Mark.create({
17
18
  addCommands() {
18
19
  return {
19
20
  applyFontFamily: createCommand(({ commands }, value) => {
20
- commands.setMark(this.name, { value });
21
+ commands.applyMark(this.name, { value });
21
22
 
22
23
  const font = commands.findFontByName(value);
23
24
  let fontWeight = unref(commands.getFontWeight());
@@ -46,10 +47,8 @@ export const FontFamily = Mark.create({
46
47
  return this.options.fonts.find((font) => font.name === name);
47
48
  }),
48
49
 
49
- getFontFamily: createCommand(({ editor, commands }) => {
50
- const defaultValue = commands.getDefaultFontFamily();
51
-
52
- return computed(() => editor.getAttributes(this.name)?.value ?? unref(defaultValue));
50
+ getFontFamily: createCommand(({ commands }) => {
51
+ return commands.getCommonSettingMark(this.name, commands.getDefaultFontFamily());
53
52
  }),
54
53
 
55
54
  getDefaultFontFamily: createCommand(({ commands }) => {
@@ -5,6 +5,7 @@ import { TextSettings } from '../enums';
5
5
 
6
6
  export const FontSize = Mark.create({
7
7
  name: TextSettings.FONT_SIZE,
8
+ group: 'settings',
8
9
 
9
10
  addOptions: () => ({
10
11
  minSize: 1,
@@ -21,11 +22,8 @@ export const FontSize = Mark.create({
21
22
 
22
23
  addCommands() {
23
24
  return {
24
- getFontSize: createCommand(({ editor, commands }) => {
25
- const device = commands.getDevice();
26
- const defaultValue = commands.getDefaultFontSize();
27
-
28
- return computed(() => editor.getAttributes(this.name)?.[unref(device)] ?? unref(defaultValue));
25
+ getFontSize: createCommand(({ commands }) => {
26
+ return commands.getDeviceSettingMark(this.name, commands.getDefaultFontSize());
29
27
  }),
30
28
 
31
29
  getDefaultFontSize: createCommand(({ commands }) => {
@@ -38,10 +36,10 @@ export const FontSize = Mark.create({
38
36
  applyFontSize: createCommand(({ commands }, value) => {
39
37
  // const device = unref(commands.getDevice());
40
38
 
41
- // commands.setMark(this.name, { [device]: value });
39
+ // commands.applyMark(this.name, { [device]: value });
42
40
 
43
41
  // Temporary until release BUILDER_MODES
44
- commands.setMark(this.name, { desktop: value, tablet: value, mobile: null });
42
+ commands.applyMark(this.name, { desktop: value, tablet: value, mobile: null });
45
43
  }),
46
44
 
47
45
  increaseFontSize: createCommand(({ commands }) => {
@@ -5,6 +5,7 @@ import { TextSettings } from '../enums';
5
5
 
6
6
  export const FontStyle = Mark.create({
7
7
  name: TextSettings.FONT_STYLE,
8
+ group: 'settings',
8
9
 
9
10
  addAttributes: () => ({
10
11
  italic: { required: true }
@@ -12,10 +13,11 @@ export const FontStyle = Mark.create({
12
13
 
13
14
  addCommands() {
14
15
  return {
15
- isItalic: createCommand(({ editor, commands }) => {
16
- const defaultValue = commands.getDefaultFontStyle();
16
+ isItalic: createCommand(({ commands }) => {
17
+ const selectionRef = commands.getMark(this.name);
18
+ const defaultValueRef = commands.getDefaultFontStyle();
17
19
 
18
- return computed(() => editor.getAttributes(this.name)?.italic ?? unref(defaultValue).italic);
20
+ return computed(() => unref(selectionRef)?.italic ?? unref(defaultValueRef).italic);
19
21
  }),
20
22
 
21
23
  isItalicAvailable: createCommand(({ commands }) => {
@@ -34,7 +36,7 @@ export const FontStyle = Mark.create({
34
36
  }),
35
37
 
36
38
  toggleItalic: createCommand(({ commands }) => {
37
- const isItalicAvailable = unref(this.editor.commands.isItalicAvailable());
39
+ const isItalicAvailable = unref(commands.isItalicAvailable());
38
40
 
39
41
  if (!isItalicAvailable) return;
40
42
 
@@ -42,11 +44,11 @@ export const FontStyle = Mark.create({
42
44
  }),
43
45
 
44
46
  applyItalic: createCommand(({ commands }) => {
45
- commands.setMark(this.name, { italic: true });
47
+ commands.applyMark(this.name, { italic: true });
46
48
  }),
47
49
 
48
50
  removeItalic: createCommand(({ commands }) => {
49
- commands.setMark(this.name, { italic: false });
51
+ commands.applyMark(this.name, { italic: false });
50
52
  })
51
53
  };
52
54
  },
@@ -57,9 +59,13 @@ export const FontStyle = Mark.create({
57
59
  }),
58
60
 
59
61
  parseHTML() {
60
- const getAttrs = (value) => value.includes('italic') && { italic: true };
62
+ const getAttrs = (value) => ({ italic: value.includes('italic') });
61
63
 
62
64
  return [
65
+ {
66
+ tag: 'i',
67
+ attrs: { italic: true }
68
+ },
63
69
  {
64
70
  style: '--zw-font-style',
65
71
  getAttrs
@@ -67,10 +73,6 @@ export const FontStyle = Mark.create({
67
73
  {
68
74
  style: 'font-style',
69
75
  getAttrs
70
- },
71
- {
72
- tag: 'i',
73
- attrs: { italic: true }
74
76
  }
75
77
  ];
76
78
  },
@@ -5,6 +5,7 @@ import { TextSettings } from '../enums';
5
5
 
6
6
  export const FontWeight = Mark.create({
7
7
  name: TextSettings.FONT_WEIGHT,
8
+ group: 'settings',
8
9
 
9
10
  addAttributes: () => ({
10
11
  value: { required: true }
@@ -13,7 +14,7 @@ export const FontWeight = Mark.create({
13
14
  addCommands() {
14
15
  return {
15
16
  applyFontWeight: createCommand(({ commands }, value) => {
16
- commands.setMark(this.name, { value });
17
+ commands.applyMark(this.name, { value });
17
18
  const font = unref(commands.getFont());
18
19
 
19
20
  if (!font.isItalicSupported(value)) {
@@ -31,19 +32,15 @@ export const FontWeight = Mark.create({
31
32
  commands.applyFontWeight(nextWeight);
32
33
  }),
33
34
 
34
- getFontWeight: createCommand(({ editor, commands }) => {
35
- const defaultValue = commands.getDefaultFontWeight();
35
+ getFontWeight: createCommand(({ commands }) => {
36
+ const selectionRef = commands.getCommonSettingMark(this.name, commands.getDefaultFontWeight());
36
37
  const fontRef = commands.getFont();
37
38
 
38
39
  return computed(() => {
39
- const weight = editor.getAttributes(this.name)?.value ?? unref(defaultValue);
40
+ const weight = unref(selectionRef);
40
41
  const font = unref(fontRef);
41
42
 
42
- if (font.isWeightSupported(weight)) {
43
- return weight;
44
- }
45
-
46
- return font.findClosestWeight(weight);
43
+ return font.isWeightSupported(weight) ? weight : font.findClosestWeight(weight);
47
44
  });
48
45
  }),
49
46
 
@@ -1,6 +1,5 @@
1
1
  import { Extension } from '@tiptap/vue-2';
2
2
  import { computed, toRef, unref } from 'vue';
3
- import { Heading } from '@tiptap/extension-heading';
4
3
  import { createCommand } from '../utils';
5
4
  import { Devices, NodeTypes, TextSettings } from '../enums';
6
5
  import { ContextWindow } from '../services';
@@ -14,13 +13,6 @@ function makePresetClass(base, preset) {
14
13
  export const StylePreset = Extension.create({
15
14
  name: 'style_preset',
16
15
 
17
- addExtensions: () => [
18
- Heading.configure({
19
- levels: [1, 2, 3, 4],
20
- HTMLAttributes: { class: 'zw-style' }
21
- })
22
- ],
23
-
24
16
  addStorage: () => ({
25
17
  presetStyleEl: null
26
18
  }),
@@ -169,12 +161,6 @@ export const StylePreset = Extension.create({
169
161
  });
170
162
  }),
171
163
 
172
- isSettingCustomized: createCommand(({ commands }, group, name) => {
173
- const customization = commands.getPresetCustomization();
174
-
175
- return computed(() => unref(customization)[group]?.includes(name) ?? false);
176
- }),
177
-
178
164
  removePresetCustomization: createCommand(({ chain }) => {
179
165
  chain()
180
166
  .storeSelection()
@@ -1,9 +1,31 @@
1
1
  import Base from '@tiptap/extension-superscript';
2
+ import { computed, unref } from 'vue';
3
+ import { createCommand } from '../utils';
4
+ import { TextSettings } from '../enums';
2
5
 
3
6
  export const Superscript = Base.extend({
7
+ name: TextSettings.SUPERSCRIPT,
4
8
  addKeyboardShortcuts: null,
5
9
 
6
10
  addOptions: () => ({
7
11
  HTMLAttributes: { class: 'zw-superscript' }
8
- })
12
+ }),
13
+
14
+ addCommands() {
15
+ return {
16
+ ...this.parent(),
17
+
18
+ toggleSuperscript: createCommand(({ commands }) => {
19
+ const isActive = unref(commands.isSuperscript());
20
+
21
+ isActive ? commands.unsetSuperscript() : commands.setSuperscript();
22
+ }),
23
+
24
+ isSuperscript: createCommand(({ commands }) => {
25
+ const selectionRef = commands.getMark(this.name);
26
+
27
+ return computed(() => !!unref(selectionRef));
28
+ })
29
+ };
30
+ }
9
31
  });
@@ -6,6 +6,7 @@ import { TextSettings } from '../enums';
6
6
  export const TextDecoration = Mark.create({
7
7
  name: TextSettings.TEXT_DECORATION,
8
8
  priority: 1000,
9
+ group: 'settings',
9
10
 
10
11
  addAttributes: () => ({
11
12
  underline: { default: false },
@@ -26,26 +27,18 @@ export const TextDecoration = Mark.create({
26
27
  return computed(() => unref(decoration).strike_through);
27
28
  }),
28
29
 
29
- getTextDecoration: createCommand(({ editor, commands }) => {
30
- const defaultValue = commands.getDefaultTextDecoration();
30
+ getTextDecoration: createCommand(({ commands }) => {
31
+ const selectionRef = commands.getMarks(this.name);
32
+ const defaultValueRef = commands.getDefaultTextDecoration();
31
33
 
32
34
  return computed(() => {
33
- const attrs = editor.getAttributes(this.name) ?? {};
34
-
35
- return {
36
- underline: attrs.underline ?? unref(defaultValue).underline,
37
- strike_through: attrs.strike_through ?? unref(defaultValue).strike_through
38
- };
35
+ return unref(selectionRef).reduceRight((collector, mark) => ({
36
+ underline: collector.underline || mark.underline,
37
+ strike_through: collector.strike_through || mark.strike_through
38
+ }), unref(defaultValueRef));
39
39
  });
40
40
  }),
41
41
 
42
- isUnderlineCustomized: createCommand(({ commands }) => {
43
- const currentValue = commands.isUnderline();
44
- const defaultValue = commands.getDefaultTextDecoration();
45
-
46
- return computed(() => unref(currentValue) !== unref(defaultValue).underline);
47
- }),
48
-
49
42
  getDefaultTextDecoration: createCommand(({ commands }) => {
50
43
  const preset = commands.getPreset();
51
44
 
@@ -67,18 +60,38 @@ export const TextDecoration = Mark.create({
67
60
  commands.toggleTextDecoration('strike_through');
68
61
  }),
69
62
 
70
- toggleTextDecoration: createCommand(({ commands }, name) => {
71
- const isEnabled = unref(commands.getTextDecoration())[name];
63
+ toggleTextDecoration: createCommand(({ commands }, name, toEnable = null) => {
64
+ const value = unref(commands.getTextDecoration());
65
+ const isEnabled = toEnable ?? !value[name];
72
66
 
73
- isEnabled ? commands.removeTextDecoration(name) : commands.applyTextDecoration(name);
67
+ commands.applyMark(this.name, { [name]: isEnabled }, {
68
+ compareParentMark: (parent, child) => {
69
+ if (parent.type.name !== child.type.name) return false;
70
+
71
+ return parent.attrs[name] || parent.eq(child);
72
+ },
73
+
74
+ onAppliedToParent: ({ tr, textPosition, initialMark, applyingMark }) => {
75
+ if (!initialMark) return;
76
+
77
+ if (initialMark.eq(applyingMark)) {
78
+ tr.removeMark(textPosition.from, textPosition.to, applyingMark.type);
79
+ return;
80
+ }
81
+
82
+ const mark = applyingMark.type.create({ ...initialMark.attrs, [name]: isEnabled });
83
+
84
+ tr.addMark(textPosition.from, textPosition.to, mark);
85
+ }
86
+ });
74
87
  }),
75
88
 
76
89
  applyTextDecoration: createCommand(({ commands }, name) => {
77
- commands.setMark(this.name, { [name]: true });
90
+ commands.toggleTextDecoration(name, true);
78
91
  }),
79
92
 
80
93
  removeTextDecoration: createCommand(({ commands }, name) => {
81
- commands.setMark(this.name, { ...unref(commands.getTextDecoration()), [name]: false });
94
+ commands.toggleTextDecoration(name, false);
82
95
  })
83
96
  };
84
97
  },
@@ -1,11 +1,11 @@
1
1
  import { Editor, Extension } from '@tiptap/vue-2';
2
2
  import { ref } from 'vue';
3
+ import { buildTestExtensions } from '../../__tests__/utils';
3
4
  import { createCommand } from '../../utils';
4
5
  import { Alignment } from '../Alignment';
5
6
  import { DeviceManager } from '../DeviceManager';
6
7
  import { Alignments } from '../../enums';
7
8
  import { ContentNormalizer, NodeFactory } from '../../services';
8
- import { buildCoreExtensions } from '../core';
9
9
 
10
10
  const MockStylePreset = Extension.create({
11
11
  name: 'style_preset',
@@ -24,11 +24,13 @@ const MockStylePreset = Extension.create({
24
24
  function createEditor({ content }) {
25
25
  return new Editor({
26
26
  content: ContentNormalizer.normalize(content),
27
- extensions: buildCoreExtensions().concat(
28
- MockStylePreset,
29
- DeviceManager.configure({ device: ref('desktop') }),
30
- Alignment
31
- )
27
+ extensions: buildTestExtensions({
28
+ include: [
29
+ MockStylePreset,
30
+ DeviceManager.configure({ device: ref('desktop') }),
31
+ Alignment
32
+ ]
33
+ })
32
34
  });
33
35
  }
34
36
 
@@ -74,7 +76,8 @@ describe('apply value', () => {
74
76
  content: createContent({ alignment: null })
75
77
  });
76
78
 
77
- editor.chain().selectAll().applyAlignment(Alignments.RIGHT).run();
79
+ editor.commands.selectAll();
80
+ editor.commands.applyAlignment(Alignments.RIGHT);
78
81
 
79
82
  expect(editor.getJSON()).toMatchSnapshot();
80
83
  });
@@ -1,9 +1,9 @@
1
1
  import { Editor, Extension } from '@tiptap/vue-2';
2
2
  import { ref } from 'vue';
3
+ import { buildTestExtensions } from '../../__tests__/utils';
3
4
  import { createCommand } from '../../utils';
4
5
  import { BackgroundColor } from '../BackgroundColor';
5
6
  import { ContentNormalizer, NodeFactory } from '../../services';
6
- import { buildCoreExtensions } from '../core';
7
7
 
8
8
  const MockStylePreset = Extension.create({
9
9
  name: 'style_preset',
@@ -20,7 +20,9 @@ const MockStylePreset = Extension.create({
20
20
  function createEditor({ content }) {
21
21
  return new Editor({
22
22
  content: ContentNormalizer.normalize(content),
23
- extensions: buildCoreExtensions().concat(MockStylePreset, BackgroundColor)
23
+ extensions: buildTestExtensions({
24
+ include: [MockStylePreset, BackgroundColor]
25
+ })
24
26
  });
25
27
  }
26
28
 
@@ -56,7 +58,8 @@ describe('apply background color', () => {
56
58
  content: createContent(NodeFactory.text('hello world'))
57
59
  });
58
60
 
59
- editor.chain().selectAll().applyBackgroundColor('green').run();
61
+ editor.commands.selectAll();
62
+ editor.commands.applyBackgroundColor('green');
60
63
 
61
64
  expect(editor.getJSON()).toMatchSnapshot();
62
65
  });