@zipify/wysiwyg 2.0.0-1 → 2.0.0-11

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 (97) hide show
  1. package/config/build/cli.config.js +8 -2
  2. package/dist/cli.js +3 -3
  3. package/dist/wysiwyg.css +41 -31
  4. package/dist/wysiwyg.mjs +2015 -1359
  5. package/example/ExampleApp.vue +10 -1
  6. package/lib/Wysiwyg.vue +3 -2
  7. package/lib/__tests__/utils/buildTestExtensions.js +2 -1
  8. package/lib/assets/icons/indicator.svg +4 -0
  9. package/lib/cli/commands/Command.js +39 -0
  10. package/lib/cli/commands/ToJsonCommand.js +55 -0
  11. package/lib/cli/commands/VersionCommand.js +11 -0
  12. package/lib/cli/commands/index.js +2 -0
  13. package/lib/cli/index.js +1 -0
  14. package/lib/components/base/Button.vue +6 -0
  15. package/lib/components/base/dropdown/Dropdown.vue +7 -1
  16. package/lib/components/base/dropdown/DropdownActivator.vue +25 -4
  17. package/lib/components/base/dropdown/__tests__/DropdownActivator.test.js +23 -1
  18. package/lib/components/toolbar/controls/AlignmentControl.vue +12 -1
  19. package/lib/components/toolbar/controls/FontColorControl.vue +14 -0
  20. package/lib/components/toolbar/controls/FontFamilyControl.vue +4 -0
  21. package/lib/components/toolbar/controls/FontSizeControl.vue +6 -1
  22. package/lib/components/toolbar/controls/FontWeightControl.vue +12 -0
  23. package/lib/components/toolbar/controls/ItalicControl.vue +14 -0
  24. package/lib/components/toolbar/controls/LineHeightControl.vue +15 -0
  25. package/lib/components/toolbar/controls/UnderlineControl.vue +13 -0
  26. package/lib/components/toolbar/controls/__tests__/AlignmentControl.test.js +72 -5
  27. package/lib/components/toolbar/controls/__tests__/FontColorControl.test.js +22 -1
  28. package/lib/components/toolbar/controls/__tests__/FontFamilyControl.test.js +1 -0
  29. package/lib/components/toolbar/controls/__tests__/FontSizeControl.test.js +1 -0
  30. package/lib/components/toolbar/controls/__tests__/FontWeightControl.test.js +1 -0
  31. package/lib/components/toolbar/controls/__tests__/ItalicControl.test.js +23 -1
  32. package/lib/components/toolbar/controls/__tests__/LineHeightControl.test.js +23 -1
  33. package/lib/components/toolbar/controls/__tests__/StylePresetControl.test.js +4 -4
  34. package/lib/components/toolbar/controls/__tests__/UnderlineControl.test.js +25 -1
  35. package/lib/composables/__tests__/useEditor.test.js +1 -1
  36. package/lib/composables/useEditor.js +9 -8
  37. package/lib/directives/__tests__/tooltip.test.js +22 -4
  38. package/lib/directives/tooltip.js +4 -1
  39. package/lib/entry-cli.js +7 -20
  40. package/lib/entry-lib.js +1 -1
  41. package/lib/enums/MarkGroups.js +4 -0
  42. package/lib/enums/TextSettings.js +1 -1
  43. package/lib/enums/index.js +1 -0
  44. package/lib/extensions/BackgroundColor.js +0 -1
  45. package/lib/extensions/FontColor.js +2 -2
  46. package/lib/extensions/FontFamily.js +3 -3
  47. package/lib/extensions/FontSize.js +2 -2
  48. package/lib/extensions/FontStyle.js +2 -2
  49. package/lib/extensions/FontWeight.js +2 -2
  50. package/lib/extensions/StylePreset.js +9 -2
  51. package/lib/extensions/Superscript.js +5 -2
  52. package/lib/extensions/TextDecoration.js +7 -0
  53. package/lib/extensions/__tests__/Alignment.test.js +2 -2
  54. package/lib/extensions/__tests__/BackgroundColor.test.js +4 -3
  55. package/lib/extensions/__tests__/FontColor.test.js +4 -3
  56. package/lib/extensions/__tests__/FontFamily.test.js +6 -6
  57. package/lib/extensions/__tests__/FontSize.test.js +9 -8
  58. package/lib/extensions/__tests__/FontStyle.test.js +6 -5
  59. package/lib/extensions/__tests__/LineHeight.test.js +2 -1
  60. package/lib/extensions/__tests__/StylePreset.test.js +51 -0
  61. package/lib/extensions/__tests__/Superscript.test.js +102 -0
  62. package/lib/extensions/__tests__/TextDecoration.test.js +20 -0
  63. package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +25 -25
  64. package/lib/extensions/__tests__/__snapshots__/Superscript.test.js.snap +107 -0
  65. package/lib/extensions/core/Document.js +2 -1
  66. package/lib/extensions/core/Heading.js +2 -1
  67. package/lib/extensions/core/NodeProcessor.js +42 -21
  68. package/lib/extensions/core/Paragraph.js +2 -1
  69. package/lib/extensions/core/__tests__/NodeProcessor.test.js +309 -11
  70. package/lib/extensions/core/__tests__/TextProcessor.test.js +1 -1
  71. package/lib/extensions/core/__tests__/__snapshots__/NodeProcessor.test.js.snap +249 -0
  72. package/lib/extensions/core/steps/AddNodeMarkStep.js +6 -0
  73. package/lib/extensions/core/steps/AttrStep.js +6 -0
  74. package/lib/extensions/core/steps/RemoveNodeMarkStep.js +6 -0
  75. package/lib/extensions/list/List.js +70 -9
  76. package/lib/extensions/list/ListItem.js +27 -5
  77. package/lib/extensions/list/__tests__/List.test.js +26 -17
  78. package/lib/extensions/list/__tests__/__snapshots__/List.test.js.snap +36 -36
  79. package/lib/services/NodeFactory.js +69 -3
  80. package/lib/services/__tests__/NodeFactory.test.js +124 -0
  81. package/lib/services/__tests__/__snapshots__/NodeFactory.test.js.snap +326 -0
  82. package/lib/services/normalizer/HtmlNormalizer.js +54 -2
  83. package/lib/services/normalizer/JsonNormalizer.js +6 -5
  84. package/lib/services/normalizer/__tests__/HtmlNormalizer.test.js +14 -0
  85. package/lib/services/normalizer/__tests__/JsonNormalizer.test.js +20 -3
  86. package/lib/services/normalizer/__tests__/__snapshots__/JsonNormalizer.test.js.snap +37 -0
  87. package/lib/utils/__tests__/findMarkByType.test.js +17 -0
  88. package/lib/utils/__tests__/isMarkAppliedToParent.test.js +53 -0
  89. package/lib/utils/__tests__/isNodeFullySelected.test.js +44 -0
  90. package/lib/utils/__tests__/resolveTextPosition.test.js +39 -0
  91. package/lib/utils/copyMark.js +5 -0
  92. package/lib/utils/index.js +1 -1
  93. package/lib/utils/isMarkAppliedToParent.js +1 -1
  94. package/lib/utils/isNodeFullySelected.js +4 -7
  95. package/lib/utils/resolveTextPosition.js +4 -6
  96. package/package.json +37 -27
  97. package/lib/utils/resolveNodePosition.js +0 -6
