@zipify/wysiwyg 1.0.0-dev.5 → 1.0.0-dev.52

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 (180) hide show
  1. package/.editorconfig +1 -1
  2. package/.eslintignore +1 -0
  3. package/.eslintrc.js +2 -2
  4. package/.github/dependabot.yaml +1 -0
  5. package/.lintstagedrc +2 -2
  6. package/.release-it.json +3 -1
  7. package/.stylelintignore +1 -0
  8. package/.stylelintrc +0 -4
  9. package/README.md +2 -2
  10. package/config/jest/setupTests.js +4 -0
  11. package/config/vite/example.config.js +25 -0
  12. package/config/vite/lib.config.js +30 -0
  13. package/config/{webpack → vite}/settings.js +0 -0
  14. package/dist/wysiwyg.css +1 -0
  15. package/dist/wysiwyg.mjs +18305 -0
  16. package/dist/wysiwyg.mjs.map +1 -0
  17. package/example/ExampleApp.vue +20 -1
  18. package/example/{example.html → index.html} +1 -0
  19. package/example/pageBlocks.js +31 -0
  20. package/example/presets.js +2 -2
  21. package/jest.config.js +3 -1
  22. package/lib/Wysiwyg.vue +50 -25
  23. package/lib/__tests__/utils/NodeFactory.js +13 -0
  24. package/lib/assets/icons/alignment-center.svg +3 -0
  25. package/lib/assets/icons/alignment-justify.svg +3 -0
  26. package/lib/assets/icons/alignment-left.svg +3 -0
  27. package/lib/assets/icons/alignment-right.svg +3 -0
  28. package/lib/assets/icons/arrow.svg +3 -0
  29. package/lib/assets/icons/background-color.svg +3 -0
  30. package/lib/assets/icons/case-style.svg +3 -0
  31. package/lib/assets/icons/font-color.svg +5 -0
  32. package/lib/assets/icons/italic.svg +3 -0
  33. package/lib/assets/icons/line-height.svg +3 -0
  34. package/lib/assets/icons/link.svg +3 -0
  35. package/lib/assets/icons/list-circle.svg +3 -0
  36. package/lib/assets/icons/list-decimal.svg +3 -0
  37. package/lib/assets/icons/list-disc.svg +3 -0
  38. package/lib/assets/icons/list-latin.svg +3 -0
  39. package/lib/assets/icons/list-roman.svg +3 -0
  40. package/lib/assets/icons/list-square.svg +3 -0
  41. package/lib/assets/icons/remove-format.svg +3 -0
  42. package/lib/assets/icons/reset-styles.svg +3 -0
  43. package/lib/assets/icons/strike-through.svg +3 -0
  44. package/lib/assets/icons/superscript.svg +3 -0
  45. package/lib/assets/icons/underline.svg +3 -0
  46. package/lib/assets/icons/unlink.svg +3 -0
  47. package/lib/components/base/Button.vue +21 -1
  48. package/lib/components/base/Checkbox.vue +89 -0
  49. package/lib/components/base/FieldLabel.vue +2 -1
  50. package/lib/components/base/Icon.vue +18 -10
  51. package/lib/components/base/Modal.vue +0 -1
  52. package/lib/components/base/NumberField.vue +1 -1
  53. package/lib/components/base/ScrollView.vue +0 -2
  54. package/lib/components/base/TextField.vue +106 -0
  55. package/lib/components/base/__tests__/Icon.test.js +6 -13
  56. package/lib/components/base/__tests__/Modal.test.js +6 -1
  57. package/lib/components/base/__tests__/TextField.test.js +57 -0
  58. package/lib/components/base/__tests__/__snapshots__/TextField.test.js.snap +9 -0
  59. package/lib/components/base/colorPicker/ColorPicker.vue +1 -1
  60. package/lib/components/base/colorPicker/composables/usePickerHotkeys.js +2 -1
  61. package/lib/components/base/composables/__tests__/useValidator.test.js +44 -0
  62. package/lib/components/base/composables/index.js +1 -0
  63. package/lib/components/base/composables/useValidator.js +23 -0
  64. package/lib/components/base/dropdown/Dropdown.vue +15 -3
  65. package/lib/components/base/dropdown/DropdownActivator.vue +19 -3
  66. package/lib/components/base/index.js +3 -1
  67. package/lib/components/toolbar/Toolbar.vue +49 -9
  68. package/lib/components/toolbar/ToolbarFull.vue +10 -2
  69. package/lib/components/toolbar/__tests__/Toolbar.test.js +6 -0
  70. package/lib/components/toolbar/controls/FontSizeControl.vue +7 -0
  71. package/lib/components/toolbar/controls/ListControl.vue +1 -5
  72. package/lib/components/toolbar/controls/StylePresetControl.vue +14 -1
  73. package/lib/components/toolbar/controls/UnderlineControl.vue +2 -2
  74. package/lib/components/toolbar/controls/__tests__/StylePresetControl.test.js +16 -0
  75. package/lib/components/toolbar/controls/__tests__/UnderlineControl.test.js +4 -0
  76. package/lib/components/toolbar/controls/index.js +1 -0
  77. package/lib/components/toolbar/controls/link/LinkControl.vue +155 -0
  78. package/lib/components/toolbar/controls/link/LinkControlApply.vue +35 -0
  79. package/lib/components/toolbar/controls/link/LinkControlHeader.vue +67 -0
  80. package/lib/components/toolbar/controls/link/__tests__/LinkControl.test.js +79 -0
  81. package/lib/components/toolbar/controls/link/__tests__/LinkControlHeader.test.js +42 -0
  82. package/lib/components/toolbar/controls/link/composables/__tests__/__snapshots__/useLink.test.js.snap +8 -0
  83. package/lib/components/toolbar/controls/link/composables/__tests__/useLink.test.js +114 -0
  84. package/lib/components/toolbar/controls/link/composables/index.js +1 -0
  85. package/lib/components/toolbar/controls/link/composables/useLink.js +61 -0
  86. package/lib/components/toolbar/controls/link/destination/LinkControlDestination.vue +103 -0
  87. package/lib/components/toolbar/controls/link/destination/LinkControlPageBlock.vue +54 -0
  88. package/lib/components/toolbar/controls/link/destination/LinkControlUrl.vue +52 -0
  89. package/lib/components/toolbar/controls/link/destination/__tests__/LinkControlPageBlock.test.js +36 -0
  90. package/lib/components/toolbar/controls/link/destination/__tests__/LinkControlUrl.test.js +46 -0
  91. package/lib/components/toolbar/controls/link/destination/__tests__/__snapshots__/LinkControlPageBlock.test.js.snap +9 -0
  92. package/lib/components/toolbar/controls/link/destination/__tests__/__snapshots__/LinkControlUrl.test.js.snap +17 -0
  93. package/lib/components/toolbar/controls/link/destination/index.js +1 -0
  94. package/lib/components/toolbar/controls/link/index.js +1 -0
  95. package/lib/composables/__tests__/useEditor.test.js +2 -2
  96. package/lib/composables/useEditor.js +5 -7
  97. package/lib/composables/useToolbar.js +23 -28
  98. package/lib/directives/__tests__/outClick.test.js +6 -0
  99. package/lib/directives/outClick.js +19 -6
  100. package/lib/enums/Alignments.js +10 -1
  101. package/lib/enums/LinkDestinations.js +4 -0
  102. package/lib/enums/LinkTargets.js +4 -0
  103. package/lib/enums/TextSettings.js +3 -1
  104. package/lib/enums/index.js +2 -0
  105. package/lib/extensions/Alignment.js +21 -7
  106. package/lib/extensions/BackgroundColor.js +14 -6
  107. package/lib/extensions/DeviceManager.js +0 -4
  108. package/lib/extensions/FontColor.js +14 -6
  109. package/lib/extensions/FontFamily.js +25 -8
  110. package/lib/extensions/FontSize.js +31 -12
  111. package/lib/extensions/FontStyle.js +23 -13
  112. package/lib/extensions/FontWeight.js +24 -14
  113. package/lib/extensions/LineHeight.js +31 -28
  114. package/lib/extensions/Link.js +89 -0
  115. package/lib/extensions/StylePreset.js +16 -15
  116. package/lib/extensions/TextDecoration.js +45 -12
  117. package/lib/extensions/__tests__/Alignment.test.js +11 -5
  118. package/lib/extensions/__tests__/BackgroundColor.test.js +11 -5
  119. package/lib/extensions/__tests__/CaseStyle.test.js +3 -5
  120. package/lib/extensions/__tests__/FontColor.test.js +11 -5
  121. package/lib/extensions/__tests__/FontFamily.test.js +32 -7
  122. package/lib/extensions/__tests__/FontSize.test.js +13 -6
  123. package/lib/extensions/__tests__/FontStyle.test.js +11 -5
  124. package/lib/extensions/__tests__/FontWeight.test.js +19 -5
  125. package/lib/extensions/__tests__/LineHeight.test.js +23 -11
  126. package/lib/extensions/__tests__/Link.test.js +102 -0
  127. package/lib/extensions/__tests__/StylePreset.test.js +70 -6
  128. package/lib/extensions/__tests__/TextDecoration.test.js +51 -5
  129. package/lib/extensions/__tests__/__snapshots__/Alignment.test.js.snap +26 -2
  130. package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +30 -1
  131. package/lib/extensions/__tests__/__snapshots__/FontColor.test.js.snap +18 -1
  132. package/lib/extensions/__tests__/__snapshots__/FontFamily.test.js.snap +88 -1
  133. package/lib/extensions/__tests__/__snapshots__/FontSize.test.js.snap +33 -2
  134. package/lib/extensions/__tests__/__snapshots__/FontStyle.test.js.snap +25 -4
  135. package/lib/extensions/__tests__/__snapshots__/FontWeight.test.js.snap +47 -1
  136. package/lib/extensions/__tests__/__snapshots__/LineHeight.test.js.snap +26 -2
  137. package/lib/extensions/__tests__/__snapshots__/Link.test.js.snap +225 -0
  138. package/lib/extensions/__tests__/__snapshots__/StylePreset.test.js.snap +6 -2
  139. package/lib/extensions/__tests__/__snapshots__/TextDecoration.test.js.snap +183 -3
  140. package/lib/extensions/core/CopyPasteProcessor.js +10 -0
  141. package/lib/extensions/core/TextProcessor.js +10 -0
  142. package/lib/extensions/core/__tests__/NodeProcessor.test.js +3 -5
  143. package/lib/extensions/core/__tests__/SelectionProcessor.test.js +3 -5
  144. package/lib/extensions/core/__tests__/TextProcessor.test.js +138 -12
  145. package/lib/extensions/core/__tests__/__snapshots__/TextProcessor.test.js.snap +26 -0
  146. package/lib/extensions/core/index.js +11 -2
  147. package/lib/extensions/core/plugins/PastePlugin.js +57 -0
  148. package/lib/extensions/core/plugins/ProseMirrorPlugin.js +20 -0
  149. package/lib/extensions/core/plugins/index.js +1 -0
  150. package/lib/extensions/index.js +46 -34
  151. package/lib/extensions/list/__tests__/List.test.js +3 -5
  152. package/lib/extensions/list/__tests__/__snapshots__/List.test.js.snap +45 -15
  153. package/lib/injectionTokens.js +2 -1
  154. package/lib/services/ContentNormalizer.js +113 -29
  155. package/lib/services/ContextWidnow.js +23 -0
  156. package/lib/services/__tests__/ContentNormalizer.test.js +75 -7
  157. package/lib/services/index.js +1 -0
  158. package/lib/styles/content.css +102 -13
  159. package/lib/styles/helpers/offsets.css +16 -0
  160. package/lib/styles/variables.css +6 -0
  161. package/lib/utils/__tests__/__snapshots__/renderInlineSetting.test.js.snap +4 -4
  162. package/lib/utils/__tests__/convertAlignment.test.js +16 -0
  163. package/lib/utils/__tests__/convertFontSize.test.js +21 -0
  164. package/lib/utils/__tests__/convertLineHeight.test.js +21 -0
  165. package/lib/utils/convertAlignment.js +12 -0
  166. package/lib/utils/convertColor.js +1 -1
  167. package/lib/utils/convertFontSize.js +8 -0
  168. package/lib/utils/convertLineHeight.js +17 -0
  169. package/lib/utils/importIcon.js +13 -0
  170. package/lib/utils/index.js +4 -0
  171. package/lib/utils/renderInlineSetting.js +1 -1
  172. package/package.json +21 -25
  173. package/config/webpack/example.config.js +0 -86
  174. package/config/webpack/loaders/index.js +0 -6
  175. package/config/webpack/loaders/js-loader.js +0 -5
  176. package/config/webpack/loaders/style-loader.js +0 -7
  177. package/config/webpack/loaders/svg-loader.js +0 -4
  178. package/config/webpack/loaders/vue-loader.js +0 -4
  179. package/lib/assets/icons.svg +0 -69
  180. package/lib/composables/__tests__/useToolbar.test.js +0 -56
