@onereach/ui-components 4.0.2 → 4.1.0-beta.2508.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.
Files changed (106) hide show
  1. package/dist/bundled/v2/components/OrCode/OrCode.js +6 -3727
  2. package/dist/bundled/v2/components/OrCode/index.js +6 -2
  3. package/dist/bundled/v2/components/OrCode/lang.js +3898 -3
  4. package/dist/bundled/v2/components/OrCode/theme.js +3 -1
  5. package/dist/bundled/v2/components/OrRichTextEditorV3/OrRichTextEditor.js +2033 -0
  6. package/dist/bundled/v2/components/OrRichTextEditorV3/OrRichTextEditor.vue.d.ts +181 -0
  7. package/dist/bundled/v2/components/OrRichTextEditorV3/index.d.ts +1 -0
  8. package/dist/bundled/v2/components/OrRichTextEditorV3/index.js +67 -0
  9. package/dist/bundled/v2/components/OrRichTextEditorV3/styles.d.ts +7 -0
  10. package/dist/bundled/v2/components/OrRichTextEditorV3/styles.js +43 -0
  11. package/dist/bundled/v2/components/OrRichTextEditorV3/utils/codemirror/codemirrorNode.d.ts +3 -0
  12. package/dist/bundled/v2/components/OrRichTextEditorV3/utils/codemirror/codemirrorNode.js +45 -0
  13. package/dist/bundled/v2/components/OrRichTextEditorV3/utils/codemirror/codemirrorView.d.ts +27 -0
  14. package/dist/bundled/v2/components/OrRichTextEditorV3/utils/codemirror/codemirrorView.js +183 -0
  15. package/dist/bundled/v2/components/OrRichTextEditorV3/utils/codemirror/index.d.ts +1 -0
  16. package/dist/bundled/v2/components/OrRichTextEditorV3/utils/codemirror/index.js +4 -0
  17. package/dist/bundled/v2/components/OrRichTextEditorV3/utils/codemirror/types.d.ts +19 -0
  18. package/dist/bundled/v2/components/OrRichTextEditorV3/utils/codemirror/types.js +1 -0
  19. package/dist/bundled/v2/components/OrRichTextEditorV3/utils/markdown.d.ts +3 -0
  20. package/dist/bundled/v2/components/OrRichTextEditorV3/utils/markdown.js +5 -0
  21. package/dist/bundled/v2/components/index.d.ts +1 -0
  22. package/dist/bundled/v2/components/index.js +14 -2
  23. package/dist/bundled/v2/index-62c3221b.js +6956 -0
  24. package/dist/bundled/v2/index-62e39ec2.js +4534 -0
  25. package/dist/bundled/{v3/OrCode.vue_vue_type_script_lang-c5a9adb7.js → v2/index-92e69736.js} +15 -234
  26. package/dist/bundled/v2/{index-6976c52a.js → index-c76372bb.js} +16 -4659
  27. package/dist/bundled/{v3/lang-02d2bb2d.js → v2/index-db5e8c99.js} +74 -3965
  28. package/dist/bundled/v2/index.es-3f39f316.js +115 -0
  29. package/dist/bundled/v2/index.js +17 -5
  30. package/dist/bundled/v2/markdown-00716a39.js +18683 -0
  31. package/dist/bundled/v2/tiptap-core.esm-f85402b1.js +9360 -0
  32. package/dist/bundled/v3/OrCode.vue_vue_type_script_lang-0c5e41b0.js +236 -0
  33. package/dist/bundled/v3/OrRichTextEditor.vue_vue_type_script_lang-33b56bd6.js +1815 -0
  34. package/dist/bundled/v3/components/OrCode/OrCode.js +9 -5
  35. package/dist/bundled/v3/components/OrCode/index.js +7 -3
  36. package/dist/bundled/v3/components/OrCode/lang.js +3898 -3
  37. package/dist/bundled/v3/components/OrCode/theme.js +3 -1
  38. package/dist/bundled/v3/components/OrRichTextEditorV3/OrRichTextEditor.js +219 -0
  39. package/dist/bundled/v3/components/OrRichTextEditorV3/OrRichTextEditor.vue.d.ts +181 -0
  40. package/dist/bundled/v3/components/OrRichTextEditorV3/index.d.ts +1 -0
  41. package/dist/bundled/v3/components/OrRichTextEditorV3/index.js +83 -0
  42. package/dist/bundled/v3/components/OrRichTextEditorV3/styles.d.ts +7 -0
  43. package/dist/bundled/v3/components/OrRichTextEditorV3/styles.js +43 -0
  44. package/dist/bundled/v3/components/OrRichTextEditorV3/utils/codemirror/codemirrorNode.d.ts +3 -0
  45. package/dist/bundled/v3/components/OrRichTextEditorV3/utils/codemirror/codemirrorNode.js +45 -0
  46. package/dist/bundled/v3/components/OrRichTextEditorV3/utils/codemirror/codemirrorView.d.ts +27 -0
  47. package/dist/bundled/v3/components/OrRichTextEditorV3/utils/codemirror/codemirrorView.js +183 -0
  48. package/dist/bundled/v3/components/OrRichTextEditorV3/utils/codemirror/index.d.ts +1 -0
  49. package/dist/bundled/v3/components/OrRichTextEditorV3/utils/codemirror/index.js +4 -0
  50. package/dist/bundled/v3/components/OrRichTextEditorV3/utils/codemirror/types.d.ts +19 -0
  51. package/dist/bundled/v3/components/OrRichTextEditorV3/utils/codemirror/types.js +1 -0
  52. package/dist/bundled/v3/components/OrRichTextEditorV3/utils/markdown.d.ts +3 -0
  53. package/dist/bundled/v3/components/OrRichTextEditorV3/utils/markdown.js +5 -0
  54. package/dist/bundled/v3/components/index.d.ts +1 -0
  55. package/dist/bundled/v3/components/index.js +16 -3
  56. package/dist/bundled/v3/index-62c3221b.js +6956 -0
  57. package/dist/bundled/v3/index-62e39ec2.js +4534 -0
  58. package/dist/bundled/v3/index-92e69736.js +3741 -0
  59. package/dist/bundled/v3/{index-6976c52a.js → index-c76372bb.js} +16 -4659
  60. package/dist/bundled/{v2/lang-02d2bb2d.js → v3/index-db5e8c99.js} +74 -3965
  61. package/dist/bundled/v3/index.es-3f39f316.js +115 -0
  62. package/dist/bundled/v3/index.js +20 -7
  63. package/dist/bundled/v3/markdown-00716a39.js +18683 -0
  64. package/dist/bundled/v3/tiptap-core.esm-f85402b1.js +9360 -0
  65. package/dist/esm/v2/OrRichTextEditor-45fb1867.js +718 -0
  66. package/dist/esm/v2/codemirrorView-2e87c938.js +184 -0
  67. package/dist/esm/v2/components/index.d.ts +1 -0
  68. package/dist/esm/v2/components/index.js +24 -0
  69. package/dist/esm/v2/components/or-rich-text-editor-v3/OrRichTextEditor.vue.d.ts +181 -0
  70. package/dist/esm/v2/components/or-rich-text-editor-v3/index.d.ts +1 -0
  71. package/dist/esm/v2/components/or-rich-text-editor-v3/index.js +56 -0
  72. package/dist/esm/v2/components/or-rich-text-editor-v3/styles.d.ts +7 -0
  73. package/dist/esm/v2/components/or-rich-text-editor-v3/utils/codemirror/codemirrorNode.d.ts +3 -0
  74. package/dist/esm/v2/components/or-rich-text-editor-v3/utils/codemirror/codemirrorView.d.ts +27 -0
  75. package/dist/esm/v2/components/or-rich-text-editor-v3/utils/codemirror/index.d.ts +1 -0
  76. package/dist/esm/v2/components/or-rich-text-editor-v3/utils/codemirror/index.js +5 -0
  77. package/dist/esm/v2/components/or-rich-text-editor-v3/utils/codemirror/types.d.ts +19 -0
  78. package/dist/esm/v2/components/or-rich-text-editor-v3/utils/markdown.d.ts +3 -0
  79. package/dist/esm/v2/index.js +24 -0
  80. package/dist/esm/v3/OrRichTextEditor-4c0b6030.js +680 -0
  81. package/dist/esm/v3/codemirrorView-2e87c938.js +184 -0
  82. package/dist/esm/v3/components/index.d.ts +1 -0
  83. package/dist/esm/v3/components/index.js +24 -0
  84. package/dist/esm/v3/components/or-rich-text-editor-v3/OrRichTextEditor.vue.d.ts +181 -0
  85. package/dist/esm/v3/components/or-rich-text-editor-v3/index.d.ts +1 -0
  86. package/dist/esm/v3/components/or-rich-text-editor-v3/index.js +54 -0
  87. package/dist/esm/v3/components/or-rich-text-editor-v3/styles.d.ts +7 -0
  88. package/dist/esm/v3/components/or-rich-text-editor-v3/utils/codemirror/codemirrorNode.d.ts +3 -0
  89. package/dist/esm/v3/components/or-rich-text-editor-v3/utils/codemirror/codemirrorView.d.ts +27 -0
  90. package/dist/esm/v3/components/or-rich-text-editor-v3/utils/codemirror/index.d.ts +1 -0
  91. package/dist/esm/v3/components/or-rich-text-editor-v3/utils/codemirror/index.js +5 -0
  92. package/dist/esm/v3/components/or-rich-text-editor-v3/utils/codemirror/types.d.ts +19 -0
  93. package/dist/esm/v3/components/or-rich-text-editor-v3/utils/markdown.d.ts +3 -0
  94. package/dist/esm/v3/index.js +24 -0
  95. package/package.json +25 -5
  96. package/src/components/index.ts +1 -0
  97. package/src/components/or-rich-text-editor-v3/OrRichTextEditor.docs.mdx +7 -0
  98. package/src/components/or-rich-text-editor-v3/OrRichTextEditor.stories3.ts +79 -0
  99. package/src/components/or-rich-text-editor-v3/OrRichTextEditor.vue +622 -0
  100. package/src/components/or-rich-text-editor-v3/index.ts +1 -0
  101. package/src/components/or-rich-text-editor-v3/styles.ts +72 -0
  102. package/src/components/or-rich-text-editor-v3/utils/codemirror/codemirrorNode.ts +40 -0
  103. package/src/components/or-rich-text-editor-v3/utils/codemirror/codemirrorView.ts +252 -0
  104. package/src/components/or-rich-text-editor-v3/utils/codemirror/index.ts +1 -0
  105. package/src/components/or-rich-text-editor-v3/utils/codemirror/types.ts +22 -0
  106. package/src/components/or-rich-text-editor-v3/utils/markdown.ts +110 -0
