@zipify/wysiwyg 2.0.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 (44) 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 +12 -6
  5. package/dist/wysiwyg.mjs +1464 -378
  6. package/example/ExampleApp.vue +3 -1
  7. package/lib/components/toolbar/controls/StylePresetControl.vue +1 -1
  8. package/lib/components/toolbar/controls/__tests__/StylePresetControl.test.js +2 -2
  9. package/lib/enums/TextSettings.js +5 -5
  10. package/lib/extensions/Link.js +1 -1
  11. package/lib/extensions/StylePreset.js +1 -1
  12. package/lib/extensions/TextDecoration.js +12 -29
  13. package/lib/extensions/__tests__/FontWeight.test.js +2 -2
  14. package/lib/extensions/__tests__/TextDecoration.test.js +20 -24
  15. package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +1 -1
  16. package/lib/extensions/__tests__/__snapshots__/FontColor.test.js.snap +1 -1
  17. package/lib/extensions/__tests__/__snapshots__/FontFamily.test.js.snap +19 -23
  18. package/lib/extensions/__tests__/__snapshots__/FontSize.test.js.snap +2 -2
  19. package/lib/extensions/__tests__/__snapshots__/FontStyle.test.js.snap +1 -1
  20. package/lib/extensions/__tests__/__snapshots__/FontWeight.test.js.snap +13 -17
  21. package/lib/extensions/__tests__/__snapshots__/TextDecoration.test.js.snap +102 -102
  22. package/lib/extensions/core/NodeProcessor.js +37 -15
  23. package/lib/extensions/core/TextProcessor.js +0 -5
  24. package/lib/extensions/core/__tests__/NodeProcessor.test.js +55 -0
  25. package/lib/extensions/core/__tests__/TextProcessor.test.js +0 -21
  26. package/lib/extensions/core/__tests__/__snapshots__/NodeProcessor.test.js.snap +60 -0
  27. package/lib/extensions/core/__tests__/__snapshots__/TextProcessor.test.js.snap +7 -27
  28. package/lib/extensions/core/steps/AttrStep.js +54 -0
  29. package/lib/extensions/core/steps/index.js +1 -0
  30. package/lib/services/NodeFactory.js +12 -18
  31. package/lib/services/index.js +1 -1
  32. package/lib/services/normalizer/BaseNormalizer.js +11 -0
  33. package/lib/services/{BrowserDomParser.js → normalizer/BrowserDomParser.js} +0 -0
  34. package/lib/services/normalizer/ContentNormalizer.js +24 -0
  35. package/lib/services/normalizer/HtmlNormalizer.js +245 -0
  36. package/lib/services/normalizer/JsonNormalizer.js +81 -0
  37. package/lib/services/{__tests__/ContentNormalizer.test.js → normalizer/__tests__/HtmlNormalizer.test.js} +31 -7
  38. package/lib/services/normalizer/__tests__/JsonNormalizer.test.js +70 -0
  39. package/lib/services/normalizer/__tests__/__snapshots__/JsonNormalizer.test.js.snap +159 -0
  40. package/lib/services/normalizer/index.js +1 -0
  41. package/lib/styles/content.css +8 -0
  42. package/lib/utils/isMarkAppliedToParent.js +2 -7
  43. package/package.json +3 -1
  44. package/lib/services/ContentNormalizer.js +0 -194
