@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.
- package/dist/cli.js +2 -2
- package/dist/wysiwyg.css +31 -42
- package/dist/wysiwyg.mjs +454 -399
- package/lib/__tests__/utils/buildTestExtensions.js +14 -0
- package/lib/__tests__/utils/index.js +1 -0
- package/lib/components/base/Button.vue +0 -7
- package/lib/components/base/dropdown/Dropdown.vue +1 -7
- package/lib/components/base/dropdown/DropdownActivator.vue +4 -19
- package/lib/components/base/dropdown/__tests__/DropdownActivator.test.js +1 -23
- package/lib/components/toolbar/controls/AlignmentControl.vue +1 -11
- package/lib/components/toolbar/controls/FontColorControl.vue +0 -13
- package/lib/components/toolbar/controls/FontFamilyControl.vue +0 -4
- package/lib/components/toolbar/controls/FontSizeControl.vue +1 -6
- package/lib/components/toolbar/controls/FontWeightControl.vue +0 -12
- package/lib/components/toolbar/controls/ItalicControl.vue +0 -13
- package/lib/components/toolbar/controls/LineHeightControl.vue +0 -14
- package/lib/components/toolbar/controls/SuperscriptControl.vue +2 -2
- package/lib/components/toolbar/controls/UnderlineControl.vue +0 -12
- package/lib/components/toolbar/controls/__tests__/AlignmentControl.test.js +5 -72
- package/lib/components/toolbar/controls/__tests__/FontColorControl.test.js +1 -22
- package/lib/components/toolbar/controls/__tests__/FontFamilyControl.test.js +0 -1
- package/lib/components/toolbar/controls/__tests__/FontSizeControl.test.js +0 -1
- package/lib/components/toolbar/controls/__tests__/FontWeightControl.test.js +0 -1
- package/lib/components/toolbar/controls/__tests__/ItalicControl.test.js +1 -23
- package/lib/components/toolbar/controls/__tests__/LineHeightControl.test.js +1 -23
- package/lib/components/toolbar/controls/__tests__/SuperscriptControl.test.js +2 -2
- package/lib/components/toolbar/controls/__tests__/UnderlineControl.test.js +1 -25
- package/lib/composables/__tests__/useEditor.test.js +2 -2
- package/lib/extensions/BackgroundColor.js +4 -4
- package/lib/extensions/FontColor.js +4 -5
- package/lib/extensions/FontFamily.js +4 -5
- package/lib/extensions/FontSize.js +5 -7
- package/lib/extensions/FontStyle.js +13 -11
- package/lib/extensions/FontWeight.js +6 -9
- package/lib/extensions/StylePreset.js +0 -14
- package/lib/extensions/Superscript.js +23 -1
- package/lib/extensions/TextDecoration.js +33 -20
- package/lib/extensions/__tests__/Alignment.test.js +10 -7
- package/lib/extensions/__tests__/BackgroundColor.test.js +6 -3
- package/lib/extensions/__tests__/CaseStyle.test.js +11 -7
- package/lib/extensions/__tests__/FontColor.test.js +6 -3
- package/lib/extensions/__tests__/FontFamily.test.js +29 -22
- package/lib/extensions/__tests__/FontSize.test.js +24 -17
- package/lib/extensions/__tests__/FontStyle.test.js +22 -16
- package/lib/extensions/__tests__/FontWeight.test.js +26 -19
- package/lib/extensions/__tests__/LineHeight.test.js +14 -11
- package/lib/extensions/__tests__/Link.test.js +14 -10
- package/lib/extensions/__tests__/Margin.test.js +2 -2
- package/lib/extensions/__tests__/StylePreset.test.js +49 -100
- package/lib/extensions/__tests__/TextDecoration.test.js +72 -46
- package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +24 -24
- package/lib/extensions/__tests__/__snapshots__/FontColor.test.js.snap +24 -24
- package/lib/extensions/__tests__/__snapshots__/FontFamily.test.js.snap +86 -82
- package/lib/extensions/__tests__/__snapshots__/FontSize.test.js.snap +70 -70
- package/lib/extensions/__tests__/__snapshots__/FontStyle.test.js.snap +53 -45
- package/lib/extensions/__tests__/__snapshots__/FontWeight.test.js.snap +64 -60
- package/lib/extensions/__tests__/__snapshots__/TextDecoration.test.js.snap +148 -83
- package/lib/extensions/core/Document.js +5 -0
- package/lib/extensions/core/Heading.js +10 -0
- package/lib/extensions/core/NodeProcessor.js +84 -4
- package/lib/extensions/core/Paragraph.js +9 -0
- package/lib/extensions/core/TextProcessor.js +10 -12
- package/lib/extensions/core/__tests__/NodeProcessor.test.js +82 -10
- package/lib/extensions/core/__tests__/SelectionProcessor.test.js +2 -2
- package/lib/extensions/core/__tests__/TextProcessor.test.js +18 -20
- package/lib/extensions/core/__tests__/__snapshots__/NodeProcessor.test.js.snap +132 -0
- package/lib/extensions/core/index.js +5 -5
- package/lib/extensions/core/steps/AddNodeMarkStep.js +60 -0
- package/lib/extensions/core/steps/RemoveNodeMarkStep.js +50 -0
- package/lib/extensions/core/steps/index.js +2 -0
- package/lib/extensions/list/List.js +1 -0
- package/lib/extensions/list/ListItem.js +5 -0
- package/lib/extensions/list/__tests__/List.test.js +30 -25
- package/lib/services/ContentNormalizer.js +1 -100
- package/lib/services/NodeFactory.js +16 -6
- package/lib/services/__tests__/ContentNormalizer.test.js +0 -64
- package/lib/utils/findMarkByType.js +5 -0
- package/lib/utils/index.js +5 -0
- package/lib/utils/isMarkAppliedToParent.js +15 -0
- package/lib/utils/isNodeFullySelected.js +10 -0
- package/lib/utils/resolveNodePosition.js +6 -0
- package/lib/utils/resolveTextPosition.js +6 -0
- package/package.json +1 -1
- package/lib/assets/icons/indicator.svg +0 -5
|
@@ -13,21 +13,6 @@ export class ContentNormalizer {
|
|
|
13
13
|
'margin-right'
|
|
14
14
|
];
|
|
15
15
|
|
|
16
|
-
static ASSIGN_STYLE_RULES = [
|
|
17
|
-
{
|
|
18
|
-
tag: /^(b|strong)$/,
|
|
19
|
-
ignore: /font-weight/
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
tag: /^i$/,
|
|
23
|
-
ignore: /font-style/
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
tag: /^s$/,
|
|
27
|
-
ignore: /text-decoration(.+)?/
|
|
28
|
-
}
|
|
29
|
-
];
|
|
30
|
-
|
|
31
16
|
static build(content, options = {}) {
|
|
32
17
|
return new ContentNormalizer({
|
|
33
18
|
content,
|
|
@@ -60,8 +45,6 @@ export class ContentNormalizer {
|
|
|
60
45
|
this.iterateNodes(this._normalizeBreakLines, (node) => node.tagName === 'BR');
|
|
61
46
|
this.iterateNodes(this._removeEmptyNodes, this._isBlockNode);
|
|
62
47
|
this.iterateNodes(this._normalizeListItems, (node) => node.tagName === 'LI');
|
|
63
|
-
this.iterateNodes(this._normalizeSettingsStructure, (node) => node.tagName === 'SPAN');
|
|
64
|
-
this.iterateNodes(this._normalizeStyles, (node) => node.tagName !== 'SPAN');
|
|
65
48
|
}
|
|
66
49
|
|
|
67
50
|
get normalizedHTML() {
|
|
@@ -72,10 +55,6 @@ export class ContentNormalizer {
|
|
|
72
55
|
return this._parser.types.NodeFilter;
|
|
73
56
|
}
|
|
74
57
|
|
|
75
|
-
get _Node() {
|
|
76
|
-
return this._parser.types.Node;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
58
|
_removeComments() {
|
|
80
59
|
const iterator = this.createNodeIterator(this._NodeFilter.SHOW_COMMENT);
|
|
81
60
|
|
|
@@ -159,98 +138,20 @@ export class ContentNormalizer {
|
|
|
159
138
|
this._removeStyleProperties(itemEl, ContentNormalizer.BLOCK_STYLES);
|
|
160
139
|
}
|
|
161
140
|
|
|
162
|
-
_normalizeSettingsStructure(element) {
|
|
163
|
-
if (this._isOnlyTextContent(element)) return;
|
|
164
|
-
|
|
165
|
-
const cloned = element.cloneNode(true);
|
|
166
|
-
const migratingStyles = this._getMigratingStyles(element, { customProperties: true });
|
|
167
|
-
const content = [];
|
|
168
|
-
|
|
169
|
-
for (const node of cloned.childNodes) {
|
|
170
|
-
let child = node;
|
|
171
|
-
|
|
172
|
-
if (migratingStyles.length) {
|
|
173
|
-
child = this._wrapTextNode(cloned, node);
|
|
174
|
-
this._assignElementProperties(child, cloned, migratingStyles);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
content.push(child);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
element.replaceWith(...content);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
_normalizeStyles(element) {
|
|
184
|
-
if (!this._isBlockNode(element) && this._isOnlyTextContent(element)) return;
|
|
185
|
-
|
|
186
|
-
const properties = this._getMigratingStyles(element);
|
|
187
|
-
|
|
188
|
-
if (!properties.length) return;
|
|
189
|
-
|
|
190
|
-
for (const node of element.childNodes) {
|
|
191
|
-
const child = this._wrapTextNode(element, node);
|
|
192
|
-
|
|
193
|
-
this._assignElementProperties(child, element, properties);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
this._removeStyleProperties(element, properties);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
_isOnlyTextContent(node) {
|
|
200
|
-
return Array.from(node.childNodes).every((node) => node.nodeType === this._Node.TEXT_NODE);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
141
|
_isBlockNode(node) {
|
|
204
142
|
return ContentNormalizer.BLOCK_NODE_NAMES.includes(node.tagName);
|
|
205
143
|
}
|
|
206
144
|
|
|
207
|
-
_getMigratingStyles(element, { customProperties } = {}) {
|
|
208
|
-
const blacklist = ContentNormalizer.BLOCK_STYLES;
|
|
209
|
-
const properties = [];
|
|
210
|
-
|
|
211
|
-
for (let index = 0; index < element.style.length; index++) {
|
|
212
|
-
const property = element.style.item(index);
|
|
213
|
-
|
|
214
|
-
if (blacklist.includes(property)) continue;
|
|
215
|
-
if (!customProperties && property.startsWith('--')) continue;
|
|
216
|
-
|
|
217
|
-
properties.push(property);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return properties;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
_wrapTextNode(parent, node) {
|
|
224
|
-
if (node.nodeType !== this._Node.TEXT_NODE) return node;
|
|
225
|
-
|
|
226
|
-
const span = this.dom.createElement('span');
|
|
227
|
-
|
|
228
|
-
span.append(node.cloneNode());
|
|
229
|
-
parent.replaceChild(span, node);
|
|
230
|
-
|
|
231
|
-
return span;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
145
|
_assignElementProperties(target, source, properties) {
|
|
235
146
|
for (const property of properties) {
|
|
236
147
|
const value = source.style.getPropertyValue(property);
|
|
237
148
|
|
|
238
|
-
if (value &&
|
|
149
|
+
if (value && !target.style.getPropertyValue(property)) {
|
|
239
150
|
target.style.setProperty(property, value);
|
|
240
151
|
}
|
|
241
152
|
}
|
|
242
153
|
}
|
|
243
154
|
|
|
244
|
-
_canAssignElementProperty(target, source, property) {
|
|
245
|
-
if (target.style.getPropertyValue(property)) return false;
|
|
246
|
-
|
|
247
|
-
return ContentNormalizer.ASSIGN_STYLE_RULES.every((rule) => {
|
|
248
|
-
if (!rule.tag.test(target.tagName.toLowerCase())) return true;
|
|
249
|
-
|
|
250
|
-
return !rule.ignore.test(property);
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
|
|
254
155
|
_removeStyleProperties(element, properties) {
|
|
255
156
|
for (const property of properties) {
|
|
256
157
|
element.style.removeProperty(property);
|
|
@@ -24,7 +24,7 @@ export class NodeFactory {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
static heading(level, ...args) {
|
|
27
|
-
const config = this
|
|
27
|
+
const config = this.#textBlock(args);
|
|
28
28
|
|
|
29
29
|
config.attrs ??= {};
|
|
30
30
|
config.attrs.level = level;
|
|
@@ -38,21 +38,31 @@ export class NodeFactory {
|
|
|
38
38
|
static paragraph(...args) {
|
|
39
39
|
return {
|
|
40
40
|
type: NodeTypes.PARAGRAPH,
|
|
41
|
-
...this
|
|
41
|
+
...this.#textBlock(args)
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
static
|
|
46
|
-
const attrs
|
|
47
|
-
const content = args.length === 1 ? args[0] : args[1];
|
|
45
|
+
static #textBlock(args) {
|
|
46
|
+
const { attrs, content, marks } = this.#normalizeTextBlockArgs(args);
|
|
48
47
|
const children = typeof content === 'string' ? [this.text(content)] : content;
|
|
49
48
|
|
|
50
49
|
return {
|
|
51
50
|
content: children,
|
|
52
|
-
...(attrs ? { attrs } : {})
|
|
51
|
+
...(attrs ? { attrs } : {}),
|
|
52
|
+
...(marks ? { marks } : {})
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
static #normalizeTextBlockArgs(args) {
|
|
57
|
+
if (args.length === 1) {
|
|
58
|
+
return { attrs: null, marks: null, content: args[0] };
|
|
59
|
+
}
|
|
60
|
+
if (args.length === 2) {
|
|
61
|
+
return { attrs: args[0], marks: null, content: args[1] };
|
|
62
|
+
}
|
|
63
|
+
return { attrs: args[0], marks: args[1], content: args[2] };
|
|
64
|
+
}
|
|
65
|
+
|
|
56
66
|
static text(text, marks) {
|
|
57
67
|
return {
|
|
58
68
|
type: NodeTypes.TEXT,
|
|
@@ -8,35 +8,6 @@ describe('normalize text content', () => {
|
|
|
8
8
|
expect(ContentNormalizer.normalize(content)).toBe(content);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
-
test('should flat structure', () => {
|
|
12
|
-
const input = '<p style="text-align: center; color: rgb(255, 255, 255);"><span style="background-color: rgb(255, 0, 0);">lore<span style="color: rgb(0, 0, 0);">m ip</span>sum</span></p>';
|
|
13
|
-
const output = '<p style="text-align: center;">' +
|
|
14
|
-
'<span style="background-color: rgb(255, 0, 0); color: rgb(255, 255, 255);">lore</span>' +
|
|
15
|
-
'<span style="color: rgb(0, 0, 0); background-color: rgb(255, 0, 0);">m ip</span>' +
|
|
16
|
-
'<span style="background-color: rgb(255, 0, 0); color: rgb(255, 255, 255);">sum</span>' +
|
|
17
|
-
'</p>';
|
|
18
|
-
|
|
19
|
-
expect(ContentNormalizer.normalize(input)).toBe(output);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test('should move styles from paragraph to text', () => {
|
|
23
|
-
const input = '<p style="background-color: red;">lorem ipsum</p>';
|
|
24
|
-
const output = '<p><span style="background-color: red;">lorem ipsum</span></p>';
|
|
25
|
-
|
|
26
|
-
expect(ContentNormalizer.normalize(input)).toBe(output);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test('should move styles from paragraph to unstyled text', () => {
|
|
30
|
-
const input = '<p style="background-color: red;"><span style="background-color: #000;">lorem</span> ipsum <span style="color: white;">one</span></p>';
|
|
31
|
-
const output = '<p>' +
|
|
32
|
-
'<span style="background-color: #000;">lorem</span>' +
|
|
33
|
-
'<span style="background-color: red;"> ipsum </span>' +
|
|
34
|
-
'<span style="color: white; background-color: red;">one</span' +
|
|
35
|
-
'></p>';
|
|
36
|
-
|
|
37
|
-
expect(ContentNormalizer.normalize(input)).toBe(output);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
11
|
test('should wrap list content in paragraph', () => {
|
|
41
12
|
const input = '<ul><li style="line-height: 2;">lorem impsum</li></ul>';
|
|
42
13
|
const output = '<ul><li><p style="line-height: 2;">lorem impsum</p></li></ul>';
|
|
@@ -99,34 +70,6 @@ describe('normalize text content', () => {
|
|
|
99
70
|
expect(ContentNormalizer.normalize(input)).toBe(output);
|
|
100
71
|
});
|
|
101
72
|
|
|
102
|
-
test('should not ignore setting', () => {
|
|
103
|
-
const input = '<p style="text-decoration-line: underline;">lorem ipsum</p>';
|
|
104
|
-
const output = '<p><span style="text-decoration-line: underline;">lorem ipsum</span></p>';
|
|
105
|
-
|
|
106
|
-
expect(ContentNormalizer.normalize(input)).toBe(output);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
test('should not assign font-weight to b tag', () => {
|
|
110
|
-
const input = '<p style="font-weight: 400;"><b>lorem ipsum</b></p>';
|
|
111
|
-
const output = '<p><b>lorem ipsum</b></p>';
|
|
112
|
-
|
|
113
|
-
expect(ContentNormalizer.normalize(input)).toBe(output);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test('should not assign font-style to i tag', () => {
|
|
117
|
-
const input = '<p style="font-style: normal;"><i>lorem ipsum</i></p>';
|
|
118
|
-
const output = '<p><i>lorem ipsum</i></p>';
|
|
119
|
-
|
|
120
|
-
expect(ContentNormalizer.normalize(input)).toBe(output);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test('should not assign text-decoration to s tag', () => {
|
|
124
|
-
const input = '<p style="text-decoration-line: initial;"><s>lorem ipsum</s></p>';
|
|
125
|
-
const output = '<p><s>lorem ipsum</s></p>';
|
|
126
|
-
|
|
127
|
-
expect(ContentNormalizer.normalize(input)).toBe(output);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
73
|
test('should assign block styles from list to paragraph', () => {
|
|
131
74
|
const input = '<ul style="line-height: 2;"><li>lorem ipsum</li></ul>';
|
|
132
75
|
const output = '<ul style="line-height: 2;"><li><p style="line-height: 2;">lorem ipsum</p></li></ul>';
|
|
@@ -164,11 +107,4 @@ describe('normalize text content', () => {
|
|
|
164
107
|
|
|
165
108
|
expect(ContentNormalizer.normalize(input)).toBe(output);
|
|
166
109
|
});
|
|
167
|
-
|
|
168
|
-
test('should remove comments', () => {
|
|
169
|
-
const input = '<p>lorem ipsum</p><p style="color: red;">Hello <!-- world --></p>';
|
|
170
|
-
const output = '<p>lorem ipsum</p><p><span style="color: red;">Hello </span></p>';
|
|
171
|
-
|
|
172
|
-
expect(ContentNormalizer.normalize(input)).toBe(output);
|
|
173
|
-
});
|
|
174
110
|
});
|
package/lib/utils/index.js
CHANGED
|
@@ -8,3 +8,8 @@ export { convertFontSize } from './convertFontSize';
|
|
|
8
8
|
export { convertAlignment } from './convertAlignment';
|
|
9
9
|
export { importIcon } from './importIcon';
|
|
10
10
|
export { isWysiwygContent, markWysiwygContent, unmarkWysiwygContent } from './isWysiwygContent';
|
|
11
|
+
export { resolveNodePosition } from './resolveNodePosition';
|
|
12
|
+
export { resolveTextPosition } from './resolveTextPosition';
|
|
13
|
+
export { isNodeFullySelected } from './isNodeFullySelected';
|
|
14
|
+
export { isMarkAppliedToParent } from './isMarkAppliedToParent';
|
|
15
|
+
export { findMarkByType } from './findMarkByType';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const DEFAULT_COMPARATOR = (parent, child) => child.eq(parent);
|
|
2
|
+
|
|
3
|
+
export function isMarkAppliedToParent({ doc }, position, checkingMark, comparator = DEFAULT_COMPARATOR) {
|
|
4
|
+
const steps = doc.resolve(position).path.reverse();
|
|
5
|
+
|
|
6
|
+
for (const step of steps) {
|
|
7
|
+
if (typeof step === 'number') continue;
|
|
8
|
+
|
|
9
|
+
for (const mark of step.marks) {
|
|
10
|
+
if (comparator(mark, checkingMark)) return true;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { resolveNodePosition } from './resolveNodePosition';
|
|
2
|
+
|
|
3
|
+
export function isNodeFullySelected($from, $to, node, position) {
|
|
4
|
+
const fromPosition = resolveNodePosition($from, node, -1);
|
|
5
|
+
const toPosition = resolveNodePosition($to, node, 1);
|
|
6
|
+
const isFromMatch = fromPosition <= position;
|
|
7
|
+
const isToMatch = toPosition >= node.nodeSize + position;
|
|
8
|
+
|
|
9
|
+
return isFromMatch && isToMatch;
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
<svg width="9" height="9" viewBox="0 0 9 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
-
<path d="M0 4.5C0 2.01472 2.01472 0 4.5 0C6.98528 0 9 2.01472 9 4.5C9 6.98528 6.98528 9 4.5 9C2.01472 9 0 6.98528 0 4.5Z" fill="#FFAB00"/>
|
|
3
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.0625 2.25H3.9375V5.625H5.0625V2.25Z" fill="white"/>
|
|
4
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.9375 6.75C3.9375 6.43894 4.18894 6.1875 4.5 6.1875C4.8105 6.1875 5.0625 6.43894 5.0625 6.75C5.0625 7.06106 4.8105 7.3125 4.5 7.3125C4.18894 7.3125 3.9375 7.06106 3.9375 6.75Z" fill="white"/>
|
|
5
|
-
</svg>
|