@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.
- package/config/build/cli.config.js +8 -2
- package/dist/cli.js +3 -3
- package/dist/wysiwyg.css +41 -31
- package/dist/wysiwyg.mjs +2015 -1359
- package/example/ExampleApp.vue +10 -1
- package/lib/Wysiwyg.vue +3 -2
- package/lib/__tests__/utils/buildTestExtensions.js +2 -1
- package/lib/assets/icons/indicator.svg +4 -0
- package/lib/cli/commands/Command.js +39 -0
- package/lib/cli/commands/ToJsonCommand.js +55 -0
- package/lib/cli/commands/VersionCommand.js +11 -0
- package/lib/cli/commands/index.js +2 -0
- package/lib/cli/index.js +1 -0
- package/lib/components/base/Button.vue +6 -0
- package/lib/components/base/dropdown/Dropdown.vue +7 -1
- package/lib/components/base/dropdown/DropdownActivator.vue +25 -4
- package/lib/components/base/dropdown/__tests__/DropdownActivator.test.js +23 -1
- package/lib/components/toolbar/controls/AlignmentControl.vue +12 -1
- package/lib/components/toolbar/controls/FontColorControl.vue +14 -0
- package/lib/components/toolbar/controls/FontFamilyControl.vue +4 -0
- package/lib/components/toolbar/controls/FontSizeControl.vue +6 -1
- package/lib/components/toolbar/controls/FontWeightControl.vue +12 -0
- package/lib/components/toolbar/controls/ItalicControl.vue +14 -0
- package/lib/components/toolbar/controls/LineHeightControl.vue +15 -0
- package/lib/components/toolbar/controls/UnderlineControl.vue +13 -0
- package/lib/components/toolbar/controls/__tests__/AlignmentControl.test.js +72 -5
- package/lib/components/toolbar/controls/__tests__/FontColorControl.test.js +22 -1
- package/lib/components/toolbar/controls/__tests__/FontFamilyControl.test.js +1 -0
- package/lib/components/toolbar/controls/__tests__/FontSizeControl.test.js +1 -0
- package/lib/components/toolbar/controls/__tests__/FontWeightControl.test.js +1 -0
- package/lib/components/toolbar/controls/__tests__/ItalicControl.test.js +23 -1
- package/lib/components/toolbar/controls/__tests__/LineHeightControl.test.js +23 -1
- package/lib/components/toolbar/controls/__tests__/StylePresetControl.test.js +4 -4
- package/lib/components/toolbar/controls/__tests__/UnderlineControl.test.js +25 -1
- package/lib/composables/__tests__/useEditor.test.js +1 -1
- package/lib/composables/useEditor.js +9 -8
- package/lib/directives/__tests__/tooltip.test.js +22 -4
- package/lib/directives/tooltip.js +4 -1
- package/lib/entry-cli.js +7 -20
- package/lib/entry-lib.js +1 -1
- package/lib/enums/MarkGroups.js +4 -0
- package/lib/enums/TextSettings.js +1 -1
- package/lib/enums/index.js +1 -0
- package/lib/extensions/BackgroundColor.js +0 -1
- package/lib/extensions/FontColor.js +2 -2
- package/lib/extensions/FontFamily.js +3 -3
- package/lib/extensions/FontSize.js +2 -2
- package/lib/extensions/FontStyle.js +2 -2
- package/lib/extensions/FontWeight.js +2 -2
- package/lib/extensions/StylePreset.js +9 -2
- package/lib/extensions/Superscript.js +5 -2
- package/lib/extensions/TextDecoration.js +7 -0
- package/lib/extensions/__tests__/Alignment.test.js +2 -2
- package/lib/extensions/__tests__/BackgroundColor.test.js +4 -3
- package/lib/extensions/__tests__/FontColor.test.js +4 -3
- package/lib/extensions/__tests__/FontFamily.test.js +6 -6
- package/lib/extensions/__tests__/FontSize.test.js +9 -8
- package/lib/extensions/__tests__/FontStyle.test.js +6 -5
- package/lib/extensions/__tests__/LineHeight.test.js +2 -1
- package/lib/extensions/__tests__/StylePreset.test.js +51 -0
- package/lib/extensions/__tests__/Superscript.test.js +102 -0
- package/lib/extensions/__tests__/TextDecoration.test.js +20 -0
- package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +25 -25
- package/lib/extensions/__tests__/__snapshots__/Superscript.test.js.snap +107 -0
- package/lib/extensions/core/Document.js +2 -1
- package/lib/extensions/core/Heading.js +2 -1
- package/lib/extensions/core/NodeProcessor.js +42 -21
- package/lib/extensions/core/Paragraph.js +2 -1
- package/lib/extensions/core/__tests__/NodeProcessor.test.js +309 -11
- package/lib/extensions/core/__tests__/TextProcessor.test.js +1 -1
- package/lib/extensions/core/__tests__/__snapshots__/NodeProcessor.test.js.snap +249 -0
- package/lib/extensions/core/steps/AddNodeMarkStep.js +6 -0
- package/lib/extensions/core/steps/AttrStep.js +6 -0
- package/lib/extensions/core/steps/RemoveNodeMarkStep.js +6 -0
- package/lib/extensions/list/List.js +70 -9
- package/lib/extensions/list/ListItem.js +27 -5
- package/lib/extensions/list/__tests__/List.test.js +26 -17
- package/lib/extensions/list/__tests__/__snapshots__/List.test.js.snap +36 -36
- package/lib/services/NodeFactory.js +69 -3
- package/lib/services/__tests__/NodeFactory.test.js +124 -0
- package/lib/services/__tests__/__snapshots__/NodeFactory.test.js.snap +326 -0
- package/lib/services/normalizer/HtmlNormalizer.js +54 -2
- package/lib/services/normalizer/JsonNormalizer.js +6 -5
- package/lib/services/normalizer/__tests__/HtmlNormalizer.test.js +14 -0
- package/lib/services/normalizer/__tests__/JsonNormalizer.test.js +20 -3
- package/lib/services/normalizer/__tests__/__snapshots__/JsonNormalizer.test.js.snap +37 -0
- package/lib/utils/__tests__/findMarkByType.test.js +17 -0
- package/lib/utils/__tests__/isMarkAppliedToParent.test.js +53 -0
- package/lib/utils/__tests__/isNodeFullySelected.test.js +44 -0
- package/lib/utils/__tests__/resolveTextPosition.test.js +39 -0
- package/lib/utils/copyMark.js +5 -0
- package/lib/utils/index.js +1 -1
- package/lib/utils/isMarkAppliedToParent.js +1 -1
- package/lib/utils/isNodeFullySelected.js +4 -7
- package/lib/utils/resolveTextPosition.js +4 -6
- package/package.json +37 -27
- 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
|
|
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
|
|
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({
|
|
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({
|
|
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
|
|
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
|
|
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
|
|
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: [
|
|
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: [
|
|
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: [
|
|
102
|
-
attributes: [
|
|
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
|
|
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
|
+
});
|
|
@@ -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
|
|
4
|
+
import { markWysiwygContent } from '../utils';
|
|
5
5
|
|
|
6
6
|
export function useEditor({ content, onChange, extensions, isReadonlyRef }) {
|
|
7
|
-
|
|
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(
|
|
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
|
-
|
|
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 {
|
|
2
|
+
import { ToJsonCommand, VersionCommand } from './cli';
|
|
4
3
|
|
|
5
4
|
const program = new Command();
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
const commands = [
|
|
7
|
+
ToJsonCommand,
|
|
8
|
+
VersionCommand
|
|
9
|
+
];
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
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';
|
package/lib/enums/index.js
CHANGED
|
@@ -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';
|
|
@@ -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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
.
|
|
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
|
-
|
|
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.
|
|
24
|
+
isActive ? commands.applySuperscript() : commands.removeSuperscript();
|
|
22
25
|
}),
|
|
23
26
|
|
|
24
27
|
isSuperscript: createCommand(({ commands }) => {
|