@zipify/wysiwyg 1.3.0-0 → 2.0.0-1

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 (103) hide show
  1. package/.eslintrc.js +1 -1
  2. package/config/build/lib.config.js +4 -2
  3. package/dist/cli.js +10 -2
  4. package/dist/wysiwyg.css +43 -48
  5. package/dist/wysiwyg.mjs +1928 -787
  6. package/example/ExampleApp.vue +3 -1
  7. package/lib/__tests__/utils/buildTestExtensions.js +14 -0
  8. package/lib/__tests__/utils/index.js +1 -0
  9. package/lib/components/base/Button.vue +0 -7
  10. package/lib/components/base/dropdown/Dropdown.vue +1 -7
  11. package/lib/components/base/dropdown/DropdownActivator.vue +4 -19
  12. package/lib/components/base/dropdown/__tests__/DropdownActivator.test.js +1 -23
  13. package/lib/components/toolbar/controls/AlignmentControl.vue +1 -11
  14. package/lib/components/toolbar/controls/FontColorControl.vue +0 -13
  15. package/lib/components/toolbar/controls/FontFamilyControl.vue +0 -4
  16. package/lib/components/toolbar/controls/FontSizeControl.vue +1 -6
  17. package/lib/components/toolbar/controls/FontWeightControl.vue +0 -12
  18. package/lib/components/toolbar/controls/ItalicControl.vue +0 -13
  19. package/lib/components/toolbar/controls/LineHeightControl.vue +0 -14
  20. package/lib/components/toolbar/controls/StylePresetControl.vue +1 -1
  21. package/lib/components/toolbar/controls/SuperscriptControl.vue +2 -2
  22. package/lib/components/toolbar/controls/UnderlineControl.vue +0 -12
  23. package/lib/components/toolbar/controls/__tests__/AlignmentControl.test.js +5 -72
  24. package/lib/components/toolbar/controls/__tests__/FontColorControl.test.js +1 -22
  25. package/lib/components/toolbar/controls/__tests__/FontFamilyControl.test.js +0 -1
  26. package/lib/components/toolbar/controls/__tests__/FontSizeControl.test.js +0 -1
  27. package/lib/components/toolbar/controls/__tests__/FontWeightControl.test.js +0 -1
  28. package/lib/components/toolbar/controls/__tests__/ItalicControl.test.js +1 -23
  29. package/lib/components/toolbar/controls/__tests__/LineHeightControl.test.js +1 -23
  30. package/lib/components/toolbar/controls/__tests__/StylePresetControl.test.js +2 -2
  31. package/lib/components/toolbar/controls/__tests__/SuperscriptControl.test.js +2 -2
  32. package/lib/components/toolbar/controls/__tests__/UnderlineControl.test.js +1 -25
  33. package/lib/composables/__tests__/useEditor.test.js +2 -2
  34. package/lib/enums/TextSettings.js +5 -5
  35. package/lib/extensions/BackgroundColor.js +4 -4
  36. package/lib/extensions/FontColor.js +4 -5
  37. package/lib/extensions/FontFamily.js +4 -5
  38. package/lib/extensions/FontSize.js +5 -7
  39. package/lib/extensions/FontStyle.js +13 -11
  40. package/lib/extensions/FontWeight.js +6 -9
  41. package/lib/extensions/Link.js +1 -1
  42. package/lib/extensions/StylePreset.js +1 -15
  43. package/lib/extensions/Superscript.js +23 -1
  44. package/lib/extensions/TextDecoration.js +16 -20
  45. package/lib/extensions/__tests__/Alignment.test.js +10 -7
  46. package/lib/extensions/__tests__/BackgroundColor.test.js +6 -3
  47. package/lib/extensions/__tests__/CaseStyle.test.js +11 -7
  48. package/lib/extensions/__tests__/FontColor.test.js +6 -3
  49. package/lib/extensions/__tests__/FontFamily.test.js +29 -22
  50. package/lib/extensions/__tests__/FontSize.test.js +24 -17
  51. package/lib/extensions/__tests__/FontStyle.test.js +22 -16
  52. package/lib/extensions/__tests__/FontWeight.test.js +28 -21
  53. package/lib/extensions/__tests__/LineHeight.test.js +14 -11
  54. package/lib/extensions/__tests__/Link.test.js +14 -10
  55. package/lib/extensions/__tests__/Margin.test.js +2 -2
  56. package/lib/extensions/__tests__/StylePreset.test.js +49 -100
  57. package/lib/extensions/__tests__/TextDecoration.test.js +59 -37
  58. package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +25 -25
  59. package/lib/extensions/__tests__/__snapshots__/FontColor.test.js.snap +25 -25
  60. package/lib/extensions/__tests__/__snapshots__/FontFamily.test.js.snap +105 -105
  61. package/lib/extensions/__tests__/__snapshots__/FontSize.test.js.snap +72 -72
  62. package/lib/extensions/__tests__/__snapshots__/FontStyle.test.js.snap +54 -46
  63. package/lib/extensions/__tests__/__snapshots__/FontWeight.test.js.snap +77 -77
  64. package/lib/extensions/__tests__/__snapshots__/TextDecoration.test.js.snap +68 -3
  65. package/lib/extensions/core/Document.js +5 -0
  66. package/lib/extensions/core/Heading.js +10 -0
  67. package/lib/extensions/core/NodeProcessor.js +112 -10
  68. package/lib/extensions/core/Paragraph.js +9 -0
  69. package/lib/extensions/core/TextProcessor.js +9 -16
  70. package/lib/extensions/core/__tests__/NodeProcessor.test.js +137 -10
  71. package/lib/extensions/core/__tests__/SelectionProcessor.test.js +2 -2
  72. package/lib/extensions/core/__tests__/TextProcessor.test.js +18 -41
  73. package/lib/extensions/core/__tests__/__snapshots__/NodeProcessor.test.js.snap +192 -0
  74. package/lib/extensions/core/__tests__/__snapshots__/TextProcessor.test.js.snap +7 -27
  75. package/lib/extensions/core/index.js +5 -5
  76. package/lib/extensions/core/steps/AddNodeMarkStep.js +60 -0
  77. package/lib/extensions/core/steps/AttrStep.js +54 -0
  78. package/lib/extensions/core/steps/RemoveNodeMarkStep.js +50 -0
  79. package/lib/extensions/core/steps/index.js +3 -0
  80. package/lib/extensions/list/List.js +1 -0
  81. package/lib/extensions/list/ListItem.js +5 -0
  82. package/lib/extensions/list/__tests__/List.test.js +30 -25
  83. package/lib/services/NodeFactory.js +25 -21
  84. package/lib/services/index.js +1 -1
  85. package/lib/services/normalizer/BaseNormalizer.js +11 -0
  86. package/lib/services/{BrowserDomParser.js → normalizer/BrowserDomParser.js} +0 -0
  87. package/lib/services/normalizer/ContentNormalizer.js +24 -0
  88. package/lib/services/normalizer/HtmlNormalizer.js +245 -0
  89. package/lib/services/normalizer/JsonNormalizer.js +81 -0
  90. package/lib/services/{__tests__/ContentNormalizer.test.js → normalizer/__tests__/HtmlNormalizer.test.js} +27 -67
  91. package/lib/services/normalizer/__tests__/JsonNormalizer.test.js +70 -0
  92. package/lib/services/normalizer/__tests__/__snapshots__/JsonNormalizer.test.js.snap +159 -0
  93. package/lib/services/normalizer/index.js +1 -0
  94. package/lib/styles/content.css +8 -0
  95. package/lib/utils/findMarkByType.js +5 -0
  96. package/lib/utils/index.js +5 -0
  97. package/lib/utils/isMarkAppliedToParent.js +10 -0
  98. package/lib/utils/isNodeFullySelected.js +10 -0
  99. package/lib/utils/resolveNodePosition.js +6 -0
  100. package/lib/utils/resolveTextPosition.js +6 -0
  101. package/package.json +3 -1
  102. package/lib/assets/icons/indicator.svg +0 -5
  103. package/lib/services/ContentNormalizer.js +0 -293
