@kerebron/extension-menu 0.2.0 → 0.2.1
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/esm/editor/src/CoreEditor.d.ts +25 -0
- package/esm/editor/src/CoreEditor.d.ts.map +1 -0
- package/esm/editor/src/CoreEditor.js +197 -0
- package/esm/editor/src/Extension.d.ts +26 -0
- package/esm/editor/src/Extension.d.ts.map +1 -0
- package/esm/editor/src/Extension.js +33 -0
- package/esm/editor/src/ExtensionManager.d.ts +32 -0
- package/esm/editor/src/ExtensionManager.d.ts.map +1 -0
- package/esm/editor/src/ExtensionManager.js +253 -0
- package/esm/editor/src/Mark.d.ts +18 -0
- package/esm/editor/src/Mark.d.ts.map +1 -0
- package/esm/editor/src/Mark.js +34 -0
- package/esm/editor/src/Node.d.ts +27 -0
- package/esm/editor/src/Node.d.ts.map +1 -0
- package/esm/editor/src/Node.js +43 -0
- package/esm/editor/src/commands/CommandManager.d.ts +20 -0
- package/esm/editor/src/commands/CommandManager.d.ts.map +1 -0
- package/esm/editor/src/commands/CommandManager.js +60 -0
- package/esm/editor/src/commands/createChainableState.d.ts +3 -0
- package/esm/editor/src/commands/createChainableState.d.ts.map +1 -0
- package/esm/editor/src/commands/createChainableState.js +29 -0
- package/esm/editor/src/commands/mod.d.ts +49 -0
- package/esm/editor/src/commands/mod.d.ts.map +1 -0
- package/esm/editor/src/commands/mod.js +928 -0
- package/esm/editor/src/mod.d.ts +6 -0
- package/esm/editor/src/mod.d.ts.map +1 -0
- package/esm/editor/src/mod.js +5 -0
- package/esm/editor/src/nodeToTreeString.d.ts +4 -0
- package/esm/editor/src/nodeToTreeString.d.ts.map +1 -0
- package/esm/editor/src/nodeToTreeString.js +56 -0
- package/esm/editor/src/plugins/input-rules/InputRulesPlugin.d.ts +23 -0
- package/esm/editor/src/plugins/input-rules/InputRulesPlugin.d.ts.map +1 -0
- package/esm/editor/src/plugins/input-rules/InputRulesPlugin.js +163 -0
- package/esm/editor/src/types.d.ts +29 -0
- package/esm/editor/src/types.d.ts.map +1 -0
- package/esm/editor/src/types.js +1 -0
- package/esm/editor/src/utilities/createNodeFromContent.d.ts +8 -0
- package/esm/editor/src/utilities/createNodeFromContent.d.ts.map +1 -0
- package/esm/editor/src/utilities/createNodeFromContent.js +33 -0
- package/esm/editor/src/utilities/getHtmlAttributes.d.ts +4 -0
- package/esm/editor/src/utilities/getHtmlAttributes.d.ts.map +1 -0
- package/esm/editor/src/utilities/getHtmlAttributes.js +47 -0
- package/esm/extension-menu/src/ExtensionMenu.d.ts +17 -0
- package/esm/extension-menu/src/ExtensionMenu.d.ts.map +1 -0
- package/esm/extension-menu/src/ExtensionMenu.js +318 -0
- package/esm/extension-menu/src/MenuPlugin.d.ts +9 -0
- package/esm/extension-menu/src/MenuPlugin.d.ts.map +1 -0
- package/esm/extension-menu/src/MenuPlugin.js +245 -0
- package/esm/extension-menu/src/icons.d.ts +15 -0
- package/esm/extension-menu/src/icons.d.ts.map +1 -0
- package/esm/extension-menu/src/icons.js +118 -0
- package/esm/extension-menu/src/menu.d.ts +88 -0
- package/esm/extension-menu/src/menu.d.ts.map +1 -0
- package/esm/extension-menu/src/menu.js +392 -0
- package/esm/extension-menu/src/prompt.d.ts +36 -0
- package/esm/extension-menu/src/prompt.d.ts.map +1 -0
- package/esm/extension-menu/src/prompt.js +158 -0
- package/esm/package.json +3 -0
- package/package.json +1 -4
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { NodeSelection } from 'prosemirror-state';
|
|
2
|
+
import { Extension } from '../../editor/src/mod.js';
|
|
3
|
+
import { toggleMark, wrapInList } from '../../editor/src/commands/mod.js';
|
|
4
|
+
import { blockTypeItem, Dropdown, DropdownSubmenu, MenuItem, wrapItem, } from './menu.js';
|
|
5
|
+
import { MenuPlugin } from './MenuPlugin.js';
|
|
6
|
+
import { icons } from './icons.js';
|
|
7
|
+
import { openPrompt, TextField } from './prompt.js';
|
|
8
|
+
export { blockTypeItem, Dropdown, DropdownSubmenu,
|
|
9
|
+
// MenuElement,
|
|
10
|
+
MenuItem,
|
|
11
|
+
// MenuItemSpec,
|
|
12
|
+
wrapItem, } from './menu.js';
|
|
13
|
+
function canInsert(state, nodeType) {
|
|
14
|
+
let $from = state.selection.$from;
|
|
15
|
+
for (let d = $from.depth; d >= 0; d--) {
|
|
16
|
+
let index = $from.index(d);
|
|
17
|
+
if ($from.node(d).canReplaceWith(index, index, nodeType))
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
function cmdItem(cmd, options) {
|
|
23
|
+
let passedOptions = {
|
|
24
|
+
label: options.title,
|
|
25
|
+
run: cmd,
|
|
26
|
+
};
|
|
27
|
+
for (let prop in options) {
|
|
28
|
+
passedOptions[prop] = options[prop];
|
|
29
|
+
}
|
|
30
|
+
if (!options.enable && !options.select) {
|
|
31
|
+
passedOptions[options.enable ? 'enable' : 'select'] = (state) => cmd(state);
|
|
32
|
+
}
|
|
33
|
+
return new MenuItem(passedOptions);
|
|
34
|
+
}
|
|
35
|
+
function markActive(state, type) {
|
|
36
|
+
let { from, $from, to, empty } = state.selection;
|
|
37
|
+
if (empty)
|
|
38
|
+
return !!type.isInSet(state.storedMarks || $from.marks());
|
|
39
|
+
else
|
|
40
|
+
return state.doc.rangeHasMark(from, to, type);
|
|
41
|
+
}
|
|
42
|
+
function markItem(markType, options) {
|
|
43
|
+
let passedOptions = {
|
|
44
|
+
active(state) {
|
|
45
|
+
return markActive(state, markType);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
for (let prop in options) {
|
|
49
|
+
passedOptions[prop] = options[prop];
|
|
50
|
+
}
|
|
51
|
+
return cmdItem(toggleMark(markType), passedOptions);
|
|
52
|
+
}
|
|
53
|
+
function wrapListItem(nodeType, options) {
|
|
54
|
+
return cmdItem(wrapInList(nodeType, options.attrs), options);
|
|
55
|
+
}
|
|
56
|
+
const cut = (arr) => arr.filter((x) => x);
|
|
57
|
+
export function buildMenu(editor, schema) {
|
|
58
|
+
const menu = [];
|
|
59
|
+
if (schema.marks.strong) {
|
|
60
|
+
menu.push(new MenuItem({
|
|
61
|
+
title: 'Toggle strong assets',
|
|
62
|
+
run: () => editor.chain().toggleStrong().run(),
|
|
63
|
+
enable: (state) => editor.can().toggleStrong().run(),
|
|
64
|
+
icon: icons.strong,
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
if (schema.marks.em) {
|
|
68
|
+
menu.push(new MenuItem({
|
|
69
|
+
title: 'Toggle emphasis',
|
|
70
|
+
run: () => editor.chain().toggleItalic().run(),
|
|
71
|
+
enable: (state) => editor.can().toggleItalic().run(),
|
|
72
|
+
icon: icons.em,
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
if (schema.marks.underline) {
|
|
76
|
+
menu.push(new MenuItem({
|
|
77
|
+
title: 'Toggle underline',
|
|
78
|
+
label: '_',
|
|
79
|
+
run: () => editor.chain().toggleUnderline().run(),
|
|
80
|
+
enable: (state) => editor.can().toggleUnderline().run(),
|
|
81
|
+
// icon: icons.underline
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
if (schema.marks.code) {
|
|
85
|
+
menu.push(markItem(schema.marks.code, {
|
|
86
|
+
title: 'Toggle code font',
|
|
87
|
+
icon: icons.code,
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
if (schema.marks.link) {
|
|
91
|
+
const markType = schema.marks.link;
|
|
92
|
+
menu.push(new MenuItem({
|
|
93
|
+
title: 'Add or remove link',
|
|
94
|
+
icon: icons.link,
|
|
95
|
+
active(state) {
|
|
96
|
+
return markActive(state, markType);
|
|
97
|
+
},
|
|
98
|
+
enable(state) {
|
|
99
|
+
return !state.selection.empty;
|
|
100
|
+
},
|
|
101
|
+
run(state, dispatch, view) {
|
|
102
|
+
if (markActive(state, markType)) {
|
|
103
|
+
toggleMark(markType)(state, dispatch);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
openPrompt({
|
|
107
|
+
title: 'Create a link',
|
|
108
|
+
fields: {
|
|
109
|
+
href: new TextField({
|
|
110
|
+
label: 'Link target',
|
|
111
|
+
required: true,
|
|
112
|
+
}),
|
|
113
|
+
title: new TextField({ label: 'Title' }),
|
|
114
|
+
},
|
|
115
|
+
callback(attrs) {
|
|
116
|
+
toggleMark(markType, attrs)(view.state, view.dispatch);
|
|
117
|
+
view.focus();
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
const blockMenu = [];
|
|
124
|
+
const insertMenu = [];
|
|
125
|
+
const typeMenu = [];
|
|
126
|
+
if (schema.nodes.bullet_list) {
|
|
127
|
+
blockMenu.push(wrapListItem(schema.nodes.bullet_list, {
|
|
128
|
+
title: 'Wrap in bullet list',
|
|
129
|
+
icon: icons.bulletList,
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
if (schema.nodes.ordered_list) {
|
|
133
|
+
blockMenu.push(wrapListItem(schema.nodes.ordered_list, {
|
|
134
|
+
title: 'Wrap in ordered list',
|
|
135
|
+
icon: icons.orderedList,
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
if (schema.nodes.blockquote) {
|
|
139
|
+
blockMenu.push(wrapItem(schema.nodes.blockquote, {
|
|
140
|
+
title: 'Wrap in block quote',
|
|
141
|
+
icon: icons.blockquote,
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
if (schema.nodes.paragraph) {
|
|
145
|
+
typeMenu.push(blockTypeItem(schema.nodes.paragraph, {
|
|
146
|
+
title: 'Change to paragraph',
|
|
147
|
+
label: 'Plain',
|
|
148
|
+
}));
|
|
149
|
+
}
|
|
150
|
+
if (schema.nodes.code_block) {
|
|
151
|
+
typeMenu.push(blockTypeItem(schema.nodes.code_block, {
|
|
152
|
+
title: 'Change to code block',
|
|
153
|
+
label: 'Code',
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
if (schema.nodes.heading) {
|
|
157
|
+
const makeHeadMenu = [];
|
|
158
|
+
for (let i = 1; i <= 6; i++) {
|
|
159
|
+
makeHeadMenu.push(blockTypeItem(schema.nodes.heading, {
|
|
160
|
+
title: 'Change to heading ' + i,
|
|
161
|
+
label: 'Level ' + i,
|
|
162
|
+
attrs: { level: i },
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
typeMenu.push(new DropdownSubmenu(makeHeadMenu, { label: 'Heading' }));
|
|
166
|
+
}
|
|
167
|
+
blockMenu.push(new MenuItem({
|
|
168
|
+
title: 'Join with above block',
|
|
169
|
+
run: () => editor.chain().joinUp().run(),
|
|
170
|
+
select: () => editor.can().joinUp().run(),
|
|
171
|
+
icon: icons.join,
|
|
172
|
+
}));
|
|
173
|
+
blockMenu.push(new MenuItem({
|
|
174
|
+
title: 'Lift out of enclosing block',
|
|
175
|
+
run: () => editor.chain().lift().run(),
|
|
176
|
+
select: () => editor.can().lift().run(),
|
|
177
|
+
icon: icons.lift,
|
|
178
|
+
}));
|
|
179
|
+
blockMenu.push(new MenuItem({
|
|
180
|
+
title: 'Select parent node',
|
|
181
|
+
run: () => editor.chain().selectParentNode().run(),
|
|
182
|
+
select: () => editor.can().selectParentNode().run(),
|
|
183
|
+
icon: icons.selectParentNode,
|
|
184
|
+
}));
|
|
185
|
+
if (schema.nodes.image) {
|
|
186
|
+
const nodeType = schema.nodes.image;
|
|
187
|
+
insertMenu.push(new MenuItem({
|
|
188
|
+
title: 'Insert image',
|
|
189
|
+
label: 'Image',
|
|
190
|
+
// enable: (state) => editor.can().setHorizontalRule().run(),
|
|
191
|
+
enable: (state) => canInsert(state, nodeType),
|
|
192
|
+
run(state, _, view) {
|
|
193
|
+
let { from, to } = state.selection, attrs = null;
|
|
194
|
+
if (state.selection instanceof NodeSelection &&
|
|
195
|
+
state.selection.node.type == nodeType) {
|
|
196
|
+
attrs = state.selection.node.attrs;
|
|
197
|
+
}
|
|
198
|
+
openPrompt({
|
|
199
|
+
title: 'Insert image',
|
|
200
|
+
fields: {
|
|
201
|
+
src: new TextField({
|
|
202
|
+
label: 'Location',
|
|
203
|
+
required: true,
|
|
204
|
+
value: attrs && attrs.src,
|
|
205
|
+
}),
|
|
206
|
+
title: new TextField({
|
|
207
|
+
label: 'Title',
|
|
208
|
+
value: attrs && attrs.title,
|
|
209
|
+
}),
|
|
210
|
+
alt: new TextField({
|
|
211
|
+
label: 'Description',
|
|
212
|
+
value: attrs ? attrs.alt : state.doc.textBetween(from, to, ' '),
|
|
213
|
+
}),
|
|
214
|
+
},
|
|
215
|
+
callback(attrs) {
|
|
216
|
+
view.dispatch(view.state.tr.replaceSelectionWith(nodeType.createAndFill(attrs)));
|
|
217
|
+
view.focus();
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
},
|
|
221
|
+
}));
|
|
222
|
+
}
|
|
223
|
+
if (schema.nodes.hr) {
|
|
224
|
+
insertMenu.push(new MenuItem({
|
|
225
|
+
title: 'Insert horizontal rule',
|
|
226
|
+
label: 'Horizontal rule',
|
|
227
|
+
run: () => editor.chain().setHorizontalRule().run(),
|
|
228
|
+
enable: (state) => editor.can().setHorizontalRule().run(),
|
|
229
|
+
}));
|
|
230
|
+
}
|
|
231
|
+
menu.push(new Dropdown(cut(insertMenu), {
|
|
232
|
+
label: 'Insert',
|
|
233
|
+
}));
|
|
234
|
+
menu.push(new Dropdown(cut(typeMenu), {
|
|
235
|
+
label: 'Type...',
|
|
236
|
+
}));
|
|
237
|
+
/*
|
|
238
|
+
r.blockMenu = [
|
|
239
|
+
cut([
|
|
240
|
+
r.wrapBulletList,
|
|
241
|
+
r.wrapOrderedList,
|
|
242
|
+
r.wrapBlockQuote,
|
|
243
|
+
joinUpItem,
|
|
244
|
+
liftItem,
|
|
245
|
+
selectParentNodeItem,
|
|
246
|
+
]),
|
|
247
|
+
];
|
|
248
|
+
*/
|
|
249
|
+
menu.push(new MenuItem({
|
|
250
|
+
title: 'Undo last change',
|
|
251
|
+
run: () => editor.chain().undo().run(),
|
|
252
|
+
enable: () => editor.can().undo().run(),
|
|
253
|
+
icon: icons.undo,
|
|
254
|
+
}));
|
|
255
|
+
menu.push(new MenuItem({
|
|
256
|
+
title: 'Redo last undone change',
|
|
257
|
+
run: () => editor.chain().redo().run(),
|
|
258
|
+
enable: () => editor.can().redo().run(),
|
|
259
|
+
icon: icons.redo,
|
|
260
|
+
}));
|
|
261
|
+
if (schema.nodes.table) {
|
|
262
|
+
const item = (label, cmdName) => {
|
|
263
|
+
return new MenuItem({
|
|
264
|
+
label,
|
|
265
|
+
enable: () => editor.can()[cmdName]().run(),
|
|
266
|
+
run: () => editor.chain()[cmdName]().run(),
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
const tableMenu = [
|
|
270
|
+
item('Insert table', 'insertTable'),
|
|
271
|
+
item('Insert column before', 'addColumnBefore'),
|
|
272
|
+
item('Insert column after', 'addColumnAfter'),
|
|
273
|
+
item('Delete column', 'deleteColumn'),
|
|
274
|
+
item('Insert row before', 'addRowBefore'),
|
|
275
|
+
item('Insert row after', 'addRowAfter'),
|
|
276
|
+
item('Delete row', 'deleteRow'),
|
|
277
|
+
item('Delete table', 'deleteTable'),
|
|
278
|
+
item('Merge cells', 'mergeCells'),
|
|
279
|
+
item('Split cell', 'splitCell'),
|
|
280
|
+
item('Toggle header column', 'toggleHeaderColumn'),
|
|
281
|
+
item('Toggle header row', 'toggleHeaderRow'),
|
|
282
|
+
item('Toggle header cells', 'toggleHeaderCell'),
|
|
283
|
+
// item('Make cell green', setCellAttr('background', '#dfd')),
|
|
284
|
+
// item('Make cell not-green', setCellAttr('background', null)),
|
|
285
|
+
];
|
|
286
|
+
menu.push(new Dropdown(tableMenu, { label: 'Table' }));
|
|
287
|
+
}
|
|
288
|
+
return [menu, blockMenu];
|
|
289
|
+
}
|
|
290
|
+
export class ExtensionMenu extends Extension {
|
|
291
|
+
constructor(config = { floating: true }) {
|
|
292
|
+
super(config);
|
|
293
|
+
Object.defineProperty(this, "config", {
|
|
294
|
+
enumerable: true,
|
|
295
|
+
configurable: true,
|
|
296
|
+
writable: true,
|
|
297
|
+
value: config
|
|
298
|
+
});
|
|
299
|
+
Object.defineProperty(this, "name", {
|
|
300
|
+
enumerable: true,
|
|
301
|
+
configurable: true,
|
|
302
|
+
writable: true,
|
|
303
|
+
value: 'menu'
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
getProseMirrorPlugins(editor, schema) {
|
|
307
|
+
const plugins = [];
|
|
308
|
+
let content = buildMenu(editor, schema);
|
|
309
|
+
if (this.config.modifyMenu) {
|
|
310
|
+
content = this.config.modifyMenu(content);
|
|
311
|
+
}
|
|
312
|
+
plugins.push(new MenuPlugin({
|
|
313
|
+
content,
|
|
314
|
+
floating: this.config.floating,
|
|
315
|
+
}));
|
|
316
|
+
return plugins;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Plugin } from 'prosemirror-state';
|
|
2
|
+
import { MenuElement } from './menu.js';
|
|
3
|
+
export declare class MenuPlugin extends Plugin {
|
|
4
|
+
constructor(options: {
|
|
5
|
+
content: readonly (readonly MenuElement[])[];
|
|
6
|
+
floating?: boolean;
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=MenuPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MenuPlugin.d.ts","sourceRoot":"","sources":["../../../src/extension-menu/src/MenuPlugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,MAAM,EAAa,MAAM,mBAAmB,CAAC;AAEnE,OAAO,EAAE,WAAW,EAAiB,MAAM,WAAW,CAAC;AAyLvD,qBAAa,UAAW,SAAQ,MAAM;gBACxB,OAAO,EAAE;QAGnB,OAAO,EAAE,SAAS,CAAC,SAAS,WAAW,EAAE,CAAC,EAAE,CAAC;QAK7C,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB;CAOF"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { Plugin } from 'prosemirror-state';
|
|
2
|
+
import { renderGrouped } from './menu.js';
|
|
3
|
+
const CSS_PREFIX = 'kb-menu';
|
|
4
|
+
function isIOS() {
|
|
5
|
+
if (typeof navigator == 'undefined')
|
|
6
|
+
return false;
|
|
7
|
+
let agent = navigator.userAgent;
|
|
8
|
+
return !/Edge\/\d/.test(agent) && /AppleWebKit/.test(agent) &&
|
|
9
|
+
/Mobile\/\w+/.test(agent);
|
|
10
|
+
}
|
|
11
|
+
class MenuBarView {
|
|
12
|
+
constructor(editorView, options) {
|
|
13
|
+
Object.defineProperty(this, "editorView", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
configurable: true,
|
|
16
|
+
writable: true,
|
|
17
|
+
value: editorView
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(this, "options", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
writable: true,
|
|
23
|
+
value: options
|
|
24
|
+
});
|
|
25
|
+
Object.defineProperty(this, "wrapper", {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
configurable: true,
|
|
28
|
+
writable: true,
|
|
29
|
+
value: void 0
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(this, "menu", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
configurable: true,
|
|
34
|
+
writable: true,
|
|
35
|
+
value: void 0
|
|
36
|
+
});
|
|
37
|
+
Object.defineProperty(this, "spacer", {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
configurable: true,
|
|
40
|
+
writable: true,
|
|
41
|
+
value: null
|
|
42
|
+
});
|
|
43
|
+
Object.defineProperty(this, "maxHeight", {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
configurable: true,
|
|
46
|
+
writable: true,
|
|
47
|
+
value: 0
|
|
48
|
+
});
|
|
49
|
+
Object.defineProperty(this, "widthForMaxHeight", {
|
|
50
|
+
enumerable: true,
|
|
51
|
+
configurable: true,
|
|
52
|
+
writable: true,
|
|
53
|
+
value: 0
|
|
54
|
+
});
|
|
55
|
+
Object.defineProperty(this, "floating", {
|
|
56
|
+
enumerable: true,
|
|
57
|
+
configurable: true,
|
|
58
|
+
writable: true,
|
|
59
|
+
value: false
|
|
60
|
+
});
|
|
61
|
+
Object.defineProperty(this, "contentUpdate", {
|
|
62
|
+
enumerable: true,
|
|
63
|
+
configurable: true,
|
|
64
|
+
writable: true,
|
|
65
|
+
value: void 0
|
|
66
|
+
});
|
|
67
|
+
Object.defineProperty(this, "scrollHandler", {
|
|
68
|
+
enumerable: true,
|
|
69
|
+
configurable: true,
|
|
70
|
+
writable: true,
|
|
71
|
+
value: null
|
|
72
|
+
});
|
|
73
|
+
Object.defineProperty(this, "root", {
|
|
74
|
+
enumerable: true,
|
|
75
|
+
configurable: true,
|
|
76
|
+
writable: true,
|
|
77
|
+
value: void 0
|
|
78
|
+
});
|
|
79
|
+
this.root = editorView.root;
|
|
80
|
+
this.wrapper = document.createElement('div');
|
|
81
|
+
this.wrapper.classList.add(CSS_PREFIX + '__wrapper');
|
|
82
|
+
this.menu = document.createElement('div');
|
|
83
|
+
this.menu.classList.add(CSS_PREFIX);
|
|
84
|
+
this.wrapper.appendChild(this.menu);
|
|
85
|
+
this.menu.className = CSS_PREFIX;
|
|
86
|
+
if (editorView.dom.parentNode) {
|
|
87
|
+
editorView.dom.parentNode.replaceChild(this.wrapper, editorView.dom);
|
|
88
|
+
}
|
|
89
|
+
this.wrapper.appendChild(editorView.dom);
|
|
90
|
+
let { dom, update } = renderGrouped(this.editorView, this.options.content);
|
|
91
|
+
this.contentUpdate = update;
|
|
92
|
+
this.menu.appendChild(dom);
|
|
93
|
+
this.update();
|
|
94
|
+
if (options.floating && !isIOS()) {
|
|
95
|
+
this.updateFloat();
|
|
96
|
+
let potentialScrollers = getAllWrapping(this.wrapper);
|
|
97
|
+
this.scrollHandler = (e) => {
|
|
98
|
+
let root = this.editorView.root;
|
|
99
|
+
if (!(root.body || root).contains(this.wrapper)) {
|
|
100
|
+
potentialScrollers.forEach((el) => el.removeEventListener('scroll', this.scrollHandler));
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
this.updateFloat(e.target.getBoundingClientRect
|
|
104
|
+
? e.target
|
|
105
|
+
: undefined);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
potentialScrollers.forEach((el) => el.addEventListener('scroll', this.scrollHandler));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
update() {
|
|
112
|
+
if (this.editorView.root != this.root) {
|
|
113
|
+
let { dom, update } = renderGrouped(this.editorView, this.options.content);
|
|
114
|
+
this.contentUpdate = update;
|
|
115
|
+
this.menu.replaceChild(dom, this.menu.firstChild);
|
|
116
|
+
this.root = this.editorView.root;
|
|
117
|
+
}
|
|
118
|
+
// this.contentUpdate(this.editorView.state);
|
|
119
|
+
if (this.floating) {
|
|
120
|
+
this.updateScrollCursor();
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
if (this.menu.offsetWidth != this.widthForMaxHeight) {
|
|
124
|
+
this.widthForMaxHeight = this.menu.offsetWidth;
|
|
125
|
+
this.maxHeight = 0;
|
|
126
|
+
}
|
|
127
|
+
if (this.menu.offsetHeight > this.maxHeight) {
|
|
128
|
+
this.maxHeight = this.menu.offsetHeight;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
updateScrollCursor() {
|
|
133
|
+
let selection = this.editorView.root.getSelection();
|
|
134
|
+
if (!selection.focusNode)
|
|
135
|
+
return;
|
|
136
|
+
let rects = selection.getRangeAt(0).getClientRects();
|
|
137
|
+
let selRect = rects[selectionIsInverted(selection) ? 0 : rects.length - 1];
|
|
138
|
+
if (!selRect)
|
|
139
|
+
return;
|
|
140
|
+
let menuRect = this.menu.getBoundingClientRect();
|
|
141
|
+
if (selRect.top < menuRect.bottom && selRect.bottom > menuRect.top) {
|
|
142
|
+
let scrollable = findWrappingScrollable(this.wrapper);
|
|
143
|
+
if (scrollable)
|
|
144
|
+
scrollable.scrollTop -= menuRect.bottom - selRect.top;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
updateFloat(scrollAncestor) {
|
|
148
|
+
let parent = this.wrapper, editorRect = parent.getBoundingClientRect(), top = scrollAncestor
|
|
149
|
+
? Math.max(0, scrollAncestor.getBoundingClientRect().top)
|
|
150
|
+
: 0;
|
|
151
|
+
if (this.floating) {
|
|
152
|
+
if (editorRect.top >= top || editorRect.bottom < this.menu.offsetHeight + 10) {
|
|
153
|
+
this.floating = false;
|
|
154
|
+
this.menu.style.position =
|
|
155
|
+
this.menu.style.left =
|
|
156
|
+
this.menu.style.top =
|
|
157
|
+
this.menu.style.width =
|
|
158
|
+
'';
|
|
159
|
+
this.menu.style.display = '';
|
|
160
|
+
this.spacer.parentNode.removeChild(this.spacer);
|
|
161
|
+
this.spacer = null;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
let border = (parent.offsetWidth - parent.clientWidth) / 2;
|
|
165
|
+
this.menu.style.left = (editorRect.left + border) + 'px';
|
|
166
|
+
this.menu.style.display = editorRect.top >
|
|
167
|
+
this.editorView.dom.ownerDocument.defaultView
|
|
168
|
+
.innerHeight
|
|
169
|
+
? 'none'
|
|
170
|
+
: '';
|
|
171
|
+
if (scrollAncestor)
|
|
172
|
+
this.menu.style.top = top + 'px';
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
if (editorRect.top < top && editorRect.bottom >= this.menu.offsetHeight + 10) {
|
|
177
|
+
this.floating = true;
|
|
178
|
+
let menuRect = this.menu.getBoundingClientRect();
|
|
179
|
+
this.menu.style.left = menuRect.left + 'px';
|
|
180
|
+
this.menu.style.width = menuRect.width + 'px';
|
|
181
|
+
if (scrollAncestor)
|
|
182
|
+
this.menu.style.top = top + 'px';
|
|
183
|
+
this.menu.style.position = 'fixed';
|
|
184
|
+
this.spacer = document.createElement('div');
|
|
185
|
+
this.spacer.classList.add(CSS_PREFIX + '__spacer');
|
|
186
|
+
this.spacer.style.height = `${menuRect.height}px`;
|
|
187
|
+
parent.insertBefore(this.spacer, this.menu);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
destroy() {
|
|
192
|
+
if (this.wrapper.parentNode) {
|
|
193
|
+
this.wrapper.parentNode.replaceChild(this.editorView.dom, this.wrapper);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Not precise, but close enough
|
|
198
|
+
function selectionIsInverted(selection) {
|
|
199
|
+
if (selection.anchorNode == selection.focusNode) {
|
|
200
|
+
return selection.anchorOffset > selection.focusOffset;
|
|
201
|
+
}
|
|
202
|
+
return selection.anchorNode.compareDocumentPosition(selection.focusNode) ==
|
|
203
|
+
Node.DOCUMENT_POSITION_FOLLOWING;
|
|
204
|
+
}
|
|
205
|
+
function findWrappingScrollable(node) {
|
|
206
|
+
for (let cur = node.parentNode; cur; cur = cur.parentNode) {
|
|
207
|
+
if (cur.scrollHeight > cur.clientHeight) {
|
|
208
|
+
return cur;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function getAllWrapping(node) {
|
|
213
|
+
let res = [node.ownerDocument.defaultView];
|
|
214
|
+
for (let cur = node.parentNode; cur; cur = cur.parentNode) {
|
|
215
|
+
res.push(cur);
|
|
216
|
+
}
|
|
217
|
+
return res;
|
|
218
|
+
}
|
|
219
|
+
export class MenuPlugin extends Plugin {
|
|
220
|
+
constructor(options) {
|
|
221
|
+
super({
|
|
222
|
+
view(editorView) {
|
|
223
|
+
return new MenuBarView(editorView, options);
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/*
|
|
229
|
+
/// A plugin that will place a menu bar above the editor. Note that
|
|
230
|
+
/// this involves wrapping the editor in an additional `<div>`.
|
|
231
|
+
export function menuBar(options: {
|
|
232
|
+
/// Provides the content of the menu, as a nested array to be
|
|
233
|
+
/// passed to `renderGrouped`.
|
|
234
|
+
content: readonly (readonly MenuElement[])[]
|
|
235
|
+
|
|
236
|
+
/// Determines whether the menu floats, i.e. whether it sticks to
|
|
237
|
+
/// the top of the viewport when the editor is partially scrolled
|
|
238
|
+
/// out of view.
|
|
239
|
+
floating?: boolean
|
|
240
|
+
}): Plugin {
|
|
241
|
+
return new Plugin({
|
|
242
|
+
view(editorView) { return new MenuBarView(editorView, options) }
|
|
243
|
+
})
|
|
244
|
+
}
|
|
245
|
+
*/
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IconSpec } from './menu.js';
|
|
2
|
+
export declare function getIcon(root: Document | ShadowRoot, icon: {
|
|
3
|
+
path: string;
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
} | {
|
|
7
|
+
text: string;
|
|
8
|
+
css?: string;
|
|
9
|
+
} | {
|
|
10
|
+
dom: Node;
|
|
11
|
+
}): HTMLElement;
|
|
12
|
+
export declare const icons: {
|
|
13
|
+
[name: string]: IconSpec;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=icons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../../src/extension-menu/src/icons.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAerC,wBAAgB,OAAO,CACrB,IAAI,EAAE,QAAQ,GAAG,UAAU,EAC3B,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG;IAAE,GAAG,EAAE,IAAI,CAAA;CAAE,GAChB,WAAW,CAmCb;AA8BD,eAAO,MAAM,KAAK,EAAE;IAAE,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAA;CAoE7C,CAAC"}
|