goodteditor-ui 1.0.19 → 1.0.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goodteditor-ui",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
4
4
  "main": "index.js",
5
5
  "homepage": "https://goodt-ui.netlify.app/",
6
6
  "scripts": {
@@ -13,6 +13,22 @@
13
13
  "notify": "node ./ci/teams-notify.js",
14
14
  "publish": "npm run docs:build && npm run docs:deploy && npm run notify"
15
15
  },
16
+ "dependencies": {
17
+ "@popperjs/core": "2.11.2",
18
+ "@tiptap/extension-color": "^2.0.0-beta.207",
19
+ "@tiptap/extension-font-family": "^2.0.0-beta.207",
20
+ "@tiptap/extension-image": "^2.0.0-beta.27",
21
+ "@tiptap/extension-link": "^2.0.0-beta.36",
22
+ "@tiptap/extension-table": "2.0.0-beta.48",
23
+ "@tiptap/extension-table-cell": "^2.0.0-beta.20",
24
+ "@tiptap/extension-table-header": "^2.0.0-beta.22",
25
+ "@tiptap/extension-table-row": "^2.0.0-beta.19",
26
+ "@tiptap/extension-text-align": "^2.0.0-beta.207",
27
+ "@tiptap/extension-text-style": "^2.0.0-beta.207",
28
+ "@tiptap/extension-underline": "^2.0.0-beta.207",
29
+ "@tiptap/starter-kit": "^2.0.0-beta.183",
30
+ "@tiptap/vue-2": "^2.0.0-beta.84"
31
+ },
16
32
  "devDependencies": {
17
33
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
18
34
  "@vue/cli-plugin-babel": "^4.5.11",
@@ -27,20 +43,7 @@
27
43
  "less-loader": "^5.0.0",
28
44
  "netlify-cli": "^5.0.1",
29
45
  "vue-styleguidist": "4.35.0",
30
- "vue-template-compiler": "^2.6.12",
31
- "@tiptap/extension-color": "^2.0.0-beta.207",
32
- "@tiptap/extension-font-family": "^2.0.0-beta.207",
33
- "@tiptap/extension-image": "^2.0.0-beta.27",
34
- "@tiptap/extension-link": "^2.0.0-beta.36",
35
- "@tiptap/extension-table": "2.0.0-beta.48",
36
- "@tiptap/extension-table-cell": "^2.0.0-beta.20",
37
- "@tiptap/extension-table-header": "^2.0.0-beta.22",
38
- "@tiptap/extension-table-row": "^2.0.0-beta.19",
39
- "@tiptap/extension-text-align": "^2.0.0-beta.207",
40
- "@tiptap/extension-text-style": "^2.0.0-beta.207",
41
- "@tiptap/extension-underline": "^2.0.0-beta.207",
42
- "@tiptap/starter-kit": "^2.0.0-beta.183",
43
- "@tiptap/vue-2": "^2.0.0-beta.84"
46
+ "vue-template-compiler": "^2.6.12"
44
47
  },
45
48
  "peerDependencies": {
46
49
  "vue": "^2.6.12"
@@ -63,8 +66,5 @@
63
66
  "> 1%",
64
67
  "last 2 versions",
65
68
  "not dead"
66
- ],
67
- "dependencies": {
68
- "@popperjs/core": "2.11.2"
69
- }
69
+ ]
70
70
  }
@@ -1,4 +1,4 @@
1
- import { Button, Select, InputUnits, ColorPicker, ToolbarPopover, InputAuto, InputBrowse } from './renders';
1
+ import { Button, Select, InputUnits, ColorPicker, ToolbarPopover, InputAuto, InputBrowse, Link } from './renders';
2
2
 
