@zipify/wysiwyg 1.0.0-dev.1

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 (255) hide show
  1. package/.editorconfig +18 -0
  2. package/.eslintrc.js +253 -0
  3. package/.github/actions/deploy-example/action.yaml +61 -0
  4. package/.github/actions/lint-css/action.yaml +15 -0
  5. package/.github/actions/lint-js/action.yaml +22 -0
  6. package/.github/actions/setup/action.yaml +19 -0
  7. package/.github/actions/unit-tests/action.yaml +13 -0
  8. package/.github/actions/unit-tests/jest.config.js +8 -0
  9. package/.github/dependabot.yaml +17 -0
  10. package/.github/pull_request_template.md +17 -0
  11. package/.github/workflows/frontend-ci.yaml +120 -0
  12. package/.husky/pre-commit +4 -0
  13. package/.lintstagedrc +12 -0
  14. package/.release-it.json +6 -0
  15. package/.stylelintrc +110 -0
  16. package/README.md +61 -0
  17. package/babel.config.js +15 -0
  18. package/ci/example/deploy.sh +25 -0
  19. package/config/jest/TestEnvironment.js +27 -0
  20. package/config/jest/matchers/index.js +6 -0
  21. package/config/jest/matchers/toElementHasStyle.js +27 -0
  22. package/config/jest/matchers/toVueContainComponent.js +20 -0
  23. package/config/jest/matchers/toVueContainElement.js +34 -0
  24. package/config/jest/matchers/toVueContainLazyComponent.js +19 -0
  25. package/config/jest/matchers/toVueEmpty.js +16 -0
  26. package/config/jest/matchers/toVuexActionHasBeenDispatched.js +19 -0
  27. package/config/jest/setupMatchers.js +4 -0
  28. package/config/jest/setupTests.js +32 -0
  29. package/config/jest/typing.d.ts +14 -0
  30. package/config/svgo.js +22 -0
  31. package/config/webpack/example.config.js +86 -0
  32. package/config/webpack/loaders/index.js +6 -0
  33. package/config/webpack/loaders/js-loader.js +5 -0
  34. package/config/webpack/loaders/style-loader.js +7 -0
  35. package/config/webpack/loaders/svg-loader.js +4 -0
  36. package/config/webpack/loaders/vue-loader.js +4 -0
  37. package/config/webpack/settings.js +9 -0
  38. package/example/ExampleApp.vue +136 -0
  39. package/example/example.html +17 -0
  40. package/example/example.js +19 -0
  41. package/example/fonts.js +474 -0
  42. package/example/presets.js +245 -0
  43. package/example/tooltip/Tooltip.js +241 -0
  44. package/example/tooltip/TooltipManager.js +132 -0
  45. package/example/tooltip/index.js +3 -0
  46. package/example/tooltip/modifiers/TooltipCloseOnScrollModifier.js +73 -0
  47. package/example/tooltip/modifiers/index.js +1 -0
  48. package/example/tooltip/tooltip.css +95 -0
  49. package/jest.config.js +17 -0
  50. package/lib/Wysiwyg.vue +156 -0
  51. package/lib/__mocks__/svgMock.js +1 -0
  52. package/lib/__tests__/utils/NodeFactory.js +67 -0
  53. package/lib/__tests__/utils/index.js +4 -0
  54. package/lib/__tests__/utils/setReadonlyProperty.js +9 -0
  55. package/lib/__tests__/utils/waitAsyncOperation.js +6 -0
  56. package/lib/__tests__/utils/withComponentContext.js +14 -0
  57. package/lib/assets/icons.svg +69 -0
  58. package/lib/components/base/Button.vue +117 -0
  59. package/lib/components/base/ButtonToggle.vue +40 -0
  60. package/lib/components/base/FieldLabel.vue +28 -0
  61. package/lib/components/base/Icon.vue +67 -0
  62. package/lib/components/base/Modal.vue +116 -0
  63. package/lib/components/base/NumberField.vue +242 -0
  64. package/lib/components/base/Range.vue +196 -0
  65. package/lib/components/base/ScrollView.vue +60 -0
  66. package/lib/components/base/__tests__/Button.test.js +50 -0
  67. package/lib/components/base/__tests__/Icon.test.js +56 -0
  68. package/lib/components/base/__tests__/Modal.test.js +69 -0
  69. package/lib/components/base/__tests__/Range.test.js +39 -0
  70. package/lib/components/base/colorPicker/ColorPicker.vue +93 -0
  71. package/lib/components/base/colorPicker/composables/__tests__/usePickerApi.test.js +81 -0
  72. package/lib/components/base/colorPicker/composables/index.js +2 -0
  73. package/lib/components/base/colorPicker/composables/usePickerApi.js +35 -0
  74. package/lib/components/base/colorPicker/composables/usePickerHotkeys.js +25 -0
  75. package/lib/components/base/colorPicker/index.js +1 -0
  76. package/lib/components/base/composables/__tests__/useActivatedListener.test.js +89 -0
  77. package/lib/components/base/composables/__tests__/useDeselectionLock.test.js +80 -0
  78. package/lib/components/base/composables/__tests__/useElementRef.test.js +29 -0
  79. package/lib/components/base/composables/__tests__/useModalToggler.test.js +55 -0
  80. package/lib/components/base/composables/__tests__/useNumberValue.test.js +153 -0
  81. package/lib/components/base/composables/__tests__/useScrollView.test.js +43 -0
  82. package/lib/components/base/composables/__tests__/useTempValue.test.js +38 -0
  83. package/lib/components/base/composables/index.js +7 -0
  84. package/lib/components/base/composables/useActivatedListener.js +23 -0
  85. package/lib/components/base/composables/useDeselectionLock.js +35 -0
  86. package/lib/components/base/composables/useElementRef.js +5 -0
  87. package/lib/components/base/composables/useModalToggler.js +58 -0
  88. package/lib/components/base/composables/useNumberValue.js +53 -0
  89. package/lib/components/base/composables/useScrollView.js +22 -0
  90. package/lib/components/base/composables/useTempValue.js +11 -0
  91. package/lib/components/base/dropdown/Dropdown.vue +88 -0
  92. package/lib/components/base/dropdown/DropdownActivator.vue +81 -0
  93. package/lib/components/base/dropdown/DropdownDivider.vue +21 -0
  94. package/lib/components/base/dropdown/DropdownGroup.vue +55 -0
  95. package/lib/components/base/dropdown/DropdownMenu.vue +62 -0
  96. package/lib/components/base/dropdown/DropdownOption.vue +91 -0
  97. package/lib/components/base/dropdown/__tests__/DropdownActivator.test.js +54 -0
  98. package/lib/components/base/dropdown/__tests__/DropdownMenu.test.js +67 -0
  99. package/lib/components/base/dropdown/__tests__/DropdownOption.test.js +81 -0
  100. package/lib/components/base/dropdown/composables/__tests__/useActiveOptionManager.test.js +41 -0
  101. package/lib/components/base/dropdown/composables/__tests__/useDropdownEntityTitle.test.js +24 -0
  102. package/lib/components/base/dropdown/composables/index.js +2 -0
  103. package/lib/components/base/dropdown/composables/useActiveOptionManager.js +25 -0
  104. package/lib/components/base/dropdown/composables/useDropdownEntityTitle.js +5 -0
  105. package/lib/components/base/dropdown/index.js +2 -0
  106. package/lib/components/base/dropdown/injectionTokens.js +5 -0
  107. package/lib/components/base/index.js +11 -0
  108. package/lib/components/index.js +1 -0
  109. package/lib/components/toolbar/Toolbar.vue +56 -0
  110. package/lib/components/toolbar/ToolbarDevice.vue +35 -0
  111. package/lib/components/toolbar/ToolbarDivider.vue +50 -0
  112. package/lib/components/toolbar/ToolbarFull.vue +94 -0
  113. package/lib/components/toolbar/ToolbarGroup.vue +18 -0
  114. package/lib/components/toolbar/ToolbarRow.vue +19 -0
  115. package/lib/components/toolbar/__tests__/Toolbar.test.js +33 -0
  116. package/lib/components/toolbar/__tests__/ToolbarDivider.test.js +26 -0
  117. package/lib/components/toolbar/controls/AlignmentControl.vue +72 -0
  118. package/lib/components/toolbar/controls/AlignmentDeviceControl.vue +67 -0
  119. package/lib/components/toolbar/controls/BackgroundColorControl.vue +48 -0
  120. package/lib/components/toolbar/controls/CaseStyleControl.vue +54 -0
  121. package/lib/components/toolbar/controls/FontColorControl.vue +48 -0
  122. package/lib/components/toolbar/controls/FontFamilyControl.vue +96 -0
  123. package/lib/components/toolbar/controls/FontSizeControl.vue +45 -0
  124. package/lib/components/toolbar/controls/FontWeightControl.vue +43 -0
  125. package/lib/components/toolbar/controls/ItalicControl.vue +47 -0
  126. package/lib/components/toolbar/controls/LineHeightControl.vue +102 -0
  127. package/lib/components/toolbar/controls/ListControl.vue +86 -0
  128. package/lib/components/toolbar/controls/RemoveFormatControl.vue +37 -0
  129. package/lib/components/toolbar/controls/StrikeThroughControl.vue +44 -0
  130. package/lib/components/toolbar/controls/StylePresetControl.vue +95 -0
  131. package/lib/components/toolbar/controls/SuperscriptControl.vue +44 -0
  132. package/lib/components/toolbar/controls/UnderlineControl.vue +44 -0
  133. package/lib/components/toolbar/controls/__tests__/AlignmentControl.test.js +51 -0
  134. package/lib/components/toolbar/controls/__tests__/AlignmentDeviceControl.test.js +77 -0
  135. package/lib/components/toolbar/controls/__tests__/BackgroundColorControl.test.js +59 -0
  136. package/lib/components/toolbar/controls/__tests__/CaseStyleControl.test.js +43 -0
  137. package/lib/components/toolbar/controls/__tests__/FontColorControl.test.js +59 -0
  138. package/lib/components/toolbar/controls/__tests__/FontFamilyControl.test.js +57 -0
  139. package/lib/components/toolbar/controls/__tests__/FontSizeControl.test.js +47 -0
  140. package/lib/components/toolbar/controls/__tests__/FontWeightControl.test.js +45 -0
  141. package/lib/components/toolbar/controls/__tests__/ItalicControl.test.js +63 -0
  142. package/lib/components/toolbar/controls/__tests__/LineHeightControl.test.js +120 -0
  143. package/lib/components/toolbar/controls/__tests__/ListControl.test.js +82 -0
  144. package/lib/components/toolbar/controls/__tests__/RemoveFormatControl.test.js +34 -0
  145. package/lib/components/toolbar/controls/__tests__/StrikeThroughControl.test.js +44 -0
  146. package/lib/components/toolbar/controls/__tests__/StylePresetControl.test.js +129 -0
  147. package/lib/components/toolbar/controls/__tests__/SuperscriptControl.test.js +44 -0
  148. package/lib/components/toolbar/controls/__tests__/UnderlineControl.test.js +44 -0
  149. package/lib/components/toolbar/controls/composables/__tests__/useRecentFonts.test.js +69 -0
  150. package/lib/components/toolbar/controls/composables/index.js +1 -0
  151. package/lib/components/toolbar/controls/composables/useRecentFonts.js +18 -0
  152. package/lib/components/toolbar/controls/index.js +16 -0
  153. package/lib/components/toolbar/index.js +1 -0
  154. package/lib/composables/__tests__/__snapshots__/useEditor.test.js.snap +24 -0
  155. package/lib/composables/__tests__/useEditor.test.js +67 -0
  156. package/lib/composables/__tests__/useToolbar.test.js +56 -0
  157. package/lib/composables/index.js +2 -0
  158. package/lib/composables/useEditor.js +21 -0
  159. package/lib/composables/useToolbar.js +44 -0
  160. package/lib/directives/__tests__/outClick.test.js +86 -0
  161. package/lib/directives/__tests__/tooltip.test.js +39 -0
  162. package/lib/directives/index.js +2 -0
  163. package/lib/directives/outClick.js +37 -0
  164. package/lib/directives/tooltip.js +7 -0
  165. package/lib/enums/Alignments.js +6 -0
  166. package/lib/enums/CaseStyles.js +5 -0
  167. package/lib/enums/Devices.js +15 -0
  168. package/lib/enums/ListTypes.js +23 -0
  169. package/lib/enums/NodeTypes.js +12 -0
  170. package/lib/enums/TextSettings.js +30 -0
  171. package/lib/enums/index.js +6 -0
  172. package/lib/extensions/Alignment.js +67 -0
  173. package/lib/extensions/BackgroundColor.js +28 -0
  174. package/lib/extensions/CaseStyle.js +36 -0
  175. package/lib/extensions/DeviceManager.js +16 -0
  176. package/lib/extensions/FontColor.js +36 -0
  177. package/lib/extensions/FontFamily.js +62 -0
  178. package/lib/extensions/FontSize.js +74 -0
  179. package/lib/extensions/FontStyle.js +62 -0
  180. package/lib/extensions/FontWeight.js +56 -0
  181. package/lib/extensions/LineHeight.js +60 -0
  182. package/lib/extensions/StylePreset.js +168 -0
  183. package/lib/extensions/Superscript.js +5 -0
  184. package/lib/extensions/TextDecoration.js +97 -0
  185. package/lib/extensions/__tests__/Alignment.test.js +107 -0
  186. package/lib/extensions/__tests__/BackgroundColor.test.js +75 -0
  187. package/lib/extensions/__tests__/CaseStyle.test.js +58 -0
  188. package/lib/extensions/__tests__/FontColor.test.js +85 -0
  189. package/lib/extensions/__tests__/FontFamily.test.js +171 -0
  190. package/lib/extensions/__tests__/FontSize.test.js +183 -0
  191. package/lib/extensions/__tests__/FontStyle.test.js +136 -0
  192. package/lib/extensions/__tests__/FontWeight.test.js +151 -0
  193. package/lib/extensions/__tests__/LineHeight.test.js +106 -0
  194. package/lib/extensions/__tests__/StylePreset.test.js +400 -0
  195. package/lib/extensions/__tests__/TextDecoration.test.js +258 -0
  196. package/lib/extensions/__tests__/__snapshots__/Alignment.test.js.snap +29 -0
  197. package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +28 -0
  198. package/lib/extensions/__tests__/__snapshots__/CaseStyle.test.js.snap +69 -0
  199. package/lib/extensions/__tests__/__snapshots__/FontColor.test.js.snap +28 -0
  200. package/lib/extensions/__tests__/__snapshots__/FontFamily.test.js.snap +158 -0
  201. package/lib/extensions/__tests__/__snapshots__/FontSize.test.js.snap +140 -0
  202. package/lib/extensions/__tests__/__snapshots__/FontStyle.test.js.snap +87 -0
  203. package/lib/extensions/__tests__/__snapshots__/FontWeight.test.js.snap +140 -0
  204. package/lib/extensions/__tests__/__snapshots__/LineHeight.test.js.snap +29 -0
  205. package/lib/extensions/__tests__/__snapshots__/StylePreset.test.js.snap +310 -0
  206. package/lib/extensions/__tests__/__snapshots__/TextDecoration.test.js.snap +206 -0
  207. package/lib/extensions/core/NodeProcessor.js +32 -0
  208. package/lib/extensions/core/SelectionProcessor.js +37 -0
  209. package/lib/extensions/core/TextProcessor.js +57 -0
  210. package/lib/extensions/core/__tests__/NodeProcessor.test.js +120 -0
  211. package/lib/extensions/core/__tests__/SelectionProcessor.test.js +78 -0
  212. package/lib/extensions/core/__tests__/TextProcessor.test.js +61 -0
  213. package/lib/extensions/core/__tests__/__snapshots__/NodeProcessor.test.js.snap +93 -0
  214. package/lib/extensions/core/__tests__/__snapshots__/TextProcessor.test.js.snap +43 -0
  215. package/lib/extensions/core/index.js +17 -0
  216. package/lib/extensions/core/inputRules/closeDoubleQuote.js +6 -0
  217. package/lib/extensions/core/inputRules/closeSingleQuote.js +6 -0
  218. package/lib/extensions/core/inputRules/copyright.js +6 -0
  219. package/lib/extensions/core/inputRules/ellipsis.js +6 -0
  220. package/lib/extensions/core/inputRules/emDash.js +6 -0
  221. package/lib/extensions/core/inputRules/index.js +9 -0
  222. package/lib/extensions/core/inputRules/openDoubleQuote.js +6 -0
  223. package/lib/extensions/core/inputRules/openSingleQuote.js +6 -0
  224. package/lib/extensions/core/inputRules/registeredTrademark.js +6 -0
  225. package/lib/extensions/core/inputRules/trademark.js +6 -0
  226. package/lib/extensions/index.js +49 -0
  227. package/lib/extensions/list/List.js +81 -0
  228. package/lib/extensions/list/ListItem.js +12 -0
  229. package/lib/extensions/list/__tests__/List.test.js +130 -0
  230. package/lib/extensions/list/__tests__/__snapshots__/List.test.js.snap +212 -0
  231. package/lib/extensions/list/index.js +1 -0
  232. package/lib/index.js +1 -0
  233. package/lib/injectionTokens.js +7 -0
  234. package/lib/models/Font.js +37 -0
  235. package/lib/models/__tests__/Font.test.js +58 -0
  236. package/lib/models/index.js +1 -0
  237. package/lib/services/FavoriteColors.js +6 -0
  238. package/lib/services/JsonSerializer.js +15 -0
  239. package/lib/services/Storage.js +49 -0
  240. package/lib/services/index.js +3 -0
  241. package/lib/styles/content.css +39 -0
  242. package/lib/styles/helpers/common.css +3 -0
  243. package/lib/styles/helpers/offsets.css +3 -0
  244. package/lib/styles/helpers/text.css +6 -0
  245. package/lib/styles/main.css +5 -0
  246. package/lib/styles/variables.css +57 -0
  247. package/lib/utils/__tests__/__snapshots__/renderInlineSetting.test.js.snap +40 -0
  248. package/lib/utils/__tests__/capitalize.test.js +11 -0
  249. package/lib/utils/__tests__/renderInlineSetting.test.js +39 -0
  250. package/lib/utils/capitalize.js +3 -0
  251. package/lib/utils/createCommand.js +3 -0
  252. package/lib/utils/createKeyboardShortcut.js +6 -0
  253. package/lib/utils/index.js +4 -0
  254. package/lib/utils/renderInlineSetting.js +17 -0
  255. package/package.json +75 -0
