@zipify/wysiwyg 2.0.0-2 → 2.0.0-3

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/wysiwyg.mjs CHANGED
@@ -26,7 +26,7 @@ var __privateMethod = (obj, member, method) => {
26
26
  __accessCheck(obj, member, "access private method");
27
27
  return method;
28
28
  };
29
- var _domParser, _parser, _NodeFilter, NodeFilter_get, _Node, Node_get, _removeComments, removeComments_fn, _createNodeIterator, createNodeIterator_fn, _iterateNodes, iterateNodes_fn, _runIterator, runIterator_fn, _removeEmptyNodes, removeEmptyNodes_fn, _normalizeListItems, normalizeListItems_fn, _isBlockNode, isBlockNode_fn, _assignElementProperties, assignElementProperties_fn, _removeStyleProperties, removeStyleProperties_fn, _normalizeBreakLines, normalizeBreakLines_fn, _normalizeBlockTextDecoration, normalizeBlockTextDecoration_fn, _moveTextDecorationToChildren, moveTextDecorationToChildren_fn, _parseTextDecoration, parseTextDecoration_fn, _wrapTextNode, wrapTextNode_fn, _iterateNodes2, iterateNodes_fn2, _iterateChildNodes, iterateChildNodes_fn, _bubbleMarks, bubbleMarks_fn, _canBubbleMark, canBubbleMark_fn, _includesMark, includesMark_fn, _includesMarkType, includesMarkType_fn, _removeMark, removeMark_fn, _addMark, addMark_fn, _findMarkIndexByType, findMarkIndexByType_fn, _buildHtml, buildHtml_fn, _buildJson, buildJson_fn, _textBlock, textBlock_fn, _normalizeTextBlockArgs, normalizeTextBlockArgs_fn;
29
+ var _domParser, _parser, _NodeFilter, NodeFilter_get, _Node, Node_get, _removeComments, removeComments_fn, _createNodeIterator, createNodeIterator_fn, _iterateNodes, iterateNodes_fn, _runIterator, runIterator_fn, _removeEmptyNodes, removeEmptyNodes_fn, _normalizeListItems, normalizeListItems_fn, _isBlockNode, isBlockNode_fn, _assignElementProperties, assignElementProperties_fn, _removeStyleProperties, removeStyleProperties_fn, _normalizeBreakLines, normalizeBreakLines_fn, _normalizeBlockTextDecoration, normalizeBlockTextDecoration_fn, _moveTextDecorationToChildren, moveTextDecorationToChildren_fn, _parseTextDecoration, parseTextDecoration_fn, _normalizeBlockBackgroundColor, normalizeBlockBackgroundColor_fn, _moveBackgroundColorToChildren, moveBackgroundColorToChildren_fn, _wrapTextNode, wrapTextNode_fn, _iterateNodes2, iterateNodes_fn2, _iterateChildNodes, iterateChildNodes_fn, _bubbleMarks, bubbleMarks_fn, _canBubbleMark, canBubbleMark_fn, _includesMark, includesMark_fn, _includesMarkType, includesMarkType_fn, _removeMark, removeMark_fn, _addMark, addMark_fn, _findMarkIndexByType, findMarkIndexByType_fn, _buildHtml, buildHtml_fn, _buildJson, buildJson_fn, _textBlock, textBlock_fn, _normalizeTextBlockArgs, normalizeTextBlockArgs_fn;
30
30
  import { computed, ref, watch, inject, onUnmounted, nextTick, provide, onMounted, toRef, unref, reactive } from "vue";
31
31
  import { ColorModel, ZipifyColorPicker } from "@zipify/colorpicker";