3
3
  export type Render = Readonly<{
4
4
  BUTTON: Button;
@@ -8,6 +8,7 @@ export type Render = Readonly<{
8
8
  TOOLBAR_POPOVER: ToolbarPopover;
9
9
  INPUT_AUTO: InputAuto;
10
10
  INPUT_BROWSE: InputBrowse;
11
+ LINK: Link;
11
12
  }>;
12
13
 
13
14
  export type CommandDef = {
@@ -23,10 +24,10 @@ export type ToolDef = {
23
24
  render: Render;
24
25
  title: String;
25
26
  icon: String;
26
- exec: (value?: String) => void;
27
+ exec: (value?: String | Record<String, any>) => void;
27
28
  isActive: () => Boolean;
28
29
  isEnabled: () => Boolean;
29
- getValue?: () => String;
30
+ getValue?: () => String | Record<String, any>;
30
31
  options?: Array<String | ToolDef | CommandDef>;
31
32
  units?: Array<String>
32
33
  };
@@ -114,6 +115,5 @@ export type ToolType = Readonly<{
114
115
  ALIGN_V_BOT: 'alignVBot',
115
116
  TOGGLE_BORDERS: 'toggleBorders',
116
117
  TOGGLE_ZEBRA: 'toggleZebra',
117
- INSERT_IMAGE: 'insertImage',
118
- INSERT_LINK: 'insertLink'
118
+ INSERT_IMAGE: 'insertImage'
119
119
  }>;
@@ -1,4 +1,4 @@
1
- import { Button, Select, InputUnits, ColorPicker, ToolbarPopover, InputAuto, InputBrowse } from './renders';
1
+ import { Button, Select, InputUnits, ColorPicker, ToolbarPopover, InputAuto, InputBrowse, Link } from './renders';
2
2
 
3
3
  /**
4
4
  * @typedef {import('./WysiwygEditor').NodeType} NodeType
@@ -116,8 +116,7 @@ export const ToolType = Object.freeze({
116
116
  TOGGLE_BORDERS: 'toggleBorders',
117
117
  TOGGLE_ZEBRA: 'toggleZebra',
118
118
  /** image options */
119
- INSERT_IMAGE: 'insertImage',
120
- INSERT_LINK: 'insertLink'
119
+ INSERT_IMAGE: 'insertImage'
121
120
  });
122
121
 
