@kerebron/extension-menu 0.0.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/LICENSE +23 -0
- package/README.md +3 -0
- package/esm/ExtensionMenu.d.ts +10 -0
- package/esm/ExtensionMenu.d.ts.map +1 -0
- package/esm/ExtensionMenu.js +302 -0
- package/esm/MenuPlugin.d.ts +9 -0
- package/esm/MenuPlugin.d.ts.map +1 -0
- package/esm/MenuPlugin.js +247 -0
- package/esm/_dnt.shims.d.ts +6 -0
- package/esm/_dnt.shims.d.ts.map +1 -0
- package/esm/_dnt.shims.js +61 -0
- package/esm/icons.d.ts +15 -0
- package/esm/icons.d.ts.map +1 -0
- package/esm/icons.js +118 -0
- package/esm/menu.d.ts +86 -0
- package/esm/menu.d.ts.map +1 -0
- package/esm/menu.js +354 -0
- package/esm/package.json +3 -0
- package/esm/prompt.d.ts +36 -0
- package/esm/prompt.d.ts.map +1 -0
- package/esm/prompt.js +158 -0
- package/package.json +18 -0
package/esm/prompt.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
const prefix = 'ProseMirror-prompt';
|
|
2
|
+
export function openPrompt(options) {
|
|
3
|
+
let wrapper = document.body.appendChild(document.createElement('div'));
|
|
4
|
+
wrapper.className = prefix;
|
|
5
|
+
let mouseOutside = (e) => {
|
|
6
|
+
if (!wrapper.contains(e.target))
|
|
7
|
+
close();
|
|
8
|
+
};
|
|
9
|
+
setTimeout(() => globalThis.addEventListener('mousedown', mouseOutside), 50);
|
|
10
|
+
let close = () => {
|
|
11
|
+
globalThis.removeEventListener('mousedown', mouseOutside);
|
|
12
|
+
if (wrapper.parentNode)
|
|
13
|
+
wrapper.parentNode.removeChild(wrapper);
|
|
14
|
+
};
|
|
15
|
+
let domFields = [];
|
|
16
|
+
for (let name in options.fields) {
|
|
17
|
+
domFields.push(options.fields[name].render());
|
|
18
|
+
}
|
|
19
|
+
let submitButton = document.createElement('button');
|
|
20
|
+
submitButton.type = 'submit';
|
|
21
|
+
submitButton.className = prefix + '-submit';
|
|
22
|
+
submitButton.textContent = 'OK';
|
|
23
|
+
let cancelButton = document.createElement('button');
|
|
24
|
+
cancelButton.type = 'button';
|
|
25
|
+
cancelButton.className = prefix + '-cancel';
|
|
26
|
+
cancelButton.textContent = 'Cancel';
|
|
27
|
+
cancelButton.addEventListener('click', close);
|
|
28
|
+
let form = wrapper.appendChild(document.createElement('form'));
|
|
29
|
+
if (options.title) {
|
|
30
|
+
form.appendChild(document.createElement('h5')).textContent = options.title;
|
|
31
|
+
}
|
|
32
|
+
domFields.forEach((field) => {
|
|
33
|
+
form.appendChild(document.createElement('div')).appendChild(field);
|
|
34
|
+
});
|
|
35
|
+
let buttons = form.appendChild(document.createElement('div'));
|
|
36
|
+
buttons.className = prefix + '-buttons';
|
|
37
|
+
buttons.appendChild(submitButton);
|
|
38
|
+
buttons.appendChild(document.createTextNode(' '));
|
|
39
|
+
buttons.appendChild(cancelButton);
|
|
40
|
+
let box = wrapper.getBoundingClientRect();
|
|
41
|
+
wrapper.style.top = ((globalThis.innerHeight - box.height) / 2) + 'px';
|
|
42
|
+
wrapper.style.left = ((globalThis.innerWidth - box.width) / 2) + 'px';
|
|
43
|
+
let submit = () => {
|
|
44
|
+
let params = getValues(options.fields, domFields);
|
|
45
|
+
if (params) {
|
|
46
|
+
close();
|
|
47
|
+
options.callback(params);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
form.addEventListener('submit', (e) => {
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
submit();
|
|
53
|
+
});
|
|
54
|
+
form.addEventListener('keydown', (e) => {
|
|
55
|
+
if (e.keyCode == 27) {
|
|
56
|
+
e.preventDefault();
|
|
57
|
+
close();
|
|
58
|
+
}
|
|
59
|
+
else if (e.keyCode == 13 && !(e.ctrlKey || e.metaKey || e.shiftKey)) {
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
submit();
|
|
62
|
+
}
|
|
63
|
+
else if (e.keyCode == 9) {
|
|
64
|
+
globalThis.setTimeout(() => {
|
|
65
|
+
if (!wrapper.contains(document.activeElement))
|
|
66
|
+
close();
|
|
67
|
+
}, 500);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
let input = form.elements[0];
|
|
71
|
+
if (input)
|
|
72
|
+
input.focus();
|
|
73
|
+
}
|
|
74
|
+
function getValues(fields, domFields) {
|
|
75
|
+
let result = Object.create(null), i = 0;
|
|
76
|
+
for (let name in fields) {
|
|
77
|
+
let field = fields[name], dom = domFields[i++];
|
|
78
|
+
let value = field.read(dom), bad = field.validate(value);
|
|
79
|
+
if (bad) {
|
|
80
|
+
reportInvalid(dom, bad);
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
result[name] = field.clean(value);
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
function reportInvalid(dom, message) {
|
|
88
|
+
// FIXME this is awful and needs a lot more work
|
|
89
|
+
let parent = dom.parentNode;
|
|
90
|
+
let msg = parent.appendChild(document.createElement('div'));
|
|
91
|
+
msg.style.left = (dom.offsetLeft + dom.offsetWidth + 2) + 'px';
|
|
92
|
+
msg.style.top = (dom.offsetTop - 5) + 'px';
|
|
93
|
+
msg.className = 'ProseMirror-invalid';
|
|
94
|
+
msg.textContent = message;
|
|
95
|
+
setTimeout(() => parent.removeChild(msg), 1500);
|
|
96
|
+
}
|
|
97
|
+
/// The type of field that `openPrompt` expects to be passed to it.
|
|
98
|
+
export class Field {
|
|
99
|
+
/// Create a field with the given options. Options support by all
|
|
100
|
+
/// field types are:
|
|
101
|
+
constructor(
|
|
102
|
+
/// @internal
|
|
103
|
+
options) {
|
|
104
|
+
Object.defineProperty(this, "options", {
|
|
105
|
+
enumerable: true,
|
|
106
|
+
configurable: true,
|
|
107
|
+
writable: true,
|
|
108
|
+
value: options
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/// Read the field's value from its DOM node.
|
|
112
|
+
read(dom) {
|
|
113
|
+
return dom.value;
|
|
114
|
+
}
|
|
115
|
+
/// A field-type-specific validation function.
|
|
116
|
+
validateType(value) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
/// @internal
|
|
120
|
+
validate(value) {
|
|
121
|
+
if (!value && this.options.required) {
|
|
122
|
+
return 'Required field';
|
|
123
|
+
}
|
|
124
|
+
return this.validateType(value) ||
|
|
125
|
+
(this.options.validate ? this.options.validate(value) : null);
|
|
126
|
+
}
|
|
127
|
+
clean(value) {
|
|
128
|
+
return this.options.clean ? this.options.clean(value) : value;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/// A field class for single-line text fields.
|
|
132
|
+
export class TextField extends Field {
|
|
133
|
+
render() {
|
|
134
|
+
let input = document.createElement('input');
|
|
135
|
+
input.type = 'text';
|
|
136
|
+
input.placeholder = this.options.label;
|
|
137
|
+
input.value = this.options.value || '';
|
|
138
|
+
input.autocomplete = 'off';
|
|
139
|
+
return input;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/// A field class for dropdown fields based on a plain `<select>`
|
|
143
|
+
/// tag. Expects an option `options`, which should be an array of
|
|
144
|
+
/// `{value: string, label: string}` objects, or a function taking a
|
|
145
|
+
/// `ProseMirror` instance and returning such an array.
|
|
146
|
+
export class SelectField extends Field {
|
|
147
|
+
render() {
|
|
148
|
+
let select = document.createElement('select');
|
|
149
|
+
this.options.options
|
|
150
|
+
.forEach((o) => {
|
|
151
|
+
let opt = select.appendChild(document.createElement('option'));
|
|
152
|
+
opt.value = o.value;
|
|
153
|
+
opt.selected = o.value == this.options.value;
|
|
154
|
+
opt.label = o.label;
|
|
155
|
+
});
|
|
156
|
+
return select;
|
|
157
|
+
}
|
|
158
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kerebron/extension-menu",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"module": "./esm/ExtensionMenu.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./esm/ExtensionMenu.js"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@deno/shim-deno": "~0.18.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/node": "^20.9.0"
|
|
16
|
+
},
|
|
17
|
+
"_generatedBy": "dnt@dev"
|
|
18
|
+
}
|