32
32
  function OrderedMap(content) {
@@ -14031,7 +14031,7 @@ const TextSettings = Object.freeze({
14031
14031
  return [this.ALIGNMENT, this.LINE_HEIGHT, this.MARGIN];
14032
14032
  },
14033
14033
  get inlineMarks() {
14034
- return [this.TEXT_DECORATION, this.LINK, this.SUPERSCRIPT];
14034
+ return [this.TEXT_DECORATION, this.LINK, this.SUPERSCRIPT, this.BACKGROUND_COLOR];
14035
14035
  },
14036
14036
  get marks() {
14037
14037
  return [
@@ -14459,15 +14459,10 @@ const resolveTextPosition = ($from, $to, node, position) => ({
14459
14459
  from: Math.max(position, $from.pos),
14460
14460
  to: Math.min(position + node.nodeSize, $to.pos)
14461
14461
  });
14462
- function resolveNodeTextOffset({ path }, node) {
14463
- const nodes = path.filter((step) => typeof step === "object");
14464
- const index = nodes.indexOf(node);
14465
- return nodes.slice(index).reverse().length;
14466
- }
14467
- function isNodeFullySelected($from, $to, node, position) {
14468
- const offset2 = resolveNodeTextOffset($from, node);
14469
- const isFromMatch = $from.pos - offset2 <= position;
14470
- const isToMatch = $to.pos + offset2 >= node.nodeSize + position;
14462
+ function isNodeFullySelected(doc2, selection, node, position) {
14463
+ const offset2 = doc2.resolve(position).depth + 1;
14464
+ const isFromMatch = selection.from - offset2 <= position;
14465
+ const isToMatch = selection.to + offset2 >= node.nodeSize + position;
14471
14466
  return isFromMatch && isToMatch;
14472
14467
  }
14473
14468
  function isMarkAppliedToParent(doc2, position, checkingMark) {
@@ -19558,6 +19553,8 @@ const _HtmlNormalizer = class extends BaseNormalizer {
19558
19553
  __privateAdd(this, _normalizeBlockTextDecoration);
19559
19554
  __privateAdd(this, _moveTextDecorationToChildren);
19560
19555
  __privateAdd(this, _parseTextDecoration);
19556
+ __privateAdd(this, _normalizeBlockBackgroundColor);
19557
+ __privateAdd(this, _moveBackgroundColorToChildren);
19561
19558
  __privateAdd(this, _wrapTextNode);
19562
19559
  __privateAdd(this, _parser, void 0);
19563
19560
  __privateSet(this, _parser, parser);
@@ -19574,6 +19571,7 @@ const _HtmlNormalizer = class extends BaseNormalizer {
19574
19571
  __privateMethod(this, _iterateNodes, iterateNodes_fn).call(this, __privateMethod(this, _removeEmptyNodes, removeEmptyNodes_fn), __privateMethod(this, _isBlockNode, isBlockNode_fn));
19575
19572
  __privateMethod(this, _iterateNodes, iterateNodes_fn).call(this, __privateMethod(this, _normalizeListItems, normalizeListItems_fn), (node) => node.tagName === "LI");
19576
19573
  __privateMethod(this, _normalizeBlockTextDecoration, normalizeBlockTextDecoration_fn).call(this);
19574
+ __privateMethod(this, _normalizeBlockBackgroundColor, normalizeBlockBackgroundColor_fn).call(this);
19577
19575
  }
19578
19576
  get normalizedHTML() {
19579
19577
  return this.dom.body.innerHTML;
@@ -19746,6 +19744,25 @@ parseTextDecoration_fn = function(element) {
19746
19744
  line_through: decoration.includes("line-through")
19747
19745
  };
19748
19746
  };
19747
+ _normalizeBlockBackgroundColor = new WeakSet();
19748
+ normalizeBlockBackgroundColor_fn = function() {
19749
+ const blockEls = this.dom.querySelectorAll('[style*="background-color"]:where(p, h1, h2, h3, h4, li)');
19750
+ for (const blockEl of blockEls) {
19751
+ __privateMethod(this, _moveBackgroundColorToChildren, moveBackgroundColorToChildren_fn).call(this, blockEl);
19752
+ }
19753
+ };
19754
+ _moveBackgroundColorToChildren = new WeakSet();
19755
+ moveBackgroundColorToChildren_fn = function(blockEl) {
19756
+ const blockColor = blockEl.style.backgroundColor;
19757
+ blockEl.style.removeProperty("background-color");
19758
+ if (!blockEl.style.cssText)
19759
+ blockEl.removeAttribute("style");
19760
+ for (const childNode of blockEl.childNodes) {
19761
+ const textEl = __privateMethod(this, _wrapTextNode, wrapTextNode_fn).call(this, blockEl, childNode);
19762
+ const color = textEl.style.backgroundColor || blockColor;
19763
+ textEl.style.backgroundColor = color;
19764
+ }
19765
+ };
19749
19766
  _wrapTextNode = new WeakSet();
19750
19767
  wrapTextNode_fn = function(parent, node) {
19751
19768
  if (node.nodeType !== __privateGet(this, _Node, Node_get).TEXT_NODE)
@@ -20680,7 +20697,7 @@ canBubbleMark_fn = function(node, childMark) {
20680
20697
  for (const child of node.content) {
20681
20698
  if (!child.marks)
20682
20699
  return false;
20683
- if (!__privateMethod(this, _includesMarkType, includesMarkType_fn).call(this, child, childMark.type))
20700
+ if (!__privateMethod(this, _includesMark, includesMark_fn).call(this, child, childMark))
20684
20701
  return false;
20685
20702
  }
20686
20703
  return true;
@@ -24177,7 +24194,7 @@ const StylePreset = Extension.create({
24177
24194
  chain().storeSelection().expandSelectionToBlock().removeMarks(TextSettings.marks).resetAttributes(NodeTypes.PARAGRAPH, TextSettings.attributes).resetAttributes(NodeTypes.HEADING, TextSettings.attributes).restoreSelection().run();
24178
24195
  }),
24179
24196
  removeFormat: createCommand(({ chain }) => {
24180
- chain().storeSelection().expandSelectionToBlock().unsetAllMarks().applyDefaultPreset().restoreSelection().run();
24197
+ chain().storeSelection().expandSelectionToBlock().removeAllMarks().applyDefaultPreset().restoreSelection().run();
24181
24198
  })
24182
24199
  };
24183
24200
  },
@@ -24394,7 +24411,6 @@ const FontColor = Mark.create({
24394
24411
  });
24395
24412
  const BackgroundColor = Mark.create({
24396
24413
  name: TextSettings.BACKGROUND_COLOR,
24397
- group: MarkGroups.SETTINGS,
24398
24414
  addAttributes: () => ({
24399
24415
  value: { required: true }
24400
24416
  }),
@@ -26778,7 +26794,7 @@ const NodeProcessor = Extension.create({
26778
26794
  tr.addMark(textPosition.from, textPosition.to, applyingMark);
26779
26795
  return;
26780
26796
  }
26781
- if (isNodeFullySelected($from, $to, node, position)) {
26797
+ if (isNodeFullySelected(tr.doc, tr.selection, node, position)) {
26782
26798
  tr.step(new AddNodeMarkStep(position, applyingMark));
26783
26799
  }
26784
26800
  });
@@ -26824,6 +26840,15 @@ const NodeProcessor = Extension.create({
26824
26840
  return unref(defaultRef);
26825
26841
  });
26826
26842
  }),
26843
+ removeAllMarks: createCommand(({ state, commands: commands2 }) => {
26844
+ const { tr, doc: doc2 } = state;
26845
+ const { from: from2, to } = tr.selection;
26846
+ doc2.nodesBetween(from2, to, (node, position) => {
26847
+ for (const mark of node.marks) {
26848
+ commands2._removeNodeMark({ tr, node, position, mark });
26849
+ }
26850
+ });
26851
+ }),
26827
26852
  removeMarks: createCommand(({ state, commands: commands2 }, marks) => {
26828
26853
  const { tr, doc: doc2 } = state;
26829
26854
  const { from: from2, to } = tr.selection;
@@ -18,7 +18,7 @@ export const TextSettings = Object.freeze({
18
18
  },
19
19
 
20
20
  get inlineMarks() {
21
- return [this.TEXT_DECORATION, this.LINK, this.SUPERSCRIPT];
21
+ return [this.TEXT_DECORATION, this.LINK, this.SUPERSCRIPT, this.BACKGROUND_COLOR];
22
22
  },
23
23
 
24
24
  get marks() {
@@ -1,10 +1,9 @@
1
1
  import { Mark } from '@tiptap/vue-2';
2
2
  import { convertColor, createCommand, renderMark } from '../utils';
3
- import { MarkGroups, TextSettings } from '../enums';
3
+ import { TextSettings } from '../enums';
4
4
 
5
5
  export const BackgroundColor = Mark.create({
6
6
  name: TextSettings.BACKGROUND_COLOR,
7
- group: MarkGroups.SETTINGS,
8
7
 
9
8
  addAttributes: () => ({
10
9
  value: { required: true }
@@ -176,7 +176,7 @@ export const StylePreset = Extension.create({
176
176
  chain()
177
177
  .storeSelection()
178
178
  .expandSelectionToBlock()
179
- .unsetAllMarks()
179
+ .removeAllMarks()
180
180
  .applyDefaultPreset()
181
181
  .restoreSelection()
182
182
  .run();
@@ -6,18 +6,18 @@ Object {
6
6
  Object {
7
7
  "content": Array [
8
8
  Object {
9
+ "marks": Array [
10
+ Object {
11
+ "attrs": Object {
12
+ "value": "green",
13
+ },
14
+ "type": "background_color",
15
+ },
16
+ ],
9
17
  "text": "hello world",
10
18
  "type": "text",
11
19
  },
12
20
  ],
13
- "marks": Array [
14
- Object {
15
- "attrs": Object {
16
- "value": "green",
17
- },
18
- "type": "background_color",
19
- },
20
- ],
21
21
  "type": "paragraph",
22
22
  },
23
23
  ],
@@ -31,18 +31,18 @@ Object {
31
31
  Object {
32
32
  "content": Array [
33
33
  Object {
34
+ "marks": Array [
35
+ Object {
36
+ "attrs": Object {
37
+ "value": "#FF0000",
38
+ },
39
+ "type": "background_color",
40
+ },
41
+ ],
34
42
  "text": "test",
35
43
  "type": "text",
36
44
  },
37
45
  ],
38
- "marks": Array [
39
- Object {
40
- "attrs": Object {
41
- "value": "#FF0000",
42
- },
43
- "type": "background_color",
44
- },
45
- ],
46
46
  "type": "paragraph",
47
47
  },
48
48
  ],
@@ -126,18 +126,18 @@ Object {
126
126
  "type": "text",
127
127
  },
128
128
  Object {
129
+ "marks": Array [
130
+ Object {
131
+ "attrs": Object {
132
+ "value": "#FF0000",
133
+ },
134
+ "type": "background_color",
135
+ },
136
+ ],
129
137
  "text": " ipsum",
130
138
  "type": "text",
131
139
  },
132
140
  ],
133
- "marks": Array [
134
- Object {
135
- "attrs": Object {
136
- "value": "#FF0000",
137
- },
138
- "type": "background_color",
139
- },
140
- ],
141
141
  "type": "paragraph",
142
142
  },
143
143
  ],
@@ -145,4 +145,4 @@ Object {
145
145
  }
146
146
  `;
147
147
 
148
- exports[`rendering should render html 1`] = `"<span style="--zw-background-color:green;" class="zw-style"><p class="zw-style">hello world</p></span>"`;
148
+ exports[`rendering should render html 1`] = `"<p class="zw-style"><span style="--zw-background-color:green;" class="zw-style">hello world</span></p>"`;
@@ -66,7 +66,7 @@ export const NodeProcessor = Extension.create({
66
66
  return;
67
67
  }
68
68
 
69
- if (isNodeFullySelected($from, $to, node, position)) {
69
+ if (isNodeFullySelected(tr.doc, tr.selection, node, position)) {
70
70
  tr.step(new AddNodeMarkStep(position, applyingMark));
71
71
  }
72
72
  });
@@ -117,6 +117,17 @@ export const NodeProcessor = Extension.create({
117
117
  });
118
118
  }),
119
119
 
120
+ removeAllMarks: createCommand(({ state, commands }) => {
121
+ const { tr, doc } = state;
122
+ const { from, to } = tr.selection;
123
+
124
+ doc.nodesBetween(from, to, (node, position) => {
125
+ for (const mark of node.marks) {
126
+ commands._removeNodeMark({ tr, node, position, mark });
127
+ }
128
+ });
129
+ }),
130
+
120
131
  removeMarks: createCommand(({ state, commands }, marks) => {
121
132
  const { tr, doc } = state;
122
133
  const { from, to } = tr.selection;
@@ -34,6 +34,7 @@ export class HtmlNormalizer extends BaseNormalizer {
34
34
  this.#iterateNodes(this.#removeEmptyNodes, this.#isBlockNode);
35
35
  this.#iterateNodes(this.#normalizeListItems, (node) => node.tagName === 'LI');
36
36
  this.#normalizeBlockTextDecoration();
37
+ this.#normalizeBlockBackgroundColor();
37
38
  }
38
39
 
39
40
  get normalizedHTML() {
@@ -232,6 +233,28 @@ export class HtmlNormalizer extends BaseNormalizer {
232
233
  };
233
234
  }
234
235
 
236
+ #normalizeBlockBackgroundColor() {
237
+ const blockEls = this.dom.querySelectorAll('[style*="background-color"]:where(p, h1, h2, h3, h4, li)');
238
+
239
+ for (const blockEl of blockEls) {
240
+ this.#moveBackgroundColorToChildren(blockEl);
241
+ }
242
+ }
243
+
244
+ #moveBackgroundColorToChildren(blockEl) {
245
+ const blockColor = blockEl.style.backgroundColor;
246
+
247
+ blockEl.style.removeProperty('background-color');
248
+ if (!blockEl.style.cssText) blockEl.removeAttribute('style');
249
+
250
+ for (const childNode of blockEl.childNodes) {
251
+ const textEl = this.#wrapTextNode(blockEl, childNode);
252
+ const color = textEl.style.backgroundColor || blockColor;
253
+
254
+ textEl.style.backgroundColor = color;
255
+ }
256
+ }
257
+
235
258
  #wrapTextNode(parent, node) {
236
259
  if (node.nodeType !== this.#Node.TEXT_NODE) return node;
237
260
 
@@ -46,7 +46,7 @@ export class JsonNormalizer extends BaseNormalizer {
46
46
 
47
47
  for (const child of node.content) {
48
48
  if (!child.marks) return false;
49
- if (!this.#includesMarkType(child, childMark.type)) return false;
49
+ if (!this.#includesMark(child, childMark)) return false;
50
50
  }
51
51
 
52
52
  return true;
@@ -67,4 +67,19 @@ describe('normalize json content', () => {
67
67
 
68
68
  expect(ContentNormalizer.normalize(input)).toMatchSnapshot();
69
69
  });
70
+
71
+ test('should not marge mark with same type', () => {
72
+ const input = NodeFactory.doc([
73
+ NodeFactory.paragraph([
74
+ NodeFactory.text('lorem', [
75
+ NodeFactory.mark(TextSettings.FONT_WEIGHT, { value: '700' })
76
+ ]),
77
+ NodeFactory.text(' ipsum', [
78
+ NodeFactory.mark(TextSettings.FONT_WEIGHT, { value: '400' })
79
+ ])
80
+ ])
81
+ ]);
82
+
83
+ expect(ContentNormalizer.normalize(input)).toMatchSnapshot();
84
+ });
70
85
  });
@@ -157,3 +157,40 @@ Object {
157
157
  "type": "doc",
158
158
  }
159
159
  `;
160
+
161
+ exports[`normalize json content should not marge mark with same type 1`] = `
162
+ Object {
163
+ "content": Array [
164
+ Object {
165
+ "content": Array [
166
+ Object {
167
+ "marks": Array [
168
+ Object {
169
+ "attrs": Object {
170
+ "value": "700",
171
+ },
172
+ "type": "font_weight",
173
+ },
174
+ ],
175
+ "text": "lorem",
176
+ "type": "text",
177
+ },
178
+ Object {
179
+ "marks": Array [
180
+ Object {
181
+ "attrs": Object {
182
+ "value": "400",
183
+ },
184
+ "type": "font_weight",
185
+ },
186
+ ],
187
+ "text": " ipsum",
188
+ "type": "text",
189
+ },
190
+ ],
191
+ "type": "paragraph",
192
+ },
193
+ ],
194
+ "type": "doc",
195
+ }
196
+ `;
@@ -1,52 +1,43 @@
1
1
  import { isNodeFullySelected } from '../isNodeFullySelected';
2
2
 
3
- const createResolvedPosition = (attrs = {}) => ({
4
- pos: 0,
5
- path: [],
3
+ const createResolvedPosition = (attrs = {}) => ({ ...attrs });
4
+ const createSelection = (from, to) => ({ from, to });
5
+
6
+ const createNode = (attrs = {}) => ({
7
+ resolve: jest.fn(() => 0),
6
8
  ...attrs
7
9
  });
8
10
 
9
- const createNode = (attrs = {}) => ({ ...attrs });
10
-
11
11
  describe('is node fully selected', () => {
12
12
  test('should return false if selected part of text node', () => {
13
- const paragraph = createNode();
14
- const isSelected = isNodeFullySelected(
15
- createResolvedPosition({ pos: 7, path: [createNode(), 0, 0, paragraph, 0, 1] }),
16
- createResolvedPosition({ pos: 12, path: [createNode(), 0, 0, paragraph, 0, 1] }),
17
- paragraph,
18
- 0
19
- );
13
+ const doc = createNode();
14
+ const paragraph = createNode({ nodeSize: 245 });
15
+
16
+ doc.resolve.mockReturnValue(createResolvedPosition({ depth: 0 }));
17
+
18
+ const isSelected = isNodeFullySelected(doc, createSelection(7, 12), paragraph, 0);
20
19
 
21
20
  expect(isSelected).toBe(false);
22
21
  });
23
22
 
24
23
  test('should return true if selected paragraph node', () => {
24
+ const doc = createNode();
25
25
  const paragraph = createNode({ nodeSize: 245 });
26
- const isSelected = isNodeFullySelected(
27
- createResolvedPosition({ pos: 1, path: [createNode(), 0, 0, paragraph, 0, 1] }),
28
- createResolvedPosition({ pos: 244, path: [createNode(), 0, 0, paragraph, 0, 1] }),
29
- paragraph,
30
- 0
31
- );
26
+
27
+ doc.resolve.mockReturnValue(createResolvedPosition({ depth: 0 }));
28
+
29
+ const isSelected = isNodeFullySelected(doc, createSelection(1, 244), paragraph, 0);
32
30
 
33
31
  expect(isSelected).toBe(true);
34
32
  });
35
33
 
36
34
  test('should return true if selected list item node', () => {
35
+ const doc = createNode();
37
36
  const listItem = createNode({ nodeSize: 247 });
38
- const isSelected = isNodeFullySelected(
39
- createResolvedPosition({
40
- pos: 3,
41
- path: [createNode(), 0, 0, createNode(), 0, 1, listItem, 0, 2, createNode(), 0, 3]
42
- }),
43
- createResolvedPosition({
44
- pos: 246,
45
- path: [createNode(), 0, 0, createNode(), 0, 1, listItem, 0, 2, createNode(), 0, 3]
46
- }),
47
- listItem,
48
- 1
49
- );
37
+
38
+ doc.resolve.mockReturnValue(createResolvedPosition({ depth: 2 }));
39
+
40
+ const isSelected = isNodeFullySelected(doc, createSelection(3, 246), listItem, 1);
50
41
 
51
42
  expect(isSelected).toBe(true);
52
43
  });
@@ -1,14 +1,7 @@
1
- function resolveNodeTextOffset({ path }, node) {
2
- const nodes = path.filter((step) => typeof step === 'object');
3
- const index = nodes.indexOf(node);
4
-
5
- return nodes.slice(index).reverse().length;
6
- }
7
-
8
- export function isNodeFullySelected($from, $to, node, position) {
9
- const offset = resolveNodeTextOffset($from, node);
10
- const isFromMatch = $from.pos - offset <= position;
11
- const isToMatch = $to.pos + offset >= node.nodeSize + position;
1
+ export function isNodeFullySelected(doc, selection, node, position) {
2
+ const offset = doc.resolve(position).depth + 1;
3
+ const isFromMatch = selection.from - offset <= position;
4
+ const isToMatch = selection.to + offset >= node.nodeSize + position;
12
5
 
13
6
  return isFromMatch && isToMatch;
14
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zipify/wysiwyg",
3
- "version": "2.0.0-2",
3
+ "version": "2.0.0-3",
4
4
  "description": "Zipify modification of TipTap text editor",
5
5
  "main": "dist/wysiwyg.mjs",
6
6
  "bin": {