@@ -0,0 +1,159 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`normalize json content should bubble mark from single text node to paragraph 1`] = `
4
+ Object {
5
+ "content": Array [
6
+ Object {
7
+ "content": Array [
8
+ Object {
9
+ "text": "lorem ipsum",
10
+ "type": "text",
11
+ },
12
+ ],
13
+ "marks": Array [
14
+ Object {
15
+ "attrs": Object {
16
+ "value": "700",
17
+ },
18
+ "type": "font_weight",
19
+ },
20
+ ],
21
+ "type": "paragraph",
22
+ },
23
+ ],
24
+ "type": "doc",
25
+ }
26
+ `;
27
+
28
+ exports[`normalize json content should bubble mark from text to list item 1`] = `
29
+ Object {
30
+ "content": Array [
31
+ Object {
32
+ "attrs": Object {
33
+ "bullet": Object {
34
+ "type": "disc",
35
+ },
36
+ },
37
+ "content": Array [
38
+ Object {
39
+ "content": Array [
40
+ Object {
41
+ "content": Array [
42
+ Object {
43
+ "text": "lorem ipsum",
44
+ "type": "text",
45
+ },
46
+ ],
47
+ "type": "paragraph",
48
+ },
49
+ ],
50
+ "marks": Array [
51
+ Object {
52
+ "attrs": Object {
53
+ "value": "700",
54
+ },
55
+ "type": "font_weight",
56
+ },
57
+ ],
58
+ "type": "listItem",
59
+ },
60
+ ],
61
+ "type": "list",
62
+ },
63
+ ],
64
+ "type": "doc",
65
+ }
66
+ `;
67
+
68
+ exports[`normalize json content should bubble mark from two text nodes to paragraph 1`] = `
69
+ Object {
70
+ "content": Array [
71
+ Object {
72
+ "content": Array [
73
+ Object {
74
+ "text": "lorem",
75
+ "type": "text",
76
+ },
77
+ Object {
78
+ "marks": Array [
79
+ Object {
80
+ "attrs": Object {
81
+ "value": "#FF0000",
82
+ },
83
+ "type": "font_color",
84
+ },
85
+ ],
86
+ "text": " ipsum",
87
+ "type": "text",
88
+ },
89
+ ],
90
+ "marks": Array [
91
+ Object {
92
+ "attrs": Object {
93
+ "value": "700",
94
+ },
95
+ "type": "font_weight",
96
+ },
97
+ ],
98
+ "type": "paragraph",
99
+ },
100
+ ],
101
+ "type": "doc",
102
+ }
103
+ `;
104
+
105
+ exports[`normalize json content should bubble two marks 1`] = `
106
+ Object {
107
+ "content": Array [
108
+ Object {
109
+ "content": Array [
110
+ Object {
111
+ "text": "hello world",
112
+ "type": "text",
113
+ },
114
+ ],
115
+ "marks": Array [
116
+ Object {
117
+ "attrs": Object {
118
+ "value": "Bungee",
119
+ },
120
+ "type": "font_family",
121
+ },
122
+ Object {
123
+ "attrs": Object {
124
+ "value": "800",
125
+ },
126
+ "type": "font_weight",
127
+ },
128
+ ],
129
+ "type": "paragraph",
130
+ },
131
+ ],
132
+ "type": "doc",
133
+ }
134
+ `;
135
+
136
+ exports[`normalize json content should not bubble inline marks 1`] = `
137
+ Object {
138
+ "content": Array [
139
+ Object {
140
+ "content": Array [
141
+ Object {
142
+ "marks": Array [
143
+ Object {
144
+ "attrs": Object {
145
+ "underline": true,
146
+ },
147
+ "type": "text_decoration",
148
+ },
149
+ ],
150
+ "text": "hello world",
151
+ "type": "text",
152
+ },
153
+ ],
154
+ "type": "paragraph",
155
+ },
156
+ ],
157
+ "type": "doc",
158
+ }
159
+ `;
@@ -0,0 +1 @@
1
+ export { ContentNormalizer } from './ContentNormalizer';
@@ -112,6 +112,14 @@ img.ProseMirror-separator {
112
112
  animation: ProseMirror-cursor-blink 1.1s steps(2, start) infinite;
113
113
  }
114
114
 
