@zipify/wysiwyg 1.0.0-dev.17 → 1.0.0-dev.18

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 (98) hide show
  1. package/.github/dependabot.yaml +1 -0
  2. package/dist/wysiwyg.css +199 -12
  3. package/dist/wysiwyg.js +1 -1
  4. package/example/ExampleApp.vue +6 -2
  5. package/example/pageBlocks.js +31 -0
  6. package/example/presets.js +2 -2
  7. package/lib/Wysiwyg.vue +14 -3
  8. package/lib/assets/icons/link.svg +3 -0
  9. package/lib/assets/icons/unlink.svg +3 -0
  10. package/lib/components/base/Button.vue +21 -1
  11. package/lib/components/base/Checkbox.vue +89 -0
  12. package/lib/components/base/FieldLabel.vue +2 -1
  13. package/lib/components/base/Icon.vue +2 -2
  14. package/lib/components/base/Modal.vue +0 -1
  15. package/lib/components/base/TextField.vue +106 -0
  16. package/lib/components/base/__tests__/TextField.test.js +57 -0
  17. package/lib/components/base/__tests__/__snapshots__/TextField.test.js.snap +9 -0
  18. package/lib/components/base/composables/index.js +1 -0
  19. package/lib/components/base/composables/useValidator.js +19 -0
  20. package/lib/components/base/dropdown/Dropdown.vue +15 -3
  21. package/lib/components/base/dropdown/DropdownActivator.vue +19 -3
  22. package/lib/components/base/index.js +2 -0
  23. package/lib/components/toolbar/Toolbar.vue +5 -5
  24. package/lib/components/toolbar/ToolbarFull.vue +10 -2
  25. package/lib/components/toolbar/controls/FontSizeControl.vue +7 -0
  26. package/lib/components/toolbar/controls/UnderlineControl.vue +2 -2
  27. package/lib/components/toolbar/controls/__tests__/UnderlineControl.test.js +4 -0
  28. package/lib/components/toolbar/controls/index.js +1 -0
  29. package/lib/components/toolbar/controls/link/LinkControl.vue +152 -0
  30. package/lib/components/toolbar/controls/link/LinkControlApply.vue +35 -0
  31. package/lib/components/toolbar/controls/link/LinkControlHeader.vue +67 -0
  32. package/lib/components/toolbar/controls/link/composables/index.js +1 -0
  33. package/lib/components/toolbar/controls/link/composables/useLink.js +61 -0
  34. package/lib/components/toolbar/controls/link/destination/LinkControlDestination.vue +103 -0
  35. package/lib/components/toolbar/controls/link/destination/LinkControlPageBlock.vue +54 -0
  36. package/lib/components/toolbar/controls/link/destination/LinkControlUrl.vue +52 -0
  37. package/lib/components/toolbar/controls/link/destination/index.js +1 -0
  38. package/lib/components/toolbar/controls/link/index.js +1 -0
  39. package/lib/composables/__tests__/useEditor.test.js +2 -2
  40. package/lib/composables/useEditor.js +2 -4
  41. package/lib/enums/LinkDestinations.js +4 -0
  42. package/lib/enums/LinkTargets.js +4 -0
  43. package/lib/enums/TextSettings.js +3 -1
  44. package/lib/enums/index.js +2 -0
  45. package/lib/extensions/Alignment.js +18 -6
  46. package/lib/extensions/BackgroundColor.js +14 -6
  47. package/lib/extensions/FontColor.js +14 -6
  48. package/lib/extensions/FontFamily.js +25 -8
  49. package/lib/extensions/FontSize.js +26 -13
  50. package/lib/extensions/FontStyle.js +23 -13
  51. package/lib/extensions/FontWeight.js +22 -14
  52. package/lib/extensions/LineHeight.js +11 -3
  53. package/lib/extensions/Link.js +101 -0
  54. package/lib/extensions/StylePreset.js +4 -2
  55. package/lib/extensions/TextDecoration.js +27 -12
  56. package/lib/extensions/__tests__/Alignment.test.js +11 -5
  57. package/lib/extensions/__tests__/BackgroundColor.test.js +11 -5
  58. package/lib/extensions/__tests__/CaseStyle.test.js +3 -5
  59. package/lib/extensions/__tests__/FontColor.test.js +11 -5
  60. package/lib/extensions/__tests__/FontFamily.test.js +32 -7
  61. package/lib/extensions/__tests__/FontSize.test.js +11 -5
  62. package/lib/extensions/__tests__/FontStyle.test.js +11 -5
  63. package/lib/extensions/__tests__/FontWeight.test.js +11 -5
  64. package/lib/extensions/__tests__/LineHeight.test.js +11 -5
  65. package/lib/extensions/__tests__/StylePreset.test.js +70 -6
  66. package/lib/extensions/__tests__/TextDecoration.test.js +27 -5
  67. package/lib/extensions/__tests__/__snapshots__/Alignment.test.js.snap +26 -2
  68. package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +30 -1
  69. package/lib/extensions/__tests__/__snapshots__/FontColor.test.js.snap +18 -1
  70. package/lib/extensions/__tests__/__snapshots__/FontFamily.test.js.snap +88 -1
  71. package/lib/extensions/__tests__/__snapshots__/FontSize.test.js.snap +33 -2
  72. package/lib/extensions/__tests__/__snapshots__/FontStyle.test.js.snap +25 -4
  73. package/lib/extensions/__tests__/__snapshots__/FontWeight.test.js.snap +30 -1
  74. package/lib/extensions/__tests__/__snapshots__/LineHeight.test.js.snap +26 -2
  75. package/lib/extensions/__tests__/__snapshots__/StylePreset.test.js.snap +6 -2
  76. package/lib/extensions/__tests__/__snapshots__/TextDecoration.test.js.snap +93 -3
  77. package/lib/extensions/core/CopyPasteProcessor.js +10 -0
  78. package/lib/extensions/core/TextProcessor.js +10 -0
  79. package/lib/extensions/core/__tests__/NodeProcessor.test.js +3 -5
  80. package/lib/extensions/core/__tests__/SelectionProcessor.test.js +3 -5
  81. package/lib/extensions/core/__tests__/TextProcessor.test.js +138 -12
  82. package/lib/extensions/core/__tests__/__snapshots__/TextProcessor.test.js.snap +26 -0
  83. package/lib/extensions/core/index.js +11 -2
  84. package/lib/extensions/core/plugins/PastePlugin.js +48 -0
  85. package/lib/extensions/core/plugins/ProseMirrorPlugin.js +20 -0
  86. package/lib/extensions/core/plugins/index.js +1 -0
  87. package/lib/extensions/index.js +41 -34
  88. package/lib/extensions/list/__tests__/List.test.js +3 -5
  89. package/lib/extensions/list/__tests__/__snapshots__/List.test.js.snap +45 -15
  90. package/lib/injectionTokens.js +2 -1
  91. package/lib/services/ContentNormalizer.js +62 -20
  92. package/lib/services/__tests__/ContentNormalizer.test.js +40 -7
  93. package/lib/styles/content.css +17 -9
  94. package/lib/styles/helpers/offsets.css +16 -0
  95. package/lib/styles/variables.css +6 -0
  96. package/lib/utils/__tests__/__snapshots__/renderInlineSetting.test.js.snap +4 -4
  97. package/lib/utils/renderInlineSetting.js +1 -1
  98. package/package.json +11 -9