@@ -225,6 +225,36 @@ Object {
225
225
  }
226
226
  `;
227
227
 
228
+ exports[`parsing html should get both from rendered view 1`] = `
229
+ Object {
230
+ "content": Array [
231
+ Object {
232
+ "content": Array [
233
+ Object {
234
+ "marks": Array [
235
+ Object {
236
+ "attrs": Object {
237
+ "strike_through": true,
238
+ "underline": true,
239
+ },
240
+ "type": "text_decoration",
241
+ },
242
+ ],
243
+ "text": "lorem",
244
+ "type": "text",
245
+ },
246
+ Object {
247
+ "text": " ipsum",
248
+ "type": "text",
249
+ },
250
+ ],
251
+ "type": "paragraph",
252
+ },
253
+ ],
254
+ "type": "doc",
255
+ }
256
+ `;
257
+
228
258
  exports[`parsing html should get both from text 1`] = `
229
259
  Object {
230
260
  "content": Array [
@@ -255,6 +285,36 @@ Object {
255
285
  }
256
286
  `;
257
287
 
288
+ exports[`parsing html should get both from text with property shorthand 1`] = `
289
+ Object {
290
+ "content": Array [
291
+ Object {
292
+ "content": Array [
293
+ Object {
294
+ "marks": Array [
295
+ Object {
296
+ "attrs": Object {
297
+ "strike_through": true,
298
+ "underline": true,
299
+ },
300
+ "type": "text_decoration",
301
+ },
302
+ ],
303
+ "text": "lorem",
304
+ "type": "text",
305
+ },
306
+ Object {
307
+ "text": " ipsum",
308
+ "type": "text",
309
+ },
310
+ ],
311
+ "type": "paragraph",
312
+ },
313
+ ],
314
+ "type": "doc",
315
+ }
316
+ `;
317
+
258
318
  exports[`parsing html should get strike through from paragraph 1`] = `
259
319
  Object {
260
320
  "content": Array [
@@ -281,6 +341,36 @@ Object {
281
341
  }
282
342
  `;
283
343
 
344
+ exports[`parsing html should get strike through from rendered view 1`] = `
345
+ Object {
346
+ "content": Array [
347
+ Object {
348
+ "content": Array [
349
+ Object {
350
+ "marks": Array [
351
+ Object {
352
+ "attrs": Object {
353
+ "strike_through": true,
354
+ "underline": false,
355
+ },
356
+ "type": "text_decoration",
357
+ },
358
+ ],
359
+ "text": "lorem",
360
+ "type": "text",
361
+ },
362
+ Object {
363
+ "text": " ipsum",
364
+ "type": "text",
365
+ },
366
+ ],
367
+ "type": "paragraph",
368
+ },
369
+ ],
370
+ "type": "doc",
371
+ }
372
+ `;
373
+
284
374
  exports[`parsing html should get strike through from text 1`] = `
285
375
  Object {
286
376
  "content": Array [
@@ -337,6 +427,36 @@ Object {
337
427
  }
338
428
  `;
339
429
 
430
+ exports[`parsing html should get underline from rendered view 1`] = `
431
+ Object {
432
+ "content": Array [
433
+ Object {
434
+ "content": Array [
435
+ Object {
436
+ "marks": Array [
437
+ Object {
438
+ "attrs": Object {
439
+ "strike_through": false,
440
+ "underline": true,
441
+ },
442
+ "type": "text_decoration",
443
+ },
444
+ ],
445
+ "text": "lorem",
446
+ "type": "text",
447
+ },
448
+ Object {
449
+ "text": " ipsum",
450
+ "type": "text",
451
+ },
452
+ ],
453
+ "type": "paragraph",
454
+ },
455
+ ],
456
+ "type": "doc",
457
+ }
458
+ `;
459
+
340
460
  exports[`parsing html should get underline from text 1`] = `
341
461
  Object {
342
462
  "content": Array [
@@ -406,8 +526,68 @@ Object {
406
526
  }
407
527
  `;
408
528
 
409
- exports[`rendering should render both 1`] = `"<p class=\\"zw-style\\"><span style=\\"--zw-text-decoration: underline line-through;\\" class=\\"zw-style\\">hello world</span></p>"`;
529
+ exports[`parsing html should parse strike through from tag 1`] = `
530
+ Object {
531
+ "content": Array [
532
+ Object {
533
+ "content": Array [
534
+ Object {
535
+ "marks": Array [
536
+ Object {
537
+ "attrs": Object {
538
+ "strike_through": true,
539
+ "underline": false,
540
+ },
541
+ "type": "text_decoration",
542
+ },
543
+ ],
544
+ "text": "lorem",
545
+ "type": "text",
546
+ },
547
+ Object {
548
+ "text": " ipsum",
549
+ "type": "text",
550
+ },
551
+ ],
552
+ "type": "paragraph",
553
+ },
554
+ ],
555
+ "type": "doc",
556
+ }
557
+ `;
558
+
559
+ exports[`parsing html should parse underline from tag 1`] = `
560
+ Object {
561
+ "content": Array [
562
+ Object {
563
+ "content": Array [
564
+ Object {
565
+ "marks": Array [
566
+ Object {
567
+ "attrs": Object {
568
+ "strike_through": false,
569
+ "underline": true,
570
+ },
571
+ "type": "text_decoration",
572
+ },
573
+ ],
574
+ "text": "lorem",
575
+ "type": "text",
576
+ },
577
+ Object {
578
+ "text": " ipsum",
579
+ "type": "text",
580
+ },
581
+ ],
582
+ "type": "paragraph",
583
+ },
584
+ ],
585
+ "type": "doc",
586
+ }
587
+ `;
588
+
589
+ exports[`rendering should render both 1`] = `"<p class=\\"zw-style\\"><span style=\\"--zw-text-decoration:underline line-through;\\" class=\\"zw-style\\">hello world</span></p>"`;
410
590
 
411
- exports[`rendering should render strike through only 1`] = `"<p class=\\"zw-style\\"><span style=\\"--zw-text-decoration: line-through;\\" class=\\"zw-style\\">hello world</span></p>"`;
591
+ exports[`rendering should render strike through only 1`] = `"<p class=\\"zw-style\\"><span style=\\"--zw-text-decoration:line-through;\\" class=\\"zw-style\\">hello world</span></p>"`;
412
592
 
413
- exports[`rendering should render underline only 1`] = `"<p class=\\"zw-style\\"><span style=\\"--zw-text-decoration: underline;\\" class=\\"zw-style\\">hello world</span></p>"`;
593
+ exports[`rendering should render underline only 1`] = `"<p class=\\"zw-style\\"><span style=\\"--zw-text-decoration:underline;\\" class=\\"zw-style\\">hello world</span></p>"`;
@@ -0,0 +1,10 @@
1
+ import { Extension } from '@tiptap/vue-2';
2
+ import { PastePlugin } from './plugins';
3
+
4
+ export const CopyPasteProcessor = Extension.create({
5
+ name: 'copy_paste_processor',
6
+
7
+ addProseMirrorPlugins() {
8
+ return [PastePlugin.create()];
9
+ }
10
+ });
@@ -17,6 +17,16 @@ export const TextProcessor = Extension.create({
17
17
 
18
18
  addCommands() {
19
19
  return {
20
+ getSelectedText: createCommand(({ state }) => {
21
+ const { from, to } = state.selection;
22
+
23
+ return state.doc.textBetween(from, to, ' ');
24
+ }),
25
+
26
+ unsetMarks: createCommand(({ commands }, marks) => {
27
+ marks.forEach((mark) => commands.unsetMark(mark));
28
+ }),
29
+
20
30
  transformText: createCommand(({ state }, transform) => {
21
31
  const { selection } = state.tr;
22
32
 
@@ -1,8 +1,8 @@
1
1
  import { Editor, Extension } from '@tiptap/vue-2';
2
2
  import { NodeFactory } from '../../../__tests__/utils';
3
- import { CORE_EXTENSIONS } from '../index';
4
3
  import { NodeTypes } from '../../../enums';
5
4
  import { ContentNormalizer } from '../../../services';
5
+ import { buildCoreExtensions } from '../index';
6
6
 
7
7
  const LineHeight = Extension.create({
8
8
  name: 'line_height',
@@ -21,11 +21,9 @@ const LineHeight = Extension.create({
21
21
  });
22
22
 
23
23
  function createEditor({ content }) {
24
- const normalizer = new ContentNormalizer();
25
-
26
24
  return new Editor({
27
- content: normalizer.normalize(content),
28
- extensions: CORE_EXTENSIONS.concat(LineHeight) // Included to core extensions
25
+ content: ContentNormalizer.normalize(content),
26
+ extensions: buildCoreExtensions().concat(LineHeight) // Included to core extensions
29
27
  });
30
28
  }
31
29
 
@@ -1,19 +1,17 @@
1
1
  import { Editor } from '@tiptap/vue-2';
2
- import { CORE_EXTENSIONS } from '../index';
3
2
  import { NodeFactory } from '../../../__tests__/utils';
4
3
  import { ContentNormalizer } from '../../../services';
4
+ import { buildCoreExtensions } from '../index';
5
5
 
6
6
  function createEditor() {
7
- const normalizer = new ContentNormalizer();
8
-
9
7
  const content = NodeFactory.doc([
10
8
  NodeFactory.paragraph('Lorem ipsum dolor sit amet'),
11
9
  NodeFactory.paragraph('consectetur adipisicing elit')
12
10
  ]);
13
11
 
14
12
  return new Editor({
15
- content: normalizer.normalize(content),
16
- extensions: CORE_EXTENSIONS // included to core
13
+ content: ContentNormalizer.normalize(content),
14
+ extensions: buildCoreExtensions() // included to core
17
15
  });
18
16
  }
19
17
 
@@ -1,29 +1,120 @@
1
- import { Editor, Mark } from '@tiptap/vue-2';
1
+ import { Editor, Mark, Extension } from '@tiptap/vue-2';
2
2
  import { NodeFactory } from '../../../__tests__/utils';
3
- import { CORE_EXTENSIONS } from '../index';
4
3
  import { ContentNormalizer } from '../../../services';
4
+ import { NodeTypes, TextSettings } from '../../../enums';
5
+ import { buildCoreExtensions } from '../index';
6
+
7
+ const MockFontSize = Mark.create({
8
+ name: TextSettings.FONT_SIZE,
9
+
10
+ addAttributes: () => ({
11
+ value: { default: null }
12
+ }),
13
+
14
+ renderHTML: () => ['span', {}, 0]
15
+ });
5
16
 
6
17
  const MockFontWeight = Mark.create({
7
- name: 'font_weight',
18
+ name: TextSettings.FONT_WEIGHT,
8
19
 
9
20
  addAttributes: () => ({
10
- value: { required: true }
21
+ value: { default: null }
11
22
  }),
12
23
 
13
- renderHTML(context) {
14
- const { value } = context.HTMLAttributes;
24
+ renderHTML: () => ['span', {}, 0]
25
+ });
26
+
27
+ const MockAlignment = Extension.create({
28
+ name: TextSettings.ALIGNMENT,
15
29
 
16
- return ['span', { style: `font-weight: ${value}` }, 0];
17
- }
30
+ addGlobalAttributes: () => [
31
+ {
32
+ types: [NodeTypes.PARAGRAPH, NodeTypes.HEADING],
33
+ attributes: {
34
+ [TextSettings.ALIGNMENT]: {
35
+ default: null,
36
+ renderHTML: () => ({})
37
+ }
38
+ }
39
+ }
40
+ ]
18
41
  });
19
42
 
20
- function createEditor({ content }) {
21
- const normalizer = new ContentNormalizer();
43
+ const MockBackgroundColor = Mark.create({
44
+ name: TextSettings.BACKGROUND_COLOR,
45
+
46
+ addAttributes: () => ({
47
+ value: { default: null }
48
+ }),
49
+
50
+ renderHTML: () => ['span', {}, 0]
51
+ });
52
+
53
+ const MockFontColor = Mark.create({
54
+ name: TextSettings.FONT_COLOR,
55
+
56
+ addAttributes: () => ({
57
+ value: { default: null }
58
+ }),
59
+
60
+ renderHTML: () => ['span', {}, 0]
61
+ });
62
+
63
+ const MockFontFamily = Mark.create({
64
+ name: TextSettings.FONT_FAMILY,
65
+
66
+ addAttributes: () => ({
67
+ value: { default: null }
68
+ }),
69
+
70
+ renderHTML: () => ['span', {}, 0]
71
+ });
72
+
73
+ const MockFontStyle = Mark.create({
74
+ name: TextSettings.FONT_STYLE,
75
+
76
+ addAttributes: () => ({
77
+ value: { default: null }
78
+ }),
79
+
80
+ renderHTML: () => ['span', {}, 0]
81
+ });
82
+
83
+ const MockTextDecoration = Mark.create({
84
+ name: TextSettings.TEXT_DECORATION,
85
+
86
+ addAttributes: () => ({
87
+ value: { default: null }
88
+ }),
22
89
 
90
+ renderHTML: () => ['span', {}, 0]
91
+ });
92
+
93
+ const MockSuperscript = Mark.create({
94
+ name: TextSettings.SUPERSCRIPT,
95
+
96
+ addAttributes: () => ({
97
+ value: { default: null }
98
+ }),
99
+
100
+ renderHTML: () => ['span', {}, 0]
101
+ });
102
+
103
+ function createEditor({ content }) {
23
104
  return new Editor({
24
- content: normalizer.normalize(content),
105
+ content: ContentNormalizer.normalize(content),
25
106
  element: document.createElement('div'),
26
- extensions: CORE_EXTENSIONS.concat(MockFontWeight)
107
+ extensions: buildCoreExtensions().concat(
108
+ MockFontSize,
109
+ MockFontWeight,
110
+ MockAlignment,
111
+ MockBackgroundColor,
112
+ MockFontColor,
113
+ MockFontFamily,
114
+ MockFontStyle,
115
+ MockTextDecoration,
116
+ MockSuperscript
117
+ )
27
118
  });
28
119
  }
29
120
 
@@ -62,3 +153,38 @@ describe('transform text', () => {
62
153
  expect(editor.getJSON()).toMatchSnapshot();
63
154
  });
64
155
  });
156
+
157
+ describe('selected text', () => {
158
+ test('should return selected text', () => {
159
+ const editor = createEditor({
160
+ content: NodeFactory.doc([
161
+ NodeFactory.paragraph('hello world')
162
+ ])
163
+ });
164
+
165
+ editor.commands.setTextSelection({ from: 5, to: 11 });
166
+
167
+ expect(editor.commands.getSelectedText()).toEqual('o worl');
168
+ });
169
+ });
170
+
171
+ describe('unset marks', () => {
172
+ test('should reset all marks', () => {
173
+ const editor = createEditor({
174
+ content: NodeFactory.doc([
175
+ NodeFactory.paragraph([
176
+ NodeFactory.text('hello world', [
177
+ NodeFactory.mark('font_weight', { value: '700' })
178
+ ])
179
+ ])
180
+ ])
181
+ });
182
+
183
+ editor.chain()
184
+ .selectAll()
185
+ .unsetMarks(TextSettings.marks)
186
+ .run();
187
+
188
+ expect(editor.getJSON()).toMatchSnapshot();
189
+ });
190
+ });
@@ -4,6 +4,9 @@ exports[`transform text should keep text marks 1`] = `
4
4
  Object {
5
5
  "content": Array [
6
6
  Object {
7
+ "attrs": Object {
8
+ "alignment": null,
9
+ },
7
10
  "content": Array [
8
11
  Object {
9
12
  "marks": Array [
@@ -29,6 +32,9 @@ exports[`transform text should transform selected text 1`] = `
29
32
  Object {
30
33
  "content": Array [
31
34
  Object {
35
+ "attrs": Object {
36
+ "alignment": null,
37
+ },
32
38
  "content": Array [
33
39
  Object {
34
40
  "text": "hELLO world",
@@ -41,3 +47,23 @@ Object {
41
47
  "type": "doc",
42
48
  }
43
49
  `;
50
+
51
+ exports[`unset marks should reset all marks 1`] = `
52
+ Object {
53
+ "content": Array [
54
+ Object {
55
+ "attrs": Object {
56
+ "alignment": null,
57
+ },
58
+ "content": Array [
59
+ Object {
60
+ "text": "hello world",
61
+ "type": "text",
62
+ },
63
+ ],
64
+ "type": "paragraph",
65
+ },
66
+ ],
67
+ "type": "doc",
68
+ }
69
+ `;
@@ -1,17 +1,26 @@
1
1
  import Document from '@tiptap/extension-document';
2
2
  import Paragraph from '@tiptap/extension-paragraph';
3
3
  import Text from '@tiptap/extension-text';
4
+ import Placeholder from '@tiptap/extension-placeholder';
5
+ import History from '@tiptap/extension-history';
4
6
  import { NodeProcessor } from './NodeProcessor';
5
7
  import { TextProcessor } from './TextProcessor';
6
8
  import { SelectionProcessor } from './SelectionProcessor';
9
+ import { CopyPasteProcessor } from './CopyPasteProcessor';
7
10
 
8
- export const CORE_EXTENSIONS = [
11
+ export const buildCoreExtensions = () => [
9
12
  Document,
10
13
  Paragraph.configure({
11
14
  HTMLAttributes: { class: 'zw-style' }
12
15
  }),
13
16
  Text,
17
+ Placeholder.configure({
18
+ placeholder: 'Type your text here...',
19
+ emptyNodeClass: 'zw-wysiwyg__placeholder'
20
+ }),
21
+ History,
14
22
  NodeProcessor,
15
23
  TextProcessor,
16
- SelectionProcessor
24
+ SelectionProcessor,
25
+ CopyPasteProcessor
17
26
  ];
@@ -0,0 +1,57 @@
1
+ import { ContentNormalizer } from '../../../services';
2
+ import { NodeTypes } from '../../../enums';
3
+ import { ProseMirrorPlugin } from './ProseMirrorPlugin';
4
+
5
+ export class PastePlugin extends ProseMirrorPlugin {
6
+ buildProps() {
7
+ return {
8
+ transformPastedHTML: ContentNormalizer.normalize,
9
+ handlePaste: this._handlePaste.bind(this)
10
+ };
11
+ }
12
+
13
+ _handlePaste(view, _, slice) {
14
+ const transaction = this._insertPastedContent(view, slice)
15
+ .scrollIntoView()
16
+ .setMeta('paste', true)
17
+ .setMeta('uiEvent', 'paste');
18
+
19
+ view.dispatch(transaction);
20
+
21
+ return true;
22
+ }
23
+
24
+ _insertPastedContent({ state, input }, slice) {
25
+ if (!this._isFullBlockSelected(state)) {
26
+ return state.tr.replaceSelection(slice);
27
+ }
28
+
29
+ return state.tr.replaceSelectionWith(slice.content, input.shiftKey);
30
+ }
31
+
32
+ _isFullBlockSelected(state) {
33
+ const blocksSelection = this._expandSelectionToBlocks(state);
34
+ const isFromMatch = this._isMatchPosition(blocksSelection.from, state.selection.from);
35
+ const isToMatch = this._isMatchPosition(blocksSelection.to, state.selection.to);
36
+
37
+ return isFromMatch && isToMatch;
38
+ }
39
+
40
+ _expandSelectionToBlocks({ selection, doc }) {
41
+ let from = selection.from;
42
+ let to = selection.to;
43
+
44
+ doc.nodesBetween(from, to, (node, position, parent) => {
45
+ if (parent.type.name !== NodeTypes.DOCUMENT) return;
46
+
47
+ from = Math.min(from, position + 1);
48
+ to = Math.max(to, position + node.nodeSize - 1);
49
+ });
50
+
51
+ return { from, to };
52
+ }
53
+
54
+ _isMatchPosition(position1, position2) {
55
+ return Math.abs(position1 - position2) < 5;
56
+ }
57
+ }
@@ -0,0 +1,20 @@
1
+ import { Plugin, PluginKey } from 'prosemirror-state';
2
+
3
+ export class ProseMirrorPlugin {
4
+ static create(options) {
5
+ const plugin = new this(options || {});
6
+
7
+ return new Plugin({
8
+ key: new PluginKey(this.name),
9
+ props: plugin.buildProps()
10
+ });
11
+ }
12
+
13
+ constructor(options) {
14
+ this.options = options;
15
+ }
16
+
17
+ buildProps() {
18
+ return {};
19
+ }
20
+ }
@@ -0,0 +1 @@
1
+ export { PastePlugin } from './PastePlugin';