@onereach/ui-components 10.2.0 → 10.2.1-beta.4272.0
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/dist/bundled/v2/components/OrRichTextEditorV3/OrRichTextEditor.js +382 -252
- package/dist/bundled/v2/components/OrRichTextEditorV3/OrRichTextEditor.vue.d.ts +21 -68
- package/dist/bundled/v2/components/OrRichTextEditorV3/styles.d.ts +1 -0
- package/dist/bundled/v2/components/OrRichTextEditorV3/styles.js +5 -4
- package/dist/bundled/v2/components/OrRichTextEditorV3/utils/codemirror/codemirrorNode.js +1 -1
- package/dist/bundled/v2/components/OrRichTextEditorV3/utils/codemirror/codemirrorView.js +1 -1
- package/dist/bundled/v2/components/OrRichTextEditorV3/utils/markdown.js +2 -2
- package/dist/bundled/v2/{index-02a897ac.js → index-0e9c2b43.js} +1 -1
- package/dist/bundled/v2/{index-7516cf60.js → index-f379c836.js} +258 -173
- package/dist/bundled/v2/{markdown-fe3bfb01.js → markdown-2d22cf16.js} +66 -113
- package/dist/bundled/v3/components/OrRichTextEditorV3/OrRichTextEditor.js +1 -1
- package/dist/bundled/v3/components/OrRichTextEditorV3/OrRichTextEditor.vue.d.ts +14 -18
- package/dist/bundled/v3/components/OrRichTextEditorV3/index.js +1 -1
- package/dist/bundled/v3/components/OrRichTextEditorV3/props.js +1 -1
- package/dist/bundled/v3/components/OrRichTextEditorV3/styles.d.ts +1 -0
- package/dist/bundled/v3/components/OrRichTextEditorV3/styles.js +1 -1
- package/dist/bundled/v3/components/OrRichTextEditorV3/utils/codemirror/codemirrorNode.js +1 -1
- package/dist/bundled/v3/components/OrRichTextEditorV3/utils/codemirror/codemirrorView.js +1 -1
- package/dist/bundled/v3/components/OrRichTextEditorV3/utils/codemirror/index.js +1 -1
- package/dist/bundled/v3/components/OrRichTextEditorV3/utils/codemirror/theme.js +1 -1
- package/dist/bundled/v3/components/OrRichTextEditorV3/utils/markdown.js +1 -1
- package/dist/bundled/v3/components/{OrRichTextEditorV3-358d7df2.js → OrRichTextEditorV3-45e64a85.js} +673 -531
- package/dist/bundled/v3/components/index.js +1 -1
- package/dist/bundled/v3/index.js +1 -1
- package/dist/esm/v2/{OrRichTextEditor-734b8b27.js → OrRichTextEditor-fbcc33fd.js} +353 -244
- package/dist/esm/v2/components/index.js +1 -1
- package/dist/esm/v2/components/or-rich-text-editor-v3/OrRichTextEditor.vue.d.ts +21 -68
- package/dist/esm/v2/components/or-rich-text-editor-v3/index.js +7 -7
- package/dist/esm/v2/components/or-rich-text-editor-v3/partials/EditorToolbar.vue.d.ts +160 -0
- package/dist/esm/v2/components/or-rich-text-editor-v3/styles.d.ts +1 -0
- package/dist/esm/v2/index.js +1 -1
- package/dist/esm/v3/{OrRichTextEditor-b5684aab.js → OrRichTextEditor-cdd9e3e4.js} +325 -242
- package/dist/esm/v3/components/index.js +1 -1
- package/dist/esm/v3/components/or-rich-text-editor-v3/OrRichTextEditor.vue.d.ts +14 -18
- package/dist/esm/v3/components/or-rich-text-editor-v3/index.js +6 -6
- package/dist/esm/v3/components/or-rich-text-editor-v3/partials/EditorToolbar.vue.d.ts +89 -0
- package/dist/esm/v3/components/or-rich-text-editor-v3/styles.d.ts +1 -0
- package/dist/esm/v3/index.js +1 -1
- package/package.json +19 -20
- package/src/components/or-rich-text-editor-v3/OrRichTextEditor.vue +48 -203
- package/src/components/or-rich-text-editor-v3/partials/EditorToolbar.vue +238 -0
- package/src/components/or-rich-text-editor-v3/styles.ts +13 -10
|
@@ -16,53 +16,22 @@
|
|
|
16
16
|
</OrLabel>
|
|
17
17
|
</template>
|
|
18
18
|
<div
|
|
19
|
-
|
|
19
|
+
ref="containerRef"
|
|
20
20
|
:class="containerStyles"
|
|
21
21
|
:invalid="!!error"
|
|
22
22
|
@click="handleEditorClick()"
|
|
23
23
|
>
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
:key="item"
|
|
36
|
-
:class="['flex gap-md', { 'hidden': !isVisible(item)}]"
|
|
37
|
-
>
|
|
38
|
-
<or-icon-button
|
|
39
|
-
v-if="item==='heading'"
|
|
40
|
-
:ref="'toolbarButtonRef'"
|
|
41
|
-
:selected="isActive[item]"
|
|
42
|
-
:disabled="!isFocused"
|
|
43
|
-
:tooltip="{content: item, placement: 'top'}"
|
|
44
|
-
:icon="{icon: headingIcon, variant: 'inherit'}"
|
|
45
|
-
@click="menuRef && menuRef.toggle()"
|
|
46
|
-
/>
|
|
47
|
-
<or-icon-button
|
|
48
|
-
v-else-if="isVisible(item)"
|
|
49
|
-
:tooltip="{content: iconTooltipsEnum[item], placement: 'top'}"
|
|
50
|
-
:selected="isActive[item]"
|
|
51
|
-
:disabled="!isFocused"
|
|
52
|
-
:icon="{icon: iconsEnum[item], variant: 'inherit'}"
|
|
53
|
-
@click="handleToolbarClick(item)"
|
|
54
|
-
/>
|
|
55
|
-
</div>
|
|
56
|
-
</div>
|
|
57
|
-
<or-icon-button
|
|
58
|
-
v-if="countOfNotVisibleTools > 0"
|
|
59
|
-
:ref="'moreButtonRef'"
|
|
60
|
-
:disabled="!isFocused"
|
|
61
|
-
:icon="{icon: 'more_horiz', variant: 'inherit'}"
|
|
62
|
-
class="px-sm"
|
|
63
|
-
@click="moreRef && moreRef.open()"
|
|
64
|
-
/>
|
|
65
|
-
</div>
|
|
24
|
+
<editor-toolbar
|
|
25
|
+
v-if="!readonly"
|
|
26
|
+
ref="toolbarContainerRef"
|
|
27
|
+
:count-of-not-visible-tools="countOfNotVisibleTools"
|
|
28
|
+
:toolbar="toolbar"
|
|
29
|
+
:is-focused="isFocused"
|
|
30
|
+
:active-heading-level="activeHeadingLevel"
|
|
31
|
+
:is-active="isActive"
|
|
32
|
+
:heading-levels="headingLevels"
|
|
33
|
+
@click-tool="handleToolbarClick"
|
|
34
|
+
/>
|
|
66
35
|
<div :class="['p-sm', 'overflow-auto', 'min-h-[88px]']">
|
|
67
36
|
<textarea
|
|
68
37
|
v-show="disableMarkdown"
|
|
@@ -74,7 +43,7 @@
|
|
|
74
43
|
/>
|
|
75
44
|
<div
|
|
76
45
|
v-show="!disableMarkdown"
|
|
77
|
-
|
|
46
|
+
ref="editorRef"
|
|
78
47
|
:class="editorInputStyles"
|
|
79
48
|
/>
|
|
80
49
|
<slot name="files" />
|
|
@@ -95,44 +64,6 @@
|
|
|
95
64
|
{{ error }}
|
|
96
65
|
</OrError>
|
|
97
66
|
</template>
|
|
98
|
-
<or-popover
|
|
99
|
-
v-if="moreButtonRef"
|
|
100
|
-
:ref="'moreRef'"
|
|
101
|
-
:trigger="moreButtonRef && moreButtonRef.root"
|
|
102
|
-
placement="top-end"
|
|
103
|
-
>
|
|
104
|
-
<div class="flex p-sm gap-md">
|
|
105
|
-
<or-icon-button
|
|
106
|
-
v-for="item in notVisibleTools"
|
|
107
|
-
:key="item"
|
|
108
|
-
:tooltip="{content: iconTooltipsEnum[item], placement: 'top'}"
|
|
109
|
-
:selected="isActive[item]"
|
|
110
|
-
:icon="{icon: iconsEnum[item], variant: 'inherit'}"
|
|
111
|
-
@click="handleToolbarClick(item)"
|
|
112
|
-
/>
|
|
113
|
-
</div>
|
|
114
|
-
</or-popover>
|
|
115
|
-
<or-menu
|
|
116
|
-
v-if="toolbarButtonRef"
|
|
117
|
-
:ref="'menuRef'"
|
|
118
|
-
:trigger="toolbarButtonRef[getIndexOfHeading] && toolbarButtonRef[getIndexOfHeading].root"
|
|
119
|
-
placement="bottom-start"
|
|
120
|
-
>
|
|
121
|
-
<or-menu-item
|
|
122
|
-
v-for="heading in headingLevels"
|
|
123
|
-
:key="heading"
|
|
124
|
-
:selected="activeHeadingLevel === heading"
|
|
125
|
-
@click="handleToolbarClick('heading', heading)"
|
|
126
|
-
>
|
|
127
|
-
Heading {{ heading }}
|
|
128
|
-
</or-menu-item>
|
|
129
|
-
<or-menu-item
|
|
130
|
-
:selected="!activeHeadingLevel"
|
|
131
|
-
@click="handleToolbarClick('heading')"
|
|
132
|
-
>
|
|
133
|
-
None
|
|
134
|
-
</or-menu-item>
|
|
135
|
-
</or-menu>
|
|
136
67
|
<or-modal
|
|
137
68
|
:is-open="isOpenLinkModal"
|
|
138
69
|
size="s"
|
|
@@ -184,24 +115,19 @@ import { UseFocusTrapReturn, useFocusTrap } from '@vueuse/integrations/useFocusT
|
|
|
184
115
|
import { ComponentPublicInstance, PropType, computed, defineComponent, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue-demi';
|
|
185
116
|
import { deserialize, serialize } from './utils/markdown';
|
|
186
117
|
|
|
118
|
+
import EditorToolbar from './partials/EditorToolbar.vue';
|
|
119
|
+
|
|
187
120
|
import { OrButtonV3 as OrButton } from '../or-button-v3';
|
|
188
|
-
import { OrIconButtonV3 as OrIconButton } from '../or-icon-button-v3';
|
|
189
121
|
import { OrInputV3 as OrInput } from '../or-input-v3';
|
|
190
|
-
import { OrLabelV3 as OrLabel } from '../or-label-v3';
|
|
191
|
-
import { OrMenuItemV3 as OrMenuItem } from '../or-menu-item-v3';
|
|
192
|
-
import { OrMenuV3 as OrMenu } from '../or-menu-v3';
|
|
193
122
|
import { OrModalV3 as OrModal } from '../or-modal-v3';
|
|
194
|
-
import { OrPopoverV3 as OrPopover } from '../or-popover-v3';
|
|
195
123
|
import { OrHintV3 as OrHint } from '../or-hint-v3';
|
|
196
124
|
import { OrErrorV3 as OrError } from '../or-error-v3';
|
|
125
|
+
import { OrLabelV3 as OrLabel } from '../or-label-v3';
|
|
197
126
|
import {
|
|
198
127
|
OrRichTextEditor,
|
|
199
128
|
EditorContainer,
|
|
129
|
+
EditorContainerFocus,
|
|
200
130
|
EditorInput,
|
|
201
|
-
Toolbar,
|
|
202
|
-
ToolbarButton,
|
|
203
|
-
ToolbarButtonFocused,
|
|
204
|
-
ToolbarContainer,
|
|
205
131
|
} from './styles';
|
|
206
132
|
|
|
207
133
|
import { Formats, Tools } from './props';
|
|
@@ -224,16 +150,13 @@ export default defineComponent({
|
|
|
224
150
|
name: 'OrRichTextEditor',
|
|
225
151
|
|
|
226
152
|
components: {
|
|
227
|
-
OrIconButton,
|
|
228
|
-
OrLabel,
|
|
229
|
-
OrMenuItem,
|
|
230
|
-
OrMenu,
|
|
231
153
|
OrModal,
|
|
232
154
|
OrInput,
|
|
233
155
|
OrButton,
|
|
234
|
-
OrPopover,
|
|
235
156
|
OrHint,
|
|
236
157
|
OrError,
|
|
158
|
+
OrLabel,
|
|
159
|
+
EditorToolbar,
|
|
237
160
|
},
|
|
238
161
|
|
|
239
162
|
model: {
|
|
@@ -291,6 +214,11 @@ export default defineComponent({
|
|
|
291
214
|
type: [String, Boolean],
|
|
292
215
|
default: undefined,
|
|
293
216
|
},
|
|
217
|
+
|
|
218
|
+
readonly: {
|
|
219
|
+
type: Boolean,
|
|
220
|
+
default: false,
|
|
221
|
+
},
|
|
294
222
|
},
|
|
295
223
|
|
|
296
224
|
emits: [
|
|
@@ -312,12 +240,7 @@ export default defineComponent({
|
|
|
312
240
|
const editorRef = ref<HTMLDivElement>();
|
|
313
241
|
const textareaRef = ref<HTMLTextAreaElement>();
|
|
314
242
|
const containerRef = ref<ComponentPublicInstance<HTMLInputElement>>();
|
|
315
|
-
const
|
|
316
|
-
const moreButtonRef = ref<InstanceType<typeof OrIconButton>>();
|
|
317
|
-
const moreRef = ref<InstanceType<typeof OrPopover>>();
|
|
318
|
-
const toolbarButtonRef = ref<InstanceType<typeof OrIconButton>>();
|
|
319
|
-
const menuRef = ref<InstanceType<typeof OrMenu>>();
|
|
320
|
-
|
|
243
|
+
const toolbarContainerRef = ref<ComponentPublicInstance<HTMLInputElement>>();
|
|
321
244
|
|
|
322
245
|
// isActive should be set with default values for all toolbar buttons, otherwise it will not work in vue2
|
|
323
246
|
const isActive = ref<{[key: string]: boolean;}>({
|
|
@@ -336,7 +259,7 @@ export default defineComponent({
|
|
|
336
259
|
file: false,
|
|
337
260
|
source: false,
|
|
338
261
|
});
|
|
339
|
-
const isFocused = ref<boolean>(props.autofocus);
|
|
262
|
+
const isFocused = ref<boolean>(!props.readonly ? props.autofocus : false);
|
|
340
263
|
const headingLevels = [1, 2, 3, 4] as Level[];
|
|
341
264
|
const activeHeadingLevel = ref<number>(0);
|
|
342
265
|
const markdownOutput = ref<string>('');
|
|
@@ -353,48 +276,18 @@ export default defineComponent({
|
|
|
353
276
|
allowOutsideClick: true,
|
|
354
277
|
});
|
|
355
278
|
|
|
356
|
-
const iconsEnum = ref<{[key: string]: string;}>({
|
|
357
|
-
bold: 'format_bold',
|
|
358
|
-
italic: 'format_italic',
|
|
359
|
-
underline: 'format_underlined',
|
|
360
|
-
strike: 'format_strikethrough',
|
|
361
|
-
bulletList: 'format_list_bulleted',
|
|
362
|
-
orderedList: 'format_list_numbered',
|
|
363
|
-
link: 'link',
|
|
364
|
-
highlight: 'highlight',
|
|
365
|
-
redo: 'redo',
|
|
366
|
-
undo: 'undo',
|
|
367
|
-
codeBlock: 'code_blocks',
|
|
368
|
-
blockquote: 'format_quote',
|
|
369
|
-
file: 'attach_file',
|
|
370
|
-
source: 'source_notes',
|
|
371
|
-
});
|
|
372
|
-
const iconTooltipsEnum = ref<{[key: string]: string;}>({
|
|
373
|
-
bold: 'Bold',
|
|
374
|
-
italic: 'Italic',
|
|
375
|
-
underline: 'Underline',
|
|
376
|
-
strike: 'Strike',
|
|
377
|
-
bulletList: 'Bulleted List',
|
|
378
|
-
orderedList: 'Numbered List',
|
|
379
|
-
link: 'Link',
|
|
380
|
-
highlight: 'Highlight',
|
|
381
|
-
redo: 'Redo',
|
|
382
|
-
undo: 'Undo',
|
|
383
|
-
codeBlock: 'Code Block',
|
|
384
|
-
blockquote: 'Quote',
|
|
385
|
-
file: 'File',
|
|
386
|
-
source: 'Source',
|
|
387
|
-
});
|
|
388
|
-
|
|
389
279
|
useResizeObserver(root, useDebounceFn((entries) => {
|
|
390
280
|
const entry = entries[0];
|
|
391
281
|
const { width } = entry.contentRect;
|
|
392
|
-
|
|
282
|
+
const toolbarLength = props.toolbar.flat().length;
|
|
283
|
+
|
|
284
|
+
if (containerRef.value && toolbarContainerRef.value && toolbarLength) {
|
|
393
285
|
let lengthOfItem = 0;
|
|
394
|
-
|
|
286
|
+
const toolbarRef = toolbarContainerRef.value.$refs.toolbarRef as HTMLDivElement;
|
|
287
|
+
lengthOfItem = (toolbarRef?.firstElementChild?.firstElementChild as HTMLDivElement)?.offsetWidth + 16;
|
|
395
288
|
|
|
396
289
|
const count = (width / lengthOfItem) - 2;
|
|
397
|
-
countOfNotVisibleTools.value = Math.round(toolbarLength
|
|
290
|
+
countOfNotVisibleTools.value = Math.round(toolbarLength - count);
|
|
398
291
|
}
|
|
399
292
|
}, 10));
|
|
400
293
|
|
|
@@ -421,7 +314,8 @@ export default defineComponent({
|
|
|
421
314
|
}
|
|
422
315
|
},
|
|
423
316
|
element: editorRef.value,
|
|
424
|
-
autofocus: props.autofocus,
|
|
317
|
+
autofocus: !props.readonly ? props.autofocus : false,
|
|
318
|
+
editable: !props.readonly,
|
|
425
319
|
enableInputRules: true,
|
|
426
320
|
enablePasteRules: true,
|
|
427
321
|
extensions: [
|
|
@@ -518,47 +412,14 @@ export default defineComponent({
|
|
|
518
412
|
},
|
|
519
413
|
});
|
|
520
414
|
|
|
521
|
-
const getIndexOfHeading = computed(() => {
|
|
522
|
-
return props.toolbar.flat().indexOf('heading');
|
|
523
|
-
});
|
|
524
|
-
|
|
525
|
-
const headingIcon = computed(() => {
|
|
526
|
-
if (activeHeadingLevel.value && isActive.value.heading) {
|
|
527
|
-
return `format_h${activeHeadingLevel.value}`;
|
|
528
|
-
}
|
|
529
|
-
return 'format_paragraph';
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
const toolbarLength = computed(() => {
|
|
533
|
-
return props.toolbar.flat().length;
|
|
534
|
-
});
|
|
535
|
-
|
|
536
|
-
const notVisibleTools = computed((): Set<string> => {
|
|
537
|
-
const count = countOfNotVisibleTools.value;
|
|
538
|
-
const toolbar = props.toolbar.flat();
|
|
539
|
-
let notVisible = new Set(toolbar.slice(toolbar.length - count, toolbar.length));
|
|
540
|
-
props.toolbar.forEach(tools => {
|
|
541
|
-
if (tools.some(item => notVisible.has(item))) {
|
|
542
|
-
tools.forEach(item => notVisible.add(item));
|
|
543
|
-
}
|
|
544
|
-
});
|
|
545
|
-
return notVisible;
|
|
546
|
-
});
|
|
547
|
-
|
|
548
415
|
//Methods
|
|
549
416
|
const handleEditorClick = () => {
|
|
550
417
|
setActiveFormats();
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
};
|
|
555
|
-
|
|
556
|
-
const isVisible = (value: string | Array<string>) => {
|
|
557
|
-
if (Array.isArray(value)) {
|
|
558
|
-
const isHaveNotVisibleTools = value.some(item => notVisibleTools.value.has(item));
|
|
559
|
-
return isHaveNotVisibleTools;
|
|
418
|
+
if (!props.readonly) {
|
|
419
|
+
isFocused.value = true;
|
|
420
|
+
editor?.commands.focus();
|
|
560
421
|
}
|
|
561
|
-
|
|
422
|
+
activeHeadingLevel.value = editor?.getAttributes('heading')?.level || 0;
|
|
562
423
|
};
|
|
563
424
|
|
|
564
425
|
const handleInput = (event: InputEvent) => {
|
|
@@ -569,7 +430,7 @@ export default defineComponent({
|
|
|
569
430
|
proxyModelValue.value = markdownOutput.value;
|
|
570
431
|
};
|
|
571
432
|
|
|
572
|
-
const handleToolbarClick = (item: string
|
|
433
|
+
const handleToolbarClick = ({ item, level }: {item: string; level?: number;}) => {
|
|
573
434
|
switch (item) {
|
|
574
435
|
case 'source':
|
|
575
436
|
disableMarkdown.value = !disableMarkdown.value;
|
|
@@ -701,16 +562,7 @@ export default defineComponent({
|
|
|
701
562
|
|
|
702
563
|
const containerStyles = computed(() => [
|
|
703
564
|
...EditorContainer,
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
const toolbarContainerStyles = computed(() => [
|
|
707
|
-
...ToolbarContainer,
|
|
708
|
-
]);
|
|
709
|
-
|
|
710
|
-
const toolbarStyles = computed(() => [
|
|
711
|
-
...Toolbar,
|
|
712
|
-
// 'overflow-x-hidden',
|
|
713
|
-
...isFocused.value ? ToolbarButtonFocused : ToolbarButton,
|
|
565
|
+
...isFocused.value ? EditorContainerFocus : [],
|
|
714
566
|
]);
|
|
715
567
|
|
|
716
568
|
const editorInputStyles = computed(() => [
|
|
@@ -724,44 +576,37 @@ export default defineComponent({
|
|
|
724
576
|
editor?.commands.setContent(value as string);
|
|
725
577
|
}
|
|
726
578
|
if (props.format === 'markdown' && value !== markdownOutput.value) {
|
|
727
|
-
|
|
728
|
-
editor?.commands.setContent(
|
|
579
|
+
const deserialized = deserialize(editor?.schema, value);
|
|
580
|
+
editor?.commands.setContent(deserialized as string);
|
|
729
581
|
}
|
|
730
582
|
});
|
|
731
583
|
|
|
584
|
+
watch(props, ({ readonly }) => {
|
|
585
|
+
isFocused.value = !readonly;
|
|
586
|
+
editor?.setEditable(!readonly);
|
|
587
|
+
});
|
|
588
|
+
|
|
732
589
|
return {
|
|
733
590
|
editor,
|
|
734
591
|
editorRef,
|
|
735
|
-
|
|
592
|
+
toolbarContainerRef,
|
|
736
593
|
containerRef,
|
|
737
|
-
toolbarButtonRef,
|
|
738
|
-
moreButtonRef,
|
|
739
594
|
textareaRef,
|
|
740
|
-
moreRef,
|
|
741
|
-
menuRef,
|
|
742
|
-
iconsEnum,
|
|
743
595
|
handleToolbarClick,
|
|
744
596
|
handleEditorClick,
|
|
745
597
|
isActive,
|
|
746
|
-
iconTooltipsEnum,
|
|
747
598
|
containerStyles,
|
|
748
|
-
toolbarContainerStyles,
|
|
749
|
-
toolbarStyles,
|
|
750
599
|
rootStyles,
|
|
751
600
|
root,
|
|
752
601
|
editorInputStyles,
|
|
753
|
-
getIndexOfHeading,
|
|
754
602
|
headingLevels,
|
|
755
|
-
headingIcon,
|
|
756
603
|
attachLink,
|
|
757
604
|
discardLink,
|
|
758
605
|
isOpenLinkModal,
|
|
759
606
|
text,
|
|
760
607
|
link,
|
|
761
608
|
isFocused,
|
|
762
|
-
isVisible,
|
|
763
609
|
countOfNotVisibleTools,
|
|
764
|
-
notVisibleTools,
|
|
765
610
|
handleInput,
|
|
766
611
|
proxyModelValue,
|
|
767
612
|
disableMarkdown,
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
ref="toolbarRef"
|
|
4
|
+
:class="toolbarContainerStyles"
|
|
5
|
+
>
|
|
6
|
+
<div
|
|
7
|
+
v-for="(tools, index) in toolbar"
|
|
8
|
+
:key="index"
|
|
9
|
+
:class="[...toolbarStyles, { 'hidden': isVisible(tools)}]"
|
|
10
|
+
>
|
|
11
|
+
<div
|
|
12
|
+
v-for="item in tools"
|
|
13
|
+
:key="item"
|
|
14
|
+
:class="['flex gap-md', { 'hidden': !isVisible(item)}]"
|
|
15
|
+
>
|
|
16
|
+
<or-icon-button
|
|
17
|
+
v-if="item==='heading'"
|
|
18
|
+
ref="toolbarButtonRef"
|
|
19
|
+
:selected="isActive[item]"
|
|
20
|
+
:disabled="!isFocused"
|
|
21
|
+
:tooltip="{content: item, placement: 'top'}"
|
|
22
|
+
:icon="{icon: headingIcon, variant: 'inherit'}"
|
|
23
|
+
@click="menuRef && menuRef.toggle()"
|
|
24
|
+
/>
|
|
25
|
+
<or-icon-button
|
|
26
|
+
v-else-if="isVisible(item)"
|
|
27
|
+
:tooltip="{content: iconTooltipsEnum[item], placement: 'top'}"
|
|
28
|
+
:selected="isActive[item]"
|
|
29
|
+
:disabled="!isFocused"
|
|
30
|
+
:icon="{icon: iconsEnum[item], variant: 'inherit'}"
|
|
31
|
+
@click="handleClick(item)"
|
|
32
|
+
/>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<or-icon-button
|
|
36
|
+
v-if="countOfNotVisibleTools > 0"
|
|
37
|
+
ref="moreButtonRef"
|
|
38
|
+
:disabled="!isFocused"
|
|
39
|
+
:icon="{icon: 'more_horiz', variant: 'inherit'}"
|
|
40
|
+
class="px-sm"
|
|
41
|
+
@click="moreRef && moreRef.open()"
|
|
42
|
+
/>
|
|
43
|
+
<or-popover
|
|
44
|
+
v-if="moreButtonRef"
|
|
45
|
+
ref="moreRef"
|
|
46
|
+
:trigger="moreButtonRef && moreButtonRef.root"
|
|
47
|
+
placement="top-end"
|
|
48
|
+
>
|
|
49
|
+
<div class="flex p-sm gap-md">
|
|
50
|
+
<or-icon-button
|
|
51
|
+
v-for="item in notVisibleTools"
|
|
52
|
+
:key="item"
|
|
53
|
+
:tooltip="{content: iconTooltipsEnum[item], placement: 'top'}"
|
|
54
|
+
:selected="isActive[item]"
|
|
55
|
+
:icon="{icon: iconsEnum[item], variant: 'inherit'}"
|
|
56
|
+
@click="handleClick(item)"
|
|
57
|
+
/>
|
|
58
|
+
</div>
|
|
59
|
+
</or-popover>
|
|
60
|
+
<or-menu
|
|
61
|
+
v-if="toolbarButtonRef"
|
|
62
|
+
ref="menuRef"
|
|
63
|
+
:trigger="toolbarButtonRef[getIndexOfHeading] && toolbarButtonRef[getIndexOfHeading].root"
|
|
64
|
+
placement="bottom-start"
|
|
65
|
+
>
|
|
66
|
+
<or-menu-item
|
|
67
|
+
v-for="heading in headingLevels"
|
|
68
|
+
:key="heading"
|
|
69
|
+
:selected="activeHeadingLevel === heading"
|
|
70
|
+
@click="handleClick('heading', heading)"
|
|
71
|
+
>
|
|
72
|
+
Heading {{ heading }}
|
|
73
|
+
</or-menu-item>
|
|
74
|
+
<or-menu-item
|
|
75
|
+
:selected="!activeHeadingLevel"
|
|
76
|
+
@click="handleClick('heading')"
|
|
77
|
+
>
|
|
78
|
+
None
|
|
79
|
+
</or-menu-item>
|
|
80
|
+
</or-menu>
|
|
81
|
+
</div>
|
|
82
|
+
</template>
|
|
83
|
+
|
|
84
|
+
<script lang="ts">
|
|
85
|
+
import { defineComponent, ref, computed, PropType, ComponentPublicInstance } from 'vue-demi';
|
|
86
|
+
import { ToolbarContainer, ToolbarButtonFocused, ToolbarButton, Toolbar } from '../styles';
|
|
87
|
+
import { OrIconButtonV3 as OrIconButton } from '../../or-icon-button-v3';
|
|
88
|
+
import { OrMenuItemV3 as OrMenuItem } from '../../or-menu-item-v3';
|
|
89
|
+
import { OrMenuV3 as OrMenu } from '../../or-menu-v3';
|
|
90
|
+
import { OrPopoverV3 as OrPopover } from '../../or-popover-v3';
|
|
91
|
+
import { Level } from '@tiptap/extension-heading';
|
|
92
|
+
|
|
93
|
+
import { Tools } from '../props';
|
|
94
|
+
|
|
95
|
+
export default defineComponent({
|
|
96
|
+
components: {
|
|
97
|
+
OrIconButton,
|
|
98
|
+
OrMenuItem,
|
|
99
|
+
OrMenu,
|
|
100
|
+
OrPopover,
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
props: {
|
|
104
|
+
toolbar: {
|
|
105
|
+
type: Array as PropType<Tools>,
|
|
106
|
+
default: () => [],
|
|
107
|
+
},
|
|
108
|
+
isFocused: {
|
|
109
|
+
type: Boolean,
|
|
110
|
+
default: false,
|
|
111
|
+
},
|
|
112
|
+
countOfNotVisibleTools: {
|
|
113
|
+
type: Number,
|
|
114
|
+
default: 0,
|
|
115
|
+
},
|
|
116
|
+
activeHeadingLevel: {
|
|
117
|
+
type: Number,
|
|
118
|
+
default: 0,
|
|
119
|
+
},
|
|
120
|
+
isActive: {
|
|
121
|
+
type: Object as PropType<{ [key: string]: boolean; }>,
|
|
122
|
+
default: () => ({}),
|
|
123
|
+
},
|
|
124
|
+
headingLevels: {
|
|
125
|
+
type: Array as PropType<Level[]>,
|
|
126
|
+
default: () => [1, 2, 3, 4],
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
emits: ['click-tool'],
|
|
131
|
+
|
|
132
|
+
setup(props, { emit }) {
|
|
133
|
+
const toolbarRef = ref<ComponentPublicInstance<HTMLInputElement>>();
|
|
134
|
+
const moreButtonRef = ref<InstanceType<typeof OrIconButton>>();
|
|
135
|
+
const moreRef = ref<InstanceType<typeof OrPopover>>();
|
|
136
|
+
const toolbarButtonRef = ref<InstanceType<typeof OrIconButton>>();
|
|
137
|
+
const menuRef = ref<InstanceType<typeof OrMenu>>();
|
|
138
|
+
|
|
139
|
+
const iconsEnum = ref<{[key: string]: string;}>({
|
|
140
|
+
bold: 'format_bold',
|
|
141
|
+
italic: 'format_italic',
|
|
142
|
+
underline: 'format_underlined',
|
|
143
|
+
strike: 'format_strikethrough',
|
|
144
|
+
bulletList: 'format_list_bulleted',
|
|
145
|
+
orderedList: 'format_list_numbered',
|
|
146
|
+
link: 'link',
|
|
147
|
+
highlight: 'highlight',
|
|
148
|
+
redo: 'redo',
|
|
149
|
+
undo: 'undo',
|
|
150
|
+
codeBlock: 'code_blocks',
|
|
151
|
+
blockquote: 'format_quote',
|
|
152
|
+
file: 'attach_file',
|
|
153
|
+
source: 'source_notes',
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const iconTooltipsEnum = ref<{[key: string]: string;}>({
|
|
157
|
+
bold: 'Bold',
|
|
158
|
+
italic: 'Italic',
|
|
159
|
+
underline: 'Underline',
|
|
160
|
+
strike: 'Strike',
|
|
161
|
+
bulletList: 'Bulleted List',
|
|
162
|
+
orderedList: 'Numbered List',
|
|
163
|
+
link: 'Link',
|
|
164
|
+
highlight: 'Highlight',
|
|
165
|
+
redo: 'Redo',
|
|
166
|
+
undo: 'Undo',
|
|
167
|
+
codeBlock: 'Code Block',
|
|
168
|
+
blockquote: 'Quote',
|
|
169
|
+
file: 'File',
|
|
170
|
+
source: 'Source',
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const notVisibleTools = computed((): Set<string> => {
|
|
174
|
+
const count = props.countOfNotVisibleTools;
|
|
175
|
+
const toolbar = props.toolbar.flat();
|
|
176
|
+
let notVisible = new Set(toolbar.slice(toolbar.length - count, toolbar.length));
|
|
177
|
+
props.toolbar.forEach(tools => {
|
|
178
|
+
if (tools.some(item => notVisible.has(item))) {
|
|
179
|
+
tools.forEach(item => notVisible.add(item));
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
return notVisible;
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const toolbarContainerStyles = computed(() => [
|
|
186
|
+
...ToolbarContainer,
|
|
187
|
+
]);
|
|
188
|
+
|
|
189
|
+
const toolbarStyles = computed(() => [
|
|
190
|
+
...Toolbar,
|
|
191
|
+
...props.isFocused ? ToolbarButtonFocused : ToolbarButton,
|
|
192
|
+
]);
|
|
193
|
+
|
|
194
|
+
const getIndexOfHeading = computed(() => {
|
|
195
|
+
return props.toolbar.flat().indexOf('heading');
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const headingIcon = computed(() => {
|
|
199
|
+
if (props.activeHeadingLevel && props.isActive.heading) {
|
|
200
|
+
return `format_h${props.activeHeadingLevel}`;
|
|
201
|
+
}
|
|
202
|
+
return 'format_paragraph';
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const isVisible = (value: string | Array<string>) => {
|
|
206
|
+
if (Array.isArray(value)) {
|
|
207
|
+
const isHaveNotVisibleTools = value.some(item => notVisibleTools.value.has(item));
|
|
208
|
+
return isHaveNotVisibleTools;
|
|
209
|
+
}
|
|
210
|
+
return !notVisibleTools.value.has(value);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const handleClick = (item: string, level?: number) => {
|
|
214
|
+
emit('click-tool', {
|
|
215
|
+
item,
|
|
216
|
+
level,
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
toolbarRef,
|
|
222
|
+
moreButtonRef,
|
|
223
|
+
moreRef,
|
|
224
|
+
toolbarButtonRef,
|
|
225
|
+
menuRef,
|
|
226
|
+
toolbarContainerStyles,
|
|
227
|
+
toolbarStyles,
|
|
228
|
+
isVisible,
|
|
229
|
+
handleClick,
|
|
230
|
+
headingIcon,
|
|
231
|
+
getIndexOfHeading,
|
|
232
|
+
notVisibleTools,
|
|
233
|
+
iconsEnum,
|
|
234
|
+
iconTooltipsEnum,
|
|
235
|
+
};
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
</script>
|
|
@@ -7,22 +7,13 @@ export const OrRichTextEditor: string[] = [
|
|
|
7
7
|
|
|
8
8
|
// Box
|
|
9
9
|
'max-h-full',
|
|
10
|
+
'w-full',
|
|
10
11
|
];
|
|
11
12
|
|
|
12
13
|
export const EditorContainer: string[] = [
|
|
13
14
|
// Layout
|
|
14
15
|
'layout-column',
|
|
15
16
|
|
|
16
|
-
// Theme (focus)
|
|
17
|
-
'focus-within:theme-background-primary-translucent-1',
|
|
18
|
-
'dark:focus-within:theme-background-primary-translucent-1-dark',
|
|
19
|
-
|
|
20
|
-
'focus-within:theme-border-1-primary',
|
|
21
|
-
'dark:focus-within:theme-border-1-primary-dark',
|
|
22
|
-
|
|
23
|
-
'focus-within:theme-outline-2-primary',
|
|
24
|
-
'dark:focus-within:theme-outline-2-primary-dark',
|
|
25
|
-
|
|
26
17
|
// Theme (invalid)
|
|
27
18
|
'invalid:theme-background-error-translucent-1',
|
|
28
19
|
'dark:invalid:theme-background-error-translucent-1-dark',
|
|
@@ -44,6 +35,18 @@ export const EditorContainer: string[] = [
|
|
|
44
35
|
'grow',
|
|
45
36
|
];
|
|
46
37
|
|
|
38
|
+
export const EditorContainerFocus: string[] = [
|
|
39
|
+
// Theme (focus)
|
|
40
|
+
'focus-within:theme-background-primary-translucent-1',
|
|
41
|
+
'dark:focus-within:theme-background-primary-translucent-1-dark',
|
|
42
|
+
|
|
43
|
+
'focus-within:theme-border-1-primary',
|
|
44
|
+
'dark:focus-within:theme-border-1-primary-dark',
|
|
45
|
+
|
|
46
|
+
'focus-within:theme-outline-2-primary',
|
|
47
|
+
'dark:focus-within:theme-outline-2-primary-dark',
|
|
48
|
+
];
|
|
49
|
+
|
|
47
50
|
export const ToolbarContainer: string[] = [
|
|
48
51
|
// Layout
|
|
49
52
|
'layout-row',
|