@zipify/wysiwyg 1.0.0-dev.42 → 1.0.0-dev.43

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 (50) hide show
  1. package/config/vite/example.config.js +25 -0
  2. package/dist/wysiwyg.css +1 -1
  3. package/dist/wysiwyg.mjs +3272 -3219
  4. package/example/ExampleApp.vue +5 -0
  5. package/example/{example.html → index.html} +1 -0
  6. package/lib/Wysiwyg.vue +1 -4
  7. package/lib/__tests__/utils/NodeFactory.js +13 -0
  8. package/lib/components/base/__tests__/Modal.test.js +2 -3
  9. package/lib/components/base/composables/__tests__/useValidator.test.js +44 -0
  10. package/lib/components/base/composables/useValidator.js +7 -3
  11. package/lib/components/toolbar/__tests__/Toolbar.test.js +2 -3
  12. package/lib/components/toolbar/controls/StylePresetControl.vue +14 -1
  13. package/lib/components/toolbar/controls/__tests__/StylePresetControl.test.js +16 -0
  14. package/lib/components/toolbar/controls/link/LinkControl.vue +28 -25
  15. package/lib/components/toolbar/controls/link/__tests__/LinkControl.test.js +79 -0
  16. package/lib/components/toolbar/controls/link/__tests__/LinkControlHeader.test.js +42 -0
  17. package/lib/components/toolbar/controls/link/composables/__tests__/__snapshots__/useLink.test.js.snap +8 -0
  18. package/lib/components/toolbar/controls/link/composables/__tests__/useLink.test.js +114 -0
  19. package/lib/components/toolbar/controls/link/destination/LinkControlDestination.vue +2 -2
  20. package/lib/components/toolbar/controls/link/destination/LinkControlUrl.vue +2 -2
  21. package/lib/components/toolbar/controls/link/destination/__tests__/LinkControlPageBlock.test.js +36 -0
  22. package/lib/components/toolbar/controls/link/destination/__tests__/LinkControlUrl.test.js +46 -0
  23. package/lib/components/toolbar/controls/link/destination/__tests__/__snapshots__/LinkControlPageBlock.test.js.snap +9 -0
  24. package/lib/components/toolbar/controls/link/destination/__tests__/__snapshots__/LinkControlUrl.test.js.snap +17 -0
  25. package/lib/composables/useToolbar.js +12 -0
  26. package/lib/directives/__tests__/outClick.test.js +6 -0
  27. package/lib/directives/outClick.js +12 -15
  28. package/lib/extensions/FontWeight.js +3 -1
  29. package/lib/extensions/LineHeight.js +3 -2
  30. package/lib/extensions/Link.js +3 -15
  31. package/lib/extensions/TextDecoration.js +18 -0
  32. package/lib/extensions/__tests__/FontWeight.test.js +8 -0
  33. package/lib/extensions/__tests__/Link.test.js +102 -0
  34. package/lib/extensions/__tests__/TextDecoration.test.js +24 -0
  35. package/lib/extensions/__tests__/__snapshots__/FontWeight.test.js.snap +17 -0
  36. package/lib/extensions/__tests__/__snapshots__/Link.test.js.snap +225 -0
  37. package/lib/extensions/__tests__/__snapshots__/TextDecoration.test.js.snap +90 -0
  38. package/lib/extensions/core/plugins/PastePlugin.js +23 -14
  39. package/lib/extensions/index.js +5 -3
  40. package/lib/services/ContentNormalizer.js +55 -15
  41. package/lib/services/__tests__/ContentNormalizer.test.js +39 -4
  42. package/package.json +3 -13
  43. package/config/webpack/example.config.js +0 -88
  44. package/config/webpack/lib.config.js +0 -43
  45. package/config/webpack/loaders/index.js +0 -6
  46. package/config/webpack/loaders/js-loader.js +0 -5
  47. package/config/webpack/loaders/style-loader.js +0 -9
  48. package/config/webpack/loaders/svg-loader.js +0 -4
  49. package/config/webpack/loaders/vue-loader.js +0 -4
  50. package/config/webpack/settings.js +0 -9
