frappe-ui 0.0.67 → 0.0.69

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": "frappe-ui",
3
- "version": "0.0.67",
3
+ "version": "0.0.69",
4
4
  "description": "A set of components and utilities for rapid UI development",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
@@ -33,6 +33,7 @@
33
33
  "@tiptap/extension-table-row": "^2.0.0-beta.22",
34
34
  "@tiptap/extension-text-align": "^2.0.0-beta.31",
35
35
  "@tiptap/starter-kit": "^2.0.0-beta.191",
36
+ "@tiptap/suggestion": "^2.0.0-beta.195",
36
37
  "@tiptap/vue-3": "^2.0.0-beta.96",
37
38
  "autoprefixer": "^10.4.2",
38
39
  "feather-icons": "^4.28.0",
@@ -43,8 +43,7 @@
43
43
  @click="item.onClick"
44
44
  >
45
45
  <component :is="item.component" v-if="item.component" />
46
-
47
- <span v-else>
46
+ <template v-else>
48
47
  <FeatherIcon
49
48
  v-if="item.icon"
50
49
  :name="item.icon"
@@ -54,7 +53,7 @@
54
53
  <span class="whitespace-nowrap">
55
54
  {{ item.label }}
56
55
  </span>
57
- </span>
56
+ </template>
58
57
  </button>
59
58
  </MenuItem>
60
59
  </div>
@@ -88,7 +88,8 @@ import { Popover, Dialog, Input, Button } from 'frappe-ui'
88
88
  import InsertImage from './InsertImage.vue'
