weml-monaco 0.5.2 → 0.7.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/CHANGELOG.md +56 -3
- package/README.md +161 -47
- package/dist/index.cjs +25587 -24926
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +204 -11
- package/dist/index.d.ts +204 -11
- package/dist/index.global.js +142 -132
- package/dist/index.mjs +25591 -24930
- package/dist/index.mjs.map +1 -1
- package/dist/panel.cjs +1314 -0
- package/dist/panel.cjs.map +1 -0
- package/dist/panel.css +261 -0
- package/dist/panel.d.mts +106 -0
- package/dist/panel.d.ts +106 -0
- package/dist/panel.mjs +1291 -0
- package/dist/panel.mjs.map +1 -0
- package/dist/preview.cjs +324 -0
- package/dist/preview.cjs.map +1 -0
- package/dist/preview.d.mts +63 -0
- package/dist/preview.d.ts +63 -0
- package/dist/preview.mjs +301 -0
- package/dist/preview.mjs.map +1 -0
- package/dist/weml.worker.d.mts +2 -0
- package/dist/weml.worker.mjs +25164 -0
- package/dist/weml.worker.mjs.map +1 -0
- package/dist/worker.cjs +8596 -0
- package/dist/worker.cjs.map +1 -0
- package/dist/worker.d.mts +21 -0
- package/dist/worker.d.ts +21 -0
- package/dist/worker.mjs +8597 -0
- package/dist/worker.mjs.map +1 -0
- package/package.json +57 -12
package/dist/panel.cjs
ADDED
|
@@ -0,0 +1,1314 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/panel/index.ts
|
|
21
|
+
var panel_exports = {};
|
|
22
|
+
__export(panel_exports, {
|
|
23
|
+
PANEL_CLASS: () => PANEL_CLASS,
|
|
24
|
+
PANEL_CSS: () => PANEL_CSS,
|
|
25
|
+
createWemlPanel: () => createWemlPanel,
|
|
26
|
+
injectPanelStyles: () => injectPanelStyles
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(panel_exports);
|
|
29
|
+
|
|
30
|
+
// src/panel/panes.ts
|
|
31
|
+
var MIN_BODY = 48;
|
|
32
|
+
var HEADER = 22;
|
|
33
|
+
function createPanes(specs, state, save) {
|
|
34
|
+
const root = document.createElement("div");
|
|
35
|
+
root.className = "weml-panes";
|
|
36
|
+
const collapsed = new Set(state.collapsed ?? []);
|
|
37
|
+
const weights = { ...state.weights };
|
|
38
|
+
const cleanups = [];
|
|
39
|
+
const panes = specs.map((spec) => {
|
|
40
|
+
const pane = document.createElement("section");
|
|
41
|
+
pane.className = "pane";
|
|
42
|
+
pane.setAttribute("data-group", spec.id);
|
|
43
|
+
const sash = document.createElement("div");
|
|
44
|
+
sash.className = "sash";
|
|
45
|
+
sash.setAttribute("aria-hidden", "true");
|
|
46
|
+
const header = document.createElement("div");
|
|
47
|
+
header.className = "pane-header";
|
|
48
|
+
header.setAttribute("role", "button");
|
|
49
|
+
header.tabIndex = 0;
|
|
50
|
+
header.textContent = spec.title;
|
|
51
|
+
const body = document.createElement("div");
|
|
52
|
+
body.className = spec.fill ? "pane-body fill" : "pane-body";
|
|
53
|
+
body.append(spec.body);
|
|
54
|
+
pane.append(sash, header, body);
|
|
55
|
+
root.append(pane);
|
|
56
|
+
return { spec, pane, sash, header };
|
|
57
|
+
});
|
|
58
|
+
const isOpen = (id) => !collapsed.has(id);
|
|
59
|
+
const layout = () => {
|
|
60
|
+
const known = panes.filter((p) => isOpen(p.spec.id)).map((p) => weights[p.spec.id]).filter((w) => w !== void 0);
|
|
61
|
+
const fallback = known.length > 0 ? known.reduce((sum, w) => sum + w, 0) / known.length : 1;
|
|
62
|
+
let openAbove = false;
|
|
63
|
+
for (const { spec, pane, header } of panes) {
|
|
64
|
+
const open = isOpen(spec.id);
|
|
65
|
+
pane.classList.toggle("collapsed", !open);
|
|
66
|
+
header.setAttribute("aria-expanded", String(open));
|
|
67
|
+
pane.style.flex = open ? `${weights[spec.id] ?? fallback} 1 0px` : "0 0 auto";
|
|
68
|
+
pane.classList.toggle("resizable", open && openAbove);
|
|
69
|
+
openAbove || (openAbove = open);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const persist = () => {
|
|
73
|
+
state.collapsed = [...collapsed];
|
|
74
|
+
state.weights = { ...weights };
|
|
75
|
+
save();
|
|
76
|
+
};
|
|
77
|
+
panes.forEach(({ spec, pane, sash, header }, index) => {
|
|
78
|
+
const toggle = () => {
|
|
79
|
+
if (collapsed.has(spec.id)) collapsed.delete(spec.id);
|
|
80
|
+
else collapsed.add(spec.id);
|
|
81
|
+
persist();
|
|
82
|
+
layout();
|
|
83
|
+
};
|
|
84
|
+
header.addEventListener("click", toggle);
|
|
85
|
+
header.addEventListener("keydown", (event) => {
|
|
86
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
toggle();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
sash.addEventListener("pointerdown", (event) => {
|
|
92
|
+
if (!pane.classList.contains("resizable")) return;
|
|
93
|
+
const above = panes.slice(0, index).reverse().find((p) => isOpen(p.spec.id));
|
|
94
|
+
if (!above) return;
|
|
95
|
+
event.preventDefault();
|
|
96
|
+
sash.setPointerCapture?.(event.pointerId);
|
|
97
|
+
sash.classList.add("active");
|
|
98
|
+
for (const open of panes.filter((p) => isOpen(p.spec.id))) {
|
|
99
|
+
weights[open.spec.id] = open.pane.getBoundingClientRect().height;
|
|
100
|
+
}
|
|
101
|
+
const startY = event.clientY;
|
|
102
|
+
const aboveStart = weights[above.spec.id];
|
|
103
|
+
const paneStart = weights[spec.id];
|
|
104
|
+
const min = HEADER + MIN_BODY;
|
|
105
|
+
const move = (moveEvent) => {
|
|
106
|
+
const total = aboveStart + paneStart;
|
|
107
|
+
const aboveHeight = Math.min(Math.max(aboveStart + moveEvent.clientY - startY, min), total - min);
|
|
108
|
+
weights[above.spec.id] = aboveHeight;
|
|
109
|
+
weights[spec.id] = total - aboveHeight;
|
|
110
|
+
layout();
|
|
111
|
+
};
|
|
112
|
+
const end = () => {
|
|
113
|
+
sash.classList.remove("active");
|
|
114
|
+
sash.removeEventListener("pointermove", move);
|
|
115
|
+
persist();
|
|
116
|
+
};
|
|
117
|
+
sash.addEventListener("pointermove", move);
|
|
118
|
+
sash.addEventListener("pointerup", end, { once: true });
|
|
119
|
+
sash.addEventListener("pointercancel", end, { once: true });
|
|
120
|
+
});
|
|
121
|
+
sash.addEventListener("dblclick", () => {
|
|
122
|
+
for (const key of Object.keys(weights)) delete weights[key];
|
|
123
|
+
persist();
|
|
124
|
+
layout();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
layout();
|
|
128
|
+
const onScroll = (event) => {
|
|
129
|
+
const target = event.target;
|
|
130
|
+
if (target instanceof HTMLElement && target.matches(".pane-body, .scroll")) {
|
|
131
|
+
target.classList.toggle("scrolled", target.scrollTop > 0);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
root.addEventListener("scroll", onScroll, true);
|
|
135
|
+
cleanups.push(() => root.removeEventListener("scroll", onScroll, true));
|
|
136
|
+
return {
|
|
137
|
+
element: root,
|
|
138
|
+
dispose: () => cleanups.forEach((cleanup) => cleanup())
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/panel/dom.ts
|
|
143
|
+
function element(tag, options = {}, children = []) {
|
|
144
|
+
const node = document.createElement(tag);
|
|
145
|
+
if (options.className) node.className = options.className;
|
|
146
|
+
if (options.text !== void 0) node.textContent = options.text;
|
|
147
|
+
if (options.title) node.title = options.title;
|
|
148
|
+
node.append(...children);
|
|
149
|
+
return node;
|
|
150
|
+
}
|
|
151
|
+
var ICONS = {
|
|
152
|
+
search: '<circle cx="7" cy="7" r="4.5"/><path d="M10.3 10.3L14 14"/>',
|
|
153
|
+
copy: '<rect x="5.5" y="5.5" width="8" height="8" rx="1"/><path d="M3.5 10.5h-1v-8h8v1"/>',
|
|
154
|
+
insert: '<path d="M13 3v5.5a2 2 0 0 1-2 2H4"/><path d="M6.5 8L4 10.5 6.5 13"/>',
|
|
155
|
+
wrap: '<path d="M5.5 3H3.5v10h2"/><path d="M10.5 3h2v10h-2"/><path d="M6.5 8h3"/>',
|
|
156
|
+
add: '<path d="M8 3.5v9M3.5 8h9"/>'
|
|
157
|
+
};
|
|
158
|
+
function icon(name) {
|
|
159
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
160
|
+
svg.setAttribute("viewBox", "0 0 16 16");
|
|
161
|
+
svg.setAttribute("aria-hidden", "true");
|
|
162
|
+
svg.innerHTML = ICONS[name];
|
|
163
|
+
return svg;
|
|
164
|
+
}
|
|
165
|
+
function button(options, onClick) {
|
|
166
|
+
const node = element("button", { className: options.className, text: options.text, title: options.title });
|
|
167
|
+
node.type = options.type ?? "button";
|
|
168
|
+
if (options.icon) {
|
|
169
|
+
node.append(icon(options.icon));
|
|
170
|
+
if (options.title) node.setAttribute("aria-label", options.title);
|
|
171
|
+
}
|
|
172
|
+
if (onClick) node.addEventListener("click", onClick);
|
|
173
|
+
return node;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/panel/searchPane.ts
|
|
177
|
+
function createSearchPane(search, memory) {
|
|
178
|
+
const account = element("div", { className: "account" });
|
|
179
|
+
const query = element("input", { className: "grow" });
|
|
180
|
+
query.type = "text";
|
|
181
|
+
query.placeholder = "Search\u2026";
|
|
182
|
+
query.setAttribute("aria-label", "Search suggestions");
|
|
183
|
+
const lang = element("input", { className: "weml-lang", title: "Language code, e.g. en" });
|
|
184
|
+
lang.type = "text";
|
|
185
|
+
lang.placeholder = "lang";
|
|
186
|
+
lang.setAttribute("aria-label", "Language");
|
|
187
|
+
const searchButton = button({ icon: "search", title: "Search", className: "icon", type: "submit" });
|
|
188
|
+
const form = element("form", {}, [element("div", { className: "row" }, [query, lang, searchButton])]);
|
|
189
|
+
form.hidden = true;
|
|
190
|
+
const status = element("div", { className: "status" });
|
|
191
|
+
status.setAttribute("aria-live", "polite");
|
|
192
|
+
const results = element("ol", { className: "results scroll" });
|
|
193
|
+
const root = element("section", {}, [account, form, status, results]);
|
|
194
|
+
lang.value = memory.get()?.lang ?? "";
|
|
195
|
+
lang.addEventListener("input", () => memory.set({ lang: lang.value }));
|
|
196
|
+
let generation = 0;
|
|
197
|
+
let disposed = false;
|
|
198
|
+
const renderResults = (state) => {
|
|
199
|
+
searchButton.disabled = !!state.loading;
|
|
200
|
+
status.className = state.error ? "status error" : "status";
|
|
201
|
+
status.textContent = state.loading ? "Searching\u2026" : state.error ?? (state.query && state.results?.length === 0 ? `Nothing found for \u201C${state.query}\u201D` : "");
|
|
202
|
+
results.replaceChildren();
|
|
203
|
+
(state.results ?? []).forEach((suggestion, index) => {
|
|
204
|
+
const item = element("li");
|
|
205
|
+
item.append(element("span", { className: "number", text: String(index + 1) }));
|
|
206
|
+
const meta = element("div", { className: "meta" });
|
|
207
|
+
const paraId = element("span", { className: "field" }, [
|
|
208
|
+
element("span", { className: "label", text: "ParaId " }),
|
|
209
|
+
element("span", { className: "value", text: suggestion.paraId || "\u2014" })
|
|
210
|
+
]);
|
|
211
|
+
if (suggestion.paraId) {
|
|
212
|
+
paraId.append(button({ icon: "copy", title: "Copy ParaId", className: "icon flat" }, () => search.copy(suggestion.paraId)));
|
|
213
|
+
}
|
|
214
|
+
meta.append(paraId, element("span", { className: "field" }, [
|
|
215
|
+
element("span", { className: "label", text: "BookCode " }),
|
|
216
|
+
element("span", { className: "value", text: suggestion.bookCode || "\u2014" })
|
|
217
|
+
]));
|
|
218
|
+
item.append(meta, element("div", { className: "title", text: suggestion.title }));
|
|
219
|
+
if (suggestion.link) {
|
|
220
|
+
const link = suggestion.link;
|
|
221
|
+
item.append(element("div", { className: "link" }, [
|
|
222
|
+
element("code", { text: link }),
|
|
223
|
+
element("div", { className: "actions" }, [
|
|
224
|
+
button({ icon: "copy", title: "Copy link", className: "icon flat" }, () => search.copy(link)),
|
|
225
|
+
button(
|
|
226
|
+
{
|
|
227
|
+
icon: "insert",
|
|
228
|
+
title: "Insert the link in place of the selection (the selection becomes its label)",
|
|
229
|
+
className: "icon flat primary"
|
|
230
|
+
},
|
|
231
|
+
() => search.insertLink(index)
|
|
232
|
+
)
|
|
233
|
+
])
|
|
234
|
+
]));
|
|
235
|
+
}
|
|
236
|
+
results.append(item);
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
const clearResults = () => {
|
|
240
|
+
generation++;
|
|
241
|
+
renderResults({ query: null, results: [] });
|
|
242
|
+
};
|
|
243
|
+
form.addEventListener("submit", (event) => {
|
|
244
|
+
event.preventDefault();
|
|
245
|
+
const text = query.value.trim();
|
|
246
|
+
if (!text) {
|
|
247
|
+
clearResults();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const current = ++generation;
|
|
251
|
+
renderResults({ query: text, loading: true });
|
|
252
|
+
search.search(text, lang.value.trim()).then(
|
|
253
|
+
(found) => {
|
|
254
|
+
if (!disposed && current === generation) renderResults({ query: text, results: found });
|
|
255
|
+
},
|
|
256
|
+
(error) => {
|
|
257
|
+
if (!disposed && current === generation) {
|
|
258
|
+
renderResults({ query: text, error: error instanceof Error ? error.message : "Search failed" });
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
});
|
|
263
|
+
const renderState = (state) => {
|
|
264
|
+
account.replaceChildren();
|
|
265
|
+
const fallback = state.kind === "not-configured" ? void 0 : state.defaultLanguage || (state.kind === "signed-in" ? "en" : void 0);
|
|
266
|
+
if (!lang.value && fallback) lang.value = fallback;
|
|
267
|
+
const signedIn = state.kind === "signed-in";
|
|
268
|
+
account.hidden = signedIn;
|
|
269
|
+
form.hidden = !signedIn;
|
|
270
|
+
if (!signedIn) clearResults();
|
|
271
|
+
if (state.kind === "not-configured") {
|
|
272
|
+
account.append(element("span", { text: state.message }));
|
|
273
|
+
if (state.canOpenSettings && search.openSettings) {
|
|
274
|
+
account.append(button({ text: "Open Settings", className: "link" }, () => search.openSettings?.()));
|
|
275
|
+
}
|
|
276
|
+
} else if (state.kind === "signed-out") {
|
|
277
|
+
const failure = element("span", { className: "status error" });
|
|
278
|
+
const signIn = () => {
|
|
279
|
+
failure.textContent = "";
|
|
280
|
+
Promise.resolve(search.signIn()).catch((error) => {
|
|
281
|
+
if (!disposed) failure.textContent = error instanceof Error ? error.message : "Sign-in failed";
|
|
282
|
+
});
|
|
283
|
+
};
|
|
284
|
+
account.append(button({ text: "Sign in", className: "full", title: "Sign in to EGW Writings" }, signIn), failure);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
const refresh = () => {
|
|
288
|
+
Promise.resolve(search.getState()).then(
|
|
289
|
+
(state) => {
|
|
290
|
+
if (!disposed) renderState(state);
|
|
291
|
+
},
|
|
292
|
+
() => {
|
|
293
|
+
if (!disposed) renderState({ kind: "not-configured", message: "Search is not available." });
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
};
|
|
297
|
+
const unsubscribe = search.onDidChangeState(refresh);
|
|
298
|
+
refresh();
|
|
299
|
+
return {
|
|
300
|
+
element: root,
|
|
301
|
+
dispose: () => {
|
|
302
|
+
disposed = true;
|
|
303
|
+
unsubscribe();
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// src/panel/styles.ts
|
|
309
|
+
var PANEL_CLASS = "weml-panel";
|
|
310
|
+
var STYLE_ID = "weml-panel-styles";
|
|
311
|
+
var PANEL_CSS = `
|
|
312
|
+
.weml-panel {
|
|
313
|
+
display: flex;
|
|
314
|
+
flex-direction: column;
|
|
315
|
+
height: 100%;
|
|
316
|
+
min-height: 0;
|
|
317
|
+
box-sizing: border-box;
|
|
318
|
+
overflow: hidden;
|
|
319
|
+
font-family: var(--vscode-font-family, system-ui, sans-serif);
|
|
320
|
+
font-size: var(--vscode-font-size, 13px);
|
|
321
|
+
/* A webview's own; a host page's (Mantine: 1.55) would make every row taller than in VS Code. */
|
|
322
|
+
line-height: normal;
|
|
323
|
+
color: var(--vscode-foreground);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/* Panes, like the Explorer's (Outline, Timeline): the panel's height is shared by the open panes,
|
|
327
|
+
each scrolls on its own, a collapsed one is just its 22px header; the sash on a pane's top edge
|
|
328
|
+
resizes it against the open pane above. */
|
|
329
|
+
.weml-panel .weml-panes { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
|
|
330
|
+
.weml-panel .pane { position: relative; display: flex; flex-direction: column; min-height: 22px; overflow: hidden; }
|
|
331
|
+
.weml-panel .pane:not(.collapsed) { min-height: 70px; }
|
|
332
|
+
/* The border colours fall back to editorWidget.border: Monaco defines no sideBar*, panel or widget
|
|
333
|
+
colours, only the editor's own, and without it the panes and results run into each other. */
|
|
334
|
+
.weml-panel .pane + .pane { border-top: 1px solid var(--vscode-sideBarSectionHeader-border, var(--vscode-panel-border, var(--vscode-editorWidget-border, transparent))); }
|
|
335
|
+
.weml-panel .pane-header {
|
|
336
|
+
display: flex;
|
|
337
|
+
align-items: center;
|
|
338
|
+
gap: 2px;
|
|
339
|
+
flex: none;
|
|
340
|
+
height: 22px;
|
|
341
|
+
padding: 0 8px 0 2px;
|
|
342
|
+
cursor: pointer;
|
|
343
|
+
user-select: none;
|
|
344
|
+
font-size: 11px;
|
|
345
|
+
font-weight: 700;
|
|
346
|
+
text-transform: uppercase;
|
|
347
|
+
color: var(--vscode-sideBarSectionHeader-foreground, var(--vscode-foreground));
|
|
348
|
+
background: var(--vscode-sideBarSectionHeader-background, transparent);
|
|
349
|
+
}
|
|
350
|
+
.weml-panel .pane-header::before {
|
|
351
|
+
content: '';
|
|
352
|
+
width: 16px;
|
|
353
|
+
height: 16px;
|
|
354
|
+
flex: none;
|
|
355
|
+
/* chevron-right, turned down when open */
|
|
356
|
+
background: currentColor;
|
|
357
|
+
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 4l4 4-4 4' fill='none' stroke='black' stroke-width='1.3'/%3E%3C/svg%3E") center / 16px no-repeat;
|
|
358
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 4l4 4-4 4' fill='none' stroke='black' stroke-width='1.3'/%3E%3C/svg%3E") center / 16px no-repeat;
|
|
359
|
+
transform: rotate(90deg);
|
|
360
|
+
transition: transform .1s;
|
|
361
|
+
}
|
|
362
|
+
.weml-panel .pane.collapsed .pane-header::before { transform: none; }
|
|
363
|
+
.weml-panel .pane-header:focus-visible { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; }
|
|
364
|
+
.weml-panel .pane-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 6px 12px 12px 20px; }
|
|
365
|
+
.weml-panel .pane.collapsed .pane-body { display: none; }
|
|
366
|
+
/* A pane that lays itself out (the search): nothing scrolls but its .scroll part. */
|
|
367
|
+
.weml-panel .pane-body.fill { display: flex; flex-direction: column; overflow: hidden; padding-bottom: 0; }
|
|
368
|
+
.weml-panel .pane-body.fill > section { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin: 0; }
|
|
369
|
+
.weml-panel .pane-body.fill > section > * { flex: none; }
|
|
370
|
+
.weml-panel .pane-body.fill .scroll { flex: 1 1 auto; min-height: 0; overflow: auto; padding-bottom: 12px; }
|
|
371
|
+
|
|
372
|
+
.weml-panel .sash { position: absolute; top: -2px; left: 0; right: 0; height: 4px; z-index: 10; display: none; }
|
|
373
|
+
.weml-panel .pane.resizable .sash { display: block; cursor: ns-resize; }
|
|
374
|
+
.weml-panel .sash:hover, .weml-panel .sash.active {
|
|
375
|
+
background: var(--vscode-sash-hoverBorder, var(--vscode-focusBorder));
|
|
376
|
+
transition: background .1s .2s;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.weml-panel .pane-body section { margin-bottom: 14px; }
|
|
380
|
+
.weml-panel .pane-body section:last-child { margin-bottom: 0; }
|
|
381
|
+
.weml-panel h2 {
|
|
382
|
+
margin: 0 0 6px;
|
|
383
|
+
font-size: 11px;
|
|
384
|
+
font-weight: 600;
|
|
385
|
+
text-transform: uppercase;
|
|
386
|
+
letter-spacing: .04em;
|
|
387
|
+
color: var(--vscode-sideBarSectionHeader-foreground, var(--vscode-foreground));
|
|
388
|
+
opacity: .8;
|
|
389
|
+
}
|
|
390
|
+
.weml-panel [hidden] { display: none !important; }
|
|
391
|
+
.weml-panel .row { display: flex; gap: 6px; margin-bottom: 6px; }
|
|
392
|
+
.weml-panel input, .weml-panel select, .weml-panel button {
|
|
393
|
+
box-sizing: border-box;
|
|
394
|
+
min-width: 0;
|
|
395
|
+
font-family: inherit;
|
|
396
|
+
font-size: inherit;
|
|
397
|
+
color: var(--vscode-input-foreground);
|
|
398
|
+
background: var(--vscode-input-background);
|
|
399
|
+
border: 1px solid var(--vscode-input-border, transparent);
|
|
400
|
+
border-radius: 2px;
|
|
401
|
+
padding: 4px 6px;
|
|
402
|
+
/* 26px with the padding and border, VS Code's input and button height (the icon buttons too). */
|
|
403
|
+
line-height: 16px;
|
|
404
|
+
}
|
|
405
|
+
.weml-panel select { height: 26px; padding-block: 0; }
|
|
406
|
+
.weml-panel select {
|
|
407
|
+
color: var(--vscode-dropdown-foreground);
|
|
408
|
+
background: var(--vscode-dropdown-background);
|
|
409
|
+
border-color: var(--vscode-dropdown-border, transparent);
|
|
410
|
+
}
|
|
411
|
+
.weml-panel input:focus, .weml-panel select:focus, .weml-panel button:focus-visible { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; }
|
|
412
|
+
.weml-panel .full { width: 100%; }
|
|
413
|
+
.weml-panel .grow { flex: 1 1 auto; }
|
|
414
|
+
.weml-panel .weml-lang { flex: 0 0 44px; }
|
|
415
|
+
|
|
416
|
+
/* Icon buttons: a square with a 16px inline SVG; the name is in title / aria-label. */
|
|
417
|
+
.weml-panel button.icon {
|
|
418
|
+
display: inline-flex;
|
|
419
|
+
align-items: center;
|
|
420
|
+
justify-content: center;
|
|
421
|
+
flex: none;
|
|
422
|
+
width: 26px;
|
|
423
|
+
height: 26px;
|
|
424
|
+
padding: 0;
|
|
425
|
+
}
|
|
426
|
+
.weml-panel button.icon svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.2; stroke-linecap: round; stroke-linejoin: round; }
|
|
427
|
+
.weml-panel button.icon.flat {
|
|
428
|
+
width: 20px;
|
|
429
|
+
height: 20px;
|
|
430
|
+
border: none;
|
|
431
|
+
background: none;
|
|
432
|
+
color: var(--vscode-icon-foreground, var(--vscode-foreground));
|
|
433
|
+
border-radius: 3px;
|
|
434
|
+
}
|
|
435
|
+
.weml-panel button.icon.flat:hover { background: var(--vscode-toolbar-hoverBackground, rgba(128, 128, 128, .2)); }
|
|
436
|
+
/* The main action of a row: the same small square, filled like a primary button. */
|
|
437
|
+
.weml-panel button.icon.flat.primary { color: var(--vscode-button-foreground); background: var(--vscode-button-background); }
|
|
438
|
+
.weml-panel button.icon.flat.primary:hover { background: var(--vscode-button-hoverBackground); }
|
|
439
|
+
|
|
440
|
+
/* The tag picker: an input with its action inside (as the find widget's toggles), and a list drawn
|
|
441
|
+
as the quick pick \u2014 rows, matched characters, group separators \u2014 on the quick input's colours,
|
|
442
|
+
which VS Code and Monaco (its own command palette) both define. */
|
|
443
|
+
.weml-panel .tool-field {
|
|
444
|
+
display: flex;
|
|
445
|
+
align-items: center;
|
|
446
|
+
gap: 2px;
|
|
447
|
+
box-sizing: border-box;
|
|
448
|
+
height: 26px;
|
|
449
|
+
padding-right: 2px;
|
|
450
|
+
background: var(--vscode-input-background);
|
|
451
|
+
border: 1px solid var(--vscode-input-border, transparent);
|
|
452
|
+
border-radius: 2px;
|
|
453
|
+
}
|
|
454
|
+
.weml-panel .tool-field:focus-within { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; }
|
|
455
|
+
.weml-panel .tool-field input { flex: 1 1 auto; height: 24px; border: none; background: none; }
|
|
456
|
+
.weml-panel .tool-field input:focus { outline: none; }
|
|
457
|
+
.weml-panel .tool-field input::placeholder, .weml-panel input::placeholder { color: var(--vscode-input-placeholderForeground); }
|
|
458
|
+
.weml-panel button[aria-disabled="true"] { opacity: .5; cursor: default; }
|
|
459
|
+
.weml-panel button.icon.flat.primary[aria-disabled="true"]:hover { background: var(--vscode-button-background); }
|
|
460
|
+
.weml-panel .tool-list {
|
|
461
|
+
position: fixed;
|
|
462
|
+
z-index: 1000;
|
|
463
|
+
box-sizing: border-box;
|
|
464
|
+
overflow-y: auto;
|
|
465
|
+
padding: 4px 0;
|
|
466
|
+
color: var(--vscode-quickInput-foreground, var(--vscode-foreground));
|
|
467
|
+
background: var(--vscode-quickInput-background, var(--vscode-editorWidget-background));
|
|
468
|
+
border: 1px solid var(--vscode-widget-border, var(--vscode-editorWidget-border, transparent));
|
|
469
|
+
border-radius: 3px;
|
|
470
|
+
box-shadow: 0 0 8px 2px var(--vscode-widget-shadow, rgba(0, 0, 0, .36));
|
|
471
|
+
}
|
|
472
|
+
.weml-panel .tool-group + .tool-group { margin-top: 4px; border-top: 1px solid var(--vscode-pickerGroup-border, transparent); }
|
|
473
|
+
.weml-panel .tool-group-label {
|
|
474
|
+
padding: 2px 8px 0;
|
|
475
|
+
text-align: right;
|
|
476
|
+
font-size: 11px;
|
|
477
|
+
line-height: 16px;
|
|
478
|
+
color: var(--vscode-pickerGroup-foreground, var(--vscode-descriptionForeground));
|
|
479
|
+
}
|
|
480
|
+
.weml-panel .tool-option {
|
|
481
|
+
display: flex;
|
|
482
|
+
align-items: center;
|
|
483
|
+
gap: 12px;
|
|
484
|
+
height: 22px;
|
|
485
|
+
padding: 0 8px;
|
|
486
|
+
white-space: nowrap;
|
|
487
|
+
cursor: pointer;
|
|
488
|
+
}
|
|
489
|
+
.weml-panel .tool-option:hover { background: var(--vscode-list-hoverBackground); }
|
|
490
|
+
.weml-panel .tool-option.active {
|
|
491
|
+
color: var(--vscode-quickInputList-focusForeground, var(--vscode-list-activeSelectionForeground));
|
|
492
|
+
background: var(--vscode-quickInputList-focusBackground, var(--vscode-list-activeSelectionBackground));
|
|
493
|
+
}
|
|
494
|
+
.weml-panel .tool-option .highlight { font-weight: 600; color: var(--vscode-list-highlightForeground); }
|
|
495
|
+
.weml-panel .tool-option.active .highlight { color: var(--vscode-list-focusHighlightForeground, var(--vscode-list-highlightForeground)); }
|
|
496
|
+
.weml-panel .tool-kind { margin-left: auto; font-size: 11px; color: var(--vscode-descriptionForeground); }
|
|
497
|
+
.weml-panel .tool-option.active .tool-kind { color: inherit; opacity: .8; }
|
|
498
|
+
.weml-panel .tool-empty { padding: 2px 8px; color: var(--vscode-descriptionForeground); }
|
|
499
|
+
|
|
500
|
+
/* Scrollbars like the workbench's lists: thin, theme-coloured, shown while the pointer is over the
|
|
501
|
+
scrolling area; a shadow under the top edge once the content is scrolled. */
|
|
502
|
+
.weml-panel .pane-body, .weml-panel .scroll { scrollbar-gutter: stable; }
|
|
503
|
+
/* Chromium ignores every ::-webkit-scrollbar rule on an element whose scrollbar-color or
|
|
504
|
+
scrollbar-width is set - and scrollbar-color inherits - drawing its standard scrollbar with arrow
|
|
505
|
+
buttons instead. Reset both, whoever set them, so the rules below apply. */
|
|
506
|
+
.weml-panel, .weml-panel *, .weml-panel *::before, .weml-panel *::after { scrollbar-color: auto !important; scrollbar-width: auto !important; }
|
|
507
|
+
.weml-panel ::-webkit-scrollbar { width: 10px; height: 10px; }
|
|
508
|
+
.weml-panel ::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
|
|
509
|
+
.weml-panel ::-webkit-scrollbar-track, .weml-panel ::-webkit-scrollbar-corner { background: transparent; }
|
|
510
|
+
.weml-panel ::-webkit-scrollbar-thumb { background: transparent; }
|
|
511
|
+
.weml-panel .pane-body:hover::-webkit-scrollbar-thumb, .weml-panel .scroll:hover::-webkit-scrollbar-thumb { background: var(--vscode-scrollbarSlider-background); }
|
|
512
|
+
.weml-panel ::-webkit-scrollbar-thumb:hover { background: var(--vscode-scrollbarSlider-hoverBackground) !important; }
|
|
513
|
+
.weml-panel ::-webkit-scrollbar-thumb:active { background: var(--vscode-scrollbarSlider-activeBackground) !important; }
|
|
514
|
+
.weml-panel .pane-body.scrolled, .weml-panel .scroll.scrolled { box-shadow: var(--vscode-scrollbar-shadow, rgba(0, 0, 0, .4)) 0 6px 6px -6px inset; }
|
|
515
|
+
.weml-panel button {
|
|
516
|
+
cursor: pointer;
|
|
517
|
+
color: var(--vscode-button-foreground);
|
|
518
|
+
background: var(--vscode-button-background);
|
|
519
|
+
border: 1px solid var(--vscode-button-border, transparent);
|
|
520
|
+
}
|
|
521
|
+
.weml-panel button:hover { background: var(--vscode-button-hoverBackground); }
|
|
522
|
+
.weml-panel button:disabled { opacity: .6; cursor: default; }
|
|
523
|
+
.weml-panel button.secondary {
|
|
524
|
+
color: var(--vscode-button-secondaryForeground);
|
|
525
|
+
background: var(--vscode-button-secondaryBackground);
|
|
526
|
+
}
|
|
527
|
+
.weml-panel button.secondary:hover { background: var(--vscode-button-secondaryHoverBackground); }
|
|
528
|
+
.weml-panel button.link {
|
|
529
|
+
padding: 0;
|
|
530
|
+
border: none;
|
|
531
|
+
background: none;
|
|
532
|
+
color: var(--vscode-textLink-foreground);
|
|
533
|
+
}
|
|
534
|
+
.weml-panel button.link:hover { background: none; color: var(--vscode-textLink-activeForeground); text-decoration: underline; }
|
|
535
|
+
|
|
536
|
+
/* Search suggestions */
|
|
537
|
+
.weml-panel .account { display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; margin-bottom: 8px; color: var(--vscode-descriptionForeground); }
|
|
538
|
+
.weml-panel .status { color: var(--vscode-descriptionForeground); margin: 4px 0; }
|
|
539
|
+
.weml-panel .status.error { color: var(--vscode-errorForeground); }
|
|
540
|
+
.weml-panel .results { list-style: none; margin: 0; padding: 0; }
|
|
541
|
+
.weml-panel .results li {
|
|
542
|
+
display: grid;
|
|
543
|
+
grid-template-columns: auto 1fr;
|
|
544
|
+
column-gap: 8px;
|
|
545
|
+
padding: 6px 0;
|
|
546
|
+
border-top: 1px solid var(--vscode-widget-border, var(--vscode-panel-border, var(--vscode-editorWidget-border)));
|
|
547
|
+
}
|
|
548
|
+
.weml-panel .results li:last-child { border-bottom: 1px solid var(--vscode-widget-border, var(--vscode-panel-border, var(--vscode-editorWidget-border))); }
|
|
549
|
+
.weml-panel .results .number { grid-row: span 3; color: var(--vscode-descriptionForeground); font-variant-numeric: tabular-nums; }
|
|
550
|
+
.weml-panel .results .meta { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; }
|
|
551
|
+
.weml-panel .results .label { color: var(--vscode-descriptionForeground); font-size: 11px; }
|
|
552
|
+
.weml-panel .results .value { font-family: var(--vscode-editor-font-family); }
|
|
553
|
+
.weml-panel .results .title { margin: 2px 0; overflow-wrap: anywhere; }
|
|
554
|
+
.weml-panel .results .field { display: inline-flex; align-items: center; gap: 2px; white-space: nowrap; }
|
|
555
|
+
/* The link and its actions share one box: the code, then Copy and Insert in a row under it. */
|
|
556
|
+
.weml-panel .results .link {
|
|
557
|
+
margin-top: 2px;
|
|
558
|
+
padding: 4px 6px 2px;
|
|
559
|
+
border-radius: 3px;
|
|
560
|
+
background: var(--vscode-textPreformat-background, var(--vscode-textCodeBlock-background));
|
|
561
|
+
}
|
|
562
|
+
.weml-panel .results .link code {
|
|
563
|
+
display: block;
|
|
564
|
+
padding: 0;
|
|
565
|
+
background: none;
|
|
566
|
+
font-family: var(--vscode-editor-font-family);
|
|
567
|
+
font-size: 11px;
|
|
568
|
+
overflow-wrap: anywhere;
|
|
569
|
+
color: var(--vscode-textPreformat-foreground);
|
|
570
|
+
}
|
|
571
|
+
.weml-panel .results .link .actions { display: flex; justify-content: flex-end; gap: 2px; margin-top: 2px; }
|
|
572
|
+
.weml-panel .dim { color: var(--vscode-descriptionForeground); }
|
|
573
|
+
`;
|
|
574
|
+
function injectPanelStyles(doc = document) {
|
|
575
|
+
if (doc.getElementById(STYLE_ID)) return;
|
|
576
|
+
const style = doc.createElement("style");
|
|
577
|
+
style.id = STYLE_ID;
|
|
578
|
+
style.textContent = PANEL_CSS;
|
|
579
|
+
doc.head.appendChild(style);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// ../weml-language-core/src/generated/schema.ts
|
|
583
|
+
var ENUMS = {
|
|
584
|
+
"entity-type": {
|
|
585
|
+
"id": "entity-type",
|
|
586
|
+
"title": "Entity type",
|
|
587
|
+
"values": [
|
|
588
|
+
{
|
|
589
|
+
"value": "addressee",
|
|
590
|
+
"name": "Addressee",
|
|
591
|
+
"description": "For Letter it means person whom this letter is addressed to."
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
"value": "date",
|
|
595
|
+
"name": "Date",
|
|
596
|
+
"description": "Date entity. For LT/MS it means date when document was written. Optional value contains single date, range of dates (two date via `...`) or two different date via `,` \u2014 all of dates must be in ISO 8601 format."
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
"value": "place",
|
|
600
|
+
"name": "Place",
|
|
601
|
+
"description": "Place. For Lt/Ms it means place where manuscript was written"
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
"value": "topic",
|
|
605
|
+
"name": "Topic",
|
|
606
|
+
"description": "Topic entity. For topical index it marks whole topic. For dictionary it marks topic in the header."
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
"value": "topic-word",
|
|
610
|
+
"name": "Topic word",
|
|
611
|
+
"description": "Topic word entity. For topical index it marks the main term of a topic. For dictionary it marks topic in the regular paragraph."
|
|
612
|
+
}
|
|
613
|
+
]
|
|
614
|
+
},
|
|
615
|
+
"horizontal-alignment": {
|
|
616
|
+
"id": "horizontal-alignment",
|
|
617
|
+
"title": "Horizontal Alignment",
|
|
618
|
+
"values": [
|
|
619
|
+
{
|
|
620
|
+
"value": "left",
|
|
621
|
+
"name": "Left",
|
|
622
|
+
"description": "Align text to the left"
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
"value": "center",
|
|
626
|
+
"name": "Center",
|
|
627
|
+
"description": "Align text to the center"
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
"value": "right",
|
|
631
|
+
"name": "Right",
|
|
632
|
+
"description": "Align text to the right"
|
|
633
|
+
}
|
|
634
|
+
]
|
|
635
|
+
},
|
|
636
|
+
"figure-alignment": {
|
|
637
|
+
"id": "figure-alignment",
|
|
638
|
+
"title": "Figure Alignment",
|
|
639
|
+
"values": [
|
|
640
|
+
{
|
|
641
|
+
"value": "left",
|
|
642
|
+
"name": "Left",
|
|
643
|
+
"description": "Align to the left"
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
"value": "center",
|
|
647
|
+
"name": "Center",
|
|
648
|
+
"description": "Align to the center"
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
"value": "right",
|
|
652
|
+
"name": "Right",
|
|
653
|
+
"description": "Align to the right"
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
"value": "justify",
|
|
657
|
+
"name": "Justify",
|
|
658
|
+
"description": "Full-width alignment"
|
|
659
|
+
}
|
|
660
|
+
]
|
|
661
|
+
},
|
|
662
|
+
"list-type": {
|
|
663
|
+
"id": "list-type",
|
|
664
|
+
"title": "List Type",
|
|
665
|
+
"values": [
|
|
666
|
+
{
|
|
667
|
+
"value": "unordered",
|
|
668
|
+
"name": "Unordered",
|
|
669
|
+
"description": "Unordered list. Each item is marked with a bullet."
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
"value": "ordered",
|
|
673
|
+
"name": "Ordered",
|
|
674
|
+
"description": "Ordered list. Each item is marked with a number."
|
|
675
|
+
}
|
|
676
|
+
]
|
|
677
|
+
},
|
|
678
|
+
"non-egw-type": {
|
|
679
|
+
"id": "non-egw-type",
|
|
680
|
+
"title": "Non-EGW Type",
|
|
681
|
+
"values": [
|
|
682
|
+
{
|
|
683
|
+
"value": "appendix",
|
|
684
|
+
"name": "Appendix",
|
|
685
|
+
"description": "Non-EGW Appendix"
|
|
686
|
+
},
|
|
687
|
+
{
|
|
688
|
+
"value": "comment",
|
|
689
|
+
"name": "Comment",
|
|
690
|
+
"description": "Non-EGW Commentary"
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
"value": "foreword",
|
|
694
|
+
"name": "Foreword",
|
|
695
|
+
"description": "Non-EGW Foreword"
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
"value": "intro",
|
|
699
|
+
"name": "Intro",
|
|
700
|
+
"description": "Non-EGW Introduction"
|
|
701
|
+
},
|
|
702
|
+
{
|
|
703
|
+
"value": "note",
|
|
704
|
+
"name": "Note",
|
|
705
|
+
"description": "Non-EGW Note"
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
"value": "preface",
|
|
709
|
+
"name": "Preface",
|
|
710
|
+
"description": "Non-EGW Preface"
|
|
711
|
+
},
|
|
712
|
+
{
|
|
713
|
+
"value": "text",
|
|
714
|
+
"name": "Text",
|
|
715
|
+
"description": "Non-EGW Text"
|
|
716
|
+
}
|
|
717
|
+
]
|
|
718
|
+
},
|
|
719
|
+
"note-types": {
|
|
720
|
+
"id": "note-types",
|
|
721
|
+
"title": "Note types",
|
|
722
|
+
"values": [
|
|
723
|
+
{
|
|
724
|
+
"value": "footnote",
|
|
725
|
+
"name": "Footnote",
|
|
726
|
+
"description": "Placed at the bottom of the page."
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
"value": "chapter-endnote",
|
|
730
|
+
"name": "Chapter End Note",
|
|
731
|
+
"description": "Placed at the end of the chapter."
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
"value": "book-endnote",
|
|
735
|
+
"name": "Book End Note",
|
|
736
|
+
"description": "Placed at the end of the book"
|
|
737
|
+
}
|
|
738
|
+
]
|
|
739
|
+
},
|
|
740
|
+
"paragraph-role": {
|
|
741
|
+
"id": "paragraph-role",
|
|
742
|
+
"title": "Paragraph role",
|
|
743
|
+
"values": [
|
|
744
|
+
{
|
|
745
|
+
"value": "address",
|
|
746
|
+
"name": "Address",
|
|
747
|
+
"description": "Paragraph contains address. For letter it means address of the addressee"
|
|
748
|
+
},
|
|
749
|
+
{
|
|
750
|
+
"value": "addressee",
|
|
751
|
+
"name": "Addressee",
|
|
752
|
+
"description": "Paragraph contains addressee. For letter it means addressee name"
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
"value": "author",
|
|
756
|
+
"name": "Author",
|
|
757
|
+
"description": "Paragraph contains author name."
|
|
758
|
+
},
|
|
759
|
+
{
|
|
760
|
+
"value": "date",
|
|
761
|
+
"name": "Date",
|
|
762
|
+
"description": "Paragraph contains date."
|
|
763
|
+
},
|
|
764
|
+
{
|
|
765
|
+
"value": "place",
|
|
766
|
+
"name": "Place",
|
|
767
|
+
"description": "Paragraph contains place."
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
"value": "introduction",
|
|
771
|
+
"name": "Introduction",
|
|
772
|
+
"description": "Paragraph contains introduction text."
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
"value": "letterhead",
|
|
776
|
+
"name": "Letterhead",
|
|
777
|
+
"description": "Paragraph contains letter header."
|
|
778
|
+
},
|
|
779
|
+
{
|
|
780
|
+
"value": "salutation",
|
|
781
|
+
"name": "Salutation",
|
|
782
|
+
"description": "Paragraph contains salutation."
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
"value": "signature-date",
|
|
786
|
+
"name": "Signature Date",
|
|
787
|
+
"description": "Paragraph contains signature date."
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
"value": "signature-line",
|
|
791
|
+
"name": "Signature Line",
|
|
792
|
+
"description": "Paragraph contains signature line."
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
"value": "signature-source",
|
|
796
|
+
"name": "Signature Source",
|
|
797
|
+
"description": "Paragraph contains signature source."
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
"value": "bible-text",
|
|
801
|
+
"name": "Bible Text",
|
|
802
|
+
"description": "Paragraph contains Bible text."
|
|
803
|
+
},
|
|
804
|
+
{
|
|
805
|
+
"value": "devotional-text",
|
|
806
|
+
"name": "Devotional Text",
|
|
807
|
+
"description": "Paragraph contains devotional text."
|
|
808
|
+
},
|
|
809
|
+
{
|
|
810
|
+
"value": "poem-source",
|
|
811
|
+
"name": "Poem Source",
|
|
812
|
+
"description": "Paragraph contains poem source."
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
"value": "publication-info",
|
|
816
|
+
"name": "Publication Info",
|
|
817
|
+
"description": "Paragraph contains publication info."
|
|
818
|
+
},
|
|
819
|
+
{
|
|
820
|
+
"value": "title",
|
|
821
|
+
"name": "Title",
|
|
822
|
+
"description": "Paragraph contains title."
|
|
823
|
+
}
|
|
824
|
+
]
|
|
825
|
+
},
|
|
826
|
+
"paragraph-type": {
|
|
827
|
+
"id": "paragraph-type",
|
|
828
|
+
"title": "Paragraph type",
|
|
829
|
+
"values": [
|
|
830
|
+
{
|
|
831
|
+
"value": "blockquote",
|
|
832
|
+
"name": "Blockquote",
|
|
833
|
+
"description": "Blockquote"
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
"value": "paragraph",
|
|
837
|
+
"name": "Paragraph",
|
|
838
|
+
"description": "Paragraph"
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
"value": "poem",
|
|
842
|
+
"name": "Poem",
|
|
843
|
+
"description": "Poem. Lines are separated with <br/>"
|
|
844
|
+
}
|
|
845
|
+
]
|
|
846
|
+
},
|
|
847
|
+
"paragraphs-group-type": {
|
|
848
|
+
"id": "paragraphs-group-type",
|
|
849
|
+
"title": "Paragraphs group type",
|
|
850
|
+
"values": [
|
|
851
|
+
{
|
|
852
|
+
"value": "frame",
|
|
853
|
+
"name": "Frame",
|
|
854
|
+
"description": "Blockquote with several paragraphs"
|
|
855
|
+
}
|
|
856
|
+
]
|
|
857
|
+
},
|
|
858
|
+
"publication-type": {
|
|
859
|
+
"id": "publication-type",
|
|
860
|
+
"title": "Publication Type",
|
|
861
|
+
"values": [
|
|
862
|
+
{
|
|
863
|
+
"value": "bible",
|
|
864
|
+
"name": "Bible",
|
|
865
|
+
"description": "Bible translation"
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
"value": "bible-commentary",
|
|
869
|
+
"name": "Bible Commentary",
|
|
870
|
+
"description": "Bible commentaries"
|
|
871
|
+
},
|
|
872
|
+
{
|
|
873
|
+
"value": "book",
|
|
874
|
+
"name": "Book",
|
|
875
|
+
"description": "Paginated book"
|
|
876
|
+
},
|
|
877
|
+
{
|
|
878
|
+
"value": "devotional",
|
|
879
|
+
"name": "Devotional",
|
|
880
|
+
"description": "Daily devotional"
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
"value": "dictionary",
|
|
884
|
+
"name": "Dictionary",
|
|
885
|
+
"description": "Dictionary"
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
"value": "manuscript-volume",
|
|
889
|
+
"name": "Manuscript Volume",
|
|
890
|
+
"description": "One of EGW Lt&Ms bound volumes"
|
|
891
|
+
},
|
|
892
|
+
{
|
|
893
|
+
"value": "periodical/page-break",
|
|
894
|
+
"name": "Periodical",
|
|
895
|
+
"description": "Periodical with page markers"
|
|
896
|
+
},
|
|
897
|
+
{
|
|
898
|
+
"value": "periodical/no-page-break",
|
|
899
|
+
"name": "Periodical",
|
|
900
|
+
"description": "Periodical without page markers"
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
"value": "topical-index",
|
|
904
|
+
"name": "Topical Index",
|
|
905
|
+
"description": "Topical index"
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
"value": "scripture-index",
|
|
909
|
+
"name": "Scripture Index",
|
|
910
|
+
"description": "Scripture index"
|
|
911
|
+
}
|
|
912
|
+
]
|
|
913
|
+
},
|
|
914
|
+
"text-direction": {
|
|
915
|
+
"id": "text-direction",
|
|
916
|
+
"title": "Text Direction",
|
|
917
|
+
"values": [
|
|
918
|
+
{
|
|
919
|
+
"value": "ltr",
|
|
920
|
+
"name": "Left to right",
|
|
921
|
+
"description": "Text is written from left to right"
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
"value": "rtl",
|
|
925
|
+
"name": "Right to left",
|
|
926
|
+
"description": "Text is written from right to left"
|
|
927
|
+
}
|
|
928
|
+
]
|
|
929
|
+
},
|
|
930
|
+
"text-formatting": {
|
|
931
|
+
"id": "text-formatting",
|
|
932
|
+
"title": "Text formatting",
|
|
933
|
+
"values": [
|
|
934
|
+
{
|
|
935
|
+
"value": "bold",
|
|
936
|
+
"name": "Bold",
|
|
937
|
+
"description": "Bold text"
|
|
938
|
+
},
|
|
939
|
+
{
|
|
940
|
+
"value": "italic",
|
|
941
|
+
"name": "Italic",
|
|
942
|
+
"description": "Italic text"
|
|
943
|
+
},
|
|
944
|
+
{
|
|
945
|
+
"value": "underline",
|
|
946
|
+
"name": "Underline",
|
|
947
|
+
"description": "Underlined text"
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
"value": "superscript",
|
|
951
|
+
"name": "Superscript",
|
|
952
|
+
"description": "Superscript text"
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
"value": "subscript",
|
|
956
|
+
"name": "Subscript",
|
|
957
|
+
"description": "Subscript text"
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
"value": "small-caps",
|
|
961
|
+
"name": "Small Caps",
|
|
962
|
+
"description": "Small caps text"
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
"value": "all-caps",
|
|
966
|
+
"name": "All Caps",
|
|
967
|
+
"description": "All caps text"
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
"value": "overline",
|
|
971
|
+
"name": "Overline",
|
|
972
|
+
"description": "Overlined text"
|
|
973
|
+
}
|
|
974
|
+
]
|
|
975
|
+
},
|
|
976
|
+
"vertical-alignment": {
|
|
977
|
+
"id": "vertical-alignment",
|
|
978
|
+
"title": "Vertical Alignment",
|
|
979
|
+
"values": [
|
|
980
|
+
{
|
|
981
|
+
"value": "top",
|
|
982
|
+
"name": "Top alignment",
|
|
983
|
+
"description": "Align text to the top"
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
"value": "center",
|
|
987
|
+
"name": "Center alignment",
|
|
988
|
+
"description": "Align text to the center"
|
|
989
|
+
},
|
|
990
|
+
{
|
|
991
|
+
"value": "bottom",
|
|
992
|
+
"name": "Bottom alignment",
|
|
993
|
+
"description": "Align text to the bottom"
|
|
994
|
+
}
|
|
995
|
+
]
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
|
|
999
|
+
// ../weml-language-core/src/toolbar/toolModel.ts
|
|
1000
|
+
var WRAP_INLINE_TAGS = ["w-color", "w-lang", "w-non-egw", "w-entity", "w-sent", "a"];
|
|
1001
|
+
var WRAP_OPTIONS = [
|
|
1002
|
+
...(ENUMS["text-formatting"]?.values ?? []).map((v) => ({
|
|
1003
|
+
value: `w-format:${v.value}`,
|
|
1004
|
+
label: `w-format.${v.value}`,
|
|
1005
|
+
tag: "w-format",
|
|
1006
|
+
type: v.value
|
|
1007
|
+
})),
|
|
1008
|
+
...WRAP_INLINE_TAGS.map((t) => ({ value: t, label: t, tag: t }))
|
|
1009
|
+
];
|
|
1010
|
+
var TOOL_GROUPS = ["Containers", "Blocks", "Inlines"];
|
|
1011
|
+
var ANCHOR_SNIPPET_ID = "a (anchor)";
|
|
1012
|
+
var INSERT_TOOLS = [
|
|
1013
|
+
...["w-para", "w-heading", "w-para-group", "w-toc"].map((tag) => ({ label: tag, id: tag, group: "Containers" })),
|
|
1014
|
+
// A new section of <body>: a <div id> with its container, or with a page break (the docs list
|
|
1015
|
+
// `w-page` among the containers too: a <div> holds one container or one `w-page`).
|
|
1016
|
+
...["div + w-para", "div + w-heading", "div + w-para-group", "div + w-toc", "div + w-page"].map((id) => ({
|
|
1017
|
+
label: id,
|
|
1018
|
+
id,
|
|
1019
|
+
group: "Containers",
|
|
1020
|
+
documentOnly: true
|
|
1021
|
+
})),
|
|
1022
|
+
{ label: "w-text-block", id: "w-text-block", group: "Blocks" },
|
|
1023
|
+
{ label: "table", id: "table (with row)", group: "Blocks" },
|
|
1024
|
+
{ label: "w-list", id: "w-list (with item)", group: "Blocks" },
|
|
1025
|
+
{ label: "figure", id: "figure (with caption)", group: "Blocks" },
|
|
1026
|
+
{ label: "hr", id: "hr", group: "Blocks" },
|
|
1027
|
+
...["w-note", "w-page", "br"].map((tag) => ({ label: tag, id: tag, group: "Inlines" })),
|
|
1028
|
+
{ label: ANCHOR_SNIPPET_ID, id: ANCHOR_SNIPPET_ID, group: "Inlines" }
|
|
1029
|
+
];
|
|
1030
|
+
var TOOL_ITEMS = (() => {
|
|
1031
|
+
const items = [
|
|
1032
|
+
...INSERT_TOOLS.map((tool) => ({
|
|
1033
|
+
value: tool.label,
|
|
1034
|
+
label: tool.label,
|
|
1035
|
+
group: tool.group,
|
|
1036
|
+
action: { kind: "insert", snippetId: tool.id },
|
|
1037
|
+
...tool.documentOnly ? { documentOnly: true } : {}
|
|
1038
|
+
})),
|
|
1039
|
+
...WRAP_OPTIONS.map((option) => ({
|
|
1040
|
+
value: option.value,
|
|
1041
|
+
// `a` wraps as a link; the anchor is an insert of its own.
|
|
1042
|
+
label: option.tag === "a" ? "a (link)" : option.label,
|
|
1043
|
+
group: "Inlines",
|
|
1044
|
+
action: { kind: "wrap", option }
|
|
1045
|
+
}))
|
|
1046
|
+
];
|
|
1047
|
+
return TOOL_GROUPS.flatMap((group) => items.filter((item) => item.group === group));
|
|
1048
|
+
})();
|
|
1049
|
+
function toolItemsFor(mode = "file") {
|
|
1050
|
+
return mode === "paragraph" ? TOOL_ITEMS.filter((item) => !item.documentOnly) : TOOL_ITEMS;
|
|
1051
|
+
}
|
|
1052
|
+
function filterToolItems(query, items = TOOL_ITEMS) {
|
|
1053
|
+
const needle = query.trim().toLowerCase();
|
|
1054
|
+
if (!needle) return items.map((item) => ({ item, matches: [] }));
|
|
1055
|
+
const found = [];
|
|
1056
|
+
for (const item of items) {
|
|
1057
|
+
const at = item.label.toLowerCase().indexOf(needle);
|
|
1058
|
+
if (at >= 0) found.push({ item, matches: [[at, at + needle.length]] });
|
|
1059
|
+
}
|
|
1060
|
+
return found;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// src/panel/toolPicker.ts
|
|
1064
|
+
var PAGE = 8;
|
|
1065
|
+
var MAX_LIST_HEIGHT = 320;
|
|
1066
|
+
var pickers = 0;
|
|
1067
|
+
function createToolPicker(tools, state, mode = "file") {
|
|
1068
|
+
const items = toolItemsFor(mode);
|
|
1069
|
+
const id = `weml-tool-picker-${++pickers}`;
|
|
1070
|
+
const input = element("input", { className: "tool-input" });
|
|
1071
|
+
input.type = "text";
|
|
1072
|
+
input.placeholder = "Tag to wrap or insert";
|
|
1073
|
+
input.spellcheck = false;
|
|
1074
|
+
input.autocomplete = "off";
|
|
1075
|
+
input.setAttribute("role", "combobox");
|
|
1076
|
+
input.setAttribute("aria-label", "Tag to wrap or insert");
|
|
1077
|
+
input.setAttribute("aria-autocomplete", "list");
|
|
1078
|
+
input.setAttribute("aria-expanded", "false");
|
|
1079
|
+
input.setAttribute("aria-controls", `${id}-list`);
|
|
1080
|
+
const action = button({ className: "icon flat primary" }, () => apply());
|
|
1081
|
+
const field = element("div", { className: "tool-field" }, [input, action]);
|
|
1082
|
+
const list = element("div", { className: "tool-list" });
|
|
1083
|
+
list.id = `${id}-list`;
|
|
1084
|
+
list.setAttribute("role", "listbox");
|
|
1085
|
+
list.hidden = true;
|
|
1086
|
+
list.addEventListener("mousedown", (event) => event.preventDefault());
|
|
1087
|
+
const view = () => input.ownerDocument.defaultView;
|
|
1088
|
+
let chosen = items.find((item) => item.value === state.get()?.tool);
|
|
1089
|
+
let shown = [];
|
|
1090
|
+
let active = -1;
|
|
1091
|
+
const updateAction = () => {
|
|
1092
|
+
const label = !chosen ? "Choose a tag first" : chosen.action.kind === "wrap" ? `Wrap selection in ${chosen.label}` : `Insert ${chosen.label}`;
|
|
1093
|
+
action.replaceChildren(icon(chosen?.action.kind === "insert" ? "add" : "wrap"));
|
|
1094
|
+
action.title = label;
|
|
1095
|
+
action.setAttribute("aria-label", label);
|
|
1096
|
+
action.setAttribute("aria-disabled", String(!chosen));
|
|
1097
|
+
};
|
|
1098
|
+
const apply = () => {
|
|
1099
|
+
if (!chosen) return;
|
|
1100
|
+
if (chosen.action.kind === "wrap") tools.wrap(chosen.action.option);
|
|
1101
|
+
else tools.insertSnippet(chosen.action.snippetId);
|
|
1102
|
+
};
|
|
1103
|
+
const choose = (item) => {
|
|
1104
|
+
chosen = item;
|
|
1105
|
+
input.value = item.label;
|
|
1106
|
+
state.set({ tool: item.value });
|
|
1107
|
+
updateAction();
|
|
1108
|
+
close();
|
|
1109
|
+
};
|
|
1110
|
+
const query = () => chosen && input.value === chosen.label ? "" : input.value;
|
|
1111
|
+
const optionId = (index) => `${id}-option-${index}`;
|
|
1112
|
+
const setActive = (index) => {
|
|
1113
|
+
list.querySelector(".tool-option.active")?.classList.remove("active");
|
|
1114
|
+
active = shown.length ? Math.max(0, Math.min(shown.length - 1, index)) : -1;
|
|
1115
|
+
const node = active >= 0 ? list.querySelector(`#${optionId(active)}`) : null;
|
|
1116
|
+
node?.classList.add("active");
|
|
1117
|
+
node?.scrollIntoView?.({ block: "nearest" });
|
|
1118
|
+
if (node) input.setAttribute("aria-activedescendant", node.id);
|
|
1119
|
+
else input.removeAttribute("aria-activedescendant");
|
|
1120
|
+
};
|
|
1121
|
+
const render = () => {
|
|
1122
|
+
shown = filterToolItems(query(), items);
|
|
1123
|
+
list.replaceChildren();
|
|
1124
|
+
if (!shown.length) {
|
|
1125
|
+
list.append(element("div", { className: "tool-empty", text: "No such tag" }));
|
|
1126
|
+
}
|
|
1127
|
+
let index = 0;
|
|
1128
|
+
for (const group of TOOL_GROUPS) {
|
|
1129
|
+
const inGroup = shown.filter((match) => match.item.group === group);
|
|
1130
|
+
if (!inGroup.length) continue;
|
|
1131
|
+
const node = element("div", { className: "tool-group" });
|
|
1132
|
+
node.setAttribute("role", "group");
|
|
1133
|
+
node.setAttribute("aria-label", group);
|
|
1134
|
+
node.append(element("div", { className: "tool-group-label", text: group }));
|
|
1135
|
+
for (const match of inGroup) {
|
|
1136
|
+
const at = index++;
|
|
1137
|
+
const option = element("div", { className: "tool-option" }, [
|
|
1138
|
+
highlighted(match),
|
|
1139
|
+
element("span", { className: "tool-kind", text: match.item.action.kind })
|
|
1140
|
+
]);
|
|
1141
|
+
option.id = optionId(at);
|
|
1142
|
+
option.setAttribute("role", "option");
|
|
1143
|
+
option.setAttribute("aria-selected", String(match.item === chosen));
|
|
1144
|
+
option.addEventListener("click", () => choose(match.item));
|
|
1145
|
+
node.append(option);
|
|
1146
|
+
}
|
|
1147
|
+
list.append(node);
|
|
1148
|
+
}
|
|
1149
|
+
const current = shown.findIndex((match) => match.item === chosen);
|
|
1150
|
+
setActive(current >= 0 ? current : 0);
|
|
1151
|
+
};
|
|
1152
|
+
const place = () => {
|
|
1153
|
+
const rect = field.getBoundingClientRect();
|
|
1154
|
+
const below = (view()?.innerHeight ?? 0) - rect.bottom - 8;
|
|
1155
|
+
list.style.left = `${rect.left}px`;
|
|
1156
|
+
list.style.top = `${rect.bottom}px`;
|
|
1157
|
+
list.style.width = `${rect.width}px`;
|
|
1158
|
+
list.style.maxHeight = `${Math.max(88, Math.min(MAX_LIST_HEIGHT, below))}px`;
|
|
1159
|
+
};
|
|
1160
|
+
const open = () => {
|
|
1161
|
+
if (list.hidden) {
|
|
1162
|
+
list.hidden = false;
|
|
1163
|
+
input.setAttribute("aria-expanded", "true");
|
|
1164
|
+
view()?.addEventListener("resize", close);
|
|
1165
|
+
view()?.addEventListener("scroll", onScroll, true);
|
|
1166
|
+
}
|
|
1167
|
+
render();
|
|
1168
|
+
place();
|
|
1169
|
+
};
|
|
1170
|
+
function close() {
|
|
1171
|
+
if (list.hidden) return;
|
|
1172
|
+
list.hidden = true;
|
|
1173
|
+
input.setAttribute("aria-expanded", "false");
|
|
1174
|
+
input.removeAttribute("aria-activedescendant");
|
|
1175
|
+
view()?.removeEventListener("resize", close);
|
|
1176
|
+
view()?.removeEventListener("scroll", onScroll, true);
|
|
1177
|
+
}
|
|
1178
|
+
function onScroll(event) {
|
|
1179
|
+
if (event.target !== list) close();
|
|
1180
|
+
}
|
|
1181
|
+
let keepSelection = false;
|
|
1182
|
+
input.addEventListener("focus", () => {
|
|
1183
|
+
if (chosen && input.value === chosen.label) {
|
|
1184
|
+
input.select();
|
|
1185
|
+
keepSelection = true;
|
|
1186
|
+
}
|
|
1187
|
+
open();
|
|
1188
|
+
});
|
|
1189
|
+
input.addEventListener("mouseup", (event) => {
|
|
1190
|
+
if (keepSelection) event.preventDefault();
|
|
1191
|
+
keepSelection = false;
|
|
1192
|
+
});
|
|
1193
|
+
input.addEventListener("click", () => {
|
|
1194
|
+
if (list.hidden) open();
|
|
1195
|
+
});
|
|
1196
|
+
input.addEventListener("input", () => {
|
|
1197
|
+
if (!input.value && chosen) {
|
|
1198
|
+
chosen = void 0;
|
|
1199
|
+
state.set({});
|
|
1200
|
+
updateAction();
|
|
1201
|
+
}
|
|
1202
|
+
open();
|
|
1203
|
+
});
|
|
1204
|
+
input.addEventListener("blur", () => {
|
|
1205
|
+
close();
|
|
1206
|
+
input.value = chosen?.label ?? "";
|
|
1207
|
+
});
|
|
1208
|
+
input.addEventListener("keydown", (event) => {
|
|
1209
|
+
const moves = { ArrowDown: 1, ArrowUp: -1, PageDown: PAGE, PageUp: -PAGE };
|
|
1210
|
+
if (event.key in moves) {
|
|
1211
|
+
event.preventDefault();
|
|
1212
|
+
if (list.hidden) open();
|
|
1213
|
+
else setActive(active + moves[event.key]);
|
|
1214
|
+
} else if (event.key === "Enter") {
|
|
1215
|
+
event.preventDefault();
|
|
1216
|
+
const match = list.hidden ? void 0 : shown[active];
|
|
1217
|
+
if (match) choose(match.item);
|
|
1218
|
+
} else if (event.key === "Escape") {
|
|
1219
|
+
if (list.hidden) return;
|
|
1220
|
+
event.preventDefault();
|
|
1221
|
+
event.stopPropagation();
|
|
1222
|
+
close();
|
|
1223
|
+
input.value = chosen?.label ?? "";
|
|
1224
|
+
} else if (event.key === "Tab") {
|
|
1225
|
+
close();
|
|
1226
|
+
}
|
|
1227
|
+
});
|
|
1228
|
+
input.value = chosen?.label ?? "";
|
|
1229
|
+
updateAction();
|
|
1230
|
+
return {
|
|
1231
|
+
element: element("div", { className: "tool-picker" }, [field, list]),
|
|
1232
|
+
dispose: close
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
function highlighted({ item, matches }) {
|
|
1236
|
+
const label = element("span", { className: "tool-label" });
|
|
1237
|
+
let at = 0;
|
|
1238
|
+
for (const [start, end] of matches) {
|
|
1239
|
+
if (start > at) label.append(item.label.slice(at, start));
|
|
1240
|
+
label.append(element("span", { className: "highlight", text: item.label.slice(start, end) }));
|
|
1241
|
+
at = end;
|
|
1242
|
+
}
|
|
1243
|
+
if (at < item.label.length) label.append(item.label.slice(at));
|
|
1244
|
+
return label;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
// src/panel/toolsPane.ts
|
|
1248
|
+
function createToolsPane(tools, options) {
|
|
1249
|
+
const root = element("div");
|
|
1250
|
+
const picker = createToolPicker(tools, options.state, options.mode);
|
|
1251
|
+
root.append(element("section", {}, [element("h2", { text: "Wrap or insert" }), picker.element]));
|
|
1252
|
+
if (options.mode === "file") {
|
|
1253
|
+
root.append(element("section", {}, [
|
|
1254
|
+
element("h2", { text: "Document" }),
|
|
1255
|
+
button({ text: "Renumber div ids (1\u2026n)", className: "full" }, () => tools.renumber())
|
|
1256
|
+
]));
|
|
1257
|
+
}
|
|
1258
|
+
return { element: root, dispose: picker.dispose };
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// src/panel/panel.ts
|
|
1262
|
+
var TOOLS = "tools";
|
|
1263
|
+
var SEARCH = "suggestions";
|
|
1264
|
+
function createWemlPanel(host, options = {}) {
|
|
1265
|
+
if (options.injectStyles !== false) injectPanelStyles();
|
|
1266
|
+
let memory = {};
|
|
1267
|
+
try {
|
|
1268
|
+
const stored = host.storage?.get();
|
|
1269
|
+
if (stored && typeof stored === "object") memory = { ...stored };
|
|
1270
|
+
} catch {
|
|
1271
|
+
}
|
|
1272
|
+
const save = () => {
|
|
1273
|
+
try {
|
|
1274
|
+
host.storage?.set(memory);
|
|
1275
|
+
} catch {
|
|
1276
|
+
}
|
|
1277
|
+
};
|
|
1278
|
+
const toolsPane = createToolsPane(host.tools, {
|
|
1279
|
+
mode: options.mode ?? "file",
|
|
1280
|
+
state: {
|
|
1281
|
+
get: () => memory.modules?.[TOOLS],
|
|
1282
|
+
set: (value) => {
|
|
1283
|
+
memory.modules = { ...memory.modules, [TOOLS]: value };
|
|
1284
|
+
save();
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
});
|
|
1288
|
+
const specs = [{ id: TOOLS, title: "Tools", body: toolsPane.element }];
|
|
1289
|
+
const search = host.search ? createSearchPane(host.search, {
|
|
1290
|
+
get: () => memory.modules?.[SEARCH],
|
|
1291
|
+
set: (value) => {
|
|
1292
|
+
memory.modules = { ...memory.modules, [SEARCH]: value };
|
|
1293
|
+
save();
|
|
1294
|
+
}
|
|
1295
|
+
}) : void 0;
|
|
1296
|
+
if (search) {
|
|
1297
|
+
specs.push({ id: SEARCH, title: "Search Suggestions", body: search.element, fill: true });
|
|
1298
|
+
}
|
|
1299
|
+
const panes = createPanes(specs, memory, save);
|
|
1300
|
+
const element2 = document.createElement("div");
|
|
1301
|
+
element2.className = options.monacoTheme === false ? PANEL_CLASS : `${PANEL_CLASS} monaco-component`;
|
|
1302
|
+
element2.append(panes.element);
|
|
1303
|
+
options.container?.append(element2);
|
|
1304
|
+
return {
|
|
1305
|
+
element: element2,
|
|
1306
|
+
dispose: () => {
|
|
1307
|
+
toolsPane.dispose();
|
|
1308
|
+
search?.dispose();
|
|
1309
|
+
panes.dispose();
|
|
1310
|
+
element2.remove();
|
|
1311
|
+
}
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
//# sourceMappingURL=panel.cjs.map
|