@@ -152,4 +152,9 @@ body {
152
152
  .zpa-text__list--square { list-style-type: square }
153
153
  .zpa-text__list--latin { list-style-type: upper-roman }
154
154
  .zpa-text__list--roman { list-style-type: upper-latin }
155
+
156
+ p, h1, h2, h3, h4 {
157
+ margin-top: 0.3em;
158
+ margin-bottom: 0.3em;
159
+ }
155
160
  </style>
@@ -13,5 +13,6 @@
13
13
  </head>
14
14
  <body>
15
15
  <div data-app></div>
16
+ <script type="module" src="./example.js"></script>
16
17
  </body>
17
18
  </html>
package/lib/Wysiwyg.vue CHANGED
@@ -114,8 +114,6 @@ export default {
114
114
  ContextWindow.use(props.window);
115
115
 
116
116
  const fonts = props.fonts.map((font) => new Font(font));
117
- const presets = toRef(props, 'presets');
118
-
119
117
  const toolbarRef = ref(null);
120
118
  const wysiwygRef = ref(null);
121
119
 
@@ -145,9 +143,8 @@ export default {
145
143
  makePresetVariable: props.makePresetVariable,
146
144
  basePresetClass: props.basePresetClass,
147
145
  baseListClass: props.baseListClass,
148
- linkPreset: presets.value.find((preset) => preset.id === 'link'),
149
146
  deviceRef: toRef(props, 'device'),
150
- pageBlocks
147
+ pageBlocksRef: pageBlocks
151
148
  })
152
149
  });
153
150
 
@@ -64,4 +64,17 @@ export class NodeFactory {
64
64
  static mark(type, attrs) {
65
65
  return { type, attrs };
66
66
  }
67
+
68
+ static link(attrs) {
69
+ return {
70
+ type: 'text',
71
+ marks: [
72
+ {
73
+ type: 'link',
74
+ attrs: { ...attrs }
75
+ }
76
+ ],
77
+ text: attrs.text
78
+ };
79
+ }
67
80
  }
@@ -46,9 +46,8 @@ describe('open/close', () => {
46
46
  expect(wrapper).toVueEmpty();
47
47
  });
48
48
 
