@zipify/wysiwyg 4.12.0-beta.2 → 4.12.0-beta.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.
Files changed (48) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +27 -27
  3. package/dist/node.js +21 -21
  4. package/dist/types/enums/Device.d.ts +2 -1
  5. package/dist/types/enums/TextSetting.d.ts +0 -1
  6. package/dist/types/services/NodeFactory.d.ts +1 -1
  7. package/dist/types/utils/clone.d.ts +1 -0
  8. package/dist/types/utils/index.d.ts +1 -1
  9. package/dist/wysiwyg.css +28 -46
  10. package/dist/wysiwyg.mjs +184 -326
  11. package/example/ExampleApp.vue +6 -3
  12. package/example/presets.js +203 -227
  13. package/lib/components/base/NumberField.vue +2 -2
  14. package/lib/components/toolbar/controls/index.js +0 -1
  15. package/lib/components/toolbar/layouts/ToolbarDesktop.vue +0 -2
  16. package/lib/components/toolbar/layouts/ToolbarMobile.vue +0 -2
  17. package/lib/enums/Device.ts +2 -1
  18. package/lib/enums/TextSetting.ts +0 -2
  19. package/lib/extensions/Alignment.js +3 -2
  20. package/lib/extensions/DeviceManager.js +20 -3
  21. package/lib/extensions/FontSize.js +12 -6
  22. package/lib/extensions/LineHeight.js +3 -2
  23. package/lib/extensions/__tests__/Alignment.test.js +14 -2
  24. package/lib/extensions/__tests__/FontSize.test.js +14 -2
  25. package/lib/extensions/__tests__/LineHeight.test.js +14 -2
  26. package/lib/extensions/__tests__/__snapshots__/Alignment.test.js.snap +27 -0
  27. package/lib/extensions/__tests__/__snapshots__/FontSize.test.js.snap +30 -0
  28. package/lib/extensions/__tests__/__snapshots__/LineHeight.test.js.snap +27 -0
  29. package/lib/extensions/core/NodeProcessor.js +4 -2
  30. package/lib/extensions/core/__tests__/NodeProcessor.test.js +10 -1
  31. package/lib/extensions/index.js +0 -2
  32. package/lib/services/NodeFactory.ts +1 -1
  33. package/lib/styles/content.css +0 -3
  34. package/lib/utils/clone.ts +3 -0
  35. package/lib/utils/convertFontSize.js +7 -2
  36. package/lib/utils/index.ts +1 -1
  37. package/package.json +3 -2
  38. package/dist/types/components/toolbar/controls/LetterSpacingControl.vue.d.ts +0 -2
  39. package/dist/types/extensions/LetterSpacing.d.ts +0 -2
  40. package/dist/types/utils/convertEmToPx.d.ts +0 -1
  41. package/dist/types/utils/convertLetterSpacing.d.ts +0 -1
  42. package/lib/assets/icons/letter-spacing.svg +0 -3
  43. package/lib/components/toolbar/controls/LetterSpacingControl.vue +0 -96
  44. package/lib/extensions/LetterSpacing.js +0 -78
  45. package/lib/extensions/__tests__/LetterSpacing.test.js +0 -117
  46. package/lib/extensions/__tests__/__snapshots__/LetterSpacing.test.js.snap +0 -121
  47. package/lib/utils/convertEmToPx.ts +0 -8
  48. package/lib/utils/convertLetterSpacing.ts +0 -5
@@ -34,22 +34,28 @@ export const FontSize = Mark.create({
34
34
  }),
35
35
 
