@milkdown/plugin-tooltip 4.11.2 → 4.13.2
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/README.md +3 -0
- package/lib/button-manager/create-tooltip.d.ts +6 -1
- package/lib/button-manager/create-tooltip.d.ts.map +1 -1
- package/lib/button-manager/create-tooltip.js +11 -7
- package/lib/button-manager/create-tooltip.js.map +1 -1
- package/lib/button-manager/index.d.ts +2 -1
- package/lib/button-manager/index.d.ts.map +1 -1
- package/lib/button-manager/index.js +3 -2
- package/lib/button-manager/index.js.map +1 -1
- package/lib/button-manager/style.d.ts.map +1 -1
- package/lib/button-manager/style.js +1 -0
- package/lib/button-manager/style.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +32 -11
- package/lib/index.js.map +1 -1
- package/lib/input-manager/filter-input.d.ts +16 -1
- package/lib/input-manager/filter-input.d.ts.map +1 -1
- package/lib/input-manager/filter-input.js +8 -2
- package/lib/input-manager/filter-input.js.map +1 -1
- package/lib/input-manager/index.d.ts +2 -1
- package/lib/input-manager/index.d.ts.map +1 -1
- package/lib/input-manager/index.js +19 -7
- package/lib/input-manager/index.js.map +1 -1
- package/lib/input-manager/style.d.ts.map +1 -1
- package/lib/input-manager/style.js +5 -1
- package/lib/input-manager/style.js.map +1 -1
- package/lib/item.d.ts +10 -2
- package/lib/item.d.ts.map +1 -1
- package/lib/item.js +4 -2
- package/lib/item.js.map +1 -1
- package/lib/selection-marks-tooltip.d.ts +3 -1
- package/lib/selection-marks-tooltip.d.ts.map +1 -1
- package/lib/selection-marks-tooltip.js +13 -5
- package/lib/selection-marks-tooltip.js.map +1 -1
- package/lib/utility/input.d.ts +2 -0
- package/lib/utility/input.d.ts.map +1 -1
- package/lib/utility/input.js +33 -0
- package/lib/utility/input.js.map +1 -1
- package/lib/utility/prosemirror.d.ts.map +1 -1
- package/lib/utility/prosemirror.js +2 -2
- package/lib/utility/prosemirror.js.map +1 -1
- package/package.json +5 -3
- package/src/button-manager/calc-button-pos.ts +16 -0
- package/src/button-manager/create-tooltip.ts +32 -0
- package/src/button-manager/filter-button.ts +28 -0
- package/src/button-manager/index.ts +44 -0
- package/src/button-manager/no-active.ts +10 -0
- package/src/button-manager/style.ts +50 -0
- package/src/index.ts +56 -0
- package/src/input-manager/calc-input-pos.ts +15 -0
- package/src/input-manager/create-input.ts +39 -0
- package/src/input-manager/filter-input.ts +33 -0
- package/src/input-manager/index.ts +55 -0
- package/src/input-manager/style.ts +67 -0
- package/src/item.ts +117 -0
- package/src/selection-marks-tooltip.ts +50 -0
- package/src/utility/element.ts +3 -0
- package/src/utility/index.ts +5 -0
- package/src/utility/input.ts +133 -0
- package/src/utility/prosemirror.ts +37 -0
- package/src/utility/toggle.ts +21 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
+
import { Utils } from '@milkdown/utils';
|
|
3
|
+
import type { EditorState } from 'prosemirror-state';
|
|
4
|
+
import type { EditorView } from 'prosemirror-view';
|
|
5
|
+
|
|
6
|
+
import { createButtonManager } from './button-manager';
|
|
7
|
+
import { createInputManager } from './input-manager';
|
|
8
|
+
import type { ButtonMap, InputMap } from './item';
|
|
9
|
+
|
|
10
|
+
export const createPlugin = (buttonMap: ButtonMap, inputMap: InputMap, utils: Utils) => {
|
|
11
|
+
const buttonManager = createButtonManager(buttonMap, utils);
|
|
12
|
+
const inputManager = createInputManager(inputMap, utils);
|
|
13
|
+
let shouldHide = false;
|
|
14
|
+
|
|
15
|
+
const hide = () => {
|
|
16
|
+
buttonManager.hide();
|
|
17
|
+
inputManager.hide();
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const update = (view: EditorView, prevState?: EditorState) => {
|
|
21
|
+
const { state } = view;
|
|
22
|
+
|
|
23
|
+
if (!view.editable || shouldHide) {
|
|
24
|
+
hide();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const isEqualSelection = prevState?.doc.eq(state.doc) && prevState.selection.eq(state.selection);
|
|
29
|
+
if (isEqualSelection) return;
|
|
30
|
+
|
|
31
|
+
buttonManager.update(view);
|
|
32
|
+
inputManager.update(view);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
update,
|
|
37
|
+
destroy: () => {
|
|
38
|
+
buttonManager.destroy();
|
|
39
|
+
inputManager.destroy();
|
|
40
|
+
},
|
|
41
|
+
render: (editorView: EditorView) => {
|
|
42
|
+
buttonManager.render(editorView);
|
|
43
|
+
inputManager.render(editorView);
|
|
44
|
+
update(editorView);
|
|
45
|
+
},
|
|
46
|
+
setHide: (isTyping: boolean) => {
|
|
47
|
+
shouldHide = isTyping;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
+
import { commandsCtx, Ctx } from '@milkdown/core';
|
|
3
|
+
import { ModifyInlineMath } from '@milkdown/plugin-math';
|
|
4
|
+
import { ModifyImage, ModifyLink } from '@milkdown/preset-commonmark';
|
|
5
|
+
import { findChildren } from '@milkdown/utils';
|
|
6
|
+
import { Node as ProseNode } from 'prosemirror-model';
|
|
7
|
+
|
|
8
|
+
import { Event2Command, Updater } from '../item';
|
|
9
|
+
import { elementIsTag } from './element';
|
|
10
|
+
|
|
11
|
+
export const modifyLink =
|
|
12
|
+
(ctx: Ctx): Event2Command =>
|
|
13
|
+
(e) => {
|
|
14
|
+
const { target } = e;
|
|
15
|
+
if (!(target instanceof HTMLElement)) {
|
|
16
|
+
return () => true;
|
|
17
|
+
}
|
|
18
|
+
if (elementIsTag(target, 'input')) {
|
|
19
|
+
target.focus();
|
|
20
|
+
return () => false;
|
|
21
|
+
}
|
|
22
|
+
const parent = target.parentNode;
|
|
23
|
+
if (!parent) return () => false;
|
|
24
|
+
|
|
25
|
+
const inputEl = Array.from(parent.children).find((el) => el.tagName === 'INPUT');
|
|
26
|
+
if (!(inputEl instanceof HTMLInputElement)) return () => false;
|
|
27
|
+
|
|
28
|
+
return ctx.get(commandsCtx).call(ModifyLink, inputEl.value);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const modifyInlineMath =
|
|
32
|
+
(ctx: Ctx): Event2Command =>
|
|
33
|
+
(e) => {
|
|
34
|
+
const { target } = e;
|
|
35
|
+
if (!(target instanceof HTMLElement)) {
|
|
36
|
+
return () => true;
|
|
37
|
+
}
|
|
38
|
+
const parent = target.parentNode;
|
|
39
|
+
if (!parent) return () => false;
|
|
40
|
+
|
|
41
|
+
const inputEl = Array.from(parent.children).find((el) => el.tagName === 'INPUT');
|
|
42
|
+
if (!(inputEl instanceof HTMLInputElement)) return () => false;
|
|
43
|
+
|
|
44
|
+
return ctx.get(commandsCtx).call(ModifyInlineMath, inputEl.value);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const modifyImage =
|
|
48
|
+
(ctx: Ctx): Event2Command =>
|
|
49
|
+
(e) => {
|
|
50
|
+
const { target } = e;
|
|
51
|
+
if (!(target instanceof HTMLElement)) {
|
|
52
|
+
return () => true;
|
|
53
|
+
}
|
|
54
|
+
if (elementIsTag(target, 'input')) {
|
|
55
|
+
target.focus();
|
|
56
|
+
return () => false;
|
|
57
|
+
}
|
|
58
|
+
const parent = target.parentNode;
|
|
59
|
+
if (!parent) return () => false;
|
|
60
|
+
|
|
61
|
+
const inputEl = Array.from(parent.children).find((el) => el.tagName === 'INPUT');
|
|
62
|
+
if (!(inputEl instanceof HTMLInputElement)) return () => false;
|
|
63
|
+
|
|
64
|
+
return ctx.get(commandsCtx).call(ModifyImage, inputEl.value);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const updateLinkView: Updater = (view, $) => {
|
|
68
|
+
const { marks } = view.state.schema;
|
|
69
|
+
const { firstChild, lastElementChild } = $;
|
|
70
|
+
if (!(firstChild instanceof HTMLInputElement) || !(lastElementChild instanceof HTMLButtonElement)) return;
|
|
71
|
+
|
|
72
|
+
const { selection } = view.state;
|
|
73
|
+
let node: ProseNode | undefined;
|
|
74
|
+
view.state.doc.nodesBetween(selection.from, selection.to, (n) => {
|
|
75
|
+
if (marks.link.isInSet(n.marks)) {
|
|
76
|
+
node = n;
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
});
|
|
81
|
+
if (!node) return;
|
|
82
|
+
|
|
83
|
+
const mark = node.marks.find((m) => m.type === marks.link);
|
|
84
|
+
if (!mark) return;
|
|
85
|
+
|
|
86
|
+
const value = mark.attrs.href;
|
|
87
|
+
firstChild.value = value;
|
|
88
|
+
if (!value) {
|
|
89
|
+
lastElementChild.classList.add('disable');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (lastElementChild.classList.contains('disable')) {
|
|
93
|
+
lastElementChild.classList.remove('disable');
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const updateInlineMathView: Updater = (view, $) => {
|
|
98
|
+
const { nodes } = view.state.schema;
|
|
99
|
+
const { firstChild, lastElementChild } = $;
|
|
100
|
+
if (!(firstChild instanceof HTMLInputElement) || !(lastElementChild instanceof HTMLButtonElement)) return;
|
|
101
|
+
|
|
102
|
+
const node = findChildren((node) => node.type === nodes.math_inline)(view.state.selection.$from.node())[0]?.node;
|
|
103
|
+
if (!node) return;
|
|
104
|
+
|
|
105
|
+
const value = node.attrs.value;
|
|
106
|
+
firstChild.value = value;
|
|
107
|
+
if (!value) {
|
|
108
|
+
lastElementChild.classList.add('disable');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (lastElementChild.classList.contains('disable')) {
|
|
112
|
+
lastElementChild.classList.remove('disable');
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export const updateImageView: Updater = (view, $) => {
|
|
117
|
+
const { nodes } = view.state.schema;
|
|
118
|
+
const { firstChild, lastElementChild } = $;
|
|
119
|
+
if (!(firstChild instanceof HTMLInputElement) || !(lastElementChild instanceof HTMLButtonElement)) return;
|
|
120
|
+
|
|
121
|
+
const node = findChildren((node) => node.type === nodes.image)(view.state.selection.$from.node())[0]?.node;
|
|
122
|
+
if (!node) return;
|
|
123
|
+
|
|
124
|
+
const value = node.attrs.src;
|
|
125
|
+
firstChild.value = value;
|
|
126
|
+
if (!value) {
|
|
127
|
+
lastElementChild.classList.add('disable');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (lastElementChild.classList.contains('disable')) {
|
|
131
|
+
lastElementChild.classList.remove('disable');
|
|
132
|
+
}
|
|
133
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
+
import { findParentNode } from '@milkdown/utils';
|
|
3
|
+
import type { MarkType, Node, NodeType } from 'prosemirror-model';
|
|
4
|
+
import { EditorState, TextSelection } from 'prosemirror-state';
|
|
5
|
+
|
|
6
|
+
export type Position = {
|
|
7
|
+
start: number;
|
|
8
|
+
end: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const hasMark = (editorState: EditorState, type: MarkType): boolean => {
|
|
12
|
+
const { from, to } = editorState.selection;
|
|
13
|
+
|
|
14
|
+
return editorState.doc.rangeHasMark(from, from === to ? to + 1 : to, type);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const isTextSelection = (editorState: EditorState): boolean => {
|
|
18
|
+
const { selection } = editorState;
|
|
19
|
+
if (selection instanceof TextSelection) {
|
|
20
|
+
const text = editorState.doc.textBetween(selection.from, selection.to);
|
|
21
|
+
|
|
22
|
+
if (!text) return false;
|
|
23
|
+
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const isInCodeFence = (editorState: EditorState): boolean =>
|
|
30
|
+
Boolean(findParentNode((node) => !!node.type.spec.code)(editorState.selection));
|
|
31
|
+
|
|
32
|
+
export const isTextAndNotHasMark = (editorState: EditorState, mark: MarkType): boolean =>
|
|
33
|
+
!isTextSelection(editorState) || isInCodeFence(editorState) || hasMark(editorState, mark);
|
|
34
|
+
|
|
35
|
+
export const equalNodeType = (nodeType: NodeType, node: Node) => {
|
|
36
|
+
return (Array.isArray(nodeType) && nodeType.indexOf(node.type) > -1) || node.type === nodeType;
|
|
37
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
+
import { CmdKey, commandsCtx, Ctx, themeToolCtx } from '@milkdown/core';
|
|
3
|
+
import type { Icon } from '@milkdown/design-system';
|
|
4
|
+
import type { MarkType } from 'prosemirror-model';
|
|
5
|
+
|
|
6
|
+
import type { ButtonItem } from '../item';
|
|
7
|
+
import { hasMark, isTextAndNotHasMark } from './prosemirror';
|
|
8
|
+
|
|
9
|
+
export const createToggleIcon = <T>(
|
|
10
|
+
ctx: Ctx,
|
|
11
|
+
iconName: Icon,
|
|
12
|
+
commandKey: CmdKey<T>,
|
|
13
|
+
mark: MarkType,
|
|
14
|
+
disableForMark: MarkType,
|
|
15
|
+
): ButtonItem => ({
|
|
16
|
+
$: ctx.get(themeToolCtx).slots.icon(iconName),
|
|
17
|
+
command: () => ctx.get(commandsCtx).call(commandKey),
|
|
18
|
+
active: (view) => hasMark(view.state, mark),
|
|
19
|
+
disable: (view) => isTextAndNotHasMark(view.state, disableForMark),
|
|
20
|
+
enable: (view) => !!mark && !!view.state.schema.marks[mark.name],
|
|
21
|
+
});
|