89
89
  export default {
90
90
  name: 'TipTapMenu',
91
- props: ['editor', 'buttons'],
91
+ props: ['buttons'],
92
+ inject: ['editor'],
92
93
  components: {
93
94
  Popover,
94
95
  Dialog,
@@ -1,51 +1,21 @@
1
1
  <template>
2
2
  <div class="relative w-full" :class="$attrs.class" v-if="editor">
3
- <BubbleMenu
4
- v-if="bubbleMenuButtons"
5
- class="bubble-menu rounded-md shadow-sm"
6
- :tippy-options="{ duration: 100 }"
7
- :editor="editor"
8
- >
9
- <Menu
10
- :editor="editor"
11
- class="rounded-md border border-gray-100 shadow-lg"
12
- :buttons="bubbleMenuButtons"
13
- />
14
- </BubbleMenu>
15
-
16
- <Menu
17
- v-if="fixedMenuButtons"
3
+ <TextEditorBubbleMenu :buttons="bubbleMenu" />
4
+ <TextEditorFixedMenu
18
5
  class="w-full overflow-x-auto rounded-t-lg border border-gray-200"
19
- :editor="editor"
20
- :buttons="fixedMenuButtons"
6
+ :buttons="fixedMenu"
21
7
  />
22
-
23
- <FloatingMenu
24
- v-if="floatingMenuButtons"
25
- :tippy-options="{ duration: 100 }"
26
- :editor="editor"
27
- class="flex"
28
- >
29
- <button
30
- v-for="button in floatingMenuButtons"
31
- :key="button.label"
32
- class="flex rounded p-1 text-gray-800 transition-colors"
33
- :class="button.isActive(editor) ? 'bg-gray-100' : 'hover:bg-gray-100'"
34
- @click="() => button.action(editor)"
35
- :title="button.label"
36
- >
37
- <component v-if="button.icon" :is="button.icon" class="h-4 w-4" />
38
- <span class="inline-block h-4 min-w-[1rem] text-sm leading-4" v-else>
39
- {{ button.text }}
40
- </span>
41
- </button>
42
- </FloatingMenu>
8
+ <TextEditorFloatingMenu :buttons="floatingMenu" />
9
+ <slot name="top" />
43
10
  <editor-content :editor="editor" />
11
+ <slot name="bottom" />
44
12
  </div>
45
13
  </template>
46
14
 
47
15
  <script>
48
- import { Editor, EditorContent, BubbleMenu, FloatingMenu } from '@tiptap/vue-3'
16
+ import { normalizeClass } from 'vue'
17
+ import { computed } from '@vue/reactivity'
18
+ import { Editor, EditorContent } from '@tiptap/vue-3'
49
19
  import StarterKit from '@tiptap/starter-kit'
50
20
  import Placeholder from '@tiptap/extension-placeholder'
51
21
  import TextAlign from '@tiptap/extension-text-align'
@@ -56,18 +26,18 @@ import TableRow from '@tiptap/extension-table-row'
56
26
  import Image from './image-extension'
57
27
  import Link from '@tiptap/extension-link'
58
28
  import configureMention from './mention'
59
- import Menu from './Menu.vue'
60
- import commands from './commands'
61
- import { normalizeClass } from 'vue'
29
+ import TextEditorFixedMenu from './TextEditorFixedMenu.vue'
30
+ import TextEditorBubbleMenu from './TextEditorBubbleMenu.vue'
31
+ import TextEditorFloatingMenu from './TextEditorFloatingMenu.vue'
62
32
 
63
33
  export default {
64
34
  name: 'TextEditor',
65
35
  inheritAttrs: false,
66
36
  components: {
67
37
  EditorContent,
68
- BubbleMenu,
69
- FloatingMenu,
70
- Menu,
38
+ TextEditorFixedMenu,
39
+ TextEditorBubbleMenu,
40
+ TextEditorFloatingMenu,
71
41
  },
72
42
  props: {
73
43
  content: {
@@ -113,6 +83,11 @@ export default {
113
83
  },
114
84
  emits: ['change'],
115
85
  expose: ['editor'],
86
+ provide() {
87
+ return {
88
+ editor: computed(() => this.editor),
89
+ }
90
+ },
116
91
  data() {
117
92
  return {
118
93
  editor: null,
@@ -175,124 +150,9 @@ export default {
175
150
  },
176
151
  beforeUnmount() {
177
152
  this.editor.destroy()
153
+ this.editor = null
178
154
  },
179
155
  computed: {
180
- fixedMenuButtons() {
181
- if (!this.fixedMenu) return false
182
-
183
- let buttons
184
- if (Array.isArray(this.fixedMenu)) {
185
- buttons = this.fixedMenu
186
- } else {
187
- buttons = [
188
- [
189
- 'Heading 1',
190
- 'Heading 2',
191
- 'Heading 3',
192
- 'Heading 4',
193
- 'Heading 5',
194
- 'Heading 6',
195
- ],
196
- 'Paragraph',
197
- 'Separator',
198
- 'Bold',
199
- 'Italic',
200
- 'Separator',
201
- 'Bullet List',
202
- 'Numbered List',
203
- 'Separator',
204
- 'Align Left',
205
- 'Align Center',
206
- 'Align Right',
207
- 'Separator',
208
- 'Image',
209
- 'Link',
210
- 'Blockquote',
211
- 'Code',
212
- 'Horizontal Rule',
213
- [
214
- 'InsertTable',
215
- 'AddColumnBefore',
216
- 'AddColumnAfter',
217
- 'DeleteColumn',
218
- 'AddRowBefore',
219
- 'AddRowAfter',
220
- 'DeleteRow',
221
- 'MergeCells',
222
- 'SplitCell',
223
- 'ToggleHeaderColumn',
224
- 'ToggleHeaderRow',
225
- 'ToggleHeaderCell',
226
- 'DeleteTable',
227
- ],
228
- 'Separator',
229
- 'Undo',
230
- 'Redo',
231
- ]
232
- }
233
- return buttons.map(createEditorButton)
234
- },
235
- bubbleMenuButtons() {
236
- if (!this.bubbleMenu) return false
237
-
238
- let buttons
239
- if (Array.isArray(this.bubbleMenu)) {
240
- buttons = this.bubbleMenu
241
- } else {
242
- buttons = [
243
- 'Paragraph',
244
- 'Heading 2',
245
- 'Heading 3',
246
- 'Separator',
247
- 'Bold',
248
- 'Italic',
249
- 'Link',
250
- 'Separator',
251
- 'Bullet List',
252
- 'Numbered List',
253
- 'Separator',
254
- 'Image',
255
- 'Blockquote',
256
- 'Code',
257
- [
258
- 'InsertTable',
259
- 'AddColumnBefore',
260
- 'AddColumnAfter',
261
- 'DeleteColumn',
262
- 'AddRowBefore',
263
- 'AddRowAfter',
264
- 'DeleteRow',
265
- 'MergeCells',
266
- 'SplitCell',
267
- 'ToggleHeaderColumn',
268
- 'ToggleHeaderRow',
269
- 'ToggleHeaderCell',
270
- 'DeleteTable',
271
- ],
272
- ]
273
- }
274
- return buttons.map(createEditorButton)
275
- },
276
- floatingMenuButtons() {
277
- if (!this.floatingMenu) return false
278
-
279
- let buttons
280
- if (Array.isArray(this.floatingMenu)) {
281
- buttons = this.floatingMenu
282
- } else {
283
- buttons = [
284
- 'Paragraph',
285
- 'Heading 2',
286
- 'Heading 3',
287
- 'Bullet List',
288
- 'Numbered List',
289
- 'Blockquote',
290
- 'Code',
291
- 'Horizontal Rule',
292
- ]
293
- }
294
- return buttons.map(createEditorButton)
295
- },
296
156
  editorProps() {
297
157
  return {
298
158
  attributes: {
@@ -305,18 +165,14 @@ export default {
305
165
  },
306
166
  },
307
167
  }
308
-
309
- function createEditorButton(option) {
310
- if (option instanceof Array) {
311
- return option.map(createEditorButton)
312
- }
313
- if (typeof option == 'object') {
314
- return option
315
- }
316
- return commands[option]
317
- }
318
168
  </script>
319
169
  <style>
170
+ .ProseMirror {
171
+ outline: none;
172
+ caret-color: theme('colors.blue.600');
173
+ word-break: break-word;
174
+ }
175
+
320
176
  /* Placeholder */
321
177
  .ProseMirror:not(.ProseMirror-focused) p.is-editor-empty:first-child::before {
322
178
  content: attr(data-placeholder);
@@ -0,0 +1,68 @@
1
+ <template>
2
+ <BubbleMenu
3
+ v-if="bubbleMenuButtons"
4
+ class="bubble-menu rounded-md shadow-sm"
5
+ :tippy-options="{ duration: 100 }"
6
+ :editor="editor"
7
+ >
8
+ <Menu
9
+ class="rounded-md border border-gray-100 shadow-lg"
10
+ :buttons="bubbleMenuButtons"
11
+ />
12
+ </BubbleMenu>
13
+ </template>
14
+ <script>
15
+ import { BubbleMenu } from '@tiptap/vue-3'
16
+ import { createEditorButton } from './utils'
17
+ import Menu from './Menu.vue'
18
+
19
+ export default {
20
+ name: 'TextEditorBubbleMenu',
21
+ props: ['buttons'],
22
+ components: { BubbleMenu, Menu },
23
+ inject: ['editor'],
24
+ computed: {
25
+ bubbleMenuButtons() {
26
+ if (!this.buttons) return false
27
+
28
+ let buttons
29
+ if (Array.isArray(this.buttons)) {
30
+ buttons = this.buttons
31
+ } else {
32
+ buttons = [
33
+ 'Paragraph',
34
+ 'Heading 2',
35
+ 'Heading 3',
36
+ 'Separator',
37
+ 'Bold',
38
+ 'Italic',
39
+ 'Link',
40
+ 'Separator',
41
+ 'Bullet List',
42
+ 'Numbered List',
43
+ 'Separator',
44
+ 'Image',
45
+ 'Blockquote',
46
+ 'Code',
47
+ [
48
+ 'InsertTable',
49
+ 'AddColumnBefore',
50
+ 'AddColumnAfter',
51
+ 'DeleteColumn',
52
+ 'AddRowBefore',
53
+ 'AddRowAfter',
54
+ 'DeleteRow',
55
+ 'MergeCells',
56
+ 'SplitCell',
57
+ 'ToggleHeaderColumn',
58
+ 'ToggleHeaderRow',
59
+ 'ToggleHeaderCell',
60
+ 'DeleteTable',
61
+ ],
62
+ ]
63
+ }
64
+ return buttons.map(createEditorButton)
65
+ },
66
+ },
67
+ }
68
+ </script>
@@ -0,0 +1,70 @@
1
+ <template>
2
+ <Menu v-if="fixedMenuButtons" :buttons="fixedMenuButtons" />
3
+ </template>
4
+ <script>
5
+ import Menu from './Menu.vue'
6
+ import { createEditorButton } from './utils'
7
+
8
+ export default {
9
+ name: 'TextEditorFixedMenu',
10
+ props: ['buttons'],
11
+ components: { Menu },
12
+ inject: ['editor'],
13
+ computed: {
14
+ fixedMenuButtons() {
15
+ if (!this.buttons) return false
16
+ let buttons
17
+ if (Array.isArray(this.buttons)) {
18
+ buttons = this.buttons
19
+ } else {
20
+ buttons = [
21
+ [
22
+ 'Heading 1',
23
+ 'Heading 2',
24
+ 'Heading 3',
25
+ 'Heading 4',
26
+ 'Heading 5',
27
+ 'Heading 6',
28
+ ],
29
+ 'Paragraph',
30
+ 'Separator',
31
+ 'Bold',
32
+ 'Italic',
33
+ 'Separator',
34
+ 'Bullet List',
35
+ 'Numbered List',
36
+ 'Separator',
37
+ 'Align Left',
38
+ 'Align Center',
39
+ 'Align Right',
40
+ 'Separator',
41
+ 'Image',
42
+ 'Link',
43
+ 'Blockquote',
44
+ 'Code',
45
+ 'Horizontal Rule',
46
+ [
47
+ 'InsertTable',
48
+ 'AddColumnBefore',
49
+ 'AddColumnAfter',
50
+ 'DeleteColumn',
51
+ 'AddRowBefore',
52
+ 'AddRowAfter',
53
+ 'DeleteRow',
54
+ 'MergeCells',
55
+ 'SplitCell',
56
+ 'ToggleHeaderColumn',
57
+ 'ToggleHeaderRow',
58
+ 'ToggleHeaderCell',
59
+ 'DeleteTable',
60
+ ],
61
+ 'Separator',
62
+ 'Undo',
63
+ 'Redo',
64
+ ]
65
+ }
66
+ return buttons.map(createEditorButton)
67
+ },
68
+ },
69
+ }
70
+ </script>
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <FloatingMenu
3
+ v-if="floatingMenuButtons"
4
+ :tippy-options="{ duration: 100 }"
5
+ :editor="editor"
6
+ class="flex"
7
+ >
8
+ <button
9
+ v-for="button in floatingMenuButtons"
10
+ :key="button.label"
11
+ class="flex rounded p-1 text-gray-800 transition-colors"
12
+ :class="button.isActive(editor) ? 'bg-gray-100' : 'hover:bg-gray-100'"
13
+ @click="() => button.action(editor)"
14
+ :title="button.label"
15
+ >
16
+ <component v-if="button.icon" :is="button.icon" class="h-4 w-4" />
17
+ <span class="inline-block h-4 min-w-[1rem] text-sm leading-4" v-else>
18
+ {{ button.text }}
19
+ </span>
20
+ </button>
21
+ </FloatingMenu>
22
+ </template>
23
+ <script>
24
+ import { FloatingMenu } from '@tiptap/vue-3'
25
+ import { createEditorButton } from './utils'
26
+
27
+ export default {
28
+ name: 'TextEditorFloatingMenu',
29
+ props: ['buttons'],
30
+ components: { FloatingMenu },
31
+ inject: ['editor'],
32
+ computed: {
33
+ floatingMenuButtons() {
34
+ if (!this.buttons) return false
35
+
36
+ let buttons
37
+ if (Array.isArray(this.buttons)) {
38
+ buttons = this.buttons
39
+ } else {
40
+ buttons = [
41
+ 'Paragraph',
42
+ 'Heading 2',
43
+ 'Heading 3',
44
+ 'Bullet List',
45
+ 'Numbered List',
46
+ 'Blockquote',
47
+ 'Code',
48
+ 'Horizontal Rule',
49
+ ]
50
+ }
51
+ return buttons.map(createEditorButton)
52
+ },
53
+ },
54
+ }
55
+ </script>
@@ -0,0 +1,11 @@
1
+ import commands from './commands'
2
+
3
+ export function createEditorButton(option) {
4
+ if (option instanceof Array) {
5
+ return option.map(createEditorButton)
6
+ }
7
+ if (typeof option == 'object') {
8
+ return option
9
+ }
10
+ return commands[option]
11
+ }