@@ -0,0 +1,79 @@
1
+ // import { action } from '@storybook/addon-actions';
2
+ import { Meta, StoryFn } from '@storybook/vue3';
3
+ import { ref } from 'vue-demi';
4
+ import OrRichTextEditorDocs from './OrRichTextEditor.docs.mdx';
5
+ import OrRichTextEditor from './OrRichTextEditor.vue';
6
+
7
+ export default {
8
+ title: 'Experimental/OrRichTextEditor',
9
+ component: OrRichTextEditor,
10
+
11
+ argTypes: {
12
+ // Props
13
+ modelValue: {
14
+ control: { type: 'text' },
15
+ },
16
+ value: { // TODO: Remove Vue 2 fallback
17
+ table: { disable: true },
18
+ },
19
+ description: {
20
+ control: { type: 'text' },
21
+ },
22
+ placeholder: {
23
+ control: { type: 'text' },
24
+ },
25
+ markdownFormat: {
26
+ control: { type: 'boolean' },
27
+ },
28
+ fullHeight: {
29
+ control: { type: 'boolean' },
30
+ },
31
+ // Events
32
+ 'update:modelValue': {
33
+ table: { disable: true },
34
+ },
35
+
36
+ input: {
37
+ table: { disable: true },
38
+ },
39
+ },
40
+
41
+ parameters: {
42
+ docs: {
43
+ page: OrRichTextEditorDocs,
44
+ },
45
+
46
+ design: {
47
+ type: 'figma',
48
+ url: 'https://www.figma.com/file/o7DdkaznUW2PtX4wiSuhhQ/Core?node-id=608%3A2926',
49
+ },
50
+ },
51
+ } as Meta<typeof OrRichTextEditor>;
52
+
53
+ const Template: StoryFn<typeof OrRichTextEditor> = (args) => ({
54
+ components: {
55
+ OrRichTextEditor,
56
+ },
57
+
58
+ setup() {
59
+ // Refs
60
+ const model = ref<string>();
61
+
62
+ return {
63
+ args,
64
+ model,
65
+ };
66
+ },
67
+
68
+ template: `
69
+ <div class="p-lg">
70
+ <OrRichTextEditor
71
+ v-model="model"
72
+ v-bind="args"
73
+ >
74
+ </OrRichTextEditor>
75
+ </div>
76
+ `,
77
+ });
78
+
79
+ export const RichTextEditor = Template.bind({});
@@ -0,0 +1,622 @@
1
+ <template>
2
+ <div
3
+ ref="root"
4
+ :class="rootStyles"
5
+ >
6
+ <or-label>
7
+ {{ description }}
8
+ </or-label>
9
+ <div
10
+ ref="containerRef"
11
+ :class="containerStyles"
12
+ @click="handleEditorClick()"
13
+ >
14
+ <div :class="toolbarContainerStyles">
15
+ <div
16
+ v-for="(tool, index) in toolbar"
17
+ :key="index"
18
+ :class="toolbarStyles"
19
+ >
20
+ <div
21
+ v-for="item in tool"
22
+ :key="item"
23
+ :class="toolbarButtonStyles(item)"
24
+ class="-my-xs"
25
+ >
26
+ <or-icon-button
27
+ v-if="item==='heading'"
28
+ ref="toolbarButtonRef"
29
+ :tooltip="{text: item, placement: 'top'}"
30
+ :icon="{icon: headingIcon, variant: 'inherit', size: 'm'}"
31
+ @click="menuRef.open()"
32
+ />
33
+ <or-icon-button
34
+ v-else
35
+ :tooltip="{text: iconTooltipsEnum[item], placement: 'top'}"
36
+ :icon="{icon: iconsEnum[item], variant: 'inherit', size: 'm'}"
37
+ @click="handleToolbarClick(item)"
38
+ />
39
+ </div>
40
+ </div>
41
+ </div>
42
+ <div
43
+ ref="editorRef"
44
+ :class="editorInputStyles"
45
+ />
46
+ </div>
47
+ <or-menu
48
+ v-if="toolbarButtonRef"
49
+ ref="menuRef"
50
+ :trigger="toolbarButtonRef[getIndexOfHeading].root"
51
+ placement="bottom-start"
52
+ >
53
+ <or-menu-item
54
+ v-for="heading in headingLevels"
55
+ :key="heading"
56
+ @click="handleToolbarClick('heading', heading)"
57
+ >
58
+ Heading {{ heading }}
59
+ </or-menu-item>
60
+ <or-menu-item
61
+ @click="handleToolbarClick('heading')"
62
+ >
63
+ None
64
+ </or-menu-item>
65
+ </or-menu>
66
+ <or-modal
67
+ :is-open="isOpenLinkModal"
68
+ size="s"
69
+ >
70
+ <template v-slot:header>
71
+ <p class="text-headline-2">
72
+ Add Link
73
+ </p>
74
+ </template>
75
+ <div>
76
+ <or-label>
77
+ Text
78
+ </or-label>
79
+ <or-input
80
+ v-model="text"
81
+ placeholder="Placeholder"
82
+ class="pb-md"
83
+ />
84
+ <or-label>
85
+ Link
86
+ </or-label>
87
+ <or-input
88
+ v-model="link"
89
+ placeholder="Placeholder"
90
+ />
91
+ </div>
92
+ <template v-slot:footer>
93
+ <div class="flex ml-auto gap-md">
94
+ <or-button
95
+ variant="outlined"
96
+ @click="discardLink"
97
+ >
98
+ <p>Cancel</p>
99
+ </or-button>
100
+ <or-button
101
+ @click="attachLink"
102
+ >
103
+ <p>Save</p>
104
+ </or-button>
105
+ </div>
106
+ </template>
107
+ </or-modal>
108
+ </div>
109
+ </template>
110
+
111
+ <script lang="ts">
112
+ import { defineComponent, ref, computed, onBeforeUnmount, onMounted, watch } from 'vue-demi';
113
+ // import { useFocusTrap, UseFocusTrapReturn } from '@vueuse/integrations/useFocusTrap';
114
+ import { onClickOutside } from '@vueuse/core';
115
+ import { serialize, deserialize } from './utils/markdown';
116
+
117
+ import { OrIconButtonV3 as OrIconButton } from '../or-icon-button-v3';
118
+ import { OrLabelV3 as OrLabel } from '../or-label-v3';
119
+ import { OrMenuV3 as OrMenu } from '../or-menu-v3';
120
+ import { OrMenuItemV3 as OrMenuItem } from '../or-menu-item-v3';
121
+ import { OrModalV3 as OrModal } from '../or-modal-v3';
122
+ import { OrInputV3 as OrInput } from '../or-input-v3';
123
+ import { OrButtonV3 as OrButton } from '../or-button-v3';
124
+
125
+ import {
126
+ EditorContainer,
127
+ ToolbarContainer,
128
+ Toolbar,
129
+ ToolbarButtonActive,
130
+ ToolbarButtonFocused,
131
+ ToolbarButton,
132
+ EditorInput,
133
+ } from './styles';
134
+
135
+ import { Editor, mergeAttributes } from '@tiptap/core';
136
+ import StarterKit from '@tiptap/starter-kit';
137
+ import Underline from '@tiptap/extension-underline';
138
+ import Link from '@tiptap/extension-link';
139
+ import Highlight from '@tiptap/extension-highlight';
140
+ import Heading, { Level } from '@tiptap/extension-heading';
141
+ import Placeholder from '@tiptap/extension-placeholder';
142
+
143
+ import codemirrorNode from './utils/codemirror/codemirrorNode';
144
+
145
+ export default defineComponent({
146
+ name: 'OrRichTextEditor',
147
+
148
+ components: {
149
+ OrIconButton,
150
+ OrLabel,
151
+ OrMenuItem,
152
+ OrMenu,
153
+ OrModal,
154
+ OrInput,
155
+ OrButton,
156
+ },
157
+
158
+ inheritAttrs: false,
159
+
160
+ props: {
161
+ modelValue: {
162
+ type: String,
163
+ default: undefined,
164
+ },
165
+ value: { // TODO: Remove Vue 2 fallback
166
+ type: String,
167
+ default: undefined,
168
+ },
169
+ toolbar: {
170
+ type: Array,
171
+ default: () => [['heading'], ['bold', 'italic', 'strike'], ['underline', 'highlight'], ['link'], ['blockquote', 'codeBlock'], ['bulletList', 'orderedList'], ['undo', 'redo']],
172
+ },
173
+ description: {
174
+ type: String,
175
+ default: '',
176
+ },
177
+ placeholder: {
178
+ type: String,
179
+ default: 'Write something...',
180
+ },
181
+ autofocus: {
182
+ type: Boolean,
183
+ default: false,
184
+ },
185
+ markdownFormat: {
186
+ type: Boolean,
187
+ default: false,
188
+ },
189
+ fullHeight: {
190
+ type: Boolean,
191
+ default: false,
192
+ },
193
+ },
194
+
195
+ emits: [
196
+ 'update:modelValue',
197
+
198
+ 'input',
199
+ ],
200
+
201
+ expose: [
202
+ 'root',
203
+ ],
204
+
205
+ setup(props, context) {
206
+ // Refs
207
+ const root = ref<HTMLElement>();
208
+ let editor = null as Editor | null;
209
+ const editorRef = ref<HTMLDivElement>();
210
+ const containerRef = ref<HTMLDivElement>();
211
+ const toolbarButtonRef = ref<InstanceType<typeof OrIconButton>>();
212
+ const menuRef = ref<InstanceType<typeof OrMenu>>();
213
+ const isActive = ref<{[key: string]: boolean;}>({});
214
+ const isFocused = ref<boolean>(props.autofocus);
215
+ const headingLevels = [1, 2, 3, 4] as Level[];
216
+ const previousHeadingLevel = ref<Level>();
217
+ const activeHeadingLevel = ref<number>(0);
218
+ const markdownOutput = ref<string>('');
219
+ const isOpenLinkModal = ref<boolean>(false);
220
+ const text = ref<string>('');
221
+ const link = ref<string>('');
222
+ // let trap: UseFocusTrapReturn = useFocusTrap(editorRef, {
223
+ // immediate: true,
224
+ // fallbackFocus: '.container',
225
+ // allowOutsideClick: true,
226
+ // });
227
+ const iconsEnum = ref<{[key: string]: string;}>({
228
+ bold: 'format_bold',
229
+ italic: 'format_italic',
230
+ underline: 'format_underlined',
231
+ strike: 'format_strikethrough',
232
+ bulletList: 'format_list_bulleted',
233
+ orderedList: 'format_list_numbered',
234
+ link: 'link',
235
+ highlight: 'highlight',
236
+ redo: 'redo',
237
+ undo: 'undo',
238
+ codeBlock: 'code_blocks',
239
+ blockquote: 'format_quote',
240
+ });
241
+ const iconTooltipsEnum = ref<{[key: string]: string;}>({
242
+ bold: 'Bold',
243
+ italic: 'Italic',
244
+ underline: 'Underline',
245
+ strike: 'Strike',
246
+ bulletList: 'Bulleted List',
247
+ orderedList: 'Numbered List',
248
+ link: 'Link',
249
+ highlight: 'Highlight',
250
+ redo: 'Redo',
251
+ undo: 'Undo',
252
+ codeBlock: 'Code Block',
253
+ blockquote: 'Quote',
254
+ });
255
+
256
+ onMounted(() => {
257
+ editor = new Editor({
258
+ onUpdate: ({ editor }) => {
259
+ isFocused.value = true;
260
+ setActiveFormats();
261
+ const html = editor.getHTML();
262
+ const text = editor.getText();
263
+ if (props.markdownFormat) {
264
+ markdownOutput.value = serialize(editor.schema, editor.getJSON());
265
+ proxyModelValue.value = markdownOutput.value;
266
+ } else {
267
+ proxyModelValue.value = text === '' ? text : html;
268
+ }
269
+ },
270
+ onCreate: ({ editor }) => {
271
+ if (props.markdownFormat) {
272
+ const deserialized = deserialize(editor.schema, proxyModelValue.value);
273
+ editor.commands.setContent(deserialized);
274
+ } else {
275
+ editor.commands.setContent(proxyModelValue.value as string);
276
+ }
277
+ },
278
+ element: editorRef.value,
279
+ autofocus: props.autofocus,
280
+ extensions: [
281
+ codemirrorNode,
282
+ StarterKit.configure({
283
+ heading: false,
284
+ codeBlock: false,
285
+ }),
286
+ Heading.configure({ levels: headingLevels }).extend({
287
+ levels: headingLevels,
288
+ renderHTML({ node, HTMLAttributes }) {
289
+ return [
290
+ 'h' + node.attrs.level,
291
+ mergeAttributes(HTMLAttributes, {
292
+ class: `typography-headline-${node.attrs.level}`,
293
+ }),
294
+ 0,
295
+ ];
296
+ },
297
+ }),
298
+ Underline,
299
+ Link.configure({
300
+ openOnClick: true,
301
+ linkOnPaste: true,
302
+ autolink: false,
303
+ protocols: ['ftp', 'mailto', 'http', 'https'],
304
+ validate: href => /^https?:\/\//.test(href),
305
+ HTMLAttributes: {
306
+ class: 'text-primary cursor-pointer',
307
+ },
308
+ }),
309
+ Highlight,
310
+ Placeholder
311
+ .configure({
312
+ placeholder: props.placeholder,
313
+ emptyEditorClass: 'is-editor-empty text-outline',
314
+ }),
315
+ ],
316
+ editorProps: {
317
+ attributes: {
318
+ class: 'focus:outline-none',
319
+ },
320
+ },
321
+ });
322
+ setActiveFormats();
323
+ });
324
+
325
+ onBeforeUnmount(() => {
326
+ editor?.destroy();
327
+ });
328
+
329
+ onClickOutside(root, () => {
330
+ isFocused.value = false;
331
+ // trap.deactivate();
332
+ });
333
+
334
+ // Computed
335
+ const proxyModelValue = computed({
336
+ get: () => {
337
+ return props.modelValue ?? props.value; // TODO: Remove Vue 2 fallback
338
+ },
339
+
340
+ set: (value) => {
341
+ context.emit('input', value);
342
+ context.emit('update:modelValue', value);
343
+ },
344
+ });
345
+
346
+ const getIndexOfHeading = computed(() => {
347
+ return props.toolbar.flat().indexOf('heading');
348
+ });
349
+
350
+ const headingIcon = computed(() => {
351
+ if (activeHeadingLevel.value && isActive.value.heading) {
352
+ return `format_h${activeHeadingLevel.value}`;
353
+ }
354
+ return 'format_paragraph';
355
+ });
356
+
357
+ //Methods
358
+ const handleEditorClick = () => {
359
+ setActiveFormats();
360
+ isFocused.value = true;
361
+ editor?.commands.focus();
362
+ };
363
+
364
+ const handleToolbarClick = (item: string, level?: number) => {
365
+ switch (item) {
366
+ case 'bulletList':
367
+ case 'orderedList':
368
+ item === 'bulletList' ? editor?.commands.toggleBulletList() : editor?.commands.toggleOrderedList();
369
+ break;
370
+ case 'link':
371
+ if (editor) {
372
+ const cursorPosition = editor?.state.selection.$anchor.pos || 0;
373
+ const { from, to, empty } = editor.state.selection;
374
+ const isLink = editor.view.state.doc.nodeAt(cursorPosition)?.marks.filter((mark) => mark.type.name === 'link');
375
+ const existedText = isLink?.length ? editor.view.state.doc.nodeAt(cursorPosition)?.text || '' : '';
376
+
377
+ text.value = empty ? existedText : editor.state.doc.textBetween(from, to, ' ');
378
+ link.value = editor.getAttributes('link').href || '';
379
+ }
380
+ isOpenLinkModal.value = !isOpenLinkModal.value;
381
+ break;
382
+ case 'blockquote':
383
+ editor?.chain().focus().toggleBlockquote().run();
384
+ break;
385
+ case 'codeBlock':
386
+ if (!isActive.value['codeBlock']) {
387
+ editor?.commands.setNode(item, { language: 'javascript' });
388
+ } else {
389
+ editor?.commands.setNode('paragraph');
390
+ }
391
+ break;
392
+ case 'heading':
393
+ if (!level) {
394
+ editor?.commands.toggleHeading({ level: previousHeadingLevel.value as Level });
395
+ activeHeadingLevel.value = 0;
396
+ } else {
397
+ activeHeadingLevel.value = level;
398
+ previousHeadingLevel.value = level as Level;
399
+ editor?.commands.toggleHeading({ level: level as Level });
400
+ }
401
+ editor?.commands.focus();
402
+ break;
403
+ case 'undo':
404
+ case 'redo':
405
+ item === 'undo' ? editor?.commands.undo() : editor?.commands.redo();
406
+ break;
407
+ default:
408
+ editor?.chain().focus().toggleMark(item).run();
409
+ break;
410
+ }
411
+ };
412
+
413
+ const attachLink = async () => {
414
+ // empty
415
+ if (link.value === '') {
416
+ editor?.chain().focus().extendMarkRange('link').unsetLink().run();
417
+ }
418
+
419
+ const isEmptySelection = editor?.state.selection.empty;
420
+ const cursorPosition = editor?.state.selection.$anchor.pos || 0;
421
+ const isLink = editor?.view.state.doc.nodeAt(cursorPosition)?.marks.filter((mark) => mark.type.name === 'link');
422
+ const existedText = isLink?.length ? editor?.view.state.doc.nodeAt(cursorPosition)?.text : '';
423
+
424
+ if (link.value && isEmptySelection && !existedText) {
425
+ editor?.chain()
426
+ .focus()
427
+ .setMark('link', {
428
+ href: link.value,
429
+ target: '__blank',
430
+ })
431
+ .command(({ tr }) => {
432
+ const preparedValue = text.value[text.value.length - 1] === ' ' ? text.value : `${text.value} `;
433
+ tr.insertText(preparedValue);
434
+ return true;
435
+ })
436
+ .run();
437
+ }
438
+
439
+ if (link.value && existedText === text.value && isEmptySelection) {
440
+ editor?.chain()
441
+ .extendMarkRange('link')
442
+ .updateAttributes('link', {
443
+ href: link.value,
444
+ })
445
+ .run();
446
+ }
447
+
448
+ if (link.value && !isEmptySelection) {
449
+ editor?.chain()
450
+ .focus()
451
+ .setMark('link', {
452
+ href: link.value,
453
+ target: '__blank',
454
+ })
455
+ .run();
456
+ }
457
+
458
+ text.value = '';
459
+ link.value = '';
460
+
461
+ isOpenLinkModal.value = false;
462
+ };
463
+
464
+ const discardLink = () => {
465
+ isOpenLinkModal.value = false;
466
+ };
467
+
468
+ const setActiveFormats = () => {
469
+ const toolbarList = props.toolbar.flat() as string[];
470
+ toolbarList.forEach((item) => {
471
+ isActive.value[item] = editor?.isActive(item) || false;
472
+ });
473
+ };
474
+
475
+ // Styles
476
+ const rootStyles = computed(() => {
477
+ return [
478
+ 'or-rich-text-editor',
479
+ ...props.fullHeight ? ['h-full'] : [],
480
+ ];
481
+ });
482
+
483
+ const containerStyles = computed(() => {
484
+ return [
485
+ ...EditorContainer,
486
+ ...props.fullHeight ? ['h-full'] : [],
487
+ ];
488
+ });
489
+
490
+ const toolbarContainerStyles = computed(() => {
491
+ return [
492
+ ...ToolbarContainer,
493
+ ];
494
+ });
495
+
496
+ const toolbarStyles = computed(() => {
497
+ return [
498
+ ...Toolbar,
499
+ ...isFocused.value ? ToolbarButtonFocused : ToolbarButton,
500
+ ];
501
+ });
502
+
503
+ const editorInputStyles = computed(() => {
504
+ return [
505
+ 'tiptap-editor',
506
+ ...props.fullHeight ? ['h-full'] : [],
507
+ ...EditorInput,
508
+ ];
509
+ });
510
+
511
+ const toolbarButtonStyles = (item: string) => {
512
+ return [
513
+ // Layout
514
+ 'flex',
515
+ // Spacing
516
+ 'gap-md',
517
+ ...isActive.value[item] ? ToolbarButtonActive : [],
518
+ ];
519
+ };
520
+
521
+ //Effects
522
+ watch(proxyModelValue, (value) => {
523
+ if (value !== editor?.getHTML() && !props.markdownFormat) {
524
+ editor?.commands.setContent(value as string);
525
+ }
526
+ if (props.markdownFormat && value !== markdownOutput.value) {
527
+ const deserialized = deserialize(editor?.schema, value);
528
+ editor?.commands.setContent(deserialized);
529
+ }
530
+ });
531
+
532
+ return {
533
+ editor,
534
+ editorRef,
535
+ containerRef,
536
+ toolbarButtonRef,
537
+ menuRef,
538
+ iconsEnum,
539
+ handleToolbarClick,
540
+ handleEditorClick,
541
+ isActive,
542
+ iconTooltipsEnum,
543
+ containerStyles,
544
+ toolbarContainerStyles,
545
+ toolbarStyles,
546
+ rootStyles,
547
+ root,
548
+ toolbarButtonStyles,
549
+ editorInputStyles,
550
+ getIndexOfHeading,
551
+ headingLevels,
552
+ headingIcon,
553
+ attachLink,
554
+ discardLink,
555
+ isOpenLinkModal,
556
+ text,
557
+ link,
558
+ };
559
+ },
560
+ });
561
+ </script>
562
+
563
+ <style lang="scss">
564
+ .tiptap-editor {
565
+ ol { //see if editor can not inherit it
566
+ margin: 0 24px;
567
+ list-style: decimal;
568
+ }
569
+
570
+ ul {
571
+ margin: 0 24px;
572
+ list-style: initial;
573
+ }
574
+
575
+ pre { //TODO: test styles for code block, need to discuss with team
576
+ background-color: rgba($color: #bad1ec, $alpha: .3);
577
+ padding: 4px 8px;
578
+ margin: 4px 0;
579
+ width: 100%;
580
+ border-radius: 4px;
581
+ }
582
+
583
+ blockquote {
584
+ margin: 8px 24px;
585
+ padding: 0 24px;
586
+ border-left: 4px solid #bad1ec;
587
+ }
588
+
589
+ .is-editor-empty::before {
590
+ content: attr(data-placeholder);
591
+ height: 0;
592
+ pointer-events: none;
593
+ float: left;
594
+ }
595
+
596
+ .cm-editor {
597
+ border: none;
598
+ border-radius: 4px;
599
+
600
+ .cm-scroller {
601
+ border-radius: 4px;
602
+ }
603
+
604
+ &.cm-focused {
605
+ outline: none;
606
+ }
607
+
608
+ .cm-gutters {
609
+ background-color: rgba(0, 95, 177, 0.08);
610
+ border: none;
611
+
612
+ .cm-gutterElement {
613
+ padding: 0 10px;
614
+
615
+ &.cm-activeLineGutter {
616
+ background-color: rgba(0, 95, 177, 0.07)
617
+ }
618
+ }
619
+ }
620
+ }
621
+ }
622
+ </style>
@@ -0,0 +1 @@
1
+ export { default as OrRichTextEditorV3 } from './OrRichTextEditor.vue';