@@ -1,5 +1,3 @@
1
- import History from '@tiptap/extension-history';
2
- import { CORE_EXTENSIONS } from './core';
3
1
  import { FontFamily } from './FontFamily';
4
2
  import { StylePreset } from './StylePreset';
5
3
  import { FontWeight } from './FontWeight';
@@ -13,38 +11,47 @@ import { CaseStyle } from './CaseStyle';
13
11
  import { Alignment } from './Alignment';
14
12
  import { LineHeight } from './LineHeight';
15
13
  import { List } from './list';
14
+ import { Link } from './Link';
16
15
  import { Superscript } from './Superscript';
16
+ import { buildCoreExtensions } from './core';
17
17
 
18
- export { CORE_EXTENSIONS };
18
+ export function buildExtensions(options) {
19
+ const getPresetById = (id) => options.presetsRef.value.find((preset) => preset.id === id);
20
+ const defaultPreset = getPresetById(options.defaultPresetId);
19
21
 
20
- export const getExtensions = (options) => CORE_EXTENSIONS.concat([
21
- History,
22
- StylePreset.configure({
23
- presetsRef: options.presetsRef,
24
- defaultId: options.defaultPresetId,
25
- baseClass: options.basePresetClass,
26
- makeVariable: options.makePresetVariable
27
- }),
28
- List.configure({
29
- baseClass: options.baseListClass
30
- }),
31
- DeviceManager.configure({
32
- deviceRef: options.deviceRef
33
- }),
34
- FontFamily.configure({
35
- fonts: options.fonts
36
- }),
37
- FontWeight,
38
- FontSize.configure({
39
- minSize: options.minFontSize,
40
- maxSize: options.maxFontSize
41
- }),
42
- FontColor,
43
- BackgroundColor,
44
- FontStyle,
45
- TextDecoration,
46
- CaseStyle,
47
- Superscript,
48
- Alignment,
49
- LineHeight
50
- ]);
22
+ return buildCoreExtensions(options).concat([
23
+ StylePreset.configure({
24
+ presetsRef: options.presetsRef,
25
+ defaultId: options.defaultPresetId,
26
+ baseClass: options.basePresetClass,
27
+ makeVariable: options.makePresetVariable
28
+ }),
29
+ List.configure({
30
+ baseClass: options.baseListClass
31
+ }),
32
+ DeviceManager.configure({
33
+ deviceRef: options.deviceRef
34
+ }),
35
+ FontFamily.configure({
36
+ fonts: options.fonts,
37
+ defaultFont: defaultPreset.common.font_family
38
+ }),
39
+ FontWeight,
40
+ FontSize.configure({
41
+ minSize: options.minFontSize,
42
+ maxSize: options.maxFontSize
43
+ }),
44
+ FontColor,
45
+ BackgroundColor,
46
+ FontStyle,
47
+ TextDecoration,
48
+ CaseStyle,
49
+ Superscript,
50
+ Alignment,
51
+ LineHeight,
52
+ Link.configure({
53
+ preset: options.linkPreset,
54
+ basePresetClass: options.basePresetClass,
55
+ pageBlocks: options.pageBlocks
56
+ })]);
57
+ }
@@ -2,18 +2,16 @@ import { Editor } from '@tiptap/vue-2';
2
2
  import { ref } from '@vue/composition-api';
