frappe-ui 0.1.146 → 0.1.148
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 +2 -1
- package/src/components/Charts/Charts.story.vue +4 -0
- package/src/components/Charts/axisChartOptions.ts +54 -74
- package/src/components/Charts/eChartOptions.ts +16 -4
- package/src/components/Charts/helpers.ts +31 -0
- package/src/components/Charts/types.ts +21 -0
- package/src/components/TextEditor/FontColor.vue +66 -31
- package/src/components/TextEditor/TextEditor.vue +51 -11
- package/src/components/TextEditor/extensions/color/color-extension.ts +151 -0
- package/src/components/TextEditor/extensions/color/color-styles.css +25 -0
- package/src/components/TextEditor/extensions/color/index.ts +2 -0
- package/src/components/TextEditor/{EmojiList.vue → extensions/emoji/EmojiList.vue} +15 -10
- package/src/components/TextEditor/extensions/emoji/emoji-extension.ts +55 -0
- package/src/components/TextEditor/extensions/heading/heading.ts +20 -0
- package/src/components/TextEditor/extensions/highlight/highlight-extension.ts +241 -0
- package/src/components/TextEditor/extensions/highlight/highlight-styles.css +32 -0
- package/src/components/TextEditor/extensions/highlight/index.ts +2 -0
- package/src/components/TextEditor/extensions/shared/color-utils.ts +236 -0
- package/src/components/TextEditor/{SlashCommandsList.vue → extensions/slash-commands/SlashCommandsList.vue} +22 -10
- package/src/components/TextEditor/extensions/slash-commands/slash-commands-extension.ts +155 -0
- package/src/components/TextEditor/{SuggestionList.vue → extensions/suggestion/SuggestionList.vue} +4 -7
- package/src/components/TextEditor/extensions/suggestion/createSuggestionExtension.ts +151 -0
- package/src/components/TextEditor/extensions/tag/tag-extension.ts +153 -0
- package/src/tailwind/colorPalette.js +20 -0
- package/src/components/TextEditor/emoji-extension.js +0 -100
- package/src/components/TextEditor/slash-commands-extension.ts +0 -244
- /package/src/components/TextEditor/{emojis.json → extensions/emoji/emojis.json} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frappe-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.148",
|
|
4
4
|
"description": "A set of components and utilities for rapid UI development",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"@tiptap/extension-code-block": "^2.11.9",
|
|
38
38
|
"@tiptap/extension-code-block-lowlight": "^2.11.5",
|
|
39
39
|
"@tiptap/extension-color": "^2.0.3",
|
|
40
|
+
"@tiptap/extension-heading": "^2.12.0",
|
|
40
41
|
"@tiptap/extension-highlight": "^2.0.3",
|
|
41
42
|
"@tiptap/extension-image": "^2.0.3",
|
|
42
43
|
"@tiptap/extension-link": "^2.0.3",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import useEchartsOptions from './eChartOptions'
|
|
2
|
-
import { formatValue } from './helpers'
|
|
2
|
+
import { formatValue, mergeDeep } from './helpers'
|
|
3
3
|
import {
|
|
4
4
|
AreaSeriesConfig,
|
|
5
5
|
AxisChartConfig,
|
|
@@ -33,61 +33,60 @@ export default function useAxisChartOptions(config: AxisChartConfig) {
|
|
|
33
33
|
baseOptions.yAxis[1].show = true
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const _val = swapXY ? params.value?.[0] : params.value?.[1]
|
|
67
|
-
return formatValue(_val, 1, true)
|
|
68
|
-
},
|
|
69
|
-
fontSize: 11,
|
|
70
|
-
},
|
|
71
|
-
labelLayout: { hideOverlap: true },
|
|
72
|
-
itemStyle: {
|
|
73
|
-
color: s.color,
|
|
36
|
+
baseOptions.series = config.series.map((s, idx) => {
|
|
37
|
+
let labelPosition = 'top'
|
|
38
|
+
if (s.type == 'bar' && config.stacked) {
|
|
39
|
+
labelPosition = idx == lastBarSeriesIdx ? 'top' : 'inside'
|
|
40
|
+
}
|
|
41
|
+
if (s.type == 'bar' && swapXY) {
|
|
42
|
+
labelPosition = 'right'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const standardSeriesOptions = {
|
|
46
|
+
type: s.type,
|
|
47
|
+
name: s.name,
|
|
48
|
+
data: data.map((row: any) => {
|
|
49
|
+
let x, y
|
|
50
|
+
if (swapXY) {
|
|
51
|
+
x = row[s.name]
|
|
52
|
+
y = row[config.xAxis.key]
|
|
53
|
+
} else {
|
|
54
|
+
x = row[config.xAxis.key]
|
|
55
|
+
y = row[s.name]
|
|
56
|
+
}
|
|
57
|
+
return [x, y]
|
|
58
|
+
}),
|
|
59
|
+
yAxisIndex: s.axis === 'y2' ? 1 : 0,
|
|
60
|
+
label: {
|
|
61
|
+
show: s.showDataLabels,
|
|
62
|
+
position: labelPosition,
|
|
63
|
+
formatter: (params: any) => {
|
|
64
|
+
const _val = swapXY ? params.value?.[0] : params.value?.[1]
|
|
65
|
+
return formatValue(_val, 1, true)
|
|
74
66
|
},
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
67
|
+
fontSize: 11,
|
|
68
|
+
},
|
|
69
|
+
labelLayout: { hideOverlap: true },
|
|
70
|
+
itemStyle: {
|
|
71
|
+
color: s.color,
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let seriesTypeOptions = {}
|
|
76
|
+
if (s.type === 'bar') {
|
|
77
|
+
seriesTypeOptions = getBarSeriesOptions(config, s)
|
|
78
|
+
}
|
|
79
|
+
if (s.type === 'line') {
|
|
80
|
+
seriesTypeOptions = getLineSeriesOptions(config, s)
|
|
81
|
+
}
|
|
82
|
+
if (s.type === 'area') {
|
|
83
|
+
seriesTypeOptions = getAreaSeriesOptions(config, s)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return mergeDeep(standardSeriesOptions, seriesTypeOptions, s.echartOptions)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
return mergeDeep(baseOptions, config.echartOptions)
|
|
91
90
|
}
|
|
92
91
|
|
|
93
92
|
function getBarSeriesOptions(config: AxisChartConfig, series: BarSeriesConfig) {
|
|
@@ -143,22 +142,3 @@ function getAreaSeriesOptions(
|
|
|
143
142
|
},
|
|
144
143
|
}
|
|
145
144
|
}
|
|
146
|
-
|
|
147
|
-
function isObject(item: any) {
|
|
148
|
-
return item && typeof item === 'object' && !Array.isArray(item)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function mergeDeep(target: any, source: any) {
|
|
152
|
-
let output = Object.assign({}, target)
|
|
153
|
-
if (isObject(target) && isObject(source)) {
|
|
154
|
-
Object.keys(source).forEach((key) => {
|
|
155
|
-
if (isObject(source[key])) {
|
|
156
|
-
if (!(key in target)) Object.assign(output, { [key]: source[key] })
|
|
157
|
-
else output[key] = mergeDeep(target[key], source[key])
|
|
158
|
-
} else {
|
|
159
|
-
Object.assign(output, { [key]: source[key] })
|
|
160
|
-
}
|
|
161
|
-
})
|
|
162
|
-
}
|
|
163
|
-
return output
|
|
164
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatDate, formatLabel, formatValue } from './helpers'
|
|
1
|
+
import { formatDate, formatLabel, formatValue, mergeDeep } from './helpers'
|
|
2
2
|
import { AxisChartConfig } from './types'
|
|
3
3
|
|
|
4
4
|
export const PADDING_TOP = 0
|
|
@@ -154,7 +154,7 @@ export function getTitleOptions(title: string, subtitle?: string) {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
function getXAxisOptions(config: AxisChartConfig) {
|
|
157
|
-
|
|
157
|
+
const options = config.swapXY
|
|
158
158
|
? {
|
|
159
159
|
show: true,
|
|
160
160
|
type: 'value',
|
|
@@ -220,10 +220,12 @@ function getXAxisOptions(config: AxisChartConfig) {
|
|
|
220
220
|
margin: 8,
|
|
221
221
|
},
|
|
222
222
|
}
|
|
223
|
+
|
|
224
|
+
return mergeDeep(options, config.swapXY ? config.yAxis.echartOptions : config.xAxis.echartOptions)
|
|
223
225
|
}
|
|
224
226
|
|
|
225
227
|
function getYAxisOptions(config: AxisChartConfig) {
|
|
226
|
-
|
|
228
|
+
let primaryYAxisOptions = config.swapXY
|
|
227
229
|
? {
|
|
228
230
|
show: true,
|
|
229
231
|
type: config.xAxis.type,
|
|
@@ -288,7 +290,12 @@ function getYAxisOptions(config: AxisChartConfig) {
|
|
|
288
290
|
max: config.yAxis.yMax,
|
|
289
291
|
}
|
|
290
292
|
|
|
291
|
-
|
|
293
|
+
primaryYAxisOptions = mergeDeep(
|
|
294
|
+
primaryYAxisOptions,
|
|
295
|
+
config.swapXY ? config.xAxis.echartOptions : config.yAxis.echartOptions
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
let secondaryYAxisOptions = {
|
|
292
299
|
show: false,
|
|
293
300
|
type: 'value',
|
|
294
301
|
z: 2,
|
|
@@ -330,6 +337,11 @@ function getYAxisOptions(config: AxisChartConfig) {
|
|
|
330
337
|
max: config.y2Axis?.yMax,
|
|
331
338
|
}
|
|
332
339
|
|
|
340
|
+
secondaryYAxisOptions = mergeDeep(
|
|
341
|
+
secondaryYAxisOptions,
|
|
342
|
+
config.swapXY ? config.y2Axis?.echartOptions : config.y2Axis?.echartOptions
|
|
343
|
+
)
|
|
344
|
+
|
|
333
345
|
return config.swapXY
|
|
334
346
|
? [primaryYAxisOptions]
|
|
335
347
|
: [primaryYAxisOptions, secondaryYAxisOptions]
|
|
@@ -73,3 +73,34 @@ export function formatDate(date: string, format?: string, grain: TimeGrain = 'da
|
|
|
73
73
|
|
|
74
74
|
return dayjs(date).format(format)
|
|
75
75
|
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
export function isObject(item: any) {
|
|
79
|
+
return item && typeof item === 'object' && !Array.isArray(item)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function mergeDeep(target: any, ...sources: any[]) {
|
|
83
|
+
if (!sources.length) return target;
|
|
84
|
+
const source = sources.shift();
|
|
85
|
+
|
|
86
|
+
if (!source || !isObject(target) || !isObject(source)) {
|
|
87
|
+
// Skip the current source if it's not a proper object
|
|
88
|
+
return mergeDeep(target, ...sources);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let output = Object.assign({}, target);
|
|
92
|
+
|
|
93
|
+
Object.keys(source).forEach((key) => {
|
|
94
|
+
if (isObject(source[key])) {
|
|
95
|
+
if (!(key in output)) {
|
|
96
|
+
output[key] = source[key];
|
|
97
|
+
} else {
|
|
98
|
+
output[key] = mergeDeep(output[key], source[key]);
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
output[key] = source[key];
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
return mergeDeep(output, ...sources);
|
|
106
|
+
}
|
|
@@ -10,20 +10,32 @@ export type AxisChartConfig = {
|
|
|
10
10
|
type: 'category' | 'time' | 'value'
|
|
11
11
|
timeGrain?: TimeGrain
|
|
12
12
|
title?: string
|
|
13
|
+
echartOptions?: {
|
|
14
|
+
[key: string]: any
|
|
15
|
+
}
|
|
13
16
|
}
|
|
14
17
|
yAxis: {
|
|
15
18
|
title?: string
|
|
16
19
|
yMin?: number
|
|
17
20
|
yMax?: number
|
|
21
|
+
echartOptions?: {
|
|
22
|
+
[key: string]: any
|
|
23
|
+
}
|
|
18
24
|
}
|
|
19
25
|
y2Axis?: {
|
|
20
26
|
title?: string
|
|
21
27
|
yMin?: number
|
|
22
28
|
yMax?: number
|
|
29
|
+
echartOptions?: {
|
|
30
|
+
[key: string]: any
|
|
31
|
+
}
|
|
23
32
|
}
|
|
24
33
|
swapXY?: boolean
|
|
25
34
|
stacked?: boolean
|
|
26
35
|
series: (BarSeriesConfig | LineSeriesConfig | AreaSeriesConfig)[]
|
|
36
|
+
echartOptions?: {
|
|
37
|
+
[key: string]: any
|
|
38
|
+
}
|
|
27
39
|
}
|
|
28
40
|
|
|
29
41
|
export type SeriesConfig = {
|
|
@@ -32,6 +44,9 @@ export type SeriesConfig = {
|
|
|
32
44
|
color?: string
|
|
33
45
|
axis?: 'y' | 'y2'
|
|
34
46
|
showDataLabels?: boolean
|
|
47
|
+
echartOptions?: {
|
|
48
|
+
[key: string]: any
|
|
49
|
+
}
|
|
35
50
|
}
|
|
36
51
|
|
|
37
52
|
export type BarSeriesConfig = SeriesConfig & {
|
|
@@ -61,6 +76,9 @@ export type DonutChartConfig = {
|
|
|
61
76
|
valueColumn: string
|
|
62
77
|
maxSliceCount?: number
|
|
63
78
|
showInlineLabels?: boolean
|
|
79
|
+
echartOptions?: {
|
|
80
|
+
[key: string]: any
|
|
81
|
+
}
|
|
64
82
|
}
|
|
65
83
|
|
|
66
84
|
export type FunnelChartConfig = {
|
|
@@ -71,6 +89,9 @@ export type FunnelChartConfig = {
|
|
|
71
89
|
categoryColumn: string
|
|
72
90
|
valueColumn: string
|
|
73
91
|
showPercentages?: boolean
|
|
92
|
+
echartOptions?: {
|
|
93
|
+
[key: string]: any
|
|
94
|
+
}
|
|
74
95
|
}
|
|
75
96
|
|
|
76
97
|
export type NumberChartConfig = {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<template #body-main>
|
|
9
9
|
<div class="p-2">
|
|
10
10
|
<div class="text-sm text-ink-gray-7">Text Color</div>
|
|
11
|
-
<div class="mt-1 grid grid-cols-
|
|
11
|
+
<div class="mt-1 grid grid-cols-6 gap-1">
|
|
12
12
|
<Tooltip
|
|
13
13
|
class="flex"
|
|
14
14
|
v-for="color in foregroundColors"
|
|
@@ -18,9 +18,7 @@
|
|
|
18
18
|
<button
|
|
19
19
|
:aria-label="color.name"
|
|
20
20
|
class="flex h-5 w-5 items-center justify-center rounded border text-base"
|
|
21
|
-
:
|
|
22
|
-
color: color.hex,
|
|
23
|
-
}"
|
|
21
|
+
:class="color.class"
|
|
24
22
|
@click="setForegroundColor(color)"
|
|
25
23
|
>
|
|
26
24
|
A
|
|
@@ -28,7 +26,7 @@
|
|
|
28
26
|
</Tooltip>
|
|
29
27
|
</div>
|
|
30
28
|
<div class="mt-2 text-sm text-ink-gray-7">Background Color</div>
|
|
31
|
-
<div class="mt-1 grid grid-cols-
|
|
29
|
+
<div class="mt-1 grid grid-cols-6 gap-1">
|
|
32
30
|
<Tooltip
|
|
33
31
|
class="flex"
|
|
34
32
|
v-for="color in backgroundColors"
|
|
@@ -38,12 +36,7 @@
|
|
|
38
36
|
<button
|
|
39
37
|
:aria-label="color.name"
|
|
40
38
|
class="flex h-5 w-5 items-center justify-center rounded border text-base text-ink-gray-9"
|
|
41
|
-
:class="
|
|
42
|
-
!color.hex ? 'border-outline-gray-modals' : 'border-transparent'
|
|
43
|
-
"
|
|
44
|
-
:style="{
|
|
45
|
-
backgroundColor: color.hex,
|
|
46
|
-
}"
|
|
39
|
+
:class="color.class"
|
|
47
40
|
@click="setBackgroundColor(color)"
|
|
48
41
|
>
|
|
49
42
|
A
|
|
@@ -65,14 +58,22 @@ export default {
|
|
|
65
58
|
methods: {
|
|
66
59
|
setBackgroundColor(color) {
|
|
67
60
|
if (color.name != 'Default') {
|
|
68
|
-
this.editor
|
|
61
|
+
this.editor
|
|
62
|
+
.chain()
|
|
63
|
+
.focus()
|
|
64
|
+
.toggleHighlightByName(color.name.toLowerCase())
|
|
65
|
+
.run()
|
|
69
66
|
} else {
|
|
70
67
|
this.editor.chain().focus().unsetHighlight().run()
|
|
71
68
|
}
|
|
72
69
|
},
|
|
73
70
|
setForegroundColor(color) {
|
|
74
71
|
if (color.name != 'Default') {
|
|
75
|
-
this.editor
|
|
72
|
+
this.editor
|
|
73
|
+
.chain()
|
|
74
|
+
.focus()
|
|
75
|
+
.setColorByName(color.name.toLowerCase())
|
|
76
|
+
.run()
|
|
76
77
|
} else {
|
|
77
78
|
this.editor.chain().focus().unsetColor().run()
|
|
78
79
|
}
|
|
@@ -80,29 +81,63 @@ export default {
|
|
|
80
81
|
},
|
|
81
82
|
computed: {
|
|
82
83
|
foregroundColors() {
|
|
83
|
-
// tailwind css colors, scale 600
|
|
84
84
|
return [
|
|
85
|
-
{ name: 'Default',
|
|
86
|
-
{ name: '
|
|
87
|
-
{ name: 'Orange',
|
|
88
|
-
{ name: '
|
|
89
|
-
{ name: 'Green',
|
|
90
|
-
{ name: '
|
|
91
|
-
{ name: '
|
|
92
|
-
{ name: '
|
|
85
|
+
{ name: 'Default', class: 'text-ink-gray-9' },
|
|
86
|
+
{ name: 'Red', class: 'text-red-600 dark:text-dark-red-400' },
|
|
87
|
+
{ name: 'Orange', class: 'text-orange-600 dark:text-dark-orange-400' },
|
|
88
|
+
{ name: 'Yellow', class: 'text-yellow-600 dark:text-dark-yellow-400' },
|
|
89
|
+
{ name: 'Green', class: 'text-green-600 dark:text-dark-green-400' },
|
|
90
|
+
{ name: 'Teal', class: 'text-teal-600 dark:text-dark-teal-400' },
|
|
91
|
+
{ name: 'Cyan', class: 'text-cyan-600 dark:text-dark-cyan-400' },
|
|
92
|
+
{ name: 'Blue', class: 'text-blue-600 dark:text-dark-blue-400' },
|
|
93
|
+
{ name: 'Purple', class: 'text-purple-600 dark:text-dark-purple-400' },
|
|
94
|
+
{ name: 'Pink', class: 'text-pink-600 dark:text-dark-pink-400' },
|
|
95
|
+
{ name: 'Gray', class: 'text-gray-600 dark:text-dark-gray-400' },
|
|
93
96
|
]
|
|
94
97
|
},
|
|
95
98
|
backgroundColors() {
|
|
96
|
-
// tailwind css colors, scale 100
|
|
97
99
|
return [
|
|
98
|
-
{ name: 'Default',
|
|
99
|
-
{
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
{
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
{ name: 'Default', class: 'border-outline-gray-modals' },
|
|
101
|
+
{
|
|
102
|
+
name: 'Red',
|
|
103
|
+
class: 'bg-red-100 dark:bg-dark-red-800 border-transparent',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'Orange',
|
|
107
|
+
class: 'bg-orange-100 dark:bg-dark-orange-800 border-transparent',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: 'Yellow',
|
|
111
|
+
class: 'bg-yellow-100 dark:bg-dark-yellow-800 border-transparent',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'Green',
|
|
115
|
+
class: 'bg-green-100 dark:bg-dark-green-800 border-transparent',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'Teal',
|
|
119
|
+
class: 'bg-teal-100 dark:bg-dark-teal-800 border-transparent',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'Cyan',
|
|
123
|
+
class: 'bg-cyan-100 dark:bg-dark-cyan-800 border-transparent',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: 'Blue',
|
|
127
|
+
class: 'bg-blue-100 dark:bg-dark-blue-800 border-transparent',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: 'Purple',
|
|
131
|
+
class: 'bg-purple-100 dark:bg-dark-purple-800 border-transparent',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: 'Pink',
|
|
135
|
+
class: 'bg-pink-100 dark:bg-dark-pink-800 border-transparent',
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: 'Gray',
|
|
139
|
+
class: 'bg-gray-100 dark:bg-dark-gray-800 border-transparent',
|
|
140
|
+
},
|
|
106
141
|
]
|
|
107
142
|
},
|
|
108
143
|
},
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
class="relative w-full"
|
|
4
|
+
:class="$attrs.class"
|
|
5
|
+
:style="$attrs.style"
|
|
6
|
+
v-if="editor"
|
|
7
|
+
>
|
|
3
8
|
<TextEditorBubbleMenu :buttons="bubbleMenu" :options="bubbleMenuOptions" />
|
|
4
9
|
<TextEditorFixedMenu
|
|
5
10
|
class="w-full overflow-x-auto rounded-t-lg border border-outline-gray-modals"
|
|
@@ -14,7 +19,7 @@
|
|
|
14
19
|
</div>
|
|
15
20
|
</template>
|
|
16
21
|
|
|
17
|
-
<script>
|
|
22
|
+
<script lang="ts">
|
|
18
23
|
import { normalizeClass, computed } from 'vue'
|
|
19
24
|
import { Editor, EditorContent, VueNodeViewRenderer } from '@tiptap/vue-3'
|
|
20
25
|
import StarterKit from '@tiptap/starter-kit'
|
|
@@ -30,8 +35,8 @@ import VideoExtension from './video-extension'
|
|
|
30
35
|
import LinkExtension from './link-extension'
|
|
31
36
|
import Typography from '@tiptap/extension-typography'
|
|
32
37
|
import TextStyle from '@tiptap/extension-text-style'
|
|
33
|
-
import
|
|
34
|
-
import
|
|
38
|
+
import NamedColorExtension from './extensions/color'
|
|
39
|
+
import NamedHighlightExtension from './extensions/highlight'
|
|
35
40
|
import { common, createLowlight } from 'lowlight'
|
|
36
41
|
import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight'
|
|
37
42
|
import CodeBlockComponent from './CodeBlockComponent.vue'
|
|
@@ -39,10 +44,12 @@ import configureMention from './mention'
|
|
|
39
44
|
import TextEditorFixedMenu from './TextEditorFixedMenu.vue'
|
|
40
45
|
import TextEditorBubbleMenu from './TextEditorBubbleMenu.vue'
|
|
41
46
|
import TextEditorFloatingMenu from './TextEditorFloatingMenu.vue'
|
|
42
|
-
import EmojiExtension from './emoji-extension'
|
|
43
|
-
import SlashCommands from './slash-commands-extension'
|
|
47
|
+
import EmojiExtension from './extensions/emoji/emoji-extension'
|
|
48
|
+
import SlashCommands from './extensions/slash-commands/slash-commands-extension'
|
|
44
49
|
import { detectMarkdown, markdownToHTML } from '../../utils/markdown'
|
|
45
50
|
import { DOMParser } from 'prosemirror-model'
|
|
51
|
+
import { TagNode, TagExtension } from './extensions/tag/tag-extension'
|
|
52
|
+
import { Heading } from './extensions/heading/heading'
|
|
46
53
|
|
|
47
54
|
const lowlight = createLowlight(common)
|
|
48
55
|
|
|
@@ -100,6 +107,10 @@ export default {
|
|
|
100
107
|
type: Array,
|
|
101
108
|
default: () => [],
|
|
102
109
|
},
|
|
110
|
+
tags: {
|
|
111
|
+
type: Array,
|
|
112
|
+
default: () => [],
|
|
113
|
+
},
|
|
103
114
|
uploadFunction: {
|
|
104
115
|
type: Function,
|
|
105
116
|
default: () => null,
|
|
@@ -147,6 +158,13 @@ export default {
|
|
|
147
158
|
StarterKit.configure({
|
|
148
159
|
...this.starterkitOptions,
|
|
149
160
|
codeBlock: false,
|
|
161
|
+
heading: false,
|
|
162
|
+
}),
|
|
163
|
+
Heading.configure({
|
|
164
|
+
...(typeof this.starterkitOptions?.heading === 'object' &&
|
|
165
|
+
this.starterkitOptions.heading !== null
|
|
166
|
+
? this.starterkitOptions.heading
|
|
167
|
+
: {}),
|
|
150
168
|
}),
|
|
151
169
|
Table.configure({
|
|
152
170
|
resizable: true,
|
|
@@ -159,8 +177,8 @@ export default {
|
|
|
159
177
|
types: ['heading', 'paragraph'],
|
|
160
178
|
}),
|
|
161
179
|
TextStyle,
|
|
162
|
-
|
|
163
|
-
|
|
180
|
+
NamedColorExtension,
|
|
181
|
+
NamedHighlightExtension,
|
|
164
182
|
CodeBlockLowlight.extend({
|
|
165
183
|
addNodeView() {
|
|
166
184
|
return VueNodeViewRenderer(CodeBlockComponent)
|
|
@@ -185,6 +203,10 @@ export default {
|
|
|
185
203
|
configureMention(this.mentions),
|
|
186
204
|
EmojiExtension,
|
|
187
205
|
SlashCommands,
|
|
206
|
+
TagNode,
|
|
207
|
+
TagExtension.configure({
|
|
208
|
+
tags: () => this.tags,
|
|
209
|
+
}),
|
|
188
210
|
...(this.extensions || []),
|
|
189
211
|
],
|
|
190
212
|
onUpdate: ({ editor }) => {
|
|
@@ -237,6 +259,9 @@ export default {
|
|
|
237
259
|
}
|
|
238
260
|
</script>
|
|
239
261
|
<style>
|
|
262
|
+
@import './extensions/color/color-styles.css';
|
|
263
|
+
@import './extensions/highlight/highlight-styles.css';
|
|
264
|
+
|
|
240
265
|
.ProseMirror {
|
|
241
266
|
outline: none;
|
|
242
267
|
caret-color: var(--ink-gray-9);
|
|
@@ -302,8 +327,23 @@ img.ProseMirror-selectednode {
|
|
|
302
327
|
cursor: col-resize;
|
|
303
328
|
}
|
|
304
329
|
|
|
305
|
-
.
|
|
306
|
-
|
|
307
|
-
|
|
330
|
+
.tag-item,
|
|
331
|
+
.tag-suggestion-active {
|
|
332
|
+
background-color: var(--surface-gray-1, #f8f8f8);
|
|
333
|
+
color: inherit;
|
|
334
|
+
border: 1px solid transparent;
|
|
335
|
+
padding: 0px 2px;
|
|
336
|
+
border-radius: 4px;
|
|
337
|
+
font-size: 1em;
|
|
338
|
+
white-space: nowrap;
|
|
339
|
+
cursor: default;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.tag-item.ProseMirror-selectednode {
|
|
343
|
+
border-color: var(--outline-gray-3, #c7c7c7);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.tag-suggestion-active {
|
|
347
|
+
background-color: var(--surface-gray-2, #f3f3f3);
|
|
308
348
|
}
|
|
309
349
|
</style>
|