115
+ .ProseMirror span {
116
+ display: block;
117
+ }
118
+
119
+ .ProseMirror :where(p, h1, h2, h3, h4) span {
120
+ display: initial;
121
+ }
122
+
115
123
  @keyframes ProseMirror-cursor-blink {
116
124
 
117
125
  to {
@@ -1,14 +1,9 @@
1
- const DEFAULT_COMPARATOR = (parent, child) => child.eq(parent);
2
-
3
- export function isMarkAppliedToParent({ doc }, position, checkingMark, comparator = DEFAULT_COMPARATOR) {
1
+ export function isMarkAppliedToParent({ doc }, position, checkingMark) {
4
2
  const steps = doc.resolve(position).path.reverse();
5
3
 
6
4
  for (const step of steps) {
7
5
  if (typeof step === 'number') continue;
8
-
9
- for (const mark of step.marks) {
10
- if (comparator(mark, checkingMark)) return true;
11
- }
6
+ if (checkingMark.isInSet(step.marks)) return true;
12
7
  }
13
8
 
14
9
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zipify/wysiwyg",
3
- "version": "2.0.0-0",
3
+ "version": "2.0.0-1",
4
4
  "description": "Zipify modification of TipTap text editor",
5
5
  "main": "dist/wysiwyg.mjs",
6
6
  "bin": {
@@ -45,6 +45,7 @@
45
45
  "@tiptap/vue-2": "^2.0.0-beta.85",
46
46
  "commander": "^9.4.0",
47
47
  "jsdom": "^20.0.0",
48
+ "lodash": "^4.17.21",
48
49
  "simplebar": "^5.3.8"
49
50
  },
50
51
  "peerDependencies": {
@@ -57,6 +58,7 @@
57
58
  "@babel/plugin-transform-runtime": "^7.18.10",
58
59
  "@babel/preset-env": "^7.19.0",
59
60
  "@babel/runtime": "^7.19.0",
61
+ "@optimize-lodash/rollup-plugin": "^3.0.0",
60
62
  "@rollup/plugin-babel": "^5.3.1",
61
63
  "@rollup/plugin-commonjs": "^22.0.2",
62
64
  "@rollup/plugin-node-resolve": "^14.0.0",
@@ -1,194 +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 build(content, options = {}) {
17
- return new ContentNormalizer({
18
- content,
19
- parser: options.parser || new BrowserDomParser()
20
- });
21
- }
22
-
23
- static normalize(content, options = {}) {
24
- return ContentNormalizer.build(content, options).normalize();
25
- }
26
-
27
- constructor({ content, parser }) {
28
- this._content = content;
29
- this._parser = parser;
30
- this.dom = null;
31
- }
32
-
33
- normalize() {
34
- if (typeof this._content !== 'string') {
35
- return this._content;
36
- }
37
- this.normalizeHTML();
38
- return this.normalizedHTML;
39
- }
40
-
41
- normalizeHTML() {
42
- this.dom = this._parser.parse(this._content.replace(/(\r)?\n/g, ''));
43
-
44
- this._removeComments();
45
- this.iterateNodes(this._normalizeBreakLines, (node) => node.tagName === 'BR');
46
- this.iterateNodes(this._removeEmptyNodes, this._isBlockNode);
47
- this.iterateNodes(this._normalizeListItems, (node) => node.tagName === 'LI');
48
- }
49
-
50
- get normalizedHTML() {
51
- return this.dom.body.innerHTML;
52
- }
53
-
54
- get _NodeFilter() {
55
- return this._parser.types.NodeFilter;
56
- }
57
-
58
- _removeComments() {
59
- const iterator = this.createNodeIterator(this._NodeFilter.SHOW_COMMENT);
60
-
61
- this.runIterator(iterator, (node) => node.remove());
62
- }
63
-
64
- createNodeIterator(whatToShow, filter) {
65
- return this.dom.createNodeIterator(this.dom.body, whatToShow, filter);
66
- }
67
-
68
- iterateNodes(handler, condition = () => true) {
69
- const checkCondition = (node) => node.tagName !== 'BODY' && condition.call(this, node);
70
-
71
- const iterator = this.createNodeIterator(this._NodeFilter.SHOW_ELEMENT, {
72
- acceptNode: (node) => checkCondition(node) ? this._NodeFilter.FILTER_ACCEPT : this._NodeFilter.FILTER_REJECT
73
- });
74
-
75
- this.runIterator(iterator, handler);
76
- }
77
-
78
- runIterator(iterator, handler) {
79
- let currentNode = iterator.nextNode();
80
-
81
- while (currentNode) {
82
- handler.call(this, currentNode);
83
- currentNode = iterator.nextNode();
84
- }
85
- }
86
-
87
- _removeEmptyNodes(node) {
88
- if (!node.innerHTML.trim()) node.remove();
89
- }
90
-
91
- _normalizeListItems(itemEl) {
92
- const fragment = this.dom.createDocumentFragment();
93
- const children = Array.from(itemEl.childNodes);
94
- let capturingParagraph;
95
- let previousNode;
96
-
97
- const append = (node) => {
98
- this._assignElementProperties(node, itemEl, ContentNormalizer.BLOCK_STYLES);
99
- fragment.append(node);
100
- };
101
-
102
- this._assignElementProperties(itemEl, itemEl.parentElement, ContentNormalizer.BLOCK_STYLES);
103
-
104
- for (const node of children) {
105
- if (this._isBlockNode(node)) {
106
- append(node);
107
- capturingParagraph = null;
108
- previousNode = node;
109
- continue;
110
- }
111
-
112
- if (node.tagName === 'BR' && previousNode && previousNode?.tagName !== 'BR') {
113
- node.remove();
114
- previousNode = node;
115
- continue;
116
- }
117
-
118
- if (node.tagName === 'BR') {
119
- const emptyLineEl = this.dom.createElement('p');
120
-
121
- emptyLineEl.append(node);
122
- append(emptyLineEl);
123
- capturingParagraph = null;
124
- previousNode = node;
125
- continue;
126
- }
127
-
128
- if (!capturingParagraph) {
129
- capturingParagraph = this.dom.createElement('p');
130
- append(capturingParagraph);
131
- }
132
-
133
- capturingParagraph.append(node);
134
- previousNode = node;
135
- }
136
-
137
- itemEl.append(fragment);
138
- this._removeStyleProperties(itemEl, ContentNormalizer.BLOCK_STYLES);
139
- }
140
-
141
- _isBlockNode(node) {
142
- return ContentNormalizer.BLOCK_NODE_NAMES.includes(node.tagName);
143
- }
144
-
145
- _assignElementProperties(target, source, properties) {
146
- for (const property of properties) {
147
- const value = source.style.getPropertyValue(property);
148
-
149
- if (value && !target.style.getPropertyValue(property)) {
150
- target.style.setProperty(property, value);
151
- }
152
- }
153
- }
154
-
155
- _removeStyleProperties(element, properties) {
156
- for (const property of properties) {
157
- element.style.removeProperty(property);
158
- }
159
-
160
- if (element.style.length === 0) {
161
- element.removeAttribute('style');
162
- }
163
- }
164
-
165
- _normalizeBreakLines({ parentElement }) {
166
- if (!this._isBlockNode(parentElement)) return;
167
- if (!parentElement.textContent) return;
168
-
169
- const fragment = this.dom.createDocumentFragment();
170
- const children = Array.from(parentElement.childNodes);
171
- const parentTemplate = parentElement.cloneNode(true);
172
-
173
- parentTemplate.innerHTML = '';
174
- let capturingParagraph = parentTemplate.cloneNode();
175
-
176
- const append = (node) => {
177
- this._assignElementProperties(node, parentElement, ContentNormalizer.BLOCK_STYLES);
178
- fragment.append(node);
179
- };
180
-
181
- for (const child of children) {
182
- if (child.tagName === 'BR') {
183
- append(capturingParagraph);
184
- capturingParagraph = parentTemplate.cloneNode();
185
- continue;
186
- }
187
-
188
- capturingParagraph.append(child);
189
- }
190
-
191
- fragment.append(capturingParagraph);
192
- parentElement.replaceWith(fragment);
193
- }
194
- }