3
3
  import { NodeFactory } from '../../../__tests__/utils';
4
4
  import { ListTypes } from '../../../enums';
5
- import { CORE_EXTENSIONS } from '../../core';
6
5
  import { StylePreset } from '../../StylePreset';
7
6
  import { List } from '../List';
8
7
  import { ContentNormalizer } from '../../../services';
8
+ import { buildCoreExtensions } from '../../core';
9
9
 
10
10
  function createEditor({ content }) {
11
- const normalizer = new ContentNormalizer();
12
-
13
11
  return new Editor({
14
- content: normalizer.normalize(content),
12
+ content: ContentNormalizer.normalize(content),
15
13
  element: document.createElement('div'),
16
- extensions: CORE_EXTENSIONS.concat(
14
+ extensions: buildCoreExtensions().concat(
17
15
  List.configure({
18
16
  baseClass: 'zw-list--'
19
17
  }),
@@ -92,7 +92,9 @@ Object {
92
92
  "content": Array [
93
93
  Object {
94
94
  "attrs": Object {
95
- "preset": null,
95
+ "preset": Object {
96
+ "id": "regular-1",
97
+ },
96
98
  },
97
99
  "content": Array [
98
100
  Object {
@@ -104,7 +106,9 @@ Object {
104
106
  },
105
107
  Object {
106
108
  "attrs": Object {
107
- "preset": null,
109
+ "preset": Object {
110
+ "id": "regular-1",
111
+ },
108
112
  },
109
113
  "content": Array [
110
114
  Object {
@@ -221,7 +225,9 @@ Object {
221
225
  "content": Array [
222
226
  Object {
223
227
  "attrs": Object {
224
- "preset": null,
228
+ "preset": Object {
229
+ "id": "regular-1",
230
+ },
225
231
  },
226
232
  "content": Array [
227
233
  Object {
@@ -256,7 +262,9 @@ Object {
256
262
  "content": Array [
257
263
  Object {
258
264
  "attrs": Object {
259
- "preset": null,
265
+ "preset": Object {
266
+ "id": "regular-1",
267
+ },
260
268
  },
261
269
  "content": Array [
262
270
  Object {
@@ -291,7 +299,9 @@ Object {
291
299
  "content": Array [
292
300
  Object {
293
301
  "attrs": Object {
294
- "preset": null,
302
+ "preset": Object {
303
+ "id": "regular-1",
304
+ },
295
305
  },
296
306
  "content": Array [
297
307
  Object {
@@ -326,7 +336,9 @@ Object {
326
336
  "content": Array [
327
337
  Object {
328
338
  "attrs": Object {
329
- "preset": null,
339
+ "preset": Object {
340
+ "id": "regular-1",
341
+ },
330
342
  },
331
343
  "content": Array [
332
344
  Object {
@@ -361,7 +373,9 @@ Object {
361
373
  "content": Array [
362
374
  Object {
363
375
  "attrs": Object {
364
- "preset": null,
376
+ "preset": Object {
377
+ "id": "regular-1",
378
+ },
365
379
  },
366
380
  "content": Array [
367
381
  Object {
@@ -396,7 +410,9 @@ Object {
396
410
  "content": Array [
397
411
  Object {
398
412
  "attrs": Object {
399
- "preset": null,
413
+ "preset": Object {
414
+ "id": "regular-1",
415
+ },
400
416
  },
401
417
  "content": Array [
402
418
  Object {
@@ -431,7 +447,9 @@ Object {
431
447
  "content": Array [
432
448
  Object {
433
449
  "attrs": Object {
434
- "preset": null,
450
+ "preset": Object {
451
+ "id": "regular-1",
452
+ },
435
453
  },
436
454
  "content": Array [
437
455
  Object {
@@ -466,7 +484,9 @@ Object {
466
484
  "content": Array [
467
485
  Object {
468
486
  "attrs": Object {
469
- "preset": null,
487
+ "preset": Object {
488
+ "id": "regular-1",
489
+ },
470
490
  },
471
491
  "content": Array [
472
492
  Object {
@@ -501,7 +521,9 @@ Object {
501
521
  "content": Array [
502
522
  Object {
503
523
  "attrs": Object {
504
- "preset": null,
524
+ "preset": Object {
525
+ "id": "regular-1",
526
+ },
505
527
  },
506
528
  "content": Array [
507
529
  Object {
@@ -536,7 +558,9 @@ Object {
536
558
  "content": Array [
537
559
  Object {
538
560
  "attrs": Object {
539
- "preset": null,
561
+ "preset": Object {
562
+ "id": "regular-1",
563
+ },
540
564
  },
541
565
  "content": Array [
542
566
  Object {
@@ -571,7 +595,9 @@ Object {
571
595
  "content": Array [
572
596
  Object {
573
597
  "attrs": Object {
574
- "preset": null,
598
+ "preset": Object {
599
+ "id": "regular-1",
600
+ },
575
601
  },
576
602
  "content": Array [
577
603
  Object {
@@ -606,7 +632,9 @@ Object {
606
632
  "content": Array [
607
633
  Object {
608
634
  "attrs": Object {
609
- "preset": null,
635
+ "preset": Object {
636
+ "id": "regular-1",
637
+ },
610
638
  },
611
639
  "content": Array [
612
640
  Object {
@@ -641,7 +669,9 @@ Object {
641
669
  "content": Array [
642
670
  Object {
643
671
  "attrs": Object {
644
- "preset": null,
672
+ "preset": Object {
673
+ "id": "regular-1",
674
+ },
645
675
  },
646
676
  "content": Array [
647
677
  Object {
@@ -3,5 +3,6 @@ export const InjectionTokens = Object.freeze({
3
3
  FONT_SIZES: Symbol('fontSizes'),
4
4
  EDITOR: Symbol('editor'),
5
5
  LOCAL_STORAGE: Symbol('localStorage'),
6
- FAVORITE_COLORS: Symbol('favoriteColors')
6
+ FAVORITE_COLORS: Symbol('favoriteColors'),
7
+ PAGE_BLOCKS: Symbol('pageBlocks')
7
8
  });
@@ -1,26 +1,36 @@
1
1
  import { ContextWindow } from './ContextWidnow';
2
2
 
3
3
  export class ContentNormalizer {
4
- static NORMALIZING_STYLE_BLACKLIST = ['text-align', 'line-height'];
4
+ static BLOCK_STYLES = ['text-align', 'line-height'];
5
5
 
6
- normalize(content) {
7
- if (typeof content !== 'string') return content;
6
+ static normalize(content) {
7
+ return new ContentNormalizer(content).normalize();
8
+ }
8
9
 
9
- return this._normalizeTextContent(content);
10
+ constructor(content) {
11
+ this._content = content;
12
+ this._dom = null;
10
13
  }
11
14
 
12
- _normalizeTextContent(content) {
13
- const parser = new DOMParser();
14
- const dom = parser.parseFromString(content, 'text/html');
15
+ normalize() {
16
+ if (typeof this._content !== 'string') {
17
+ return this._content;
18
+ }
19
+ return this._normalizeTextContent();
20
+ }
15
21
 
16
- this._iterateNodes(dom, this._normalizeStructure.bind(this), (node) => node.tagName === 'SPAN');
17
- this._iterateNodes(dom, this._normalizeStyles.bind(this), (node) => node.tagName !== 'SPAN');
22
+ _normalizeTextContent() {
23
+ this._dom = new DOMParser().parseFromString(this._content, 'text/html');
18
24
 
19
- return dom.body.innerHTML;
25
+ this._iterateNodes(this._normalizeListItems.bind(this), (node) => node.tagName === 'LI');
26
+ this._iterateNodes(this._normalizeSettingsStructure.bind(this), (node) => node.tagName === 'SPAN');
27
+ this._iterateNodes(this._normalizeStyles.bind(this), (node) => node.tagName !== 'SPAN');
28
+
29
+ return this._dom.body.innerHTML;
20
30
  }
21
31
 
22
- _iterateNodes(dom, handler, condition) {
23
- const iterator = dom.createNodeIterator(dom.body, NodeFilter.SHOW_ELEMENT, {
32
+ _iterateNodes(handler, condition) {
33
+ const iterator = this._dom.createNodeIterator(this._dom.body, NodeFilter.SHOW_ELEMENT, {
24
34
  acceptNode: (node) => condition(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
25
35
  });
26
36
  let currentNode = iterator.nextNode();
@@ -31,14 +41,43 @@ export class ContentNormalizer {
31
41
  }
32
42
  }
33
43
 
34
- _normalizeStructure(element) {
44
+ _normalizeListItems(itemEl) {
45
+ const fragment = new DocumentFragment();
46
+ const children = Array.from(itemEl.childNodes);
47
+ let capturingParagraph;
48
+
49
+ const append = (node) => {
50
+ this._assignElementProperties(node, itemEl, ContentNormalizer.BLOCK_STYLES);
51
+ fragment.append(node);
52
+ };
53
+
54
+ for (const node of children) {
55
+ if (node.tagName === 'P') {
56
+ append(node);
57
+ capturingParagraph = null;
58
+ continue;
59
+ }
60
+
61
+ if (!capturingParagraph) {
62
+ capturingParagraph = document.createElement('p');
63
+ append(capturingParagraph);
64
+ }
65
+
66
+ capturingParagraph.append(node);
67
+ }
68
+
69
+ itemEl.append(fragment);
70
+ this._removeStyleProperties(itemEl, ContentNormalizer.BLOCK_STYLES);
71
+ }
72
+
73
+ _normalizeSettingsStructure(element) {
35
74
  const isTextChildren = Array.from(element.childNodes)
36
75
  .every((node) => node.nodeType === Node.TEXT_NODE);
37
76
 
38
77
  if (isTextChildren) return;
39
78
 
40
79
  const cloned = element.cloneNode(true);
41
- const migratingStyles = this._getMigratingStyles(element);
80
+ const migratingStyles = this._getMigratingStyles(element, { customProperties: true });
42
81
  const content = [];
43
82
 
44
83
  for (const node of cloned.childNodes) {
@@ -67,16 +106,17 @@ export class ContentNormalizer {
67
106
  this._removeStyleProperties(element, properties);
68
107
  }
69
108
 
70
- _getMigratingStyles(element) {
71
- const blacklist = ContentNormalizer.NORMALIZING_STYLE_BLACKLIST;
109
+ _getMigratingStyles(element, { customProperties } = {}) {
110
+ const blacklist = ContentNormalizer.BLOCK_STYLES;
72
111
  const properties = [];
73
112
 
74
113
  for (let index = 0; index < element.style.length; index++) {
75
114
  const property = element.style.item(index);
76
115
 
77
- if (!blacklist.includes(property)) {
78
- properties.push(property);
79
- }
116
+ if (blacklist.includes(property)) continue;
117
+ if (!customProperties && property.startsWith('--')) continue;
118
+
119
+ properties.push(property);
80
120
  }
81
121
 
82
122
  return properties;
@@ -99,7 +139,9 @@ export class ContentNormalizer {
99
139
  continue;
100
140
  }
101
141
 
102
- target.style.setProperty(property, source.style.getPropertyValue(property));
142
+ const value = source.style.getPropertyValue(property);
143
+
144
+ if (value) target.style.setProperty(property, value);
103
145
  }
104
146
  }
105
147
 
@@ -1,13 +1,11 @@
1
1
  import { ContentNormalizer } from '../ContentNormalizer';
2
2
  import { NodeFactory } from '../../__tests__/utils';
3
3
 
4
- const normalize = (content) => new ContentNormalizer().normalize(content);
5
-
6
- describe('normalize text settings', () => {
4
+ describe('normalize text content', () => {
7
5
  test('should ignore json content', () => {
8
6
  const content = NodeFactory.doc([NodeFactory.paragraph('Test')]);
9
7
 
10
- expect(normalize(content)).toBe(content);
8
+ expect(ContentNormalizer.normalize(content)).toBe(content);
11
9
  });
12
10
 
13
11
  test('should flat structure', () => {
@@ -18,14 +16,14 @@ describe('normalize text settings', () => {
18
16
  '<span style="background-color: rgb(255, 0, 0); color: rgb(255, 255, 255);">sum</span>' +
19
17
  '</p>';
20
18
 
21
- expect(normalize(input)).toBe(output);
19
+ expect(ContentNormalizer.normalize(input)).toBe(output);
22
20
  });
23
21
 
24
22
  test('should move styles from paragraph to text', () => {
25
23
  const input = '<p style="background-color: red;">lorem ipsum</p>';
26
24
  const output = '<p><span style="background-color: red;">lorem ipsum</span></p>';
27
25
 
28
- expect(normalize(input)).toBe(output);
26
+ expect(ContentNormalizer.normalize(input)).toBe(output);
29
27
  });
30
28
 
31
29
  test('should move styles from paragraph to unstyled text', () => {
@@ -36,6 +34,41 @@ describe('normalize text settings', () => {
36
34
  '<span style="color: white; background-color: red;">one</span' +
37
35
  '></p>';
38
36
 
39
- expect(normalize(input)).toBe(output);
37
+ expect(ContentNormalizer.normalize(input)).toBe(output);
38
+ });
39
+
40
+ test('should wrap list content in paragraph', () => {
41
+ const input = '<ul><li style="line-height: 2;">lorem impsum</li></ul>';
42
+ const output = '<ul><li><p style="line-height: 2;"><span>lorem impsum</span></p></li></ul>';
43
+
44
+ expect(ContentNormalizer.normalize(input)).toBe(output);
45
+ });
46
+
47
+ test('should keep order in list nodes', () => {
48
+ const input = '<ul><li style="line-height: 2;"><span style="font-weight: 700">lorem</span> impsum</li></ul>';
49
+ const output = '<ul>' +
50
+ '<li>' +
51
+ '<p style="line-height: 2;"><span style="font-weight: 700">lorem</span><span> impsum</span></p>' +
52
+ '</li>' +
53
+ '</ul>';
54
+
55
+ expect(ContentNormalizer.normalize(input)).toBe(output);
56
+ });
57
+
58
+ test('should wrap non paragraph list content', () => {
59
+ const input = '<ul>' +
60
+ '<li style="line-height: 2;">' +
61
+ '<span style="font-weight: 700">lorem</span> impsum' +
62
+ '<p>paragraph text</p>' +
63
+ '</li>' +
64
+ '</ul>';
65
+ const output = '<ul>' +
66
+ '<li>' +
67
+ '<p style="line-height: 2;"><span style="font-weight: 700">lorem</span><span> impsum</span></p>' +
68
+ '<p style="line-height: 2;"><span>paragraph text</span></p>' +
69
+ '</li>' +
70
+ '</ul>';
71
+
72
+ expect(ContentNormalizer.normalize(input)).toBe(output);
40
73
  });
41
74
  });
@@ -2,6 +2,14 @@
2
2
  outline: none;
3
3
  }
4
4
 
5
+ .zw-wysiwyg__placeholder:first-child:last-child::before {
6
+ content: attr(data-placeholder);
7
+ color: rgb(var(--zw-color-n70));
8
+ float: left;
9
+ height: 0;
10
+ pointer-events: none;
11
+ }
12
+
5
13
  .zw-style {
6
14
  font-weight: var(--zw-font-weight, var(--zw-preset-font-weight));
7
15
  font-family: var(--zw-font-family, var(--zw-preset-font-family));
@@ -14,26 +22,26 @@
14
22
  @media (min-width: 1200px) {
15
23
 
16
24
  .zw-style {
17
- font-size: var(--zw-desktop-font-size, var(--zw-preset-desktop-font-size));
18
- text-align: var(--zw-desktop-text-align, var(--zw-preset-desktop-text-align));
19
- line-height: var(--zw-desktop-line-height, var(--zw-preset-desktop-line-height));
25
+ font-size: var(--zw-font-size-desktop, var(--zw-preset-desktop-font-size));
26
+ text-align: var(--zw-text-align-desktop, var(--zw-preset-desktop-text-align));
27
+ line-height: var(--zw-line-height-desktop, var(--zw-preset-desktop-line-height));
20
28
  }
21
29
  }
22
30
 
23
31
  @media (min-width: 769px) and (max-width: 1199.98px) {
24
32
 
25
33
  .zw-style {
26
- font-size: var(--zw-tablet-font-size, var(--zw-preset-tablet-font-size));
27
- text-align: var(--zw-tablet-text-align, var(--zw-preset-tablet-text-align));
28
- line-height: var(--zw-tablet-line-height, var(--zw-preset-tablet-line-height));
34
+ font-size: var(--zw-font-size-tablet, var(--zw-preset-tablet-font-size));
35
+ text-align: var(--zw-text-align-tablet, var(--zw-preset-tablet-text-align));
36
+ line-height: var(--zw-line-height-tablet, var(--zw-preset-tablet-line-height));
29
37
  }
30
38
  }
31
39
 
32
40
  @media (max-width: 768.98px) {
33
41
 
34
42
  .zw-style {
35
- font-size: var(--zw-mobile-font-size, var(--zw-preset-mobile-font-size));
36
- text-align: var(--zw-mobile-text-align, var(--zw-preset-mobile-text-align));
37
- line-height: var(--zw-mobile-line-height, var(--zw-preset-mobile-line-height));
43
+ font-size: var(--zw-font-size-mobile, var(--zw-preset-mobile-font-size));
44
+ text-align: var(--zw-text-align-mobile, var(--zw-preset-mobile-text-align));
45
+ line-height: var(--zw-line-height-mobile, var(--zw-preset-mobile-line-height));
38
46
  }
39
47
  }
@@ -1,3 +1,19 @@
1
+ .zw-margin-bottom--xxs {
2
+ margin-bottom: var(--zw-offset-xxs);
3
+ }
4
+
1
5
  .zw-margin-bottom--xs {
2
6
  margin-bottom: var(--zw-offset-xs);
3
7
  }
8
+
9
+ .zw-margin-bottom--sm {
10
+ margin-bottom: var(--zw-offset-sm);
11
+ }
12
+
13
+ .zw-margin-bottom--md {
14
+ margin-bottom: var(--zw-offset-md);
15
+ }
16
+
17
+ .zw-margin-right--xs {
18
+ margin-right: var(--zw-offset-xs);
19
+ }
@@ -8,13 +8,17 @@
8
8
  --zw-color-n80: 196, 196, 196; /* #C4C4C4 */
9
9
  --zw-color-n85: 217, 217, 217; /* #D9D9D9 */
10
10
  --zw-color-n90: 230, 230, 230; /* #E6E6E6 */
11
+ --zw-color-n200: 194, 200, 209; /* #C2C8D1 */
11
12
  --zw-color-black: 0, 0, 0;
12
13
  --zw-color-white: 255, 255, 255;
14
+ --zw-color-green: 59, 180, 74; /* #3BB44A */
15
+ --zw-color-red: 234, 58, 58; /* #EA3A3A */
13
16
 
14
17
  --zw-offset-xxs: 4px;
15
18
  --zw-offset-xs: 8px;
16
19
  --zw-offset-xsm: 12px;
17
20
  --zw-offset-sm: 16px;
21
+ --zw-offset-md: 24px;
18
22
 
19
23
  --zw-font-weight-thin: 400;
20
24
  --zw-font-weight-semibold: 500;
@@ -42,6 +46,8 @@ $builder-N90: #E6E6E6;
42
46
  $builder-N94: #F0F0F0;
43
47
  $builder-N96: #F5F5F5;
44
48
  $builder-N98: #FAFAFA;
49
+ $builder-N200: #C2C8D1;
50
+ $builder-R50: #EA3A3A;
45
51
 
46
52
  $font-size-xxs: 12px;
47
53
  $font-size-xs: 14px;
@@ -5,7 +5,7 @@ Array [
5
5
  "span",
6
6
  Object {
7
7
  "class": "zw-style",
8
- "style": "--zw-mobile-font-size: 12px; --zw-tablet-font-size: 14px; --zw-desktop-font-size: 16px;",
8
+ "style": "--zw-mobile-font-size:12px;--zw-tablet-font-size:14px;--zw-desktop-font-size:16px;",
9
9
  },
10
10
  0,
11
11
  ]
@@ -16,7 +16,7 @@ Array [
16
16
  "span",
17
17
  Object {
18
18
  "class": "zw-style",
19
- "style": "--zw-desktop-font-size: 16px;",
19
+ "style": "--zw-desktop-font-size:16px;",
20
20
  },
21
21
  0,
22
22
  ]
@@ -27,7 +27,7 @@ Array [
27
27
  "span",
28
28
  Object {
29
29
  "class": "zw-style",
30
- "style": "--zw-font-size: 12px;",
30
+ "style": "--zw-font-size:12px;",
31
31
  },
32
32
  0,
33
33
  ]
@@ -35,6 +35,6 @@ Array [
35
35
 
36
36
  exports[`render settings should render unwrapped styles 1`] = `
37
37
  Object {
38
- "style": "--zw-desktop-font-size: 16px;",
38
+ "style": "--zw-desktop-font-size:16px;",
39
39
  }
40
40
  `;
@@ -4,7 +4,7 @@ export function renderInlineSetting(setting) {
4
4
 
5
5
  const property = name.replace(/_/g, '-');
6
6
 
7
- return `${css} --zw-${property}: ${value};`.trimStart();
7
+ return `${css}--zw-${property}:${value};`;
8
8
  }, '');
9
9
 
10
10
  return style ? { style } : null;