@zipify/wysiwyg 4.11.3 → 4.12.0-beta.0

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.
@@ -0,0 +1,78 @@
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
+ });
@@ -0,0 +1,106 @@
1
+ import { Editor, Extension } from '@tiptap/vue-3';
2
+ import { ref } from 'vue';
3
+ import { buildTestExtensions } from '../../__tests__/utils';
4
+ import { createCommand } from '../../utils';
5
+ import { DeviceManager } from '../DeviceManager';
6
+ import { LetterSpacing } from '../LetterSpacing';
7
+ import { ContentNormalizer, NodeFactory } from '../../services';
8
+ import { TextSetting } from '../../enums';
9
+
10
+ const MockStylePreset = Extension.create({
11
+ name: TextSetting.STYLE_PRESET,
12
+
13
+ addCommands() {
14
+ return {
15
+ getPreset: createCommand(() => ref({
16
+ mobile: { letter_spacing: null },
17
+ tablet: { letter_spacing: null },
18
+ desktop: { letter_spacing: null }
19
+ }))
20
+ };
21
+ }
22
+ });
23
+
24
+ function createEditor({ content, wrapperEl } = {}) {
25
+ return new Editor({
26
+ content: ContentNormalizer.normalize(content),
27
+ extensions: buildTestExtensions({
28
+ include: [
29
+ MockStylePreset,
30
+ DeviceManager.configure({
31
+ device: ref('desktop')
32
+ }),
33
+ LetterSpacing.configure({ wrapperRef: ref(wrapperEl ?? document.createElement('div')) })
34
+ ]
35
+ })
36
+ });
37
+ }
38
+
39
+ const createContent = (attrs) => NodeFactory.doc([
40
+ NodeFactory.paragraph(attrs, [
41
+ NodeFactory.text('hello world')
42
+ ])
43
+ ]);
44
+
45
+ describe('LetterSpacing extension', () => {
46
+ describe('get value', () => {
47
+ test('should get from selection', () => {
48
+ const editor = createEditor({
49
+ content: NodeFactory.doc([
50
+ NodeFactory.paragraph({}, [
51
+ NodeFactory.text('hello world', [
52
+ NodeFactory.mark(TextSetting.LETTER_SPACING, {
53
+ mobile: '',
54
+ tablet: '',
55
+ desktop: '-0.7px'
56
+ })
57
+ ])
58
+ ])
59
+ ])
60
+ });
61
+
62
+ editor.commands.selectAll();
63
+
64
+ expect(editor.commands.getLetterSpacing().value).toBe('-0.7px');
65
+ });
66
+
67
+ test('should get default value from preset when null', () => {
68
+ const editor = createEditor({
69
+ content: createContent({ letter_spacing: null })
70
+ });
71
+
72
+ expect(editor.commands.getDefaultLetterSpacing().value).toBe(null);
73
+ });
74
+ });
75
+
76
+ describe('apply value', () => {
77
+ test('should change value', () => {
78
+ const editor = createEditor({
79
+ content: createContent({ letter_spacing: null })
80
+ });
81
+
82
+ editor.commands.selectAll();
83
+ editor.commands.applyLetterSpacing('-1');
84
+
85
+ expect(editor.getJSON()).toMatchSnapshot();
86
+ });
87
+ });
88
+
89
+ describe('parsing html', () => {
90
+ test('should parse inline letter-spacing px to value with px preserved', () => {
91
+ const editor = createEditor({
92
+ content: '<p style="letter-spacing: -0.7px">test</p>'
93
+ });
94
+
95
+ expect(editor.getJSON()).toMatchSnapshot();
96
+ });
97
+
98
+ test('should parse custom var style', () => {
99
+ const editor = createEditor({
100
+ content: '<p style="--zw-letter-spacing-desktop: -0.7px;--zw-letter-spacing-tablet: 0px;--zw-letter-spacing-mobile: 3.6px">test</p>'
101
+ });
102
+
103
+ expect(editor.getJSON()).toMatchSnapshot();
104
+ });
105
+ });
106
+ });
@@ -0,0 +1,91 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`LetterSpacing extension apply value should change value 1`] = `
4
+ Object {
5
+ "attrs": Object {
6
+ "meta": Object {},
7
+ },
8
+ "content": Array [
9
+ Object {
10
+ "content": Array [
11
+ Object {
12
+ "text": "hello world",
13
+ "type": "text",
14
+ },
15
+ ],
16
+ "marks": Array [
17
+ Object {
18
+ "attrs": Object {
19
+ "desktop": "-1",
20
+ "mobile": null,
21
+ "tablet": null,
22
+ },
23
+ "type": "letter_spacing",
24
+ },
25
+ ],
26
+ "type": "paragraph",
27
+ },
28
+ ],
29
+ "type": "doc",
30
+ }
31
+ `;
32
+
33
+ exports[`LetterSpacing extension parsing html should parse custom var style 1`] = `
34
+ Object {
35
+ "attrs": Object {
36
+ "meta": Object {},
37
+ },
38
+ "content": Array [
39
+ Object {
40
+ "content": Array [
41
+ Object {
42
+ "text": "test",
43
+ "type": "text",
44
+ },
45
+ ],
46
+ "marks": Array [
47
+ Object {
48
+ "attrs": Object {
49
+ "desktop": "-0.7px",
50
+ "mobile": "3.6px",
51
+ "tablet": "0px",
52
+ },
53
+ "type": "letter_spacing",
54
+ },
55
+ ],
56
+ "type": "paragraph",
57
+ },
58
+ ],
59
+ "type": "doc",
60
+ }
61
+ `;
62
+
63
+ exports[`LetterSpacing extension parsing html should parse inline letter-spacing px to value with px preserved 1`] = `
64
+ Object {
65
+ "attrs": Object {
66
+ "meta": Object {},
67
+ },
68
+ "content": Array [
69
+ Object {
70
+ "content": Array [
71
+ Object {
72
+ "text": "test",
73
+ "type": "text",
74
+ },
75
+ ],
76
+ "marks": Array [
77
+ Object {
78
+ "attrs": Object {
79
+ "desktop": "-0.7px",
80
+ "mobile": "-0.7px",
81
+ "tablet": "-0.7px",
82
+ },
83
+ "type": "letter_spacing",
84
+ },
85
+ ],
86
+ "type": "paragraph",
87
+ },
88
+ ],
89
+ "type": "doc",
90
+ }
91
+ `;
@@ -13,6 +13,7 @@ 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';
16
17
  import { List } from './list';
17
18
  import { Link } from './Link';
18
19
  import { Superscript } from './Superscript';
@@ -66,6 +67,7 @@ export function buildExtensions(options) {
66
67
  LineHeight.configure({
67
68
  wrapperRef: options.wrapperRef
68
69
  }),
70
+ LetterSpacing,
69
71
  Link.configure({
70
72
  preset: toRef(presetsMap, 'link'),
71
73
  basePresetClass: options.basePresetClass,
@@ -36,6 +36,7 @@ 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));
39
40
  }
40
41
  }
41
42
 
@@ -45,6 +46,7 @@ h4.zw-style.zw-style.zw-style {
45
46
  font-size: var(--zw-font-size-tablet, var(--zw-preset-font-size-tablet));
46
47
  text-align: var(--zw-alignment-tablet, var(--zw-preset-alignment-tablet));
47
48
  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));
48
50
  }
49
51
  }
50
52
 
@@ -54,6 +56,7 @@ h4.zw-style.zw-style.zw-style {
54
56
  font-size: var(--zw-font-size-mobile, var(--zw-preset-font-size-mobile));
55
57
  text-align: var(--zw-alignment-mobile, var(--zw-preset-alignment-mobile));
56
58
  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));
57
60
  }
58
61
  }
59
62
 
@@ -0,0 +1,8 @@
1
+ import { ContextWindow } from '../services';
2
+
3
+ export function convertEmToPx(value: string, wrapperEl: HTMLElement): number {
4
+ const containerValue = ContextWindow.getComputedStyle(wrapperEl).fontSize;
5
+ const size = parseFloat(value) * parseFloat(containerValue);
6
+
7
+ return Math.round(size * 10) / 10;
8
+ }
@@ -1,10 +1,5 @@
1
- import { ContextWindow } from '../services';
1
+ import { convertEmToPx } from './convertEmToPx';
2
2
 
3
3
  export function convertFontSize(value, wrapperEl) {
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);
4
+ return String(value).includes('em') ? Math.round(convertEmToPx(value, wrapperEl)) : parseInt(value);
10
5
  }
@@ -0,0 +1,5 @@
1
+ import { convertEmToPx } from './convertEmToPx';
2
+
3
+ export function convertLetterSpacing(value: string, wrapperEl: HTMLElement): number {
4
+ return String(value).includes('em') ? convertEmToPx(value, wrapperEl) : parseFloat(value);
5
+ }
@@ -5,6 +5,7 @@ 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';
8
9
  export { convertAlignment } from './convertAlignment';
9
10
  export { importIcon } from './importIcon';
10
11
  export { isWysiwygContent } from './isWysiwygContent';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zipify/wysiwyg",
3
- "version": "4.11.3",
3
+ "version": "4.12.0-beta.0",
4
4
  "description": "Zipify modification of TipTap text editor",
5
5
  "main": "dist/wysiwyg.mjs",
6
6
  "types": "dist/wysiwyg.d.ts",
@@ -88,7 +88,7 @@
88
88
  "@vue/test-utils": "^2.4.6",
89
89
  "@vue/tsconfig": "^0.7.0",
90
90
  "@vue/vue3-jest": "^29.2.6",
91
- "@zipify/colorpicker": "^4.1.4",
91
+ "@zipify/colorpicker": "^4.1.5",
92
92
  "@zipify/eslint-config": "^3.0.8",
93
93
  "babel-jest": "^29.7.0",
94
94
  "esbuild-jest-transform": "^2.0.1",