@@ -0,0 +1,59 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { h, ref } from '@vue/composition-api';
3
+ import { InjectionTokens } from '../../../../injectionTokens';
4
+ import { ColorPicker } from '../../../base';
5
+ import BackgroundColorControl from '../BackgroundColorControl';
6
+
7
+ const createEditor = ({ backgroundColor } = {}) => ({
8
+ commands: {
9
+ getBackgroundColor: () => ref(backgroundColor),
10
+ focus: jest.fn().mockReturnThis(),
11
+ applyBackgroundColor: jest.fn().mockReturnThis(),
12
+ run: jest.fn()
13
+ },
14
+
15
+ chain() {
16
+ return this.commands;
17
+ }
18
+ });
19
+
20
+ function createComponent({ editor }) {
21
+ return shallowMount(BackgroundColorControl, {
22
+ stubs: {
23
+ ColorPicker: {
24
+ name: 'ColorPicker',
25
+ props: ['value'],
26
+
27
+ render() {
28
+ const children = this.$scopedSlots.activator({
29
+ toggle: jest.fn(),
30
+ isOpened: false
31
+ });
32
+
33
+ return h('div', null, children);
34
+ }
35
+ }
36
+ },
37
+ provide: { [InjectionTokens.EDITOR]: editor }
38
+ });
39
+ }
40
+
41
+ describe('selection value', () => {
42
+ test('should render value from selection', () => {
43
+ const editor = createEditor({ backgroundColor: 'red' });
44
+ const wrapper = createComponent({ editor });
45
+ const dropdownWrapper = wrapper.findComponent(ColorPicker);
46
+
47
+ expect(dropdownWrapper.props('value')).toBe('red');
48
+ });
49
+
50
+ test('should apply new value', () => {
51
+ const editor = createEditor({ backgroundColor: 'red' });
52
+ const wrapper = createComponent({ editor });
53
+ const dropdownWrapper = wrapper.findComponent(ColorPicker);
54
+
55
+ dropdownWrapper.vm.$emit('change', 'green');
56
+
57
+ expect(editor.commands.applyBackgroundColor).toHaveBeenCalledWith('green');
58
+ });
59
+ });
@@ -0,0 +1,43 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { h } from '@vue/composition-api';
3
+ import { InjectionTokens } from '../../../../injectionTokens';
4
+ import { Dropdown } from '../../../base';
5
+ import CaseStyleControl from '../CaseStyleControl';
6
+ import { CaseStyles } from '../../../../enums';
7
+
8
+ const createEditor = () => ({
9
+ commands: {
10
+ focus: jest.fn().mockReturnThis(),
11
+ applyCaseStyle: jest.fn().mockReturnThis(),
12
+ run: jest.fn()
13
+ },
14
+
15
+ chain() {
16
+ return this.commands;
17
+ }
18
+ });
19
+
20
+ function createComponent({ editor }) {
21
+ return shallowMount(CaseStyleControl, {
22
+ stubs: {
23
+ Dropdown: {
24
+ render: () => h('div'),
25
+ props: ['value']
26
+ }
27
+ },
28
+
29
+ provide: { [InjectionTokens.EDITOR]: editor }
30
+ });
31
+ }
32
+
33
+ describe('selection value', () => {
34
+ test('should apply new style', () => {
35
+ const editor = createEditor();
36
+ const wrapper = createComponent({ editor });
37
+ const dropdownWrapper = wrapper.findComponent(Dropdown);
38
+
39
+ dropdownWrapper.vm.$emit('change', CaseStyles.UPPERCASE);
40
+
41
+ expect(editor.commands.applyCaseStyle).toHaveBeenCalledWith(CaseStyles.UPPERCASE);
42
+ });
43
+ });
@@ -0,0 +1,59 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { h, ref } from '@vue/composition-api';
3
+ import { InjectionTokens } from '../../../../injectionTokens';
4
+ import { ColorPicker } from '../../../base';
5
+ import FontColorControl from '../FontColorControl';
6
+
7
+ const createEditor = ({ fontColor } = {}) => ({
8
+ commands: {
9
+ getFontColor: () => ref(fontColor),
10
+ focus: jest.fn().mockReturnThis(),
11
+ applyFontColor: jest.fn().mockReturnThis(),
12
+ run: jest.fn()
13
+ },
14
+
15
+ chain() {
16
+ return this.commands;
17
+ }
18
+ });
19
+
20
+ function createComponent({ editor }) {
21
+ return shallowMount(FontColorControl, {
22
+ stubs: {
23
+ ColorPicker: {
24
+ name: 'ColorPicker',
25
+ props: ['value'],
26
+
27
+ render() {
28
+ const children = this.$scopedSlots.activator({
29
+ toggle: jest.fn(),
30
+ isOpened: false
31
+ });
32
+
33
+ return h('div', null, children);
34
+ }
35
+ }
36
+ },
37
+ provide: { [InjectionTokens.EDITOR]: editor }
38
+ });
39
+ }
40
+
41
+ describe('selection value', () => {
42
+ test('should render value from selection', () => {
43
+ const editor = createEditor({ fontColor: 'red' });
44
+ const wrapper = createComponent({ editor });
45
+ const dropdownWrapper = wrapper.findComponent(ColorPicker);
46
+
47
+ expect(dropdownWrapper.props('value')).toBe('red');
48
+ });
49
+
50
+ test('should apply new value', () => {
51
+ const editor = createEditor({ fontColor: 'red' });
52
+ const wrapper = createComponent({ editor });
53
+ const dropdownWrapper = wrapper.findComponent(ColorPicker);
54
+
55
+ dropdownWrapper.vm.$emit('change', 'green');
56
+
57
+ expect(editor.commands.applyFontColor).toHaveBeenCalledWith('green');
58
+ });
59
+ });
@@ -0,0 +1,57 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { h, ref } from '@vue/composition-api';
3
+ import { InjectionTokens } from '../../../../injectionTokens';
4
+ import { Dropdown } from '../../../base';
5
+ import FontFamilyControl from '../FontFamilyControl';
6
+
7
+ const createEditor = ({ fontFamily } = {}) => ({
8
+ commands: {
9
+ getFontFamily: () => ref(fontFamily),
10
+ focus: jest.fn().mockReturnThis(),
11
+ applyFontFamily: jest.fn().mockReturnThis(),
12
+ run: jest.fn()
13
+ },
14
+
15
+ chain() {
16
+ return this.commands;
17
+ }
18
+ });
19
+
20
+ function createComponent({ editor }) {
21
+ return shallowMount(FontFamilyControl, {
22
+ stubs: {
23
+ Dropdown: {
24
+ render: () => h('div'),
25
+ props: ['value']
26
+ }
27
+ },
28
+ provide: {
29
+ [InjectionTokens.EDITOR]: editor,
30
+ [InjectionTokens.FONTS]: [
31
+ { name: 'Lato', category: 'test' },
32
+ { name: 'Bungee', category: 'test' }
33
+ ],
34
+ [InjectionTokens.LOCAL_STORAGE]: localStorage
35
+ }
36
+ });
37
+ }
38
+
39
+ describe('selection value', () => {
40
+ test('should render value from selection', () => {
41
+ const editor = createEditor({ fontFamily: 'Bungee' });
42
+ const wrapper = createComponent({ editor });
43
+ const dropdownWrapper = wrapper.findComponent(Dropdown);
44
+
45
+ expect(dropdownWrapper.props('value')).toBe('Bungee');
46
+ });
47
+
48
+ test('should apply new font family', () => {
49
+ const editor = createEditor({ fontFamily: 'Lato' });
50
+ const wrapper = createComponent({ editor });
51
+ const dropdownWrapper = wrapper.findComponent(Dropdown);
52
+
53
+ dropdownWrapper.vm.$emit('change', 'Bungee');
54
+
55
+ expect(editor.commands.applyFontFamily).toHaveBeenCalledWith('Bungee');
56
+ });
57
+ });
@@ -0,0 +1,47 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { ref } from '@vue/composition-api';
3
+ import { InjectionTokens } from '../../../../injectionTokens';
4
+ import { Dropdown } from '../../../base';
5
+ import FontSizeControl from '../FontSizeControl';
6
+
7
+ const createEditor = ({ fontSize } = {}) => ({
8
+ commands: {
9
+ getFontSize: () => ref(fontSize),
10
+ focus: jest.fn().mockReturnThis(),
11
+ applyFontSize: jest.fn().mockReturnThis(),
12
+ run: jest.fn()
13
+ },
14
+
15
+ chain() {
16
+ return this.commands;
17
+ }
18
+ });
19
+
20
+ function createComponent({ editor }) {
21
+ return shallowMount(FontSizeControl, {
22
+ provide: {
23
+ [InjectionTokens.EDITOR]: editor,
24
+ [InjectionTokens.FONT_SIZES]: ['12', '23']
25
+ }
26
+ });
27
+ }
28
+
29
+ describe('selection value', () => {
30
+ test('should render value from selection', () => {
31
+ const editor = createEditor({ fontSize: '12' });
32
+ const wrapper = createComponent({ editor });
33
+ const dropdownWrapper = wrapper.findComponent(Dropdown);
34
+
35
+ expect(dropdownWrapper.props('value')).toBe('12');
36
+ });
37
+
38
+ test('should apply new font size', () => {
39
+ const editor = createEditor({ fontSize: '12' });
40
+ const wrapper = createComponent({ editor });
41
+ const dropdownWrapper = wrapper.findComponent(Dropdown);
42
+
43
+ dropdownWrapper.vm.$emit('change', '14');
44
+
45
+ expect(editor.commands.applyFontSize).toHaveBeenCalledWith('14');
46
+ });
47
+ });
@@ -0,0 +1,45 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { ref } from '@vue/composition-api';
3
+ import { InjectionTokens } from '../../../../injectionTokens';
4
+ import { Dropdown } from '../../../base';
5
+ import FontWeightControl from '../FontWeightControl';
6
+
7
+ const createEditor = ({ fontWeight, fontWeightList } = {}) => ({
8
+ commands: {
9
+ getFontWeight: () => ref(fontWeight ?? '400'),
10
+ getFont: () => ref({ weights: fontWeightList ?? ['400', '700'] }),
11
+ focus: jest.fn().mockReturnThis(),
12
+ applyFontWeight: jest.fn().mockReturnThis(),
13
+ run: jest.fn()
14
+ },
15
+
16
+ chain() {
17
+ return this.commands;
18
+ }
19
+ });
20
+
21
+ function createComponent({ editor }) {
22
+ return shallowMount(FontWeightControl, {
23
+ provide: { [InjectionTokens.EDITOR]: editor }
24
+ });
25
+ }
26
+
27
+ describe('selection value', () => {
28
+ test('should render value from selection', () => {
29
+ const editor = createEditor({ fontWeight: '400' });
30
+ const wrapper = createComponent({ editor });
31
+ const dropdownWrapper = wrapper.findComponent(Dropdown);
32
+
33
+ expect(dropdownWrapper.props('value')).toBe('400');
34
+ });
35
+
36
+ test('should apply new font weight', () => {
37
+ const editor = createEditor({ fontWeight: '400' });
38
+ const wrapper = createComponent({ editor });
39
+ const dropdownWrapper = wrapper.findComponent(Dropdown);
40
+
41
+ dropdownWrapper.vm.$emit('change', '700');
42
+
43
+ expect(editor.commands.applyFontWeight).toHaveBeenCalledWith('700');
44
+ });
45
+ });
@@ -0,0 +1,63 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { ref } from '@vue/composition-api';
3
+ import { InjectionTokens } from '../../../../injectionTokens';
4
+ import { Button } from '../../../base';
5
+ import ItalicControl from '../ItalicControl';
6
+
7
+ const createEditor = ({ isItalic, isItalicAvailable } = {}) => ({
8
+ commands: {
9
+ isItalic: () => ref(isItalic),
10
+ isItalicAvailable: () => ref(isItalicAvailable ?? true),
11
+ focus: jest.fn().mockReturnThis(),
12
+ toggleItalic: jest.fn().mockReturnThis(),
13
+ run: jest.fn()
14
+ },
15
+
16
+ chain() {
17
+ return this.commands;
18
+ }
19
+ });
20
+
21
+ function createComponent({ editor }) {
22
+ return shallowMount(ItalicControl, {
23
+ provide: { [InjectionTokens.EDITOR]: editor }
24
+ });
25
+ }
26
+
27
+ describe('rendering', () => {
28
+ test('should enable if italic available', () => {
29
+ const editor = createEditor({ isItalicAvailable: true });
30
+ const wrapper = createComponent({ editor });
31
+ const buttonWrapper = wrapper.findComponent(Button);
32
+
33
+ expect(buttonWrapper.props('disabled')).toBe(false);
34
+ });
35
+
36
+ test('should disabled if italic not available', () => {
37
+ const editor = createEditor({ isItalicAvailable: false });
38
+ const wrapper = createComponent({ editor });
39
+ const buttonWrapper = wrapper.findComponent(Button);
40
+
41
+ expect(buttonWrapper.props('disabled')).toBe(true);
42
+ });
43
+ });
44
+
45
+ describe('selection value', () => {
46
+ test('should render value from selection', () => {
47
+ const editor = createEditor({ isItalic: true });
48
+ const wrapper = createComponent({ editor });
49
+ const buttonWrapper = wrapper.findComponent(Button);
50
+
51
+ expect(buttonWrapper.props('active')).toBe(true);
52
+ });
53
+
54
+ test('should apply new value', () => {
55
+ const editor = createEditor({ isItalic: false });
56
+ const wrapper = createComponent({ editor });
57
+ const buttonWrapper = wrapper.findComponent(Button);
58
+
59
+ buttonWrapper.vm.$emit('click');
60
+
61
+ expect(editor.commands.toggleItalic).toHaveBeenCalled();
62
+ });
63
+ });
@@ -0,0 +1,120 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { h, nextTick, ref } from '@vue/composition-api';
3
+ import { InjectionTokens } from '../../../../injectionTokens';
4
+ import { Button, Modal, NumberField, Range } from '../../../base';
5
+ import LineHeightControl from '../LineHeightControl';
6
+
7
+ const createEditor = ({ height } = {}) => {
8
+ const heightRef = ref(height ?? '1.2');
9
+
10
+ return {
11
+ commands: {
12
+ getLineHeight: () => heightRef,
13
+ applyLineHeight: jest.fn(function (value) {
14
+ heightRef.value = value;
15
+ return this;
16
+ }),
17
+ focus: jest.fn().mockReturnThis(),
18
+ storeSelection: jest.fn(),
19
+ restoreSelection: jest.fn(),
20
+ run: jest.fn()
21
+ },
22
+
23
+ chain() {
24
+ return this.commands;
25
+ }
26
+ };
27
+ };
28
+
29
+ function createComponent({ editor } = {}) {
30
+ return shallowMount(LineHeightControl, {
31
+ stubs: {
32
+ Modal: {
33
+ render() {
34
+ return h('div', null, this.$slots.default);
35
+ },
36
+ props: ['toggler']
37
+ }
38
+ },
39
+ provide: { [InjectionTokens.EDITOR]: editor ?? createEditor() }
40
+ });
41
+ }
42
+
43
+ describe('selection value', () => {
44
+ test('should render value from selection', () => {
45
+ const editor = createEditor({ height: '1.2' });
46
+ const wrapper = createComponent({ editor });
47
+ const rangeWrapper = wrapper.findComponent(Range);
48
+ const fieldWrapper = wrapper.findComponent(NumberField);
49
+
50
+ expect(rangeWrapper.props('value')).toBe('1.2');
51
+ expect(fieldWrapper.props('value')).toBe('1.2');
52
+ });
53
+
54
+ test('should apply new value by range', () => {
55
+ const editor = createEditor({ height: '1.2' });
56
+ const wrapper = createComponent({ editor });
57
+ const rangeWrapper = wrapper.findComponent(Range);
58
+
59
+ rangeWrapper.vm.$emit('input', '1.3');
60
+
61
+ expect(editor.commands.applyLineHeight).toHaveBeenCalledWith('1.3');
62
+ });
63
+
64
+ test('should apply new value by field', () => {
65
+ const editor = createEditor({ height: '1.2' });
66
+ const wrapper = createComponent({ editor });
67
+ const fieldWrapper = wrapper.findComponent(NumberField);
68
+
69
+ fieldWrapper.vm.$emit('input', '1.3');
70
+
71
+ expect(editor.commands.applyLineHeight).toHaveBeenCalledWith('1.3');
72
+ });
73
+
74
+ test('should sync field on range input', async () => {
75
+ const editor = createEditor({ height: '1.2' });
76
+ const wrapper = createComponent({ editor });
77
+ const rangeWrapper = wrapper.findComponent(Range);
78
+ const fieldWrapper = wrapper.findComponent(NumberField);
79
+
80
+ rangeWrapper.vm.$emit('input', '1.3');
81
+ await nextTick();
82
+
83
+ expect(fieldWrapper.props('value')).toBe('1.3');
84
+ });
85
+
86
+ test('should sync field on field input', async () => {
87
+ const editor = createEditor({ height: '1.2' });
88
+ const wrapper = createComponent({ editor });
89
+ const rangeWrapper = wrapper.findComponent(Range);
90
+ const fieldWrapper = wrapper.findComponent(NumberField);
91
+
92
+ fieldWrapper.vm.$emit('input', '1.21');
93
+ await nextTick();
94
+
95
+ expect(rangeWrapper.props('value')).toBe('1.21');
96
+ });
97
+ });
98
+
99
+ describe('rendering', () => {
100
+ test('should render closed state', async () => {
101
+ const wrapper = createComponent();
102
+ const buttonWrapper = wrapper.findComponent(Button);
103
+ const modalWrapper = wrapper.findComponent(Modal);
104
+
105
+ expect(buttonWrapper.props('active')).toBe(false);
106
+ expect(modalWrapper.props('toggler').isOpened.value).toBe(false);
107
+ });
108
+
109
+ test('should open modal', async () => {
110
+ const wrapper = createComponent();
111
+ const buttonWrapper = wrapper.findComponent(Button);
112
+ const modalWrapper = wrapper.findComponent(Modal);
113
+
114
+ buttonWrapper.vm.$emit('click');
115
+ await nextTick();
116
+
117
+ expect(buttonWrapper.props('active')).toBe(true);
118
+ expect(modalWrapper.props('toggler').isOpened.value).toBe(true);
119
+ });
120
+ });
@@ -0,0 +1,82 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { h, ref } from '@vue/composition-api';
3
+ import { InjectionTokens } from '../../../../injectionTokens';
4
+ import { Dropdown, Icon } from '../../../base';
5
+ import ListControl from '../ListControl';
6
+ import { ListTypes } from '../../../../enums';
7
+
8
+ const createEditor = ({ listType } = {}) => ({
9
+ commands: {
10
+ getListType: () => ref(listType),
11
+ focus: jest.fn().mockReturnThis(),
12
+ applyList: jest.fn().mockReturnThis(),
13
+ run: jest.fn()
14
+ },
15
+
16
+ chain() {
17
+ return this.commands;
18
+ }
19
+ });
20
+
21
+ function createComponent({ editor }) {
22
+ return shallowMount(ListControl, {
23
+ stubs: {
24
+ Dropdown: {
25
+ render() {
26
+ const activator = this.$scopedSlots.activator({
27
+ open: jest.fn(),
28
+ isOpened: false
29
+ });
30
+
31
+ return h('div', null, [activator]);
32
+ },
33
+ props: ['value']
34
+ }
35
+ },
36
+ provide: { [InjectionTokens.EDITOR]: editor }
37
+ });
38
+ }
39
+
40
+ describe('selection value', () => {
41
+ test('should pass none type', () => {
42
+ const editor = createEditor({ listType: null });
43
+ const wrapper = createComponent({ editor });
44
+ const dropdownWrapper = wrapper.findComponent(Dropdown);
45
+
46
+ expect(dropdownWrapper.props('value')).toBe('none');
47
+ });
48
+
49
+ test('should pass type from selection', () => {
50
+ const editor = createEditor({ listType: ListTypes.LATIN });
51
+ const wrapper = createComponent({ editor });
52
+ const dropdownWrapper = wrapper.findComponent(Dropdown);
53
+
54
+ expect(dropdownWrapper.props('value')).toBe(ListTypes.LATIN);
55
+ });
56
+
57
+ test('should render none icon', () => {
58
+ const editor = createEditor({ listType: null });
59
+ const wrapper = createComponent({ editor });
60
+ const iconWrapper = wrapper.findComponent(Icon);
61
+
62
+ expect(iconWrapper.props('name')).toBe('list-disc');
63
+ });
64
+
65
+ test('should render type icon', () => {
66
+ const editor = createEditor({ listType: ListTypes.DECIMAL });
67
+ const wrapper = createComponent({ editor });
68
+ const iconWrapper = wrapper.findComponent(Icon);
69
+
70
+ expect(iconWrapper.props('name')).toBe('list-decimal');
71
+ });
72
+
73
+ test('should apply list', () => {
74
+ const editor = createEditor({ listType: ListTypes.LATIN });
75
+ const wrapper = createComponent({ editor });
76
+ const dropdownWrapper = wrapper.findComponent(Dropdown);
77
+
78
+ dropdownWrapper.vm.$emit('change', ListTypes.LATIN);
79
+
80
+ expect(editor.commands.applyList).toHaveBeenCalledWith(ListTypes.LATIN);
81
+ });
82
+ });
@@ -0,0 +1,34 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import RemoveFormatControl from '../RemoveFormatControl';
3
+ import { InjectionTokens } from '../../../../injectionTokens';
4
+ import { Button } from '../../../base';
5
+
6
+ const createEditor = () => ({
7
+ commands: {
8
+ focus: jest.fn().mockReturnThis(),
9
+ removeFormat: jest.fn().mockReturnThis(),
10
+ run: jest.fn()
11
+ },
12
+
13
+ chain() {
14
+ return this.commands;
15
+ }
16
+ });
17
+
18
+ function createComponent({ editor }) {
19
+ return shallowMount(RemoveFormatControl, {
20
+ provide: { [InjectionTokens.EDITOR]: editor }
21
+ });
22
+ }
23
+
24
+ describe('remove formatting', () => {
25
+ test('should remove text formatting', () => {
26
+ const editor = createEditor();
27
+ const wrapper = createComponent({ editor });
28
+ const buttonWrapper = wrapper.findComponent(Button);
29
+
30
+ buttonWrapper.vm.$emit('click');
31
+
32
+ expect(editor.commands.removeFormat).toHaveBeenCalled();
33
+ });
34
+ });
@@ -0,0 +1,44 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { ref } from '@vue/composition-api';
3
+ import { InjectionTokens } from '../../../../injectionTokens';
4
+ import { Button } from '../../../base';
5
+ import StrikeThroughControl from '../StrikeThroughControl';
6
+
7
+ const createEditor = ({ isStrikeThrough } = {}) => ({
8
+ commands: {
9
+ isStrikeThrough: () => ref(isStrikeThrough),
10
+ focus: jest.fn().mockReturnThis(),
11
+ toggleStrikeThrough: jest.fn().mockReturnThis(),
12
+ run: jest.fn()
13
+ },
14
+
15
+ chain() {
16
+ return this.commands;
17
+ }
18
+ });
19
+
20
+ function createComponent({ editor }) {
21
+ return shallowMount(StrikeThroughControl, {
22
+ provide: { [InjectionTokens.EDITOR]: editor }
23
+ });
24
+ }
25
+
26
+ describe('selection value', () => {
27
+ test('should render value from selection', () => {
28
+ const editor = createEditor({ isStrikeThrough: true });
29
+ const wrapper = createComponent({ editor });
30
+ const buttonWrapper = wrapper.findComponent(Button);
31
+
32
+ expect(buttonWrapper.props('active')).toBe(true);
33
+ });
34
+
35
+ test('should apply new value', () => {
36
+ const editor = createEditor({ isStrikeThrough: false });
37
+ const wrapper = createComponent({ editor });
38
+ const buttonWrapper = wrapper.findComponent(Button);
39
+
40
+ buttonWrapper.vm.$emit('click');
41
+
42
+ expect(editor.commands.toggleStrikeThrough).toHaveBeenCalled();
43
+ });
44
+ });