@milkdown/plugin-slash 6.5.3 → 7.0.0-next.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/lib/index.d.ts +2 -13
- package/lib/index.d.ts.map +1 -1
- package/lib/index.es.js +80 -382
- package/lib/index.es.js.map +1 -1
- package/lib/slash-plugin.d.ts +11 -0
- package/lib/slash-plugin.d.ts.map +1 -0
- package/lib/slash-provider.d.ts +20 -0
- package/lib/slash-provider.d.ts.map +1 -0
- package/package.json +17 -8
- package/src/index.ts +2 -34
- package/src/slash-plugin.ts +31 -0
- package/src/slash-provider.ts +119 -0
- package/lib/config.d.ts +0 -21
- package/lib/config.d.ts.map +0 -1
- package/lib/item.d.ts +0 -12
- package/lib/item.d.ts.map +0 -1
- package/lib/prose-plugin/dropdown.d.ts +0 -8
- package/lib/prose-plugin/dropdown.d.ts.map +0 -1
- package/lib/prose-plugin/index.d.ts +0 -7
- package/lib/prose-plugin/index.d.ts.map +0 -1
- package/lib/prose-plugin/input.d.ts +0 -14
- package/lib/prose-plugin/input.d.ts.map +0 -1
- package/lib/prose-plugin/props.d.ts +0 -11
- package/lib/prose-plugin/props.d.ts.map +0 -1
- package/lib/prose-plugin/status.d.ts +0 -14
- package/lib/prose-plugin/status.d.ts.map +0 -1
- package/lib/prose-plugin/view.d.ts +0 -13
- package/lib/prose-plugin/view.d.ts.map +0 -1
- package/lib/style.d.ts +0 -3
- package/lib/style.d.ts.map +0 -1
- package/lib/utility.d.ts +0 -14
- package/lib/utility.d.ts.map +0 -1
- package/src/config.ts +0 -142
- package/src/item.ts +0 -21
- package/src/prose-plugin/dropdown.ts +0 -50
- package/src/prose-plugin/index.ts +0 -26
- package/src/prose-plugin/input.ts +0 -142
- package/src/prose-plugin/props.ts +0 -104
- package/src/prose-plugin/status.ts +0 -37
- package/src/prose-plugin/view.ts +0 -112
- package/src/style.ts +0 -76
- package/src/utility.ts +0 -85
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import { Plugin, PluginKey } from '@milkdown/prose/state'
|
|
3
|
-
import type { ThemeUtils } from '@milkdown/utils'
|
|
4
|
-
|
|
5
|
-
import type { StatusConfigBuilder } from '..'
|
|
6
|
-
import { createProps } from './props'
|
|
7
|
-
import { createStatus } from './status'
|
|
8
|
-
import type { CalcPosition } from './view'
|
|
9
|
-
import { createView } from './view'
|
|
10
|
-
|
|
11
|
-
export const key = 'MILKDOWN_SLASH'
|
|
12
|
-
|
|
13
|
-
export const createSlashPlugin = (
|
|
14
|
-
utils: ThemeUtils,
|
|
15
|
-
builder: StatusConfigBuilder,
|
|
16
|
-
className: string,
|
|
17
|
-
calcPosition: CalcPosition,
|
|
18
|
-
) => {
|
|
19
|
-
const status = createStatus(builder)
|
|
20
|
-
|
|
21
|
-
return new Plugin({
|
|
22
|
-
key: new PluginKey(key),
|
|
23
|
-
props: createProps(status, utils),
|
|
24
|
-
view: view => createView(status, view, utils, className, calcPosition),
|
|
25
|
-
})
|
|
26
|
-
}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
|
|
3
|
-
import type { EditorView } from '@milkdown/prose/view'
|
|
4
|
-
import scrollIntoView from 'smooth-scroll-into-view-if-needed'
|
|
5
|
-
|
|
6
|
-
import type { Status } from './status'
|
|
7
|
-
|
|
8
|
-
export const createMouseManager = () => {
|
|
9
|
-
let mouseLock = false
|
|
10
|
-
|
|
11
|
-
return {
|
|
12
|
-
isLock: () => mouseLock,
|
|
13
|
-
lock: () => {
|
|
14
|
-
mouseLock = true
|
|
15
|
-
},
|
|
16
|
-
unlock: () => {
|
|
17
|
-
mouseLock = false
|
|
18
|
-
},
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
export type MouseManager = ReturnType<typeof createMouseManager>
|
|
22
|
-
|
|
23
|
-
export const handleMouseMove = (mouseManager: MouseManager) => () => {
|
|
24
|
-
mouseManager.unlock()
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const handleMouseEnter = (status: Status, mouseManager: MouseManager) => (e: MouseEvent) => {
|
|
28
|
-
if (mouseManager.isLock())
|
|
29
|
-
return
|
|
30
|
-
const { actions } = status.get()
|
|
31
|
-
const active = actions.findIndex(x => x.$.classList.contains('active'))
|
|
32
|
-
const active$ = actions[active]
|
|
33
|
-
if (active$ && active >= 0)
|
|
34
|
-
active$.$.classList.remove('active')
|
|
35
|
-
|
|
36
|
-
const { target } = e
|
|
37
|
-
if (!(target instanceof HTMLElement))
|
|
38
|
-
return
|
|
39
|
-
target.classList.add('active')
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const handleMouseLeave = () => (e: MouseEvent) => {
|
|
43
|
-
const { target } = e
|
|
44
|
-
if (!(target instanceof HTMLElement))
|
|
45
|
-
return
|
|
46
|
-
target.classList.remove('active')
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export const handleClick
|
|
50
|
-
= (status: Status, view: EditorView, dropdownElement: HTMLElement) =>
|
|
51
|
-
(e: Event): void => {
|
|
52
|
-
const { target } = e
|
|
53
|
-
if (!(target instanceof HTMLElement))
|
|
54
|
-
return
|
|
55
|
-
if (!view)
|
|
56
|
-
return
|
|
57
|
-
|
|
58
|
-
const stop = () => {
|
|
59
|
-
e.stopPropagation()
|
|
60
|
-
e.preventDefault()
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const { actions } = status.get()
|
|
64
|
-
|
|
65
|
-
const el = Object.values(actions).find(({ $ }) => $.contains(target))
|
|
66
|
-
if (!el) {
|
|
67
|
-
if (status.isEmpty())
|
|
68
|
-
return
|
|
69
|
-
|
|
70
|
-
status.clear()
|
|
71
|
-
dropdownElement.classList.add('hide')
|
|
72
|
-
stop()
|
|
73
|
-
|
|
74
|
-
return
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
stop()
|
|
78
|
-
el.command(view.state, view.dispatch, view)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export const handleKeydown
|
|
82
|
-
= (status: Status, view: EditorView, dropdownElement: HTMLElement, mouseManager: MouseManager) => (e: Event) => {
|
|
83
|
-
if (!(e instanceof KeyboardEvent))
|
|
84
|
-
return
|
|
85
|
-
if (!mouseManager.isLock())
|
|
86
|
-
mouseManager.lock()
|
|
87
|
-
|
|
88
|
-
const { key } = e
|
|
89
|
-
if (status.isEmpty())
|
|
90
|
-
return
|
|
91
|
-
if (!['ArrowDown', 'ArrowUp', 'Enter', 'Escape'].includes(key))
|
|
92
|
-
return
|
|
93
|
-
|
|
94
|
-
const { actions } = status.get()
|
|
95
|
-
|
|
96
|
-
let active = actions.findIndex(({ $ }) => $.classList.contains('active'))
|
|
97
|
-
if (active < 0)
|
|
98
|
-
active = 0
|
|
99
|
-
|
|
100
|
-
const moveActive = (next: number) => {
|
|
101
|
-
const active$ = actions[active]
|
|
102
|
-
const next$ = actions[next]
|
|
103
|
-
if (!active$ || !next$)
|
|
104
|
-
return
|
|
105
|
-
active$.$.classList.remove('active')
|
|
106
|
-
next$.$.classList.add('active')
|
|
107
|
-
scrollIntoView(next$.$, {
|
|
108
|
-
scrollMode: 'if-needed',
|
|
109
|
-
block: 'nearest',
|
|
110
|
-
inline: 'nearest',
|
|
111
|
-
})
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (key === 'ArrowDown') {
|
|
115
|
-
const next = active === actions.length - 1 ? 0 : active + 1
|
|
116
|
-
|
|
117
|
-
moveActive(next)
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (key === 'ArrowUp') {
|
|
122
|
-
const next = active === 0 ? actions.length - 1 : active - 1
|
|
123
|
-
|
|
124
|
-
moveActive(next)
|
|
125
|
-
return
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (key === 'Escape') {
|
|
129
|
-
if (status.isEmpty())
|
|
130
|
-
return
|
|
131
|
-
|
|
132
|
-
status.clear()
|
|
133
|
-
dropdownElement.classList.add('hide')
|
|
134
|
-
return
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const active$ = actions[active]
|
|
138
|
-
if (!active$)
|
|
139
|
-
return
|
|
140
|
-
active$.command(view.state, view.dispatch, view)
|
|
141
|
-
active$.$.classList.remove('active')
|
|
142
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import type { Color, Emotion, ThemeManager } from '@milkdown/core'
|
|
3
|
-
import { ThemeColor, ThemeFont } from '@milkdown/core'
|
|
4
|
-
import { findParentNode } from '@milkdown/prose'
|
|
5
|
-
import type { EditorState } from '@milkdown/prose/state'
|
|
6
|
-
import type { EditorView } from '@milkdown/prose/view'
|
|
7
|
-
import { Decoration, DecorationSet } from '@milkdown/prose/view'
|
|
8
|
-
import type { ThemeUtils } from '@milkdown/utils'
|
|
9
|
-
|
|
10
|
-
import type { Status } from './status'
|
|
11
|
-
|
|
12
|
-
export type Props = ReturnType<typeof createProps>
|
|
13
|
-
|
|
14
|
-
const createEmptyStyle = (themeManager: ThemeManager, { css }: Emotion) => {
|
|
15
|
-
const palette = (color: Color, opacity = 1) => themeManager.get(ThemeColor, [color, opacity])
|
|
16
|
-
const typography = themeManager.get(ThemeFont, 'typography')
|
|
17
|
-
|
|
18
|
-
return css`
|
|
19
|
-
position: relative;
|
|
20
|
-
&::before {
|
|
21
|
-
position: absolute;
|
|
22
|
-
cursor: text;
|
|
23
|
-
font-family: ${typography};
|
|
24
|
-
font-size: 14px;
|
|
25
|
-
color: ${palette('neutral', 0.6)};
|
|
26
|
-
content: attr(data-text);
|
|
27
|
-
height: 100%;
|
|
28
|
-
display: flex;
|
|
29
|
-
align-items: center;
|
|
30
|
-
}
|
|
31
|
-
`
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const createSlashStyle = (_: ThemeManager, { css }: Emotion) => css`
|
|
35
|
-
&::before {
|
|
36
|
-
left: 8px;
|
|
37
|
-
}
|
|
38
|
-
`
|
|
39
|
-
|
|
40
|
-
export const createProps = (status: Status, utils: ThemeUtils) => {
|
|
41
|
-
return {
|
|
42
|
-
handleKeyDown: (_: EditorView, event: Event) => {
|
|
43
|
-
if (status.isEmpty())
|
|
44
|
-
return false
|
|
45
|
-
|
|
46
|
-
if (!(event instanceof KeyboardEvent))
|
|
47
|
-
return false
|
|
48
|
-
|
|
49
|
-
if (!['ArrowUp', 'ArrowDown', 'Enter'].includes(event.key))
|
|
50
|
-
return false
|
|
51
|
-
|
|
52
|
-
return true
|
|
53
|
-
},
|
|
54
|
-
decorations: (state: EditorState) => {
|
|
55
|
-
const paragraph = findParentNode(({ type }) => type.name === 'paragraph')(state.selection)
|
|
56
|
-
const uploadPlugin = state.plugins.find(
|
|
57
|
-
x => (x as unknown as { key: string }).key === 'MILKDOWN_UPLOAD$',
|
|
58
|
-
)
|
|
59
|
-
const decorations: DecorationSet = uploadPlugin?.getState(state)
|
|
60
|
-
if (decorations != null && decorations.find(state.selection.from, state.selection.to).length > 0) {
|
|
61
|
-
status.clear()
|
|
62
|
-
return null
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (
|
|
66
|
-
!paragraph
|
|
67
|
-
|| paragraph.node.childCount > 1
|
|
68
|
-
|| state.selection.$from.parentOffset !== paragraph.node.textContent.length
|
|
69
|
-
|| (paragraph.node.firstChild && paragraph.node.firstChild.type.name !== 'text')
|
|
70
|
-
) {
|
|
71
|
-
status.clear()
|
|
72
|
-
return null
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const { placeholder, actions } = status.update({
|
|
76
|
-
parentNode: state.selection.$from.node(state.selection.$from.depth - 1),
|
|
77
|
-
isTopLevel: state.selection.$from.depth === 1,
|
|
78
|
-
content: paragraph.node.textContent,
|
|
79
|
-
state,
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
if (!placeholder)
|
|
83
|
-
return null
|
|
84
|
-
|
|
85
|
-
const createDecoration = (text: string, className: (string | undefined)[]) => {
|
|
86
|
-
const pos = paragraph.pos
|
|
87
|
-
return DecorationSet.create(state.doc, [
|
|
88
|
-
Decoration.node(pos, pos + paragraph.node.nodeSize, {
|
|
89
|
-
'class': className.filter(x => x).join(' '),
|
|
90
|
-
'data-text': text,
|
|
91
|
-
}),
|
|
92
|
-
])
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const emptyStyle = utils.getStyle(emotion => createEmptyStyle(utils.themeManager, emotion))
|
|
96
|
-
const slashStyle = utils.getStyle(emotion => createSlashStyle(utils.themeManager, emotion))
|
|
97
|
-
|
|
98
|
-
if (actions.length)
|
|
99
|
-
return createDecoration(placeholder, [emptyStyle, slashStyle, 'empty-node', 'is-slash'])
|
|
100
|
-
|
|
101
|
-
return createDecoration(placeholder, [emptyStyle, 'empty-node'])
|
|
102
|
-
},
|
|
103
|
-
}
|
|
104
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import type { StatusConfigBuilder, StatusConfigBuilderParams } from '..'
|
|
3
|
-
import type { Action } from '../item'
|
|
4
|
-
import { transformAction } from '../item'
|
|
5
|
-
|
|
6
|
-
export interface StatusCtx {
|
|
7
|
-
placeholder: string | null
|
|
8
|
-
actions: Action[]
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const createStatusCtx = (): StatusCtx => {
|
|
12
|
-
return {
|
|
13
|
-
placeholder: null,
|
|
14
|
-
actions: [],
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export type Status = ReturnType<typeof createStatus>
|
|
19
|
-
|
|
20
|
-
export const createStatus = (builder: StatusConfigBuilder) => {
|
|
21
|
-
const statusCtx = createStatusCtx()
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
get: () => statusCtx,
|
|
25
|
-
clear: () => {
|
|
26
|
-
statusCtx.placeholder = null
|
|
27
|
-
statusCtx.actions = []
|
|
28
|
-
},
|
|
29
|
-
update: (builderParams: StatusConfigBuilderParams) => {
|
|
30
|
-
const config = builder(builderParams)
|
|
31
|
-
statusCtx.placeholder = config?.placeholder ?? null
|
|
32
|
-
statusCtx.actions = (config?.actions ?? []).map(transformAction)
|
|
33
|
-
return statusCtx
|
|
34
|
-
},
|
|
35
|
-
isEmpty: () => statusCtx.actions.length === 0,
|
|
36
|
-
}
|
|
37
|
-
}
|
package/src/prose-plugin/view.ts
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import { missingRootElement } from '@milkdown/exception'
|
|
3
|
-
import { calculateNodePosition } from '@milkdown/prose'
|
|
4
|
-
import type { EditorView } from '@milkdown/prose/view'
|
|
5
|
-
import type { ThemeUtils } from '@milkdown/utils'
|
|
6
|
-
|
|
7
|
-
import { createDropdown } from '../utility'
|
|
8
|
-
import { renderDropdown } from './dropdown'
|
|
9
|
-
import {
|
|
10
|
-
createMouseManager,
|
|
11
|
-
handleClick,
|
|
12
|
-
handleKeydown,
|
|
13
|
-
handleMouseEnter,
|
|
14
|
-
handleMouseLeave,
|
|
15
|
-
handleMouseMove,
|
|
16
|
-
} from './input'
|
|
17
|
-
import type { Status } from './status'
|
|
18
|
-
|
|
19
|
-
export const defaultCalcPosition = (view: EditorView, dropdownElement: HTMLElement) => {
|
|
20
|
-
calculateNodePosition(view, dropdownElement, (selected, target, parent) => {
|
|
21
|
-
const $editor = dropdownElement.parentElement
|
|
22
|
-
if (!$editor)
|
|
23
|
-
throw missingRootElement()
|
|
24
|
-
|
|
25
|
-
let left = selected.left - parent.left
|
|
26
|
-
|
|
27
|
-
if (left < 0)
|
|
28
|
-
left = 0
|
|
29
|
-
|
|
30
|
-
let direction: 'top' | 'bottom'
|
|
31
|
-
let maxHeight: number | undefined
|
|
32
|
-
const selectedToTop = selected.top - parent.top
|
|
33
|
-
const selectedToBottom = parent.height + parent.top - selected.bottom
|
|
34
|
-
if (selectedToBottom >= target.height + 28) {
|
|
35
|
-
direction = 'bottom'
|
|
36
|
-
}
|
|
37
|
-
else if (selectedToTop >= target.height + 28) {
|
|
38
|
-
direction = 'top'
|
|
39
|
-
}
|
|
40
|
-
else if (selectedToBottom >= selectedToTop) {
|
|
41
|
-
direction = 'bottom'
|
|
42
|
-
maxHeight = selectedToBottom - 28
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
direction = 'top'
|
|
46
|
-
maxHeight = selectedToTop - 28
|
|
47
|
-
}
|
|
48
|
-
if (selectedToTop < 0 || selectedToBottom < 0) {
|
|
49
|
-
maxHeight = parent.height - selected.height - 28
|
|
50
|
-
if (maxHeight > target.height)
|
|
51
|
-
maxHeight = undefined
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const top
|
|
55
|
-
= direction === 'top'
|
|
56
|
-
? selected.top - parent.top - (maxHeight ?? target.height) - 14 + $editor.scrollTop
|
|
57
|
-
: selected.bottom - parent.top + 14 + $editor.scrollTop
|
|
58
|
-
|
|
59
|
-
dropdownElement.style.maxHeight = maxHeight !== undefined && maxHeight > 0 ? `${maxHeight}px` : ''
|
|
60
|
-
|
|
61
|
-
return [top, left]
|
|
62
|
-
})
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export type CalcPosition = (view: EditorView, dropdownElement: HTMLElement) => void
|
|
66
|
-
|
|
67
|
-
export const createView = (
|
|
68
|
-
status: Status,
|
|
69
|
-
view: EditorView,
|
|
70
|
-
utils: ThemeUtils,
|
|
71
|
-
className: string,
|
|
72
|
-
calcPosition: CalcPosition,
|
|
73
|
-
) => {
|
|
74
|
-
const wrapper = view.dom.parentNode
|
|
75
|
-
if (!wrapper)
|
|
76
|
-
return {}
|
|
77
|
-
|
|
78
|
-
const dropdownElement = createDropdown(utils, className)
|
|
79
|
-
const mouseManager = createMouseManager()
|
|
80
|
-
wrapper.appendChild(dropdownElement)
|
|
81
|
-
|
|
82
|
-
const _mouseMove = handleMouseMove(mouseManager)
|
|
83
|
-
const _mouseDown = handleClick(status, view, dropdownElement)
|
|
84
|
-
const _keydown = handleKeydown(status, view, dropdownElement, mouseManager)
|
|
85
|
-
const _mouseEnter = handleMouseEnter(status, mouseManager)
|
|
86
|
-
const _mouseLeave = handleMouseLeave()
|
|
87
|
-
|
|
88
|
-
wrapper.addEventListener('mousemove', _mouseMove)
|
|
89
|
-
wrapper.addEventListener('mousedown', _mouseDown)
|
|
90
|
-
wrapper.addEventListener('keydown', _keydown)
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
update: (view: EditorView) => {
|
|
94
|
-
const show = renderDropdown(status, dropdownElement, {
|
|
95
|
-
mouseEnter: _mouseEnter as EventListener,
|
|
96
|
-
mouseLeave: _mouseLeave as EventListener,
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
if (!show)
|
|
100
|
-
return
|
|
101
|
-
|
|
102
|
-
calcPosition(view, dropdownElement)
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
destroy: () => {
|
|
106
|
-
wrapper.removeEventListener('mousemove', _mouseMove)
|
|
107
|
-
wrapper.removeEventListener('mousedown', _mouseDown)
|
|
108
|
-
wrapper.removeEventListener('keydown', _keydown)
|
|
109
|
-
dropdownElement.remove()
|
|
110
|
-
},
|
|
111
|
-
}
|
|
112
|
-
}
|
package/src/style.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import type {
|
|
3
|
-
Color,
|
|
4
|
-
Emotion,
|
|
5
|
-
ThemeManager,
|
|
6
|
-
} from '@milkdown/core'
|
|
7
|
-
import {
|
|
8
|
-
ThemeBorder,
|
|
9
|
-
ThemeColor,
|
|
10
|
-
ThemeFont,
|
|
11
|
-
ThemeScrollbar,
|
|
12
|
-
ThemeShadow,
|
|
13
|
-
ThemeSize,
|
|
14
|
-
} from '@milkdown/core'
|
|
15
|
-
|
|
16
|
-
const itemStyle = (themeManager: ThemeManager, { css }: Emotion) => {
|
|
17
|
-
const palette = (color: Color, opacity = 1) => themeManager.get(ThemeColor, [color, opacity])
|
|
18
|
-
return css`
|
|
19
|
-
.slash-dropdown-item {
|
|
20
|
-
display: flex;
|
|
21
|
-
gap: 32px;
|
|
22
|
-
height: 48px;
|
|
23
|
-
padding: 0 16px;
|
|
24
|
-
align-items: center;
|
|
25
|
-
justify-content: flex-start;
|
|
26
|
-
cursor: pointer;
|
|
27
|
-
line-height: 48px;
|
|
28
|
-
font-family: ${themeManager.get(ThemeFont, 'typography')};
|
|
29
|
-
font-size: 14px;
|
|
30
|
-
|
|
31
|
-
transition: all 0.2s ease-in-out;
|
|
32
|
-
|
|
33
|
-
&,
|
|
34
|
-
.icon {
|
|
35
|
-
color: ${palette('neutral', 0.87)};
|
|
36
|
-
transition: all 0.2s ease-in-out;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
&.hide {
|
|
40
|
-
display: none;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
&.active {
|
|
44
|
-
background: ${palette('secondary', 0.12)};
|
|
45
|
-
&,
|
|
46
|
-
.icon {
|
|
47
|
-
color: ${palette('primary')};
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
`
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export const injectStyle = (themeManager: ThemeManager, emotion: Emotion) => {
|
|
55
|
-
const palette = (color: Color, opacity = 1) => themeManager.get(ThemeColor, [color, opacity])
|
|
56
|
-
|
|
57
|
-
return emotion.css`
|
|
58
|
-
width: 320px;
|
|
59
|
-
min-height: 48px;
|
|
60
|
-
max-height: 320px;
|
|
61
|
-
overflow-y: auto;
|
|
62
|
-
border-radius: ${themeManager.get(ThemeSize, 'radius')};
|
|
63
|
-
position: absolute;
|
|
64
|
-
background: ${palette('surface')};
|
|
65
|
-
|
|
66
|
-
${themeManager.get(ThemeBorder, undefined)}
|
|
67
|
-
${themeManager.get(ThemeShadow, undefined)}
|
|
68
|
-
${themeManager.get(ThemeScrollbar, undefined)}
|
|
69
|
-
|
|
70
|
-
&.hide {
|
|
71
|
-
display: none;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
${itemStyle(themeManager, emotion)}
|
|
75
|
-
`
|
|
76
|
-
}
|
package/src/utility.ts
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import type { ThemeManager } from '@milkdown/core'
|
|
3
|
-
import { ThemeIcon } from '@milkdown/core'
|
|
4
|
-
import type { Icon } from '@milkdown/design-system'
|
|
5
|
-
import { missingIcon } from '@milkdown/exception'
|
|
6
|
-
import type { Node } from '@milkdown/prose/model'
|
|
7
|
-
import type { Command } from '@milkdown/prose/state'
|
|
8
|
-
import type { ThemeUtils } from '@milkdown/utils'
|
|
9
|
-
|
|
10
|
-
import { injectStyle } from './style'
|
|
11
|
-
|
|
12
|
-
export const createDropdown = (utils: ThemeUtils, className: string) => {
|
|
13
|
-
const div = document.createElement('div')
|
|
14
|
-
div.setAttribute('role', 'listbox')
|
|
15
|
-
div.setAttribute('tabindex', '-1')
|
|
16
|
-
utils.themeManager.onFlush(() => {
|
|
17
|
-
const style = utils.getStyle(emotion => injectStyle(utils.themeManager, emotion))
|
|
18
|
-
|
|
19
|
-
if (style)
|
|
20
|
-
div.classList.add(style)
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
div.classList.add(utils.getClassName({}, className), 'hide')
|
|
24
|
-
|
|
25
|
-
return div
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface ItemOptions {
|
|
29
|
-
textClassName: string
|
|
30
|
-
}
|
|
31
|
-
export const createDropdownItem = (
|
|
32
|
-
themeManager: ThemeManager,
|
|
33
|
-
text: string,
|
|
34
|
-
icon: Icon,
|
|
35
|
-
options?: Partial<ItemOptions>,
|
|
36
|
-
) => {
|
|
37
|
-
const textClassName = options?.textClassName ?? 'text'
|
|
38
|
-
|
|
39
|
-
const div = document.createElement('div')
|
|
40
|
-
div.setAttribute('role', 'option')
|
|
41
|
-
div.classList.add('slash-dropdown-item')
|
|
42
|
-
|
|
43
|
-
const iconSpan = themeManager.get(ThemeIcon, icon)
|
|
44
|
-
|
|
45
|
-
if (!iconSpan)
|
|
46
|
-
throw missingIcon(icon)
|
|
47
|
-
|
|
48
|
-
const textSpan = document.createElement('span')
|
|
49
|
-
textSpan.textContent = text
|
|
50
|
-
textSpan.className = textClassName
|
|
51
|
-
|
|
52
|
-
div.appendChild(iconSpan.dom)
|
|
53
|
-
div.appendChild(textSpan)
|
|
54
|
-
|
|
55
|
-
return div
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export const getDepth = (node: Node) => {
|
|
59
|
-
let cur = node
|
|
60
|
-
let depth = 0
|
|
61
|
-
while (cur.childCount) {
|
|
62
|
-
cur = cur.child(0)
|
|
63
|
-
depth += 1
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return depth
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const cleanUp: Command = (state, dispatch) => {
|
|
70
|
-
const { selection } = state
|
|
71
|
-
const { $from } = selection
|
|
72
|
-
const tr = state.tr.deleteRange($from.start(), $from.pos)
|
|
73
|
-
dispatch?.(tr)
|
|
74
|
-
return false
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export const cleanUpAndCreateNode
|
|
78
|
-
= (createCommand: () => void): Command =>
|
|
79
|
-
(state, dispatch, view) => {
|
|
80
|
-
if (view) {
|
|
81
|
-
cleanUp(state, dispatch, view)
|
|
82
|
-
createCommand()
|
|
83
|
-
}
|
|
84
|
-
return true
|
|
85
|
-
}
|