36
36
  applyFontSize: createCommand(({ commands }, value) => {
37
- const device = unref(commands.getDevice());
37
+ const targetDevices = commands.getTargetDevices();
38
+ const attrs = Object.fromEntries(targetDevices.map((device) => [device, value]));
38
39
 
39
- commands.applyMark(this.name, { [device]: value }, {
40
+ commands.applyMark(this.name, attrs, {
40
41
  isAppliedToParent: (parentMark, mark) => {
41
42
  if (parentMark.type.name !== mark.type.name) return false;
42
43
 
43
- return parentMark.attrs[device] === mark.attrs[device];
44
+ return targetDevices.every((device) => parentMark.attrs[device] === mark.attrs[device]);
44
45
  },
45
46
 
46
47
  onAppliedToParent: ({ tr, node, position, mark }) => {
47
- const attrs = { ...mark.attrs, [device]: null };
48
- const canRemove = !Object.values(attrs).some((value) => !!value);
48
+ const updatedAttrs = { ...mark.attrs };
49
+
50
+ targetDevices.forEach((device) => {
51
+ updatedAttrs[device] = null;
52
+ });
53
+
54
+ const canRemove = !Object.values(updatedAttrs).some((value) => !!value);
49
55
 
50
56
  if (canRemove) return false;
51
57
 
52
- const updated = mark.type.create(attrs);
58
+ const updated = mark.type.create(updatedAttrs);
53
59
 
54
60
  if (node.isText) {
55
61
  tr.addMark(position, position + node.nodeSize, updated);
@@ -72,9 +72,10 @@ export const LineHeight = Extension.create({
72
72
  }),
73
73
 
74
74
  applyLineHeight: createCommand(({ commands }, value) => {
75
- const device = unref(commands.getDevice());
75
+ const targetDevices = commands.getTargetDevices();
76
+ const attrs = Object.fromEntries(targetDevices.map((device) => [device, value]));
76
77
 
77
- commands.setBlockAttributes(this.name, { [device]: value }, DEFAULTS);
78
+ commands.setBlockAttributes(this.name, attrs, DEFAULTS);
78
79
  })
79
80
  };
80
81
  }
@@ -21,13 +21,13 @@ const MockStylePreset = Extension.create({
21
21
  }
22
22
  });
23
23
 
24
- function createEditor({ content }) {
24
+ function createEditor({ content, device = 'desktop' }) {
25
25
  return new Editor({
26
26
  content: ContentNormalizer.normalize(content),
27
27
  extensions: buildTestExtensions({
28
28
  include: [
29
29
  MockStylePreset,
30
- DeviceManager.configure({ device: ref('desktop') }),
30
+ DeviceManager.configure({ device: ref(device) }),
31
31
  AlignmentExtension
32
32
  ]
33
33
  })
@@ -82,6 +82,18 @@ describe('change value', () => {
82
82
  expect(editor.getJSON()).toMatchSnapshot();
83
83
  });
84
84
 
85
+ test('should apply value to all devices', () => {
86
+ const editor = createEditor({
87
+ content: createContent({ alignment: null }),
88
+ device: 'all'
89
+ });
90
+
91
+ editor.commands.selectAll();
92
+ editor.commands.applyAlignment(Alignment.RIGHT);
93
+
94
+ expect(editor.getJSON()).toMatchSnapshot();
95
+ });
96
+
85
97
  test('should remove value', () => {
86
98
  const editor = createEditor({
87
99
  content: createContent({
@@ -21,14 +21,14 @@ const MockStylePreset = Extension.create({
21
21
  }
22
22
  });
23
23
 
24
- function createEditor({ content }) {
24
+ function createEditor({ content, device = 'desktop' }) {
25
25
  return new Editor({
26
26
  content: ContentNormalizer.normalize(content),
27
27
  extensions: buildTestExtensions({
28
28
  include: [
29
29
  MockStylePreset,
30
30
  DeviceManager.configure({
31
- device: ref('desktop')
31
+ device: ref(device)
32
32
  }),
33
33
  FontSize.configure({
34
34
  minSize: 5,
@@ -92,6 +92,18 @@ describe('apply font size', () => {
92
92
  expect(editor.getJSON()).toMatchSnapshot();
93
93
  });
94
94
 
95
+ test('should change font size on all devices', () => {
96
+ const editor = createEditor({
97
+ content: createContent(NodeFactory.text('hello world')),
98
+ device: 'all'
99
+ });
100
+
101
+ editor.commands.selectAll();
102
+ editor.commands.applyFontSize('16');
103
+
104
+ expect(editor.getJSON()).toMatchSnapshot();
105
+ });
106
+
95
107
  test('should increase font size', () => {
96
108
  const editor = createEditor({
97
109
  content: createContent(NodeFactory.text('hello world', [
@@ -21,14 +21,14 @@ const MockStylePreset = Extension.create({
21
21
  }
22
22
  });
23
23
 
24
- function createEditor({ content, wrapperEl }) {
24
+ function createEditor({ content, wrapperEl, device = 'desktop' }) {
25
25
  return new Editor({
26
26
  content: ContentNormalizer.normalize(content),
27
27
  extensions: buildTestExtensions({
28
28
  include: [
29
29
  MockStylePreset,
30
30
  DeviceManager.configure({
31
- device: ref('desktop')
31
+ device: ref(device)
32
32
  }),
33
33
  LineHeight.configure({
34
34
  wrapperRef: ref(wrapperEl ?? document.createElement('div'))
@@ -85,6 +85,18 @@ describe('apply value', () => {
85
85
 
86
86
  expect(editor.getJSON()).toMatchSnapshot();
87
87
  });
88
+
89
+ test('should change value on all devices', () => {
90
+ const editor = createEditor({
91
+ content: createContent({ line_height: null }),
92
+ device: 'all'
93
+ });
94
+
95
+ editor.commands.selectAll();
96
+ editor.commands.applyLineHeight('1.41');
97
+
98
+ expect(editor.getJSON()).toMatchSnapshot();
99
+ });
88
100
  });
89
101
 
90
102
  describe('rendering', () => {
@@ -27,6 +27,33 @@ Object {
27
27
  }
28
28
  `;
29
29
 
30
+ exports[`change value should apply value to all devices 1`] = `
31
+ Object {
32
+ "attrs": Object {
33
+ "meta": Object {},
34
+ },
35
+ "content": Array [
36
+ Object {
37
+ "attrs": Object {
38
+ "alignment": Object {
39
+ "desktop": "right",
40
+ "mobile": "right",
41
+ "tablet": "right",
42
+ },
43
+ },
44
+ "content": Array [
45
+ Object {
46
+ "text": "hello world",
47
+ "type": "text",
48
+ },
49
+ ],
50
+ "type": "paragraph",
51
+ },
52
+ ],
53
+ "type": "doc",
54
+ }
55
+ `;
56
+
30
57
  exports[`change value should remove value 1`] = `
31
58
  Object {
32
59
  "attrs": Object {
@@ -30,6 +30,36 @@ Object {
30
30
  }
31
31
  `;
32
32
 
33
+ exports[`apply font size should change font size on all devices 1`] = `
34
+ Object {
35
+ "attrs": Object {
36
+ "meta": Object {},
37
+ },
38
+ "content": Array [
39
+ Object {
40
+ "content": Array [
41
+ Object {
42
+ "text": "hello world",
43
+ "type": "text",
44
+ },
45
+ ],
46
+ "marks": Array [
47
+ Object {
48
+ "attrs": Object {
49
+ "desktop": "16",
50
+ "mobile": "16",
51
+ "tablet": "16",
52
+ },
53
+ "type": "font_size",
54
+ },
55
+ ],
56
+ "type": "paragraph",
57
+ },
58
+ ],
59
+ "type": "doc",
60
+ }
61
+ `;
62
+
33
63
  exports[`apply font size should decrease font size 1`] = `
34
64
  Object {
35
65
  "attrs": Object {
@@ -27,6 +27,33 @@ Object {
27
27
  }
28
28
  `;
29
29
 
30
+ exports[`apply value should change value on all devices 1`] = `
31
+ Object {
32
+ "attrs": Object {
33
+ "meta": Object {},
34
+ },
35
+ "content": Array [
36
+ Object {
37
+ "attrs": Object {
38
+ "line_height": Object {
39
+ "desktop": "1.41",
40
+ "mobile": "1.41",
41
+ "tablet": "1.41",
42
+ },
43
+ },
44
+ "content": Array [
45
+ Object {
46
+ "text": "hello world",
47
+ "type": "text",
48
+ },
49
+ ],
50
+ "type": "paragraph",
51
+ },
52
+ ],
53
+ "type": "doc",
54
+ }
55
+ `;
56
+
30
57
  exports[`parsing html should get value from rendered view 1`] = `
31
58
  Object {
32
59
  "attrs": Object {
@@ -1,6 +1,7 @@
1
1
  import { Extension, getMarkType } from '@tiptap/vue-3';
2
2
  import { computed, toRef, unref } from 'vue';
3
3
  import {
4
+ clone,
4
5
  createCommand,
5
6
  findMarkByType,
6
7
  isMarkAppliedToParent,
@@ -21,6 +22,7 @@ export const NodeProcessor = Extension.create({
21
22
  addCommands() {
22
23
  return {
23
24
  setBlockAttributes: createCommand(({ commands, state }, name, attrs, defaults = {}) => {
25
+ const safeAttrs = clone(attrs);
24
26
  const current = unref(commands.getBlockAttributes(name)) ?? {};
25
27
  const { doc, tr } = state;
26
28
  const { from, to } = tr.selection;
@@ -28,7 +30,7 @@ export const NodeProcessor = Extension.create({
28
30
  doc.nodesBetween(from, to, (node, position) => {
29
31
  if (!NodeBlockTypeList.includes(node.type.name)) return;
30
32
 
31
- tr.setNodeAttribute(position, name, { ...defaults, ...current, ...attrs });
33
+ tr.setNodeAttribute(position, name, { ...defaults, ...current, ...safeAttrs });
32
34
  });
33
35
  }),
34
36
 
@@ -139,7 +141,7 @@ export const NodeProcessor = Extension.create({
139
141
  for (const attrs of unref(selectionRef)) {
140
142
  const value = attrs[unref(deviceRef)];
141
143
 
142
- if (value || value === 0) return value;
144
+ if (value) return value;
143
145
  }
144
146
 
145
147
  return unref(defaultRef);
@@ -62,7 +62,16 @@ const DeviceManager = Extension.create({
62
62
  }),
63
63
 
64
64
  addCommands() {
65
- return { getDevice: createCommand(() => ref(this.options.device)) };
65
+ return {
66
+ getDevice: createCommand(() => ref(this.options.device)),
67
+ getTargetDevices: createCommand(() => {
68
+ const device = this.options.device;
69
+
70
+ return device === Device.ALL
71
+ ? [Device.DESKTOP, Device.TABLET, Device.MOBILE]
72
+ : [device];
73
+ })
74
+ };
66
75
  }
67
76
  });
68
77
 
@@ -13,7 +13,6 @@ import { TextDecoration } from './TextDecoration';
13
13
  import { CaseStyle } from './CaseStyle';
14
14
  import { Alignment } from './Alignment';
15
15
  import { LineHeight } from './LineHeight';
16
- import { LetterSpacing } from './LetterSpacing';
17
16
  import { List } from './list';
18
17
  import { Link } from './Link';
19
18
  import { Superscript } from './Superscript';
@@ -67,7 +66,6 @@ export function buildExtensions(options) {
67
66
  LineHeight.configure({
68
67
  wrapperRef: options.wrapperRef
69
68
  }),
70
- LetterSpacing,
71
69
  Link.configure({
72
70
  preset: toRef(presetsMap, 'link'),
73
71
  basePresetClass: options.basePresetClass,
@@ -136,7 +136,7 @@ export class NodeFactory {
136
136
  return { type, attrs };
137
137
  }
138
138
 
139
- static populateAllDevices<V>(value: V): Record<Exclude<Device, Device.COMMON>, V> {
139
+ static populateAllDevices<V>(value: V): Record<Exclude<Device, Device.COMMON | Device.ALL>, V> {
140
140
  return { mobile: value, tablet: value, desktop: value };
141
141
  }
142
142
  }
@@ -36,7 +36,6 @@ h4.zw-style.zw-style.zw-style {
36
36
  font-size: var(--zw-font-size-desktop, var(--zw-preset-font-size-desktop));
37
37
  text-align: var(--zw-alignment-desktop, var(--zw-preset-alignment-desktop));
38
38
  line-height: var(--zw-line-height-desktop, var(--zw-preset-line-height-desktop));
39
- letter-spacing: var(--zw-letter-spacing-desktop, var(--zw-preset-letter-spacing-desktop));
40
39
  }
41
40
  }
42
41
 
@@ -46,7 +45,6 @@ h4.zw-style.zw-style.zw-style {
46
45
  font-size: var(--zw-font-size-tablet, var(--zw-preset-font-size-tablet));
47
46
  text-align: var(--zw-alignment-tablet, var(--zw-preset-alignment-tablet));
48
47
  line-height: var(--zw-line-height-tablet, var(--zw-preset-line-height-tablet));
49
- letter-spacing: var(--zw-letter-spacing-tablet, var(--zw-preset-letter-spacing-tablet));
50
48
  }
51
49
  }
52
50
 
@@ -56,7 +54,6 @@ h4.zw-style.zw-style.zw-style {
56
54
  font-size: var(--zw-font-size-mobile, var(--zw-preset-font-size-mobile));
57
55
  text-align: var(--zw-alignment-mobile, var(--zw-preset-alignment-mobile));
58
56
  line-height: var(--zw-line-height-mobile, var(--zw-preset-line-height-mobile));
59
- letter-spacing: var(--zw-letter-spacing-mobile, var(--zw-preset-letter-spacing-mobile));
60
57
  }
61
58
  }
62
59
 
@@ -0,0 +1,3 @@
1
+ export function clone<T>(value: T): T {
2
+ return JSON.parse(JSON.stringify(value));
3
+ }
@@ -1,5 +1,10 @@
1
- import { convertEmToPx } from './convertEmToPx';
1
+ import { ContextWindow } from '../services';
2
2
 
3
3
  export function convertFontSize(value, wrapperEl) {
4
- return String(value).includes('em') ? Math.round(convertEmToPx(value, wrapperEl)) : parseInt(value);
4
+ if (!value.includes('em')) return parseInt(value);
5
+
6
+ const containerValue = ContextWindow.getComputedStyle(wrapperEl).fontSize;
7
+ const size = parseFloat(value) * parseFloat(containerValue);
8
+
9
+ return Math.round(size);
5
10
  }
@@ -5,7 +5,6 @@ export { createKeyboardShortcut } from './createKeyboardShortcut';
5
5
  export { convertColor } from './convertColor';
6
6
  export { convertLineHeight } from './convertLineHeight';
7
7
  export { convertFontSize } from './convertFontSize';
8
- export { convertLetterSpacing } from './convertLetterSpacing';
9
8
  export { convertAlignment } from './convertAlignment';
10
9
  export { importIcon } from './importIcon';
11
10
  export { isWysiwygContent } from './isWysiwygContent';
@@ -15,3 +14,4 @@ export { isNodeFullySelected } from './isNodeFullySelected';
15
14
  export { isMarkAppliedToParent } from './isMarkAppliedToParent';
16
15
  export { findMarkByType } from './findMarkByType';
17
16
  export { copyMark } from './copyMark';
17
+ export { clone } from './clone';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zipify/wysiwyg",
3
- "version": "4.12.0-beta.2",
3
+ "version": "4.12.0-beta.3",
4
4
  "description": "Zipify modification of TipTap text editor",
5
5
  "main": "dist/wysiwyg.mjs",
6
6
  "types": "dist/wysiwyg.d.ts",
@@ -30,7 +30,8 @@
30
30
  "lint:js": "zipify-lint-js --oxlint-tsconfig ./tsconfig.lint.json ./lib",
31
31
  "lint:css": "stylelint ./lib/**/*.{css,vue}",
32
32
  "optimize-svg": "svgo --config ./config/svgo.js",
33
- "prepare": "husky"
33
+ "prepare": "husky",
34
+ "check-types": "vue-tsc -P ./tsconfig.types.json --noEmit"
34
35
  },
35
36
  "dependencies": {
36
37
  "@floating-ui/vue": "^1.1.6",
@@ -1,2 +0,0 @@
1
- declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
- export default _default;
@@ -1,2 +0,0 @@
1
- export const LetterSpacing: Mark<any, any>;
2
- import { Mark } from '@tiptap/vue-3';
@@ -1 +0,0 @@
1
- export declare function convertEmToPx(value: string, wrapperEl: HTMLElement): number;
@@ -1 +0,0 @@
1
- export declare function convertLetterSpacing(value: string, wrapperEl: HTMLElement): number;
@@ -1,3 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" style="width:var(--zw-icon-width);height:var(--zw-icon-height)" viewBox="0 0 24 24">
2
- <path fill="var(--zw-icon-foreground)" fill-rule="evenodd" d="M3 19V5h1.8v14zm16.2 0V5H21v14zM7.815 16.375l3.375-8.75h1.62l3.375 8.75h-1.552l-.81-2.231h-3.645l-.81 2.231zm2.835-3.5h2.7l-1.305-3.631h-.09z" clip-rule="evenodd"/>
3
- </svg>
@@ -1,96 +0,0 @@
1
- <template>
2
- <div class="zw-position--relative" ref="wrapperRef">
3
- <Button
4
- class="zw-position--relative"
5
- icon
6
- skin="toolbar"
7
- :active="toggler.isOpened"
8
- @click="toggler.open"
9
- v-tooltip="'Letter Spacing'"
10
- >
11
- <Icon name="letter-spacing" size="28px" auto-color />
12
-
13
- <span
14
- v-if="isCustomized"
15
- class="zw-button__customized-indicator"
16
- data-test-selector="customizedIndicator"
17
- v-tooltip.lg="'Style differs from Page Styles'"
18
- />
19
- </Button>
20
-
21
- <Modal
22
- class="zw-letter-spacing-control__modal"
23
- :toggler="toggler"
24
- :reference-ref="wrapperRef"
25
- >
26
- <FieldLabel class="zw-margin-bottom--xs" field-id="wswg-letter-spacing">
27
- Letter Spacing
28
- </FieldLabel>
29
-
30
- <div class="zw-letter-spacing-control__row">
31
- <Range
32
- class="zw-letter-spacing-control__range"
33
- :step="STEP"
34
- :min="MIN_VALUE"
35
- :max="MAX_VALUE"
36
- :value="currentValue"
37
- @input="apply"
38
- />
39
-
40
- <NumberField
41
- :step="STEP"
42
- :min="MIN_VALUE"
43
- :max="MAX_VALUE"
44
- units="px"
45
- class="zw-letter-spacing-control__field"
46
- field-id="wswg-letter-spacing"
47
- :value="currentValue"
48
- @input="apply"
49
- />
50
- </div>
51
- </Modal>
52
- </div>
53
- </template>
54
-
55
- <script setup>
56
- import { inject, ref, computed } from 'vue';
57
- import { Button, Icon, Modal, Range, NumberField, FieldLabel, useModalToggler } from '../../base';
58
- import { InjectionTokens } from '../../../injectionTokens';
59
- import { tooltip as vTooltip } from '../../../directives';
60
- import { TextSetting } from '../../../enums';
61
-
62
- const MIN_VALUE = -1.6;
63
- const MAX_VALUE = 3.2;
64
- const STEP = 0.1;
65
-
66
- const editor = inject(InjectionTokens.EDITOR);
67
- const wrapperRef = ref(null);
68
- const toggler = useModalToggler();
69
-
70
- const valueRef = editor.commands.getLetterSpacing();
71
-
72
- const currentValue = computed(() => valueRef.value ?? 0);
73
- const isCustomized = editor.commands.isSettingCustomized(TextSetting.LETTER_SPACING);
74
-
75
- const apply = (value) => editor.commands.applyLetterSpacing(value);
76
- </script>
77
-
78
- <style scoped>
79
- .zw-letter-spacing-control__modal {
80
- padding: var(--zw-offset-sm);
81
- }
82
-
83
- .zw-letter-spacing-control__row {
84
- display: flex;
85
- align-items: center;
86
- }
87
-
88
- .zw-letter-spacing-control__range {
89
- width: 156px;
90
- }
91
-
92
- .zw-letter-spacing-control__field {
93
- width: 64px;
94
- margin-left: var(--zw-offset-sm);
95
- }
96
- </style>
@@ -1,78 +0,0 @@
1
- import { Mark } from '@tiptap/vue-3';
2
- import { computed, unref } from 'vue';
3
- import { createCommand, renderMark, convertLetterSpacing } from '../utils';
4
- import { MarkGroup, TextSetting } from '../enums';
5
-
6
- export const LetterSpacing = Mark.create({
7
- name: TextSetting.LETTER_SPACING,
8
- group: MarkGroup.SETTINGS,
9
-
10
- addAttributes: () => ({
11
- mobile: { default: null },
12
- tablet: { default: null },
13
- desktop: { default: null }
14
- }),
15
-
16
- addCommands() {
17
- return {
18
- getLetterSpacing: createCommand(({ commands }) => {
19
- return commands.getDeviceSettingMark(this.name, commands.getDefaultLetterSpacing());
20
- }),
21
-
22
- getDefaultLetterSpacing: createCommand(({ commands }) => {
23
- const device = commands.getDevice();
24
- const preset = commands.getPreset();
25
-
26
- return computed(() => unref(preset)[unref(device)].letter_spacing ?? null);
27
- }),
28
-
29
- applyLetterSpacing: createCommand(({ commands }, value) => {
30
- const device = unref(commands.getDevice());
31
-
32
- commands.applyMark(this.name, { [device]: value });
33
- })
34
- };
35
- },
36
-
37
- parseHTML() {
38
- const parse = (value) => {
39
- if (!value) return null;
40
-
41
- const wrapperEl = unref(this.options.wrapperRef);
42
- const converted = convertLetterSpacing(value, wrapperEl);
43
-
44
- return `${converted}px`;
45
- };
46
-
47
- return [
48
- {
49
- tag: '[style*="--zw-letter-spacing"]',
50
-
51
- getAttrs: ({ style }) => ({
52
- mobile: parse(style.getPropertyValue('--zw-letter-spacing-mobile')),
53
- tablet: parse(style.getPropertyValue('--zw-letter-spacing-tablet')),
54
- desktop: parse(style.getPropertyValue('--zw-letter-spacing-desktop'))
55
- })
56
- },
57
- {
58
- style: 'letter-spacing',
59
-
60
- getAttrs: (input) => {
61
- const value = parse(input);
62
-
63
- return { desktop: value, tablet: value, mobile: value };
64
- }
65
- }
66
- ];
67
- },
68
-
69
- renderHTML({ HTMLAttributes: attrs }) {
70
- const addUnits = (value) => value ? `${value}px` : null;
71
-
72
- return renderMark({
73
- letter_spacing_mobile: addUnits(attrs.mobile),
74
- letter_spacing_tablet: addUnits(attrs.tablet),
75
- letter_spacing_desktop: addUnits(attrs.desktop)
76
- });
77
- }
78
- });