123
122
  /**
@@ -148,7 +147,8 @@ export const Render = Object.freeze({
148
147
  SELECT: Select,
149
148
  TOOLBAR_POPOVER: ToolbarPopover,
150
149
  INPUT_AUTO: InputAuto,
151
- INPUT_BROWSE: InputBrowse
150
+ INPUT_BROWSE: InputBrowse,
151
+ LINK: Link
152
152
  });
153
153
 
154
154
  /**
@@ -236,6 +236,15 @@ export const createInputBrowseTool = ({ getValue = () => null, ...toolOptions })
236
236
  getValue
237
237
  });
238
238
 
239
+ /**
240
+ * @param {Tool} tool
241
+ * @return Tool
242
+ */
243
+ export const createLinkTool = ({ getValue = () => null, ...toolOptions }) => ({
244
+ ...createBaseTool({ render: Render.LINK, ...toolOptions }),
245
+ getValue
246
+ });
247
+
239
248
  export const DefaultTools = [
240
249
  [ToolType.PARAGRAPH_STYLE, ToolType.TEXT_COLOR, ToolType.FONT_SIZE, ToolType.FONT_FAMILY, ToolType.BLOCKQUOTE],
241
250
  [ToolType.BOLD, ToolType.ITALIC, ToolType.UNDERLINE, ToolType.STRIKE, ToolType.CODE],
@@ -1,15 +1,19 @@
1
1
  import { Image as ImageToExtend } from '@tiptap/extension-image';
2
2
 
3
- export const Image = ImageToExtend.extend({
4
- addAttributes() {
5
- return {
6
- ...this.parent?.(),
7
- class: {
8
- default: 'responsive'
9
- },
10
- style: {
11
- default: null
12
- }
13
- }
14
- }
15
- })
3
+ export const Image = ImageToExtend
4
+ .extend({
5
+ addAttributes() {
6
+ return {
7
+ ...this.parent?.(),
8
+ class: {
9
+ default: 'responsive',
10
+ },
11
+ style: {
12
+ default: null,
13
+ },
14
+ };
15
+ },
16
+ })
17
+ .configure({
18
+ inline: true,
19
+ });
@@ -1,5 +1,6 @@
1
1
  import { TextAlign as TextAlignToExtend } from '@tiptap/extension-text-align';
2
+ import { NodeType, MarkType } from '../constants';
2
3
 
3
4
  export const TextAlign = TextAlignToExtend.configure({
4
- types: ['heading', 'paragraph', 'link', 'codeBlock', 'blockquote']
5
+ types: [NodeType.HEADING, NodeType.PARAGRAPH, MarkType.LINK, NodeType.CODE_BLOCK, NodeType.BLOCKQUOTE]
5
6
  });
@@ -1,14 +1,16 @@
1
1
  <template>
2
- <button
3
- :class="{ 'btn-outline': !isActive, 'btn-primary': isActive }"
4
- :title="title"
5
- :disabled="!isEnabled"
6
- class="btn btn-small btn-icon"
7
- @click.stop="onClick">
8
- <div class="icon">
9
- <i :class="icon" class="mdi"></i>
10
- </div>
11
- </button>
2
+ <div :title="title">
3
+ <button
4
+ :class="{ 'btn-outline': !isActive, 'btn-primary': isActive }"
5
+ :disabled="!isEnabled"
6
+ class="btn btn-small btn-icon"
7
+ @click.stop="onClick">
8
+ <div class="icon">
9
+ <i :class="icon" class="mdi"></i>
10
+ </div>
11
+ </button>
12
+ </div>
13
+
12
14
  </template>
13
15
 
14
16
  <script>
@@ -1,7 +1,6 @@
1
1
  <template>
2
- <div :data-popover="popoverTargetId">
2
+ <div :data-popover="popoverTargetId" :title="title">
3
3
  <button
4
- :title="title"
5
4
  class="btn btn-small btn-outline btn-icon"
6
5
  @click="togglePopover">
7
6
  <div class="icon">
@@ -1,8 +1,9 @@
1
1
  <template>
2
- <input-autocomplete
3
- v-bind="{ value, options: tool.options, title, disabled: !isEnabled, size: 'small' }"
4
- class="autocomplete-tool"
5
- @input="onInput" />
2
+ <div :title="title" class="autocomplete-tool">
3
+ <input-autocomplete
4
+ v-bind="{ value, options: tool.options, disabled: !isEnabled, size: 'small' }"
5
+ @input="onInput" />
6
+ </div>
6
7
  </template>
7
8
 
8
9
  <script>
@@ -1,7 +1,7 @@
1
1
  <template>
2
- <div class="form-control form-control-icon-right w-12-12">
2
+ <div :title="title" class="form-control form-control-icon-right w-12-12">
3
3
  <input-autocomplete
4
- v-bind="{ value, title, disabled: !isEnabled, size: 'small' }"
4
+ v-bind="{ value, disabled: !isEnabled, size: 'small' }"
5
5
  @change="onChange" />
6
6
  <div class="icon">
7
7
  <i class="mdi mdi-folder cursor-pointer color-grey" @click="browse" />
@@ -1,8 +1,9 @@
1
1
  <template>
2
- <input-units
3
- v-bind="{ value, units, title, size: 'small', disabled: !isEnabled }"
4
- class="input-units-tool"
5
- @change="onChange" />
2
+ <div :title="title" class="input-units-tool">
3
+ <input-units
4
+ v-bind="{ value, units, size: 'small', disabled: !isEnabled }"
5
+ @change="onChange" />
6
+ </div>
6
7
  </template>
7
8
 
8
9
  <script>
@@ -0,0 +1,87 @@
1
+ <template>
2
+ <div :data-popover="popoverTargetId" :title="title">
3
+ <button class="btn btn-small btn-outline btn-icon" @click="togglePopover">
4
+ <div class="icon">
5
+ <i class="mdi" :class="icon"></i>
6
+ </div>
7
+ </button>
8
+ <popover :show="popoverShow" v-bind="popoverOptions">
9
+ <div class="dropdown pad-l1 pad-top-l2">
10
+ <div class="close pos-abs pos-top-right mar-2" @click="togglePopover">
11
+ <i class="mdi mdi-close color-grey" />
12
+ </div>
13
+ <div class="row row-hgap-3 mar-bot-l1">
14
+ <div class="col col-vmid text-truncate">
15
+ <div class="form-label form-label-xsmall text-truncate">Url</div>
16
+ </div>
17
+ <div class="col col-vmid col-12-12">
18
+ <input-autocomplete v-model="url" class="w-100" size="small" />
19
+ </div>
20
+ </div>
21
+ <div class="row row-hgap-3 mar-bot-l1">
22
+ <div class="col col-vmid text-truncate">
23
+ <div class="form-label form-label-xsmall text-truncate">Target</div>
24
+ </div>
25
+ <div class="col col-vmid col-12-12">
26
+ <ui-select
27
+ v-model="target"
28
+ :options="$options.static.TargetTypeOptions"
29
+ class="w-100"
30
+ size="small" />
31
+ </div>
32
+ </div>
33
+ <button class="btn btn-outline btn-small w-100" @click="execute">Применить</button>
34
+ </div>
35
+ </popover>
36
+ </div>
37
+ </template>
38
+
39
+ <script>
40
+ import Popover from '../../Popover.vue';
41
+ import InputAutocomplete from '../../InputAutocomplete.vue';
42
+ import UiSelect from '../../Select.vue';
43
+ import WithPopover from '../../utils/WithPopover';
44
+ import { useRender } from './mixins';
45
+
46
+ const TargetType = {
47
+ BLANK: '_blank',
48
+ SELF: '_self'
49
+ }
50
+
51
+ export default {
52
+ components: {
53
+ Popover,
54
+ InputAutocomplete,
55
+ UiSelect
56
+ },
57
+ mixins: [useRender(), WithPopover],
58
+ data: () => ({
59
+ url: '',
60
+ target: null
61
+ }),
62
+ static: {
63
+ TargetTypeOptions: [
64
+ { label: 'blank', value: TargetType.BLANK },
65
+ { label: 'self', value: TargetType.SELF }
66
+ ]
67
+ },
68
+ watch: {
69
+ popoverShow(isShown) {
70
+ if (isShown) {
71
+ const { url = '', target = TargetType.BLANK } = this.tool.getValue();
72
+ this.url = url;
73
+ this.target = target;
74
+ }
75
+ }
76
+ },
77
+ methods: {
78
+ execute() {
79
+ const { tool, url, target } = this;
80
+ tool.exec({ url, target });
81
+
82
+ this.popoverShow = false;
83
+ this.emitExecuted();
84
+ }
85
+ }
86
+ };
87
+ </script>
@@ -1,8 +1,10 @@
1
1
  <template>
2
- <ui-select
3
- v-bind="{ value, options, valueObjects, title, disabled: !isEnabled, size: 'small' }"
4
- class="select-tool"
5
- @change="onChange" />
2
+ <div :title="title" class="select-tool">
3
+ <ui-select
4
+ v-bind="{ value, options, valueObjects, disabled: !isEnabled, size: 'small' }"
5
+ class="w-100"
6
+ @change="onChange" />
7
+ </div>
6
8
  </template>
7
9
 
8
10
  <script>
@@ -1,7 +1,6 @@
1
1
  <template>
2
- <div :data-popover="popoverTargetId">
2
+ <div :data-popover="popoverTargetId" :title="title">
3
3
  <button
4
- :title="title"
5
4
  class="btn btn-small btn-outline btn-icon"
6
5
  @click="togglePopover">
7
6
  <div class="icon">
@@ -5,3 +5,4 @@ export { default as ColorPicker } from './ColorPicker.vue';
5
5
  export { default as ToolbarPopover } from './ToolbarPopover.vue';
6
6
  export { default as InputAuto } from './InputAuto.vue';
7
7
  export { default as InputBrowse } from './InputBrowse.vue';
8
+ export { default as Link } from './Link.vue';
@@ -5,3 +5,4 @@ export { default as ColorPicker } from './ColorPicker.vue';
5
5
  export { default as ToolbarPopover } from './ToolbarPopover.vue';
6
6
  export { default as InputAuto } from './InputAuto.vue';
7
7
  export { default as InputBrowse } from './InputBrowse.vue';
8
+ export { default as Link } from './Link.vue';
@@ -10,7 +10,8 @@ import {
10
10
  createSelectTool,
11
11
  createToolbarPopoverTool,
12
12
  createInputAutoTool,
13
- createInputBrowseTool
13
+ createInputBrowseTool,
14
+ createLinkTool
14
15
  } from './constants';
15
16
 
16
17
  export const CommandMap = {
@@ -32,7 +33,7 @@ export const CommandMap = {
32
33
  }),
33
34
  [CommandType.HEADING_1]: createCommand({
34
35
  name: CommandType.HEADING_1,
35
- title: 'Заголовок 1',
36
+ title: 'Заголовок 1 (h1)',
36
37
  exec() {
37
38
  this.editor
38
39
  .chain()
@@ -47,7 +48,7 @@ export const CommandMap = {
47
48
  }),
48
49
  [CommandType.HEADING_2]: createCommand({
49
50
  name: CommandType.HEADING_2,
50
- title: 'Заголовок 2',
51
+ title: 'Заголовок 2 (h2)',
51
52
  exec() {
52
53
  this.editor
53
54
  .chain()
@@ -62,7 +63,7 @@ export const CommandMap = {
62
63
  }),
63
64
  [CommandType.HEADING_3]: createCommand({
64
65
  name: CommandType.HEADING_3,
65
- title: 'Заголовок 3',
66
+ title: 'Заголовок 3 (h3)',
66
67
  exec() {
67
68
  this.editor
68
69
  .chain()
@@ -77,7 +78,7 @@ export const CommandMap = {
77
78
  }),
78
79
  [CommandType.HEADING_4]: createCommand({
79
80
  name: CommandType.HEADING_4,
80
- title: 'Заголовок 4',
81
+ title: 'Заголовок 4 (h4)',
81
82
  exec() {
82
83
  this.editor
83
84
  .chain()
@@ -407,40 +408,6 @@ export const ImageOptionsMap = {
407
408
  })
408
409
  };
409
410
 
410
- export const LinkOptionsMap = {
411
- [ToolType.INSERT_LINK]: createInputAutoTool({
412
- name: ToolType.INSERT_LINK,
413
- title: 'Вставить ссылку',
414
- exec(url) {
415
- const { editor } = this;
416
-
417
- if (url === '') {
418
- editor
419
- .chain()
420
- .focus()
421
- .extendMarkRange(MarkType.LINK)
422
- .unsetLink()
423
- .run();
424
-
425
- return;
426
- }
427
-
428
- editor
429
- .chain()
430
- .focus()
431
- .extendMarkRange(MarkType.LINK)
432
- .setLink({ href: url })
433
- .run();
434
- },
435
- getValue() {
436
- return this.editor.getAttributes(MarkType.LINK).href;
437
- },
438
- isEnabled() {
439
- return this.editor.can().setLink();
440
- },
441
- })
442
- }
443
-
444
411
  export const ToolsMap = {
445
412
  [ToolType.UNDO]: createButtonTool({
446
413
  name: ToolType.UNDO,
@@ -642,11 +609,39 @@ export const ToolsMap = {
642
609
  return this.editor.can().setHorizontalRule();
643
610
  }
644
611
  }),
645
- [ToolType.LINK]: createToolbarPopoverTool({
612
+ [ToolType.LINK]: createLinkTool({
646
613
  name: ToolType.LINK,
647
614
  icon: 'link-plus',
648
615
  title: 'Ссылка',
649
- options: Object.values(LinkOptionsMap)
616
+ getValue() {
617
+ const linkAttrs = this.editor.getAttributes(MarkType.LINK);
618
+ const { href: url, target } = linkAttrs;
619
+ return { url, target };
620
+ },
621
+ isEnabled() {
622
+ return this.editor.can().setLink();
623
+ },
624
+ exec({ url, target }) {
625
+ const { editor } = this;
626
+
627
+ if (url === '') {
628
+ editor
629
+ .chain()
630
+ .focus()
631
+ .extendMarkRange(MarkType.LINK)
632
+ .unsetLink()
633
+ .run();
634
+
635
+ return;
636
+ }
637
+
638
+ editor
639
+ .chain()
640
+ .focus()
641
+ .extendMarkRange(MarkType.LINK)
642
+ .setLink({ href: url, ...(target && { target }) })
643
+ .run();
644
+ }
650
645
  }),
651
646
  [ToolType.BOLD]: createButtonTool({
652
647
  name: ToolType.BOLD,
@@ -49,7 +49,7 @@
49
49
  </div>
50
50
  </template>
51
51
  <template #editor-content="{ style }">
52
- <div class="editor-content pad-v-l1" :style="style">
52
+ <div :style="style" class="editor-content pad-v-l1" >
53
53
  <div class="h-100">
54
54
  <editor-content :editor="editor" class="h-100"/>
55
55
  </div>
@@ -257,4 +257,15 @@ export default {
257
257
  margin-right: 0.25rem;
258
258
  }
259
259
  }
260
+
261
+ ::v-deep .ProseMirror {
262
+ & .ProseMirror-selectednode {
263
+ outline: 2px solid var(--color-focus);
264
+ }
265
+
266
+ li > p {
267
+ display: inline-block;
268
+ margin: 0;
269
+ }
270
+ }
260
271
  </style>