@@ -5,9 +5,14 @@ import { Alignments } from '../../../../enums';
5
5
  import { ButtonToggle } from '../../../base';
6
6
  import AlignmentControl from '../AlignmentControl';
7
7
 
8
- const createEditor = ({ alignment } = {}) => ({
8
+ const SELECTORS = {
9
+ INDICATOR: '[data-test-selector="customizedIndicator"]'
10
+ };
11
+
12
+ const createEditor = ({ alignment, isSettingCustomized } = {}) => ({
9
13
  commands: {
10
14
  getAlignment: () => ref(alignment),
15
+ isSettingCustomized: () => ref(isSettingCustomized ?? false),
11
16
  focus: jest.fn().mockReturnThis(),
12
17
  applyAlignment: jest.fn().mockReturnThis(),
13
18
  run: jest.fn()
@@ -18,11 +23,18 @@ const createEditor = ({ alignment } = {}) => ({
18
23
  }
19
24
  });
20
25
 
21
- function createComponent({ editor }) {
26
+ function createComponent({ editor, slotParams }) {
22
27
  return shallowMount(AlignmentControl, {
23
28
  stubs: {
24
29
  ButtonToggle: {
25
- render: () => h('div'),
30
+ render() {
31
+ const children = this.$scopedSlots.option({
32
+ ...slotParams,
33
+ activate: jest.fn()
34
+ });
35
+
36
+ return h('div', null, children);
37
+ },
26
38
  props: ['value']
27
39
  }
28
40
  },
@@ -33,7 +45,16 @@ function createComponent({ editor }) {
33
45
  describe('selection value', () => {
34
46
  test('should render value from selection', () => {
35
47
  const editor = createEditor({ alignment: Alignments.RIGHT });
36
- const wrapper = createComponent({ editor });
48
+ const wrapper = createComponent({
49
+ editor,
50
+ slotParams: {
51
+ option: {
52
+ id: Alignments.RIGHT,
53
+ tooltip: { text: 'Align Right', hotkey: 'Mod Shift R' }
54
+ },
55
+ isActive: true
56
+ }
57
+ });
37
58
  const buttonWrapper = wrapper.findComponent(ButtonToggle);
38
59
 
39
60
  expect(buttonWrapper.props('value')).toBe(Alignments.RIGHT);
@@ -41,7 +62,16 @@ describe('selection value', () => {
41
62
 
42
63
  test('should apply new value', () => {
43
64
  const editor = createEditor({ alignment: Alignments.RIGHT });
44
- const wrapper = createComponent({ editor });
65
+ const wrapper = createComponent({
66
+ editor,
67
+ slotParams: {
68
+ option: {
69
+ id: Alignments.RIGHT,
70
+ tooltip: { text: 'Align Right', hotkey: 'Mod Shift R' }
71
+ },
72
+ isActive: true
73
+ }
74
+ });
45
75
  const buttonWrapper = wrapper.findComponent(ButtonToggle);
46
76
 
47
77
  buttonWrapper.vm.$emit('change', Alignments.CENTER);
@@ -49,3 +79,40 @@ describe('selection value', () => {
49
79
  expect(editor.commands.applyAlignment).toHaveBeenCalledWith(Alignments.CENTER);
50
80
  });
51
81
  });
82
+
83
+ describe('render indicator of customized styles', () => {
84
+ test('should render indicator', () => {
85
+ const editor = createEditor({
86
+ alignment: Alignments.LEFT,
87
+ isSettingCustomized: true
88
+ });
89
+ const wrapper = createComponent({
90
+ editor,
91
+ slotParams: {
92
+ option: {
93
+ id: Alignments.LEFT,
94
+ tooltip: { text: 'Align Left', hotkey: 'Mod Shift L' }
95
+ },
96
+ isActive: true
97
+ }
98
+ });
99
+
100
+ expect(wrapper).toVueContainComponent(SELECTORS.INDICATOR);
101
+ });
102
+
103
+ test('should not render indicator', () => {
104
+ const editor = createEditor({ alignment: Alignments.LEFT });
105
+ const wrapper = createComponent({
106
+ editor,
107
+ slotParams: {
108
+ option: {
109
+ id: Alignments.LEFT,
110
+ tooltip: { text: 'Align Left', hotkey: 'Mod Shift L' }
111
+ },
112
+ isActive: true
113
+ }
114
+ });
115
+
116
+ expect(wrapper).not.toVueContainComponent(SELECTORS.INDICATOR);
117
+ });
118
+ });
@@ -4,9 +4,14 @@ import { InjectionTokens } from '../../../../injectionTokens';
4
4
  import { ColorPicker } from '../../../base';
5
5
  import FontColorControl from '../FontColorControl';
6
6
 
7
- const createEditor = ({ fontColor } = {}) => ({
7
+ const SELECTORS = {
8
+ INDICATOR: '[data-test-selector="customizedIndicator"]'
9
+ };
10
+
11
+ const createEditor = ({ fontColor, isSettingCustomized } = {}) => ({
8
12
  commands: {
9
13
  getFontColor: () => ref(fontColor),
14
+ isSettingCustomized: () => ref( isSettingCustomized ?? false),
10
15
  focus: jest.fn().mockReturnThis(),
11
16
  applyFontColor: jest.fn().mockReturnThis(),
12
17
  run: jest.fn()
@@ -57,3 +62,19 @@ describe('selection value', () => {
57
62
  expect(editor.commands.applyFontColor).toHaveBeenCalledWith('green');
58
63
  });
59
64
  });
65
+
66
+ describe('render indicator of customized styles', () => {
67
+ test('should render indicator', () => {
68
+ const editor = createEditor({ fontColor: 'red', isSettingCustomized: true });
69
+ const wrapper = createComponent({ editor });
70
+
71
+ expect(wrapper).toVueContainComponent(SELECTORS.INDICATOR);
72
+ });
73
+
74
+ test('should not render indicator', () => {
75
+ const editor = createEditor({ fontColor: 'red' });
76
+ const wrapper = createComponent({ editor });
77
+
78
+ expect(wrapper).not.toVueContainComponent(SELECTORS.INDICATOR);
79
+ });
80
+ });
@@ -7,6 +7,7 @@ import FontFamilyControl from '../FontFamilyControl';
7
7
  const createEditor = ({ fontFamily } = {}) => ({
8
8
  commands: {
9
9
  getFontFamily: () => ref(fontFamily),
10
+ isSettingCustomized: () => ref(false),
10
11
  focus: jest.fn().mockReturnThis(),
11
12
  applyFontFamily: jest.fn().mockReturnThis(),
12
13
  run: jest.fn()
@@ -7,6 +7,7 @@ import FontSizeControl from '../FontSizeControl';
7
7
  const createEditor = ({ fontSize } = {}) => ({
8
8
  commands: {
9
9
  getFontSize: () => ref(fontSize),
10
+ isSettingCustomized: () => ref(false),
10
11
  focus: jest.fn().mockReturnThis(),
11
12
  applyFontSize: jest.fn().mockReturnThis(),
12
13
  run: jest.fn()
@@ -7,6 +7,7 @@ import FontWeightControl from '../FontWeightControl';
7
7
  const createEditor = ({ fontWeight, fontWeightList } = {}) => ({
8
8
  commands: {
9
9
  getFontWeight: () => ref(fontWeight ?? '400'),
10
+ isSettingCustomized: () => ref(false),
10
11
  getFont: () => ref({ weights: fontWeightList ?? ['400', '700'] }),
11
12
  focus: jest.fn().mockReturnThis(),
12
13
  applyFontWeight: jest.fn().mockReturnThis(),
@@ -4,9 +4,14 @@ import { InjectionTokens } from '../../../../injectionTokens';
4
4
  import { Button } from '../../../base';
5
5
  import ItalicControl from '../ItalicControl';
6
6
 
7
- const createEditor = ({ isItalic, isItalicAvailable } = {}) => ({
7
+ const SELECTORS = {
8
+ INDICATOR: '[data-test-selector="customizedIndicator"]'
9
+ };
10
+
11
+ const createEditor = ({ isItalic, isItalicAvailable, isSettingCustomized } = {}) => ({
8
12
  commands: {
9
13
  isItalic: () => ref(isItalic),
14
+ isSettingCustomized: () => ref(isSettingCustomized ?? false),
10
15
  isItalicAvailable: () => ref(isItalicAvailable ?? true),
11
16
  focus: jest.fn().mockReturnThis(),
12
17
  toggleItalic: jest.fn().mockReturnThis(),
@@ -40,6 +45,23 @@ describe('rendering', () => {
40
45
 
41
46
  expect(buttonWrapper.props('disabled')).toBe(true);
42
47
  });
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
+ });
43
65
  });
44
66
 
45
67
  describe('selection value', () => {
@@ -4,12 +4,17 @@ import { InjectionTokens } from '../../../../injectionTokens';
4
4
  import { Button, Modal, NumberField, Range } from '../../../base';
5
5
  import LineHeightControl from '../LineHeightControl';
6
6
 
7
- const createEditor = ({ height } = {}) => {
7
+ const SELECTORS = {
8
+ INDICATOR: '[data-test-selector="customizedIndicator"]'
9
+ };
10
+
11
+ const createEditor = ({ height, isSettingCustomized } = {}) => {
8
12
  const heightRef = ref(height ?? '1.2');
9
13
 
10
14
  return {
11
15
  commands: {
12
16
  getLineHeight: () => heightRef,
17
+ isSettingCustomized: () => ref(isSettingCustomized ?? false),
13
18
  applyLineHeight: jest.fn(function (value) {
14
19
  heightRef.value = value;
15
20
  return this;
@@ -117,4 +122,21 @@ describe('rendering', () => {
117
122
  expect(buttonWrapper.props('active')).toBe(true);
118
123
  expect(modalWrapper.props('toggler').isOpened.value).toBe(true);
119
124
  });
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
+ });
120
142
  });
@@ -72,7 +72,7 @@ describe('rendering', () => {
72
72
  test('should enable reset if marks customized', () => {
73
73
  const editor = createEditor({
74
74
  customization: {
75
- marks: ['font_size'],
75
+ marks: [TextSettings.FONT_SIZE],
76
76
  attributes: []
77
77
  }
78
78
  });
@@ -86,7 +86,7 @@ describe('rendering', () => {
86
86
  const editor = createEditor({
87
87
  customization: {
88
88
  marks: [],
89
- attributes: ['alignment']
89
+ attributes: [TextSettings.ALIGNMENT]
90
90
  }
91
91
  });
92
92
  const wrapper = createComponent({ editor });
@@ -98,8 +98,8 @@ describe('rendering', () => {
98
98
  test('should enable reset if attributes and marks customized', () => {
99
99
  const editor = createEditor({
100
100
  customization: {
101
- marks: ['font_size'],
102
- attributes: ['alignment']
101
+ marks: [TextSettings.FONT_SIZE],
102
+ attributes: [TextSettings.ALIGNMENT]
103
103
  }
104
104
  });
105
105
  const wrapper = createComponent({ editor });
@@ -4,9 +4,14 @@ import { InjectionTokens } from '../../../../injectionTokens';
4
4
  import { Button } from '../../../base';
5
5
  import UnderlineControl from '../UnderlineControl';
6
6
 
7
- const createEditor = ({ isUnderline } = {}) => ({
7
+ const SELECTORS = {
8
+ INDICATOR: '[data-test-selector="customizedIndicator"]'
9
+ };
10
+
11
+ const createEditor = ({ isUnderline, isSettingCustomized } = {}) => ({
8
12
  commands: {
9
13
  isUnderline: () => ref(isUnderline),
14
+ isUnderlineCustomized: () => ref(isSettingCustomized ?? false),
10
15
  focus: jest.fn().mockReturnThis(),
11
16
  toggleUnderline: jest.fn().mockReturnThis(),
12
17
  run: jest.fn()
@@ -46,3 +51,22 @@ describe('selection value', () => {
46
51
  expect(editor.commands.toggleUnderline).toHaveBeenCalled();
47
52
  });
48
53
  });
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
+ });
@@ -17,7 +17,7 @@ const TestComponent = {
17
17
  props: ['value'],
18
18
 
19
19
  setup(props, { emit }) {
20
- const editor = useEditor({
20
+ const { editor } = useEditor({
21
21
  isReadonlyRef: ref(false),
22
22
  content: toRef(props, 'value'),
23
23
  extensions: buildTestExtensions(),
@@ -1,12 +1,16 @@
1
1
  import { Editor } from '@tiptap/vue-2';
2
2
  import { onUnmounted, watch, reactive, unref } from 'vue';
3
3
  import { ContentNormalizer } from '../services';
4
- import { markWysiwygContent, unmarkWysiwygContent } from '../utils';
4
+ import { markWysiwygContent } from '../utils';
5
5
 
6
6
  export function useEditor({ content, onChange, extensions, isReadonlyRef }) {
7
- const editor = reactive(new Editor({
7
+ let editor;
8
+
9
+ const getContent = () => markWysiwygContent(editor.getJSON());
10
+
11
+ editor = reactive(new Editor({
8
12
  content: ContentNormalizer.normalize(content.value),
9
- onUpdate: () => onChange(markWysiwygContent(editor.getJSON())),
13
+ onUpdate: () => onChange(getContent()),
10
14
  extensions,
11
15
  injectCSS: false,
12
16
  editable: !unref(isReadonlyRef)
@@ -15,10 +19,7 @@ export function useEditor({ content, onChange, extensions, isReadonlyRef }) {
15
19
  onUnmounted(() => editor.destroy());
16
20
 
17
21
  watch(content, (value) => {
18
- const content = unmarkWysiwygContent(value);
19
- const isChanged = JSON.stringify(editor.getJSON()) !== JSON.stringify(content);
20
-
21
- if (isChanged) {
22
+ if (JSON.stringify(getContent()) !== JSON.stringify(value)) {
22
23
  const content = ContentNormalizer.normalize(value);
23
24
 
24
25
  editor.commands.setContent(content, false);
@@ -27,5 +28,5 @@ export function useEditor({ content, onChange, extensions, isReadonlyRef }) {
27
28
 
28
29
  watch(isReadonlyRef, (isReadonly) => editor.setEditable(!isReadonly));
29
30
 
30
- return editor;
31
+ return { editor, getContent };
31
32
  }
@@ -4,7 +4,7 @@ describe('rendering', () => {
4
4
  test('should render text only tooltip', () => {
5
5
  const el = document.createElement('div');
6
6
 
7
- tooltip(el, { value: 'Test' });
7
+ tooltip(el, { value: 'Test', modifiers: {} });
8
8
 
9
9
  expect(el.dataset.tooltip).toBe('Test');
10
10
  });
@@ -13,7 +13,8 @@ describe('rendering', () => {
13
13
  const el = document.createElement('div');
14
14
 
15
15
  tooltip(el, {
16
- value: { text: 'Test' }
16
+ value: { text: 'Test' },
17
+ modifiers: {}
17
18
  });
18
19
 
19
20
  expect(el.dataset.tooltip).toBe('Test');
@@ -23,7 +24,8 @@ describe('rendering', () => {
23
24
  const el = document.createElement('div');
24
25
 
25
26
  tooltip(el, {
26
- value: { text: 'Test', hotkey: 'Mod B' }
27
+ value: { text: 'Test', hotkey: 'Mod B' },
28
+ modifiers: {}
27
29
  });
28
30
 
29
31
  expect(el.dataset.tooltipHotkey).toBe('Mod B');
@@ -32,8 +34,24 @@ describe('rendering', () => {
32
34
  test('should not render tooltip if no value passed', () => {
33
35
  const el = document.createElement('div');
34
36
 
35
- tooltip(el, { value: '' });
37
+ tooltip(el, { value: '', modifiers: {} });
36
38
 
37
39
  expect(el.dataset).not.toHaveProperty('tooltip');
38
40
  });
41
+
42
+ test('should render xs size', () => {
43
+ const el = document.createElement('div');
44
+
45
+ tooltip(el, { value: '', modifiers: { xs: true } });
46
+
47
+ expect(el.dataset).toHaveProperty('tooltipSize', 'xs');
48
+ });
49
+
50
+ test('should render lg size', () => {
51
+ const el = document.createElement('div');
52
+
53
+ tooltip(el, { value: '', modifiers: { lg: true } });
54
+
55
+ expect(el.dataset).toHaveProperty('tooltipSize', 'lg');
56
+ });
39
57
  });
@@ -1,7 +1,10 @@
1
- export function tooltip(el, { value }) {
1
+ export function tooltip(el, { value, modifiers }) {
2
2
  const options = typeof value === 'string' ? { text: value } : value;
3
3
  const { text, hotkey } = options;
4
4
 
5
5
  if (text) el.dataset.tooltip = text;
6
6
  if (text && hotkey) el.dataset.tooltipHotkey = hotkey;
7
+
8
+ if (modifiers.xs) el.dataset.tooltipSize = 'xs';
9
+ if (modifiers.lg) el.dataset.tooltipSize = 'lg';
7
10
  }
package/lib/entry-cli.js CHANGED
@@ -1,28 +1,15 @@
1
- import { resolve } from 'path';
2
1
  import { Command } from 'commander';
3
- import { ContentSerializer } from './cli';
2
+ import { ToJsonCommand, VersionCommand } from './cli';
4
3
 
5
4
  const program = new Command();
6
5
 
7
- function rubifyJSON(object) {
8
- const skipNullValue = (_, value) => value === null ? undefined : value;
9
- const json = JSON.stringify(object, skipNullValue, 2);
6
+ const commands = [
7
+ ToJsonCommand,
8
+ VersionCommand
9
+ ];
10
10
 
11
- return json
12
- .replace(/^[\t ]*"[^:\n\r]+(?<!\\)":/gm, (match) => match.replace(/"/g, ''))
13
- .replace(/: "(.+)"([,\n])/g, ': \'$1\'$2');
11
+ for (const CommandClass of commands) {
12
+ new CommandClass().install(program);
14
13
  }
15
14
 
16
- program.command('to-json')
17
- .argument('<html>')
18
- .option('--config <path>', 'generator config', resolve(__dirname, '../bin/zp.config.json'))
19
- .action((html, { config }) => {
20
- const configPath = resolve(process.cwd(), config);
21
- const serializer = ContentSerializer.build(require(configPath).editor);
22
- const json = rubifyJSON(serializer.toJSON(html));
23
-
24
- // eslint-disable-next-line no-console
25
- console.log(json);
26
- });
27
-
28
15
  program.parse();
package/lib/entry-lib.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { default as Wysiwyg } from './Wysiwyg';
2
2
  export { NodeFactory } from './services';
3
3
  export { NodeTypes, TextSettings, Alignments } from './enums';
4
- export { isWysiwygContent } from './utils';
4
+ export { isWysiwygContent, unmarkWysiwygContent, markWysiwygContent } from './utils';
@@ -0,0 +1,4 @@
1
+ export const MarkGroups = Object.freeze({
2
+ SETTINGS: 'settings',
3
+ ALL: '_'
4
+ });
@@ -18,7 +18,7 @@ export const TextSettings = Object.freeze({
18
18
  },
19
19
 
20
20
  get inlineMarks() {
21
- return [this.TEXT_DECORATION, this.LINK];
21
+ return [this.TEXT_DECORATION, this.LINK, this.SUPERSCRIPT, this.BACKGROUND_COLOR];
22
22
  },
23
23
 
24
24
  get marks() {
@@ -4,5 +4,6 @@ export { Alignments } from './Alignments';
4
4
  export { NodeTypes } from './NodeTypes';
5
5
  export { ListTypes } from './ListTypes';
6
6
  export { TextSettings } from './TextSettings';
7
+ export { MarkGroups } from './MarkGroups';
7
8
  export { LinkTargets } from './LinkTargets';
8
9
  export { LinkDestinations } from './LinkDestinations';
@@ -4,7 +4,6 @@ import { TextSettings } from '../enums';
4
4
 
5
5
  export const BackgroundColor = Mark.create({
6
6
  name: TextSettings.BACKGROUND_COLOR,
7
- group: 'settings',
8
7
 
9
8
  addAttributes: () => ({
10
9
  value: { required: true }
@@ -1,11 +1,11 @@
1
1
  import { Mark } from '@tiptap/vue-2';
2
2
  import { computed, unref } from 'vue';
3
3
  import { convertColor, createCommand, renderMark } from '../utils';
4
- import { TextSettings } from '../enums';
4
+ import { MarkGroups, TextSettings } from '../enums';
5
5
 
6
6
  export const FontColor = Mark.create({
7
7
  name: TextSettings.FONT_COLOR,
8
- group: 'settings',
8
+ group: MarkGroups.SETTINGS,
9
9
 
10
10
  addAttributes: () => ({
11
11
  value: { required: true }
@@ -1,11 +1,11 @@
1
1
  import { Mark } from '@tiptap/vue-2';
2
2
  import { computed, unref } from 'vue';
3
3
  import { createCommand, renderMark } from '../utils';
4
- import { TextSettings } from '../enums';
4
+ import { MarkGroups, TextSettings } from '../enums';
5
5
 
6
6
  export const FontFamily = Mark.create({
7
7
  name: TextSettings.FONT_FAMILY,
8
- group: 'settings',
8
+ group: MarkGroups.SETTINGS,
9
9
 
10
10
  addOptions: () => ({
11
11
  fonts: []
@@ -61,7 +61,7 @@ export const FontFamily = Mark.create({
61
61
 
62
62
  parseHTML() {
63
63
  const getAttrs = (input) => {
64
- const parsed = input.replace(/"/g, '');
64
+ const parsed = input.replace(/["']/g, '');
65
65
  const isExists = this.options.fonts.some((font) => font.name === parsed);
66
66
  const value = isExists ? parsed : unref(this.options.defaultPreset).common.font_family;
67
67
 
@@ -1,11 +1,11 @@
1
1
  import { Mark } from '@tiptap/vue-2';
2
2
  import { computed, unref } from 'vue';
3
3
  import { convertFontSize, createCommand, createKeyboardShortcut, renderMark } from '../utils';
4
- import { TextSettings } from '../enums';
4
+ import { MarkGroups, TextSettings } from '../enums';
5
5
 
6
6
  export const FontSize = Mark.create({
7
7
  name: TextSettings.FONT_SIZE,
8
- group: 'settings',
8
+ group: MarkGroups.SETTINGS,
9
9
 
10
10
  addOptions: () => ({
11
11
  minSize: 1,
@@ -1,11 +1,11 @@
1
1
  import { Mark } from '@tiptap/vue-2';
2
2
  import { computed, unref } from 'vue';
3
3
  import { createCommand, createKeyboardShortcut, renderMark } from '../utils';
4
- import { TextSettings } from '../enums';
4
+ import { MarkGroups, TextSettings } from '../enums';
5
5
 
6
6
  export const FontStyle = Mark.create({
7
7
  name: TextSettings.FONT_STYLE,
8
- group: 'settings',
8
+ group: MarkGroups.SETTINGS,
9
9
 
10
10
  addAttributes: () => ({
11
11
  italic: { required: true }
@@ -1,11 +1,11 @@
1
1
  import { Mark } from '@tiptap/vue-2';
2
2
  import { computed, unref } from 'vue';
3
3
  import { createCommand, createKeyboardShortcut, renderMark } from '../utils';
4
- import { TextSettings } from '../enums';
4
+ import { MarkGroups, TextSettings } from '../enums';
5
5
 
6
6
  export const FontWeight = Mark.create({
7
7
  name: TextSettings.FONT_WEIGHT,
8
- group: 'settings',
8
+ group: MarkGroups.SETTINGS,
9
9
 
10
10
  addAttributes: () => ({
11
11
  value: { required: true }
@@ -11,7 +11,7 @@ function makePresetClass(base, preset) {
11
11
  }
12
12
 
13
13
  export const StylePreset = Extension.create({
14
- name: 'style_preset',
14
+ name: TextSettings.STYLE_PRESET,
15
15
 
16
16
  addStorage: () => ({
17
17
  presetStyleEl: null
@@ -161,6 +161,13 @@ export const StylePreset = Extension.create({
161
161
  });
162
162
  }),
163
163
 
164
+ isSettingCustomized: createCommand(({ commands }, name) => {
165
+ const customization = commands.getPresetCustomization();
166
+ const group = TextSettings.attributes.includes(name) ? 'attributes' : 'marks';
167
+
168
+ return computed(() => unref(customization)[group]?.includes(name) ?? false);
169
+ }),
170
+
164
171
  removePresetCustomization: createCommand(({ chain }) => {
165
172
  chain()
166
173
  .storeSelection()
@@ -176,7 +183,7 @@ export const StylePreset = Extension.create({
176
183
  chain()
177
184
  .storeSelection()
178
185
  .expandSelectionToBlock()
179
- .unsetAllMarks()
186
+ .removeAllMarks()
180
187
  .applyDefaultPreset()
181
188
  .restoreSelection()
182
189
  .run();
@@ -12,13 +12,16 @@ export const Superscript = Base.extend({
12
12
  }),
13
13
 
14
14
  addCommands() {
15
+ const { setSuperscript, unsetSuperscript } = this.parent();
16
+
15
17
  return {
16
- ...this.parent(),
18
+ applySuperscript: setSuperscript,
19
+ removeSuperscript: unsetSuperscript,
17
20
 
18
21
  toggleSuperscript: createCommand(({ commands }) => {
19
22
  const isActive = unref(commands.isSuperscript());
20
23
 
21
- isActive ? commands.unsetSuperscript() : commands.setSuperscript();
24
+ isActive ? commands.applySuperscript() : commands.removeSuperscript();
22
25
  }),
23
26
 
24
27
  isSuperscript: createCommand(({ commands }) => {