49
- // TODO Fix later
50
- test.skip('should open', async () => {
51
- const toggler = createToggler(false);
49
+ test('should open', async () => {
50
+ const toggler = createToggler({ value: false });
52
51
  const wrapper = createComponent({ toggler });
53
52
 
54
53
  toggler.isOpened.value = true;
@@ -0,0 +1,44 @@
1
+ import { useValidator } from '../useValidator';
2
+
3
+ describe('validation', () => {
4
+ test('should show error', () => {
5
+ const value = '';
6
+ const isEmpty = () => value ? false : 'Can\'t be empty';
7
+
8
+ const validator = useValidator({
9
+ validations: [isEmpty]
10
+ });
11
+
12
+ validator.validate();
13
+
14
+ expect(validator.error.value).toBe('Can\'t be empty');
15
+ });
16
+
17
+ test('should pass validation', () => {
18
+ const value = 'hello';
19
+ const isEmpty = () => value ? false : 'Can\'t be empty';
20
+
21
+ const validator = useValidator({
22
+ validations: [isEmpty]
23
+ });
24
+
25
+ validator.validate();
26
+
27
+ expect(validator.error.value).toBe(null);
28
+ });
29
+
30
+ test('should reset error', () => {
31
+ const value = '';
32
+ const isEmpty = () => value ? false : 'Can\'t be empty';
33
+
34
+ const validator = useValidator({
35
+ validations: [isEmpty]
36
+ });
37
+
38
+ validator.validate();
39
+ expect(validator.error.value).toBe('Can\'t be empty');
40
+
41
+ validator.reset();
42
+ expect(validator.error.value).toBe(null);
43
+ });
44
+ });
@@ -3,9 +3,9 @@ import { ref } from 'vue';
3
3
  export function useValidator({ validations }) {
4
4
  const error = ref(null);
5
5
 
6
- function validate(value) {
6
+ function validate() {
7
7
  for (const validate of validations) {
8
- const validationError = validate(value);
8
+ const validationError = validate();
9
9
 
10
10
  if (validationError) {
11
11
  return error.value = validationError;
@@ -15,5 +15,9 @@ export function useValidator({ validations }) {
15
15
  }
16
16
  }
17
17
 
18
- return { error, validate };
18
+ function reset() {
19
+ error.value = null;
20
+ }
21
+
22
+ return { error, validate, reset };
19
23
  }
@@ -10,7 +10,7 @@ function createComponent({ device }) {
10
10
  propsData: {
11
11
  toolbar: {
12
12
  mount: jest.fn(),
13
- isActiveRef: ref(true),
13
+ isActiveRef: ref({ value: true }),
14
14
  offsets: [0, 8]
15
15
  },
16
16
  device: device ?? Devices.DESKTOP
@@ -18,8 +18,7 @@ function createComponent({ device }) {
18
18
  });
19
19
  }
20
20
 
21
- // TODO Fix later
22
- describe.skip('rendering', () => {
21
+ describe('rendering', () => {
23
22
  test('should render desktop toolbar', () => {
24
23
  const wrapper = createComponent({ device: Devices.DESKTOP });
25
24
 
@@ -25,6 +25,9 @@ import { computed, inject } from 'vue';
25
25
  import { InjectionTokens } from '../../../injectionTokens';
26
26
  import { Dropdown, Button, Icon } from '../../base';
27
27
  import { tooltip } from '../../../directives';
28
+ import { TextSettings } from '../../../enums';
29
+
30
+ const CLEAR_MARKS = [TextSettings.FONT_SIZE, TextSettings.FONT_WEIGHT];
28
31
 
29
32
  export default {
30
33
  name: 'StylePresetControl',
@@ -59,7 +62,17 @@ export default {
59
62
  }));
60
63
  });
61
64
 
62
- const apply = (value) => editor.chain().focus().applyPreset(value).run();
65
+ const apply = (value) => {
66
+ editor.chain()
67
+ .focus()
68
+ .applyPreset(value)
69
+ .storeSelection()
70
+ .expandSelectionToBlock()
71
+ .unsetMarks(CLEAR_MARKS)
72
+ .restoreSelection()
73
+ .run();
74
+ };
75
+
63
76
  const removeCustomization = () => editor.chain().focus().removePresetCustomization().run();
64
77
 
65
78
  return {
@@ -3,6 +3,7 @@ import { ref } from 'vue';
3
3
  import { InjectionTokens } from '../../../../injectionTokens';
4
4
  import { Button, Dropdown } from '../../../base';
5
5
  import StylePresetControl from '../StylePresetControl';
6
+ import { TextSettings } from '../../../../enums';
6
7
 
7
8
  const createEditor = ({ presets, preset, customization } = {}) => ({
8
9
  commands: {
@@ -12,6 +13,10 @@ const createEditor = ({ presets, preset, customization } = {}) => ({
12
13
  getPresetCustomization: () => ref(customization || { attributes: [], marks: [] }),
13
14
  applyPreset: jest.fn().mockReturnThis(),
14
15
  removePresetCustomization: jest.fn().mockReturnThis(),
16
+ storeSelection: jest.fn().mockReturnThis(),
17
+ restoreSelection: jest.fn().mockReturnThis(),
18
+ expandSelectionToBlock: jest.fn().mockReturnThis(),
19
+ unsetMarks: jest.fn().mockReturnThis(),
15
20
  run: jest.fn()
16
21
  },
17
22
 
@@ -114,6 +119,17 @@ describe('apply preset', () => {
114
119
 
115
120
  expect(editor.commands.applyPreset).toHaveBeenCalledWith('regular-1');
116
121
  });
122
+
123
+ test('should remove settings on preset change', () => {
124
+ const editor = createEditor();
125
+ const wrapper = createComponent({ editor });
126
+ const dropdownWrapper = wrapper.findComponent(Dropdown);
127
+
128
+ dropdownWrapper.vm.$emit('change', 'regular-1');
129
+
130
+ expect(editor.commands.expandSelectionToBlock).toHaveBeenCalled();
131
+ expect(editor.commands.unsetMarks).toHaveBeenCalledWith([TextSettings.FONT_SIZE, TextSettings.FONT_WEIGHT]);
132
+ });
117
133
  });
118
134
 
119
135
  describe('remove customization', () => {
@@ -14,7 +14,7 @@
14
14
  label="Text to display"
15
15
  placeholder="Type Text"
16
16
  :error="nameValidator.error.value"
17
- @input="link.updateText"
17
+ @input="updateLinkText"
18
18
  />
19
19
 
20
20
  <LinkControlDestination
@@ -61,16 +61,32 @@ export default {
61
61
  setup() {
62
62
  const wrapperRef = ref(null);
63
63
  const modalRef = ref(null);
64
- const nameError = ref(false);
65
- const urlError = ref(false);
66
64
 
67
65
  const editor = inject(InjectionTokens.EDITOR);
68
66
 
69
67
  const link = useLink();
68
+ const urlRegExp = /(^(https?:\/\/|\/)(?:www\.|(?!www))?[^\s])/;
69
+
70
+ const isEmpty = () => {
71
+ return link.linkData.value.text ? false : 'Can\'t be empty';
72
+ };
73
+ const isUrl = () => {
74
+ if (link.currentDestination.value.id !== 'url') return false;
75
+
76
+ return urlRegExp.test(link.destinationHrefs.value.url) ? false : 'Please enter a valid URL';
77
+ };
78
+
79
+ const nameValidator = useValidator({
80
+ validations: [isEmpty]
81
+ });
82
+
83
+ const urlValidator = useValidator({
84
+ validations: [isUrl]
85
+ });
70
86
 
71
87
  const resetErrors = () => {
72
- nameError.value = null;
73
- urlError.value = null;
88
+ nameValidator.reset();
89
+ urlValidator.reset();
74
90
  };
75
91
 
76
92
  const onBeforeOpened = () => {
@@ -86,30 +102,17 @@ export default {
86
102
  });
87
103
 
88
104
  const isActive = computed(() => toggler.isOpened.value || editor.isActive('link'));
89
- const isEmpty = () => {
90
- return link.linkData.value.text ? false : 'Can\'t be empty';
91
- };
92
- const isUrl = () => {
93
- if (link.currentDestination.value.id !== 'url') return false;
94
105
 
95
- return /(^(https?:\/\/|\/)(?:www\.|(?!www))?[^\s])/.test(link.destinationHrefs.value.url) ? false : 'Please enter a valid URL';
106
+ const updateLinkText = (value) => {
107
+ resetErrors();
108
+ link.updateText(value);
96
109
  };
97
110
 
98
- const nameValidator = useValidator({
99
- validations: [isEmpty],
100
- value: link.linkData.value.text
101
- });
102
-
103
- const urlValidator = useValidator({
104
- validations: [isUrl],
105
- value: link.linkData.value.text
106
- });
107
-
108
111
  const applyLink = () => {
109
- urlError.value = urlValidator.validate();
110
- nameError.value = nameValidator.validate();
112
+ urlValidator.validate();
113
+ nameValidator.validate();
111
114
 
112
- if (urlError.value || nameError.value) return;
115
+ if (urlValidator.error.value || nameValidator.error.value) return;
113
116
 
114
117
  link.apply();
115
118
  toggler.close();
@@ -128,7 +131,7 @@ export default {
128
131
  isActive,
129
132
  nameValidator,
130
133
  urlValidator,
131
- nameError,
134
+ updateLinkText,
132
135
  resetErrors,
133
136
  applyLink,
134
137
  removeLink
@@ -0,0 +1,79 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { ref, nextTick } from 'vue';
3
+ import LinkControl from '../LinkControl';
4
+ import { InjectionTokens } from '../../../../../injectionTokens';
5
+ import { Button, TextField } from '../../../../base';
6
+ import LinkControlApply from '../LinkControlApply';
7
+ import { LinkControlDestination } from '../destination';
8
+
9
+ const createEditor = (isActive) => ({
10
+ isActive: () => isActive ?? false
11
+ });
12
+
13
+ function createComponent({ editor }) {
14
+ return shallowMount(LinkControl, {
15
+ provide: {
16
+ [InjectionTokens.EDITOR]: editor,
17
+ [InjectionTokens.PAGE_BLOCKS]: ref([{ id: 1 }])
18
+ }
19
+ });
20
+ }
21
+
22
+ describe('selection value', () => {
23
+ test('should render link status', () => {
24
+ const editor = createEditor(true );
25
+ const wrapper = createComponent({ editor });
26
+ const buttonWrapper = wrapper.findComponent(Button);
27
+
28
+ expect(buttonWrapper.props('active')).toBe(true);
29
+ });
30
+ });
31
+
32
+ describe('validation', () => {
33
+ test('should show error on apply', async () => {
34
+ const editor = createEditor(true );
35
+ const wrapper = createComponent({ editor });
36
+ const textFieldWrapper = wrapper.findComponent(TextField);
37
+ const linkControlDestinationWrapper = wrapper.findComponent(LinkControlDestination);
38
+ const applyWrapper = wrapper.findComponent(LinkControlApply);
39
+
40
+ applyWrapper.vm.$emit('apply');
41
+ await nextTick();
42
+
43
+ expect(textFieldWrapper.props('error')).toBe('Can\'t be empty');
44
+ expect(linkControlDestinationWrapper.props('validator').error.value).toBe('Please enter a valid URL');
45
+ });
46
+
47
+ test('should reset errors on input', async () => {
48
+ const editor = createEditor(true );
49
+ const wrapper = createComponent({ editor });
50
+ const textFieldWrapper = wrapper.findComponent(TextField);
51
+ const linkControlDestinationWrapper = wrapper.findComponent(LinkControlDestination);
52
+ const applyWrapper = wrapper.findComponent(LinkControlApply);
53
+
54
+ applyWrapper.vm.$emit('apply');
55
+ textFieldWrapper.vm.$emit('input', 'hello');
56
+
57
+ await nextTick();
58
+
59
+ expect(textFieldWrapper.props('error')).toBeNull();
60
+ expect(linkControlDestinationWrapper.props('validator').error.value).toBeNull();
61
+ });
62
+
63
+ test('should reset errors on change destination', async () => {
64
+ const editor = createEditor(true );
65
+ const wrapper = createComponent({ editor });
66
+ const textFieldWrapper = wrapper.findComponent(TextField);
67
+ const linkControlDestinationWrapper = wrapper.findComponent(LinkControlDestination);
68
+ const applyWrapper = wrapper.findComponent(LinkControlApply);
69
+
70
+ applyWrapper.vm.$emit('apply');
71
+ linkControlDestinationWrapper.vm.$emit('reset-errors');
72
+
73
+ await nextTick();
74
+
75
+ expect(textFieldWrapper.props('error')).toBeNull();
76
+ expect(linkControlDestinationWrapper.props('validator').error.value).toBeNull();
77
+ });
78
+ });
79
+
@@ -0,0 +1,42 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { InjectionTokens } from '../../../../../injectionTokens';
3
+ import { Button } from '../../../../base';
4
+ import LinkControlHeader from '../LinkControlHeader';
5
+
6
+ const createEditor = (isActive) => ({
7
+ isActive: () => isActive ?? false
8
+ });
9
+
10
+ function createComponent({ editor }) {
11
+ return shallowMount(LinkControlHeader, {
12
+ provide: { [InjectionTokens.EDITOR]: editor }
13
+ });
14
+ }
15
+
16
+ describe('rendering unlink button', () => {
17
+ test('should button be disabled when no link', () => {
18
+ const editor = createEditor(true );
19
+ const wrapper = createComponent({ editor });
20
+ const buttonWrapper = wrapper.findComponent(Button);
21
+
22
+ expect(buttonWrapper.props('disabled')).toBe(false);
23
+ });
24
+
25
+ test('should button be enabled when link selected', () => {
26
+ const editor = createEditor(false );
27
+ const wrapper = createComponent({ editor });
28
+ const buttonWrapper = wrapper.findComponent(Button);
29
+
30
+ expect(buttonWrapper.props('disabled')).toBe(true);
31
+ });
32
+
33
+ test('should send unlink event', () => {
34
+ const editor = createEditor(true );
35
+ const wrapper = createComponent({ editor });
36
+ const buttonWrapper = wrapper.findComponent(Button);
37
+
38
+ buttonWrapper.vm.$emit('click');
39
+
40
+ expect(wrapper.emitted('remove-link')).toBeTruthy();
41
+ });
42
+ });
@@ -0,0 +1,8 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`init link should prepare initial fields 1`] = `
4
+ Object {
5
+ "block": 1,
6
+ "url": "",
7
+ }
8
+ `;
@@ -0,0 +1,114 @@
1
+ import { ref } from 'vue';
2
+ import { withComponentContext } from '../../../../../../__tests__/utils';
3
+ import { InjectionTokens } from '../../../../../../injectionTokens';
4
+ import { LinkDestinations, LinkTargets } from '../../../../../../enums';
5
+ import { useLink } from '../useLink';
6
+
7
+ const createEditor = (text, destination) => ({
8
+ commands: {
9
+ storeSelection: jest.fn(),
10
+ restoreSelection: jest.fn(),
11
+ getSelectedText: jest.fn(() => text ?? ''),
12
+ focus: jest.fn().mockReturnThis(),
13
+ unsetLink: jest.fn().mockReturnThis(),
14
+ applyLink: jest.fn().mockReturnThis(),
15
+ run: jest.fn()
16
+ },
17
+
18
+ chain() {
19
+ return this.commands;
20
+ },
21
+
22
+ getAttributes: jest.fn(() => ({
23
+ destination: destination ?? null
24
+ }))
25
+ });
26
+
27
+ function useComposable(text, destination) {
28
+ return withComponentContext(() => useLink(), {
29
+ provide: {
30
+ [InjectionTokens.EDITOR]: createEditor(text, destination),
31
+ [InjectionTokens.PAGE_BLOCKS]: ref([{ id: 1 }, { id: 2 }])
32
+
33
+ }
34
+ });
35
+ }
36
+
37
+ describe('init link', () => {
38
+ test('should prepare initial fields', () => {
39
+ const link = useComposable();
40
+
41
+ link.prepareInitialFields();
42
+
43
+ expect(link.currentDestination.value.id).toBe(LinkDestinations.URL);
44
+ expect(link.linkData.value.target).toBe(LinkTargets.SELF);
45
+ expect(link.destinationHrefs.value).toMatchSnapshot();
46
+ });
47
+
48
+ test('should take text from selection', () => {
49
+ const link = useComposable('hello world');
50
+
51
+ link.prepareInitialFields();
52
+
53
+ expect(link.linkData.value.text).toBe('hello world');
54
+ });
55
+ });
56
+
57
+ describe('actions with link', () => {
58
+ test('should update url', () => {
59
+ const link = useComposable('hello world');
60
+
61
+ link.updateLink('https://hello.world');
62
+
63
+ expect(link.destinationHrefs.value.url).toBe('https://hello.world');
64
+ });
65
+
66
+ test('should update block destination', () => {
67
+ const link = useComposable('hello world', LinkDestinations.BLOCK);
68
+
69
+ link.prepareInitialFields();
70
+ link.updateLink('3456');
71
+
72
+ expect(link.destinationHrefs.value.block).toBe('3456');
73
+ });
74
+
75
+ test('should remove link', () => {
76
+ const link = useComposable();
77
+
78
+ link.removeLink();
79
+
80
+ expect(link.editor.commands.unsetLink).toHaveBeenCalled();
81
+ });
82
+
83
+ test('should apply link', () => {
84
+ const link = useComposable();
85
+
86
+ link.updateText('hello');
87
+ link.updateLink('/world');
88
+
89
+ link.apply();
90
+
91
+ expect(link.editor.commands.applyLink).toHaveBeenCalledWith({
92
+ destination: 'url',
93
+ href: '/world',
94
+ target: LinkTargets.SELF,
95
+ text: 'hello'
96
+ });
97
+ });
98
+
99
+ test('should apply link target', () => {
100
+ const link = useComposable();
101
+
102
+ link.updateTarget(false);
103
+
104
+ expect(link.linkData.value.target).toBe(LinkTargets.SELF);
105
+ });
106
+
107
+ test('should apply link target', () => {
108
+ const link = useComposable();
109
+
110
+ link.updateTarget(true);
111
+
112
+ expect(link.linkData.value.target).toBe(LinkTargets.BLANK);
113
+ });
114
+ });
@@ -26,8 +26,8 @@
26
26
  :href="link.destinationHrefs.value.url"
27
27
  :isTargetBlank="isTargetBlank"
28
28
  :validator="validator"
29
- @updateLink="updateLink"
30
- @updateTarget="link.updateTarget"
29
+ @update-link="updateLink"
30
+ @update-target="link.updateTarget"
31
31
  />
32
32
 
33
33
  <LinkControlPageBlock
@@ -43,8 +43,8 @@ export default {
43
43
  },
44
44
 
45
45
  setup(props, { emit }) {
46
- const updateLink = (value) => emit('updateLink', value);
47
- const updateTarget = (value) => emit('updateTarget', value);
46
+ const updateLink = (value) => emit('update-link', value);
47
+ const updateTarget = (value) => emit('update-target', value);
48
48
 
49
49
  return { updateLink, updateTarget };
50
50
  }
@@ -0,0 +1,36 @@
1
+ import { ref, h } from 'vue';
2
+ import { shallowMount } from '@vue/test-utils';
3
+ import LinkControlPageBlock from '../LinkControlPageBlock';
4
+ import { InjectionTokens } from '../../../../../../injectionTokens';
5
+ import { Dropdown } from '../../../../../base';
6
+
7
+ function createComponent() {
8
+ return shallowMount(LinkControlPageBlock, {
9
+ propsData: {
10
+ value: 12
11
+ },
12
+
13
+ stubs: {
14
+ Dropdown: {
15
+ render: () => h('div'),
16
+ props: ['value']
17
+ }
18
+ },
19
+
20
+ provide: {
21
+ [InjectionTokens.PAGE_BLOCKS]: ref([{ id: 1 }, { id: 2 }])
22
+ }
23
+ });
24
+ }
25
+
26
+ describe('applying block', () => {
27
+ test('should apply block', () => {
28
+ const wrapper = createComponent();
29
+
30
+ const dropdownWrapper = wrapper.findComponent(Dropdown);
31
+
32
+ dropdownWrapper.vm.$emit('change', 2);
33
+
34
+ expect(wrapper.emitted('update')).toMatchSnapshot();
35
+ });
36
+ });
@@ -0,0 +1,46 @@
1
+ import { ref, h } from 'vue';
2
+ import { shallowMount } from '@vue/test-utils';
3
+ import { Checkbox, TextField } from '../../../../../base';
4
+ import LinkControlUrl from '../LinkControlUrl';
5
+
6
+ function createComponent() {
7
+ return shallowMount(LinkControlUrl, {
8
+ propsData: {
9
+ validator: { error: ref({ value: null }) },
10
+ href: '',
11
+ isTargetBlank: false
12
+ },
13
+
14
+ stubs: {
15
+ TextField: {
16
+ render: () => h('div'),
17
+ props: ['value']
18
+ },
19
+
20
+ Checkbox: {
21
+ render: () => h('div'),
22
+ props: ['value']
23
+ }
24
+ }
25
+ });
26
+ }
27
+
28
+ describe('update link', () => {
29
+ test('should update link url', () => {
30
+ const wrapper = createComponent();
31
+ const textFieldWrapper = wrapper.findComponent(TextField);
32
+
33
+ textFieldWrapper.vm.$emit('input', 'Some text');
34
+
35
+ expect(wrapper.emitted('update-link')).toMatchSnapshot();
36
+ });
37
+
38
+ test('should update link target', () => {
39
+ const wrapper = createComponent();
40
+ const textFieldWrapper = wrapper.findComponent(Checkbox);
41
+
42
+ textFieldWrapper.vm.$emit('input', true);
43
+
44
+ expect(wrapper.emitted('update-target')).toMatchSnapshot();
45
+ });
46
+ });
@@ -0,0 +1,9 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`applying block should apply block 1`] = `
4
+ Array [
5
+ Array [
6
+ 2,
7
+ ],
8
+ ]
9
+ `;