@@ -1,293 +0,0 @@
1
- import { BrowserDomParser } from './BrowserDomParser';
2
-
3
- export class ContentNormalizer {
4
- static BLOCK_NODE_NAMES = ['P', 'H1', 'H2', 'H3', 'H4'];
5
-
6
- static BLOCK_STYLES = [
7
- 'text-align',
8
- 'line-height',
9
- 'margin',
10
- 'margin-top',
11
- 'margin-bottom',
12
- 'margin-left',
13
- 'margin-right'
14
- ];
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
- static build(content, options = {}) {
32
- return new ContentNormalizer({
33
- content,
34
- parser: options.parser || new BrowserDomParser()
35
- });
36
- }
37
-
38
- static normalize(content, options = {}) {
39
- return ContentNormalizer.build(content, options).normalize();
40
- }
41
-
42
- constructor({ content, parser }) {
43
- this._content = content;
44
- this._parser = parser;
45
- this.dom = null;
46
- }
47
-
48
- normalize() {
49
- if (typeof this._content !== 'string') {
50
- return this._content;
51
- }
52
- this.normalizeHTML();
53
- return this.normalizedHTML;
54
- }
55
-
56
- normalizeHTML() {
57
- this.dom = this._parser.parse(this._content.replace(/(\r)?\n/g, ''));
58
-
59
- this._removeComments();
60
- this.iterateNodes(this._normalizeBreakLines, (node) => node.tagName === 'BR');
61
- this.iterateNodes(this._removeEmptyNodes, this._isBlockNode);
62
- 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
- }
66
-
67
- get normalizedHTML() {
68
- return this.dom.body.innerHTML;
69
- }
70
-
71
- get _NodeFilter() {
72
- return this._parser.types.NodeFilter;
73
- }
74
-
75
- get _Node() {
76
- return this._parser.types.Node;
77
- }
78
-
79
- _removeComments() {
80
- const iterator = this.createNodeIterator(this._NodeFilter.SHOW_COMMENT);
81
-
82
- this.runIterator(iterator, (node) => node.remove());
83
- }
84
-
85
- createNodeIterator(whatToShow, filter) {
86
- return this.dom.createNodeIterator(this.dom.body, whatToShow, filter);
87
- }
88
-
89
- iterateNodes(handler, condition = () => true) {
90
- const checkCondition = (node) => node.tagName !== 'BODY' && condition.call(this, node);
91
-
92
- const iterator = this.createNodeIterator(this._NodeFilter.SHOW_ELEMENT, {
93
- acceptNode: (node) => checkCondition(node) ? this._NodeFilter.FILTER_ACCEPT : this._NodeFilter.FILTER_REJECT
94
- });
95
-
96
- this.runIterator(iterator, handler);
97
- }
98
-
99
- runIterator(iterator, handler) {
100
- let currentNode = iterator.nextNode();
101
-
102
- while (currentNode) {
103
- handler.call(this, currentNode);
104
- currentNode = iterator.nextNode();
105
- }
106
- }
107
-
108
- _removeEmptyNodes(node) {
109
- if (!node.innerHTML.trim()) node.remove();
110
- }
111
-
112
- _normalizeListItems(itemEl) {
113
- const fragment = this.dom.createDocumentFragment();
114
- const children = Array.from(itemEl.childNodes);
115
- let capturingParagraph;
116
- let previousNode;
117
-
118
- const append = (node) => {
119
- this._assignElementProperties(node, itemEl, ContentNormalizer.BLOCK_STYLES);
120
- fragment.append(node);
121
- };
122
-
123
- this._assignElementProperties(itemEl, itemEl.parentElement, ContentNormalizer.BLOCK_STYLES);
124
-
125
- for (const node of children) {
126
- if (this._isBlockNode(node)) {
127
- append(node);
128
- capturingParagraph = null;
129
- previousNode = node;
130
- continue;
131
- }
132
-
133
- if (node.tagName === 'BR' && previousNode && previousNode?.tagName !== 'BR') {
134
- node.remove();
135
- previousNode = node;
136
- continue;
137
- }
138
-
139
- if (node.tagName === 'BR') {
140
- const emptyLineEl = this.dom.createElement('p');
141
-
142
- emptyLineEl.append(node);
143
- append(emptyLineEl);
144
- capturingParagraph = null;
145
- previousNode = node;
146
- continue;
147
- }
148
-
149
- if (!capturingParagraph) {
150
- capturingParagraph = this.dom.createElement('p');
151
- append(capturingParagraph);
152
- }
153
-
154
- capturingParagraph.append(node);
155
- previousNode = node;
156
- }
157
-
158
- itemEl.append(fragment);
159
- this._removeStyleProperties(itemEl, ContentNormalizer.BLOCK_STYLES);
160
- }
161
-
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
- _isBlockNode(node) {
204
- return ContentNormalizer.BLOCK_NODE_NAMES.includes(node.tagName);
205
- }
206
-
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
- _assignElementProperties(target, source, properties) {
235
- for (const property of properties) {
236
- const value = source.style.getPropertyValue(property);
237
-
238
- if (value && this._canAssignElementProperty(target, source, property)) {
239
- target.style.setProperty(property, value);
240
- }
241
- }
242
- }
243
-
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
- _removeStyleProperties(element, properties) {
255
- for (const property of properties) {
256
- element.style.removeProperty(property);
257
- }
258
-
259
- if (element.style.length === 0) {
260
- element.removeAttribute('style');
261
- }
262
- }
263
-
264
- _normalizeBreakLines({ parentElement }) {
265
- if (!this._isBlockNode(parentElement)) return;
266
- if (!parentElement.textContent) return;
267
-
268
- const fragment = this.dom.createDocumentFragment();
269
- const children = Array.from(parentElement.childNodes);
270
- const parentTemplate = parentElement.cloneNode(true);
271
-
272
- parentTemplate.innerHTML = '';
273
- let capturingParagraph = parentTemplate.cloneNode();
274
-
275
- const append = (node) => {
276
- this._assignElementProperties(node, parentElement, ContentNormalizer.BLOCK_STYLES);
277
- fragment.append(node);
278
- };
279
-
280
- for (const child of children) {
281
- if (child.tagName === 'BR') {
282
- append(capturingParagraph);
283
- capturingParagraph = parentTemplate.cloneNode();
284
- continue;
285
- }
286
-
287
- capturingParagraph.append(child);
288
- }
289
-
290
- fragment.append(capturingParagraph);
291
- parentElement.replaceWith(fragment);
292
- }
293
- }