@zipify/wysiwyg 1.0.0-dev.4 → 1.0.0-dev.7
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/.eslintignore +1 -0
- package/.release-it.json +0 -1
- package/.stylelintignore +1 -0
- package/README.md +3 -1
- package/config/jest/setupTests.js +7 -1
- package/config/webpack/example.config.js +2 -0
- package/config/webpack/lib.config.js +40 -0
- package/config/webpack/loaders/style-loader.js +3 -1
- package/config/webpack/loaders/svg-loader.js +1 -1
- package/dist/wysiwyg.css +837 -0
- package/dist/wysiwyg.js +2 -0
- package/dist/wysiwyg.js.LICENSE.txt +1 -0
- package/example/ExampleApp.vue +39 -31
- package/example/example.js +26 -0
- package/example/presets.js +2 -0
- package/lib/Wysiwyg.vue +6 -0
- package/lib/assets/icons/alignment-center.svg +3 -0
- package/lib/assets/icons/alignment-justify.svg +3 -0
- package/lib/assets/icons/alignment-left.svg +3 -0
- package/lib/assets/icons/alignment-right.svg +3 -0
- package/lib/assets/icons/arrow.svg +3 -0
- package/lib/assets/icons/background-color.svg +3 -0
- package/lib/assets/icons/case-style.svg +3 -0
- package/lib/assets/icons/font-color.svg +5 -0
- package/lib/assets/icons/italic.svg +3 -0
- package/lib/assets/icons/line-height.svg +3 -0
- package/lib/assets/icons/list-circle.svg +3 -0
- package/lib/assets/icons/list-decimal.svg +3 -0
- package/lib/assets/icons/list-disc.svg +3 -0
- package/lib/assets/icons/list-latin.svg +3 -0
- package/lib/assets/icons/list-roman.svg +3 -0
- package/lib/assets/icons/list-square.svg +3 -0
- package/lib/assets/icons/remove-format.svg +3 -0
- package/lib/assets/icons/reset-styles.svg +3 -0
- package/lib/assets/icons/strike-through.svg +3 -0
- package/lib/assets/icons/superscript.svg +3 -0
- package/lib/assets/icons/underline.svg +3 -0
- package/lib/components/base/Icon.vue +17 -9
- package/lib/components/base/__tests__/Icon.test.js +6 -13
- package/lib/composables/__tests__/useEditor.test.js +12 -3
- package/lib/composables/useEditor.js +12 -5
- package/lib/extensions/Alignment.js +6 -0
- package/lib/extensions/BackgroundColor.js +8 -1
- package/lib/extensions/FontColor.js +8 -1
- package/lib/extensions/FontFamily.js +7 -0
- package/lib/extensions/FontSize.js +12 -0
- package/lib/extensions/FontStyle.js +11 -0
- package/lib/extensions/FontWeight.js +25 -1
- package/lib/extensions/LineHeight.js +17 -0
- package/lib/extensions/StylePreset.js +30 -3
- package/lib/extensions/TextDecoration.js +11 -0
- package/lib/extensions/__tests__/Alignment.test.js +22 -1
- package/lib/extensions/__tests__/BackgroundColor.test.js +30 -1
- package/lib/extensions/__tests__/CaseStyle.test.js +4 -1
- package/lib/extensions/__tests__/FontColor.test.js +30 -1
- package/lib/extensions/__tests__/FontFamily.test.js +30 -1
- package/lib/extensions/__tests__/FontSize.test.js +30 -1
- package/lib/extensions/__tests__/FontStyle.test.js +38 -1
- package/lib/extensions/__tests__/FontWeight.test.js +58 -1
- package/lib/extensions/__tests__/LineHeight.test.js +41 -1
- package/lib/extensions/__tests__/StylePreset.test.js +76 -1
- package/lib/extensions/__tests__/TextDecoration.test.js +63 -1
- package/lib/extensions/__tests__/__snapshots__/Alignment.test.js.snap +44 -0
- package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +91 -0
- package/lib/extensions/__tests__/__snapshots__/FontColor.test.js.snap +91 -0
- package/lib/extensions/__tests__/__snapshots__/FontFamily.test.js.snap +91 -0
- package/lib/extensions/__tests__/__snapshots__/FontSize.test.js.snap +99 -0
- package/lib/extensions/__tests__/__snapshots__/FontStyle.test.js.snap +120 -0
- package/lib/extensions/__tests__/__snapshots__/FontWeight.test.js.snap +149 -0
- package/lib/extensions/__tests__/__snapshots__/LineHeight.test.js.snap +92 -0
- package/lib/extensions/__tests__/__snapshots__/StylePreset.test.js.snap +167 -2
- package/lib/extensions/__tests__/__snapshots__/TextDecoration.test.js.snap +207 -0
- package/lib/extensions/core/__tests__/NodeProcessor.test.js +4 -1
- package/lib/extensions/core/__tests__/SelectionProcessor.test.js +9 -4
- package/lib/extensions/core/__tests__/TextProcessor.test.js +4 -1
- package/lib/extensions/index.js +1 -0
- package/lib/extensions/list/List.js +34 -0
- package/lib/extensions/list/__tests__/List.test.js +115 -3
- package/lib/extensions/list/__tests__/__snapshots__/List.test.js.snap +457 -6
- package/lib/services/ContentNormalizer.js +113 -0
- package/lib/services/Storage.js +1 -13
- package/lib/services/__tests__/ContentNormalizer.test.js +41 -0
- package/lib/services/__tests__/FavoriteColors.test.js +20 -0
- package/lib/services/__tests__/JsonSerializer.test.js +23 -0
- package/lib/services/__tests__/Storage.test.js +79 -0
- package/lib/services/index.js +1 -0
- package/lib/utils/__tests__/convertColor.test.js +19 -0
- package/lib/utils/__tests__/createKeyboardShortcut.test.js +25 -0
- package/lib/utils/__tests__/renderInlineSetting.test.js +26 -0
- package/lib/utils/convertColor.js +7 -0
- package/lib/utils/importIcon.js +12 -0
- package/lib/utils/index.js +2 -0
- package/lib/utils/renderInlineSetting.js +1 -1
- package/package.json +5 -6
- package/lib/assets/icons.svg +0 -69
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export class ContentNormalizer {
|
|
2
|
+
static NORMALIZING_STYLE_BLACKLIST = ['text-align', 'line-height'];
|
|
3
|
+
|
|
4
|
+
normalize(content) {
|
|
5
|
+
if (typeof content !== 'string') return content;
|
|
6
|
+
|
|
7
|
+
return this._normalizeTextContent(content);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
_normalizeTextContent(content) {
|
|
11
|
+
const parser = new DOMParser();
|
|
12
|
+
const dom = parser.parseFromString(content, 'text/html');
|
|
13
|
+
|
|
14
|
+
this._iterateNodes(dom, this._normalizeStructure.bind(this), (node) => node.tagName === 'SPAN');
|
|
15
|
+
this._iterateNodes(dom, this._normalizeStyles.bind(this), (node) => node.tagName !== 'SPAN');
|
|
16
|
+
|
|
17
|
+
return dom.body.innerHTML;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_iterateNodes(dom, handler, condition) {
|
|
21
|
+
const iterator = dom.createNodeIterator(dom.body, NodeFilter.SHOW_ELEMENT, {
|
|
22
|
+
acceptNode: (node) => condition(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
|
|
23
|
+
});
|
|
24
|
+
let currentNode = iterator.nextNode();
|
|
25
|
+
|
|
26
|
+
while (currentNode) {
|
|
27
|
+
handler(currentNode);
|
|
28
|
+
currentNode = iterator.nextNode();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
_normalizeStructure(element) {
|
|
33
|
+
const isTextChildren = Array.from(element.childNodes)
|
|
34
|
+
.every((node) => node.nodeType === Node.TEXT_NODE);
|
|
35
|
+
|
|
36
|
+
if (isTextChildren) return;
|
|
37
|
+
|
|
38
|
+
const cloned = element.cloneNode(true);
|
|
39
|
+
const migratingStyles = this._getMigratingStyles(element);
|
|
40
|
+
const content = [];
|
|
41
|
+
|
|
42
|
+
for (const node of cloned.childNodes) {
|
|
43
|
+
let child = node;
|
|
44
|
+
|
|
45
|
+
if (migratingStyles.length) {
|
|
46
|
+
child = this._wrapTextNode(cloned, node);
|
|
47
|
+
this._assignElementProperties(child, cloned, migratingStyles);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
content.push(child);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
element.replaceWith(...content);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
_normalizeStyles(element) {
|
|
57
|
+
const properties = this._getMigratingStyles(element);
|
|
58
|
+
|
|
59
|
+
for (const node of element.childNodes) {
|
|
60
|
+
const child = this._wrapTextNode(element, node);
|
|
61
|
+
|
|
62
|
+
this._assignElementProperties(child, element, properties);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this._removeStyleProperties(element, properties);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_getMigratingStyles(element) {
|
|
69
|
+
const blacklist = ContentNormalizer.NORMALIZING_STYLE_BLACKLIST;
|
|
70
|
+
const properties = [];
|
|
71
|
+
|
|
72
|
+
for (let index = 0; index < element.style.length; index++) {
|
|
73
|
+
const property = element.style.item(index);
|
|
74
|
+
|
|
75
|
+
if (!blacklist.includes(property)) {
|
|
76
|
+
properties.push(property);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return properties;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
_wrapTextNode(parent, node) {
|
|
84
|
+
if (node.nodeType !== Node.TEXT_NODE) return node;
|
|
85
|
+
|
|
86
|
+
const span = document.createElement('span');
|
|
87
|
+
|
|
88
|
+
span.append(node.cloneNode());
|
|
89
|
+
parent.replaceChild(span, node);
|
|
90
|
+
|
|
91
|
+
return span;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
_assignElementProperties(target, source, properties) {
|
|
95
|
+
for (const property of properties) {
|
|
96
|
+
if (target.style.getPropertyValue(property)) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
target.style.setProperty(property, source.style.getPropertyValue(property));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
_removeStyleProperties(element, properties) {
|
|
105
|
+
for (const property of properties) {
|
|
106
|
+
element.style.removeProperty(property);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (element.style.length === 0) {
|
|
110
|
+
element.removeAttribute('style');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
package/lib/services/Storage.js
CHANGED
|
@@ -17,19 +17,11 @@ export class Storage {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
getItem(key) {
|
|
20
|
-
const json = this.
|
|
20
|
+
const json = this.accessToStorage((storage) => storage.getItem(this.makeKey(key)));
|
|
21
21
|
|
|
22
22
|
return JsonSerializer.decode(json);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
removeItem(key) {
|
|
26
|
-
this.accessToStorage((storage) => storage.removeItem(this.makeKey(key)));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
hasItem(key) {
|
|
30
|
-
return !!this._getItemFromStorage(key);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
25
|
accessToStorage(action) {
|
|
34
26
|
try {
|
|
35
27
|
return action(this.nativeStorage);
|
|
@@ -38,10 +30,6 @@ export class Storage {
|
|
|
38
30
|
}
|
|
39
31
|
}
|
|
40
32
|
|
|
41
|
-
_getItemFromStorage(key) {
|
|
42
|
-
return this.accessToStorage((storage) => storage.getItem(this.makeKey(key)));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
33
|
onPrivateModeEnabled(error) {
|
|
46
34
|
// eslint-disable-next-line no-console
|
|
47
35
|
console.error(error);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ContentNormalizer } from '../ContentNormalizer';
|
|
2
|
+
import { NodeFactory } from '../../__tests__/utils';
|
|
3
|
+
|
|
4
|
+
const normalize = (content) => new ContentNormalizer().normalize(content);
|
|
5
|
+
|
|
6
|
+
describe('normalize text settings', () => {
|
|
7
|
+
test('should ignore json content', () => {
|
|
8
|
+
const content = NodeFactory.doc([NodeFactory.paragraph('Test')]);
|
|
9
|
+
|
|
10
|
+
expect(normalize(content)).toBe(content);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('should flat structure', () => {
|
|
14
|
+
const input = '<p style="text-align: center; color: rgb(255, 255, 255);"><span style="background-color: rgb(255, 0, 0);">lore<span style="color: rgb(0, 0, 0);">m ip</span>sum</span></p>';
|
|
15
|
+
const output = '<p style="text-align: center;">' +
|
|
16
|
+
'<span style="background-color: rgb(255, 0, 0); color: rgb(255, 255, 255);">lore</span>' +
|
|
17
|
+
'<span style="color: rgb(0, 0, 0); background-color: rgb(255, 0, 0);">m ip</span>' +
|
|
18
|
+
'<span style="background-color: rgb(255, 0, 0); color: rgb(255, 255, 255);">sum</span>' +
|
|
19
|
+
'</p>';
|
|
20
|
+
|
|
21
|
+
expect(normalize(input)).toBe(output);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('should move styles from paragraph to text', () => {
|
|
25
|
+
const input = '<p style="background-color: red;">lorem ipsum</p>';
|
|
26
|
+
const output = '<p><span style="background-color: red;">lorem ipsum</span></p>';
|
|
27
|
+
|
|
28
|
+
expect(normalize(input)).toBe(output);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('should move styles from paragraph to unstyled text', () => {
|
|
32
|
+
const input = '<p style="background-color: red;"><span style="background-color: #000;">lorem</span> ipsum <span style="color: white;">one</span></p>';
|
|
33
|
+
const output = '<p>' +
|
|
34
|
+
'<span style="background-color: #000;">lorem</span>' +
|
|
35
|
+
'<span style="background-color: red;"> ipsum </span>' +
|
|
36
|
+
'<span style="color: white; background-color: red;">one</span' +
|
|
37
|
+
'></p>';
|
|
38
|
+
|
|
39
|
+
expect(normalize(input)).toBe(output);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ref } from '@vue/composition-api';
|
|
2
|
+
import { FavoriteColors } from '../FavoriteColors';
|
|
3
|
+
|
|
4
|
+
function createService({ colors, onUpdate }) {
|
|
5
|
+
return new FavoriteColors({
|
|
6
|
+
listRef: ref(colors ?? []),
|
|
7
|
+
triggerUpdate: onUpdate
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('trigger update', () => {
|
|
12
|
+
test('should trigger colors update', () => {
|
|
13
|
+
const onUpdate = jest.fn();
|
|
14
|
+
const service = createService({ onUpdate });
|
|
15
|
+
|
|
16
|
+
service.triggerUpdate(['red']);
|
|
17
|
+
|
|
18
|
+
expect(onUpdate).toHaveBeenCalledWith(['red']);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { JsonSerializer } from '../JsonSerializer';
|
|
2
|
+
|
|
3
|
+
describe('decode', () => {
|
|
4
|
+
test('should decode json', () => {
|
|
5
|
+
const json = JsonSerializer.decode('{ "test": 1 }');
|
|
6
|
+
|
|
7
|
+
expect(json).toEqual({ test: 1 });
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test('should return null on error', () => {
|
|
11
|
+
const json = JsonSerializer.decode('{ "tes');
|
|
12
|
+
|
|
13
|
+
expect(json).toBe(null);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('encode', () => {
|
|
18
|
+
test('should encode object to json', () => {
|
|
19
|
+
const json = JsonSerializer.encode({ test: 1 });
|
|
20
|
+
|
|
21
|
+
expect(json).toBe('{"test":1}');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Storage } from '../Storage';
|
|
2
|
+
|
|
3
|
+
const createNativeStorage = (data) => ({
|
|
4
|
+
data: data ?? {},
|
|
5
|
+
setItem: jest.fn(function (key, data) {
|
|
6
|
+
this.data[key] = data;
|
|
7
|
+
}),
|
|
8
|
+
getItem: jest.fn(function (key) {
|
|
9
|
+
return this.data[key] || null;
|
|
10
|
+
})
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
function createStorage({ storage }) {
|
|
14
|
+
return new Storage(storage ?? createNativeStorage());
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('get item', () => {
|
|
18
|
+
test('should return null if no data', () => {
|
|
19
|
+
const storage = createStorage({
|
|
20
|
+
storage: createNativeStorage({})
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
expect(storage.getItem('test')).toBe(null);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('should parse json', () => {
|
|
27
|
+
const storage = createStorage({
|
|
28
|
+
storage: createNativeStorage({
|
|
29
|
+
'zp.test': '{ "test": 1 }'
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(storage.getItem('test')).toEqual({ test: 1 });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('should handle error in private mode', () => {
|
|
37
|
+
const nativeStorage = createNativeStorage({});
|
|
38
|
+
const storage = createStorage({ storage: nativeStorage });
|
|
39
|
+
const error = new Error('private mode');
|
|
40
|
+
|
|
41
|
+
nativeStorage.getItem.mockImplementation(() => { throw error; });
|
|
42
|
+
storage.getItem('test');
|
|
43
|
+
|
|
44
|
+
// eslint-disable-next-line no-console
|
|
45
|
+
expect(console.error).toHaveBeenCalledWith(error);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('set item', () => {
|
|
50
|
+
test('should set item to storage', () => {
|
|
51
|
+
const nativeStorage = createNativeStorage({});
|
|
52
|
+
const storage = createStorage({ storage: nativeStorage });
|
|
53
|
+
|
|
54
|
+
storage.setItem('test', 'hello');
|
|
55
|
+
|
|
56
|
+
expect(nativeStorage.data).toEqual({ 'zp.test': '"hello"' });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('should stringify json', () => {
|
|
60
|
+
const nativeStorage = createNativeStorage({});
|
|
61
|
+
const storage = createStorage({ storage: nativeStorage });
|
|
62
|
+
|
|
63
|
+
storage.setItem('test', { test: 1 });
|
|
64
|
+
|
|
65
|
+
expect(nativeStorage.data).toEqual({ 'zp.test': '{"test":1}' });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('should handle error in private mode', () => {
|
|
69
|
+
const nativeStorage = createNativeStorage({});
|
|
70
|
+
const storage = createStorage({ storage: nativeStorage });
|
|
71
|
+
const error = new Error('private mode');
|
|
72
|
+
|
|
73
|
+
nativeStorage.getItem.mockImplementation(() => { throw error; });
|
|
74
|
+
storage.setItem('test', 'test');
|
|
75
|
+
|
|
76
|
+
// eslint-disable-next-line no-console
|
|
77
|
+
expect(console.error).toHaveBeenCalledWith(error);
|
|
78
|
+
});
|
|
79
|
+
});
|
package/lib/services/index.js
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { convertColor } from '../convertColor';
|
|
2
|
+
|
|
3
|
+
describe('convert color', () => {
|
|
4
|
+
test('should convert alias to color', () => {
|
|
5
|
+
expect(convertColor('red')).toBe('#FF0000');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
test('should convert short hex to full', () => {
|
|
9
|
+
expect(convertColor('#F00')).toBe('#FF0000');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('should convert short hex with alpha to rgba', () => {
|
|
13
|
+
expect(convertColor('#F003')).toBe('rgba(255, 0, 0, 20%)');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('should convert rgba from float to percent', () => {
|
|
17
|
+
expect(convertColor('rgba(255, 0, 0, 0.2)')).toBe('rgba(255, 0, 0, 20%)');
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createKeyboardShortcut } from '../createKeyboardShortcut';
|
|
2
|
+
|
|
3
|
+
describe('create shortcut', () => {
|
|
4
|
+
test('should bind command', () => {
|
|
5
|
+
const editor = {
|
|
6
|
+
commands: { toggleBold: jest.fn() }
|
|
7
|
+
};
|
|
8
|
+
const shortcut = createKeyboardShortcut('toggleBold');
|
|
9
|
+
|
|
10
|
+
shortcut({ editor });
|
|
11
|
+
|
|
12
|
+
expect(editor.commands.toggleBold).toHaveBeenCalled();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('should bind command with arguments', () => {
|
|
16
|
+
const editor = {
|
|
17
|
+
commands: { applyAlignment: jest.fn() }
|
|
18
|
+
};
|
|
19
|
+
const shortcut = createKeyboardShortcut('applyAlignment', 'left');
|
|
20
|
+
|
|
21
|
+
shortcut({ editor });
|
|
22
|
+
|
|
23
|
+
expect(editor.commands.applyAlignment).toHaveBeenCalledWith('left');
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -27,6 +27,16 @@ describe('render settings', () => {
|
|
|
27
27
|
expect(result).toMatchSnapshot();
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
+
test('should render no attributes if all styles empty', () => {
|
|
31
|
+
const result = renderMark({
|
|
32
|
+
mobile_font_size: null,
|
|
33
|
+
tablet_font_size: null,
|
|
34
|
+
desktop_font_size: null
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
expect(result[1]).toEqual({});
|
|
38
|
+
});
|
|
39
|
+
|
|
30
40
|
test('should render unwrapped styles', () => {
|
|
31
41
|
const result = renderInlineSetting({
|
|
32
42
|
mobile_font_size: '',
|
|
@@ -36,4 +46,20 @@ describe('render settings', () => {
|
|
|
36
46
|
|
|
37
47
|
expect(result).toMatchSnapshot();
|
|
38
48
|
});
|
|
49
|
+
|
|
50
|
+
test('should return null if no styles', () => {
|
|
51
|
+
const result = renderInlineSetting({});
|
|
52
|
+
|
|
53
|
+
expect(result).toBe(null);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('should return null if all styles empty', () => {
|
|
57
|
+
const result = renderInlineSetting({
|
|
58
|
+
mobile_font_size: null,
|
|
59
|
+
tablet_font_size: null,
|
|
60
|
+
desktop_font_size: null
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
expect(result).toBe(null);
|
|
64
|
+
});
|
|
39
65
|
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// register all icons in webpack module loader
|
|
2
|
+
const importFile = require.context('../assets/icons', true, /\.svg/);
|
|
3
|
+
|
|
4
|
+
export function importIcon(name) {
|
|
5
|
+
try {
|
|
6
|
+
return importFile(`./${name}.svg`);
|
|
7
|
+
} catch (error) {
|
|
8
|
+
// eslint-disable-next-line no-console
|
|
9
|
+
console.warn('Cannot resolve wysiwyg icon', error);
|
|
10
|
+
return '';
|
|
11
|
+
}
|
|
12
|
+
}
|
package/lib/utils/index.js
CHANGED
|
@@ -2,3 +2,5 @@ export { createCommand } from './createCommand';
|
|
|
2
2
|
export { renderInlineSetting, renderMark } from './renderInlineSetting';
|
|
3
3
|
export { capitalize } from './capitalize';
|
|
4
4
|
export { createKeyboardShortcut } from './createKeyboardShortcut';
|
|
5
|
+
export { convertColor } from './convertColor';
|
|
6
|
+
export { importIcon } from './importIcon';
|
|
@@ -13,5 +13,5 @@ export function renderInlineSetting(setting) {
|
|
|
13
13
|
export function renderMark(setting) {
|
|
14
14
|
const attrs = renderInlineSetting(setting);
|
|
15
15
|
|
|
16
|
-
return ['span', attrs ? { ...attrs, class: 'zw-style' } :
|
|
16
|
+
return ['span', attrs ? { ...attrs, class: 'zw-style' } : {}, 0];
|
|
17
17
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zipify/wysiwyg",
|
|
3
|
-
"version": "1.0.0-dev.
|
|
3
|
+
"version": "1.0.0-dev.7",
|
|
4
4
|
"description": "Zipify modification of TipTap text editor",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "dist/wysiwyg.js",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/ZipifyApps/ZipifyWysiwyg.git"
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"url": "https://github.com/ZipifyApps/ZipifyWysiwyg/issues"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
+
"lib:build": "webpack --config ./config/webpack/lib.config.js",
|
|
17
18
|
"example:start": "NODE_ENV=development webpack serve --config ./config/webpack/example.config.js",
|
|
18
19
|
"example:build": "NODE_ENV=production webpack --config ./config/webpack/example.config.js",
|
|
19
20
|
"test:unit": "jest .",
|
|
@@ -45,7 +46,6 @@
|
|
|
45
46
|
"@babel/plugin-transform-runtime": "^7.18.6",
|
|
46
47
|
"@babel/preset-env": "^7.18.6",
|
|
47
48
|
"@babel/runtime": "^7.18.6",
|
|
48
|
-
"@vue/composition-api": "^1.7.0",
|
|
49
49
|
"@vue/test-utils": "^1.3.0",
|
|
50
50
|
"@vue/vue2-jest": "^28.0.1",
|
|
51
51
|
"babel-jest": "^28.1.2",
|
|
@@ -60,18 +60,17 @@
|
|
|
60
60
|
"jest": "^28.1.3",
|
|
61
61
|
"jest-environment-jsdom": "^28.1.3",
|
|
62
62
|
"lint-staged": "^13.0.3",
|
|
63
|
+
"mini-css-extract-plugin": "^2.6.1",
|
|
63
64
|
"postcss-html": "^1.5.0",
|
|
64
65
|
"release-it": "^15.1.2",
|
|
65
66
|
"style-loader": "^3.3.1",
|
|
66
67
|
"stylelint": "^14.9.1",
|
|
67
68
|
"svgo": "^2.8.0",
|
|
68
|
-
"vue": "^2.6.14",
|
|
69
69
|
"vue-loader": "^15.9.8",
|
|
70
70
|
"vue-template-compiler": "^2.6.14",
|
|
71
71
|
"webpack": "^5.73.0",
|
|
72
72
|
"webpack-bundle-analyzer": "^4.5.0",
|
|
73
73
|
"webpack-cli": "^4.10.0",
|
|
74
|
-
"webpack-dev-server": "^4.9.3"
|
|
75
|
-
"zipify-colorpicker": "^1.0.28"
|
|
74
|
+
"webpack-dev-server": "^4.9.3"
|
|
76
75
|
}
|
|
77
76
|
}
|
package/lib/assets/icons.svg
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg">
|
|
2
|
-
<defs>
|
|
3
|
-
<symbol id="arrow" fill="none" viewBox="0 0 8 8">
|
|
4
|
-
<path fill="var(--zw-icon-foreground)" fill-rule="evenodd" d="m4 6.934 4-5H0l4 5Z" clip-rule="evenodd"/>
|
|
5
|
-
</symbol>
|
|
6
|
-
<symbol id="reset-styles" fill="none" viewBox="0 0 28 28">
|
|
7
|
-
<path fill="var(--zw-icon-foreground)" d="M14 9.333V6.666l-3.334 3.333L14 13.333v-2.667c2.206 0 4 1.793 4 4s-1.794 4-4 4c-2.207 0-4-1.793-4-4H8.666A5.332 5.332 0 0 0 14 19.999a5.332 5.332 0 0 0 5.333-5.333A5.332 5.332 0 0 0 14 9.333Z"/>
|
|
8
|
-
</symbol>
|
|
9
|
-
<symbol id="font-color" fill="none" viewBox="0 0 28 28">
|
|
10
|
-
<path fill="var(--zw-icon-foreground)" fill-rule="evenodd" d="M22 20.62a2.42 2.42 0 0 1-4.84 0c0-1.25 2.42-4.54 2.42-4.54S22 19.37 22 20.62ZM9.92 15.425l1.452-3.951c.071-.182.145-.394.219-.636.074-.242.149-.503.226-.783a17.223 17.223 0 0 0 .454 1.402l1.452 3.968H9.919Zm5.411 4.199c.226-.795.658-1.684 1.184-2.562L12.955 8h-2.269L6 19.93h1.725a.736.736 0 0 0 .474-.157.792.792 0 0 0 .26-.347l.891-2.434h4.941l.891 2.434c.031.079.097.134.148.198Z" clip-rule="evenodd"/>
|
|
11
|
-
</symbol>
|
|
12
|
-
<symbol id="background-color" fill="none" viewBox="0 0 28 28">
|
|
13
|
-
<path fill="#fff" stroke="#B3B3B3" d="M4.5 4.5h19v19h-19z"/>
|
|
14
|
-
<path fill="#3B3B3B" d="M26 20.7a2.51 2.51 0 0 1-5 0c0-1.31 2.5-4.7 2.5-4.7s2.5 3.39 2.5 4.7Z"/>
|
|
15
|
-
<path fill="#3B3B3B" fill-rule="evenodd" d="M19.64 19.93h-1.715a.75.75 0 0 1-.475-.145.82.82 0 0 1-.268-.359l-.89-2.433h-4.943l-.89 2.433a.78.78 0 0 1-.26.347.73.73 0 0 1-.475.157H8L12.686 8h2.269l4.686 11.93Zm-7.721-4.505h3.803l-1.452-3.968a18.048 18.048 0 0 1-.219-.623c-.08-.24-.158-.5-.235-.78-.077.28-.152.542-.227.784a8.742 8.742 0 0 1-.218.635l-1.452 3.952Z" clip-rule="evenodd"/>
|
|
16
|
-
</symbol>
|
|
17
|
-
<symbol id="italic" fill="none" viewBox="0 0 28 28">
|
|
18
|
-
<path fill="var(--zw-icon-foreground)" d="M18 9V7h-7v2h2.64l-1.22 10H10v2h7v-2h-2.83L15.4 9H18Z"/>
|
|
19
|
-
</symbol>
|
|
20
|
-
<symbol id="underline" fill="none" viewBox="0 0 28 28">
|
|
21
|
-
<path fill="var(--zw-icon-foreground)" fill-rule="evenodd" d="M15.4 16.06a3.3 3.3 0 0 1-1.4.29 3.12 3.12 0 0 1-1.39-.29 2.88 2.88 0 0 1-1.05-.81 3.711 3.711 0 0 1-.65-1.25 5.659 5.659 0 0 1-.22-1.6V7H9v5.41a6.89 6.89 0 0 0 .34 2.22 5.29 5.29 0 0 0 1 1.77c.437.501.975.904 1.58 1.18A5 5 0 0 0 14 18a5 5 0 0 0 2.08-.42 4.61 4.61 0 0 0 1.57-1.18 5.27 5.27 0 0 0 1-1.77 6.89 6.89 0 0 0 .35-2.22V7h-1.69v5.41a5.659 5.659 0 0 1-.22 1.59 3.71 3.71 0 0 1-.69 1.25c-.27.34-.61.617-1 .81ZM20 19H8v2h12v-2Z" clip-rule="evenodd"/>
|
|
22
|
-
</symbol>
|
|
23
|
-
<symbol id="strike-through" fill="none" viewBox="0 0 28 28">
|
|
24
|
-
<path fill="var(--zw-icon-foreground)" fill-rule="evenodd" d="m14 12.731.77.27H20v2H8v-2h2.84a2.892 2.892 0 0 1-.46-.71 3.61 3.61 0 0 1-.29-1.52c0-.484.1-.964.29-1.41a3.5 3.5 0 0 1 .83-1.2 4 4 0 0 1 1.35-.84 4.74 4.74 0 0 1 1.83-.32 6 6 0 0 1 2.11.41 5 5 0 0 1 1.68 1l-.46.88a.69.69 0 0 1-.18.22.41.41 0 0 1-.25.07.69.69 0 0 1-.39-.16 5.551 5.551 0 0 0-.56-.36 4.641 4.641 0 0 0-.8-.36 3.44 3.44 0 0 0-1.14-.16 3.16 3.16 0 0 0-1.11.17 2.29 2.29 0 0 0-.8.45 1.87 1.87 0 0 0-.49.67 2.138 2.138 0 0 0-.11.79c-.023.357.08.711.29 1 .206.267.465.489.76.65.338.187.693.34 1.06.46Zm1.99 6.06c.24-.22.427-.49.55-.79.135-.315.2-.657.19-1h1.74a4.58 4.58 0 0 1-.25 1.38 4 4 0 0 1-.91 1.37 4.231 4.231 0 0 1-1.46.92 5.503 5.503 0 0 1-2 .33 6.13 6.13 0 0 1-2.5-.46 5.66 5.66 0 0 1-1.89-1.31l.54-.88a.61.61 0 0 1 .19-.17.45.45 0 0 1 .25-.07.5.5 0 0 1 .28.1c.128.077.251.16.37.25l.46.33c.19.13.391.243.6.34.245.107.5.191.76.25.328.076.664.11 1 .1a3.67 3.67 0 0 0 1.19-.18c.328-.109.63-.282.89-.51Z" clip-rule="evenodd"/>
|
|
25
|
-
</symbol>
|
|
26
|
-
<symbol id="case-style" fill="none" viewBox="0 0 28 28">
|
|
27
|
-
<path fill="var(--zw-icon-foreground)" fill-rule="evenodd" d="M16.64 19.93h-1.715a.75.75 0 0 1-.475-.145.82.82 0 0 1-.268-.359l-.89-2.433H8.35l-.891 2.433a.78.78 0 0 1-.26.347.73.73 0 0 1-.475.157H5L9.686 8h2.269l4.686 11.93Zm-7.72-4.505h3.803l-1.452-3.968a18.048 18.048 0 0 1-.219-.623c-.08-.24-.158-.5-.235-.78-.077.28-.152.542-.227.784a8.742 8.742 0 0 1-.218.635L8.92 15.425Zm14.968 4.505h-.915a.987.987 0 0 1-.454-.087c-.11-.058-.192-.175-.248-.35l-.181-.603a7.005 7.005 0 0 1-.631.507c-.206.146-.42.269-.64.368a3.26 3.26 0 0 1-.7.222c-.248.05-.523.075-.826.075-.357 0-.687-.049-.99-.145a2.134 2.134 0 0 1-.78-.433 1.967 1.967 0 0 1-.507-.718 2.545 2.545 0 0 1-.181-.998c0-.319.084-.634.251-.945.168-.31.447-.59.838-.841.39-.25.91-.458 1.559-.623.649-.165 1.455-.258 2.417-.28v-.495c0-.567-.12-.986-.359-1.259-.239-.272-.587-.408-1.043-.408-.33 0-.605.039-.825.116a3.17 3.17 0 0 0-.574.26 25.11 25.11 0 0 1-.45.26.912.912 0 0 1-.453.115.59.59 0 0 1-.355-.107.843.843 0 0 1-.239-.264l-.371-.652c.973-.891 2.148-1.337 3.523-1.337.494 0 .936.081 1.324.244.387.162.716.387.985.676.27.289.475.634.615 1.036.14.401.21.841.21 1.32v5.346Zm-3.96-1.271c.21 0 .402-.02.578-.058.176-.038.342-.096.5-.173.156-.077.307-.172.453-.285a4.13 4.13 0 0 0 .441-.4v-1.427c-.594.027-1.09.078-1.489.153a3.967 3.967 0 0 0-.961.284c-.242.116-.414.25-.516.404a.894.894 0 0 0-.152.504c0 .357.106.613.317.767.212.154.489.231.83.231Z" clip-rule="evenodd"/>
|
|
28
|
-
</symbol>
|
|
29
|
-
<symbol id="superscript" fill="none" viewBox="0 0 28 28">
|
|
30
|
-
<path fill="var(--zw-icon-foreground)" d="M21.985 8.625h-1.75V9.5h2.625v.875h-3.5v-1.75c0-.481.394-.875.875-.875h1.75v-.875H19.36V6h2.625c.481 0 .875.394.875.875v.875a.878.878 0 0 1-.875.875ZM7.88 20h2.327l2.975-4.742h.105L16.262 20h2.328l-4.069-6.361L18.32 7.75h-2.345l-2.687 4.366h-.105L10.48 7.75H8.15l3.78 5.889L7.88 20Z"/>
|
|
31
|
-
</symbol>
|
|
32
|
-
<symbol id="alignment-left" fill="none" viewBox="0 0 28 28">
|
|
33
|
-
<path fill="var(--zw-icon-foreground)" fill-rule="evenodd" d="M23 7H5v2h18V7Zm-6 4H5v2h12v-2Zm6 4H5v2h18v-2ZM5 19h12v2H5v-2Z" clip-rule="evenodd"/>
|
|
34
|
-
</symbol>
|
|
35
|
-
<symbol id="alignment-center" fill="none" viewBox="0 0 28 28">
|
|
36
|
-
<path fill="var(--zw-icon-foreground)" fill-rule="evenodd" d="M23 7H5v2h18V7Zm-3 4H8v2h12v-2Zm3 4H5v2h18v-2ZM8 19h12v2H8v-2Z" clip-rule="evenodd"/>
|
|
37
|
-
</symbol>
|
|
38
|
-
<symbol id="alignment-right" fill="none" viewBox="0 0 28 28">
|
|
39
|
-
<path fill="var(--zw-icon-foreground)" fill-rule="evenodd" d="M23 7H5v2h18V7Zm0 4H11v2h12v-2Zm0 4H5v2h18v-2Zm-12 4h12v2H11v-2Z" clip-rule="evenodd"/>
|
|
40
|
-
</symbol>
|
|
41
|
-
<symbol id="alignment-justify" fill="none" viewBox="0 0 28 28">
|
|
42
|
-
<path fill="var(--zw-icon-foreground)" fill-rule="evenodd" d="M23 7H5v2h18V7Zm0 4H5v2h18v-2Zm0 4H5v2h18v-2ZM5 19h18v2H5v-2Z" clip-rule="evenodd"/>
|
|
43
|
-
</symbol>
|
|
44
|
-
<symbol id="line-height" fill="none" viewBox="0 0 28 28">
|
|
45
|
-
<path fill="var(--zw-icon-foreground)" fill-rule="evenodd" d="m5 10 3-3 3 3H9v8h2l-3 3-3-3h2v-8H5Zm8-3h10v2H13V7Zm10 6H13v2h10v-2Zm0 6H13v2h10v-2Z" clip-rule="evenodd"/>
|
|
46
|
-
</symbol>
|
|
47
|
-
<symbol id="list-disc" fill="none" viewBox="0 0 28 28">
|
|
48
|
-
<rect width="10" height="10" x="9" y="9" fill="var(--zw-icon-foreground)" rx="5"/>
|
|
49
|
-
</symbol>
|
|
50
|
-
<symbol id="list-circle" fill="none" viewBox="0 0 28 28">
|
|
51
|
-
<rect width="9" height="9" x="9.5" y="9.5" stroke="var(--zw-icon-foreground)" rx="4.5"/>
|
|
52
|
-
</symbol>
|
|
53
|
-
<symbol id="list-square" fill="none" viewBox="0 0 28 28">
|
|
54
|
-
<path fill="var(--zw-icon-foreground)" d="M9 9h10v10H9z"/>
|
|
55
|
-
</symbol>
|
|
56
|
-
<symbol id="list-decimal" fill="none" viewBox="0 0 28 28">
|
|
57
|
-
<path fill="var(--zw-icon-foreground)" d="M15.108 18.184V19H10.5v-.816h1.842v-5.862c0-.176.006-.354.018-.534l-1.53 1.314a.375.375 0 0 1-.156.084.373.373 0 0 1-.27-.048.318.318 0 0 1-.084-.078l-.336-.462 2.562-2.214h.87v7.8h1.692Zm1.519.156a.8.8 0 0 1 .054-.294.829.829 0 0 1 .156-.24.77.77 0 0 1 .534-.222.77.77 0 0 1 .696.462c.04.092.06.19.06.294a.744.744 0 0 1-.222.534.692.692 0 0 1-.24.156.73.73 0 0 1-.294.06.73.73 0 0 1-.294-.06.692.692 0 0 1-.396-.39.816.816 0 0 1-.054-.3Z"/>
|
|
58
|
-
</symbol>
|
|
59
|
-
<symbol id="list-roman" fill="none" viewBox="0 0 28 28">
|
|
60
|
-
<path fill="var(--zw-icon-foreground)" d="m13.664 15.808-1.35-3.498a7.11 7.11 0 0 1-.252-.804c-.084.324-.17.594-.258.81l-1.35 3.492h3.21ZM16.088 19h-.9a.387.387 0 0 1-.252-.078.48.48 0 0 1-.144-.198l-.804-2.076H10.13l-.804 2.076a.421.421 0 0 1-.138.192.383.383 0 0 1-.252.084h-.9l3.438-8.598h1.176L16.088 19Zm.7-.66a.8.8 0 0 1 .053-.294.829.829 0 0 1 .156-.24.77.77 0 0 1 .534-.222.77.77 0 0 1 .696.462c.04.092.06.19.06.294a.744.744 0 0 1-.222.534.692.692 0 0 1-.24.156.73.73 0 0 1-.294.06.73.73 0 0 1-.294-.06.692.692 0 0 1-.396-.39.816.816 0 0 1-.054-.3Z"/>
|
|
61
|
-
</symbol>
|
|
62
|
-
<symbol id="list-latin" fill="none" viewBox="0 0 28 28">
|
|
63
|
-
<path fill="var(--zw-icon-foreground)" d="M12.086 9.802h.834v11.292h-.834V9.802Zm2.592 8.538a.8.8 0 0 1 .054-.294.829.829 0 0 1 .156-.24.77.77 0 0 1 .534-.222.77.77 0 0 1 .696.462c.04.092.06.19.06.294a.744.744 0 0 1-.222.534.692.692 0 0 1-.24.156.73.73 0 0 1-.294.06.73.73 0 0 1-.294-.06.692.692 0 0 1-.396-.39.816.816 0 0 1-.054-.3Z"/>
|
|
64
|
-
</symbol>
|
|
65
|
-
<symbol id="remove-format" fill="none" viewBox="0 0 28 28">
|
|
66
|
-
<path fill="var(--zw-icon-foreground)" fill-rule="evenodd" d="M14.089 6.726a1 1 0 0 1 1.425-.003l6.8 6.882a1 1 0 0 1 .007 1.398L17.2 20.3l-.2.2c-2.2 2.1-5.7 2-7.8-.2l-3.516-3.6a1 1 0 0 1 0-1.399l8.405-8.575Zm1.81 12.674c.1 0 .2 0 .2-.1l4.8-5-6.1-6.2-5 5.1 6.1 6.2Z" clip-rule="evenodd"/>
|
|
67
|
-
</symbol>
|
|
68
|
-
</defs>
|
|
69
|
-
</svg>
|