@rathkit/rte-ui 0.1.0-alpha.3 → 0.1.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/css/base.css +198 -190
- package/dist/element-define.d.ts +1 -0
- package/dist/element-define.js +2 -0
- package/dist/element.d.ts +23 -0
- package/dist/element.js +62 -0
- package/dist/findbar.js +10 -10
- package/dist/floating.d.ts +24 -0
- package/dist/floating.js +286 -0
- package/dist/messages.js +2 -0
- package/dist/shortcuts.js +2 -2
- package/dist/source.js +7 -7
- package/dist/standard.d.ts +0 -3
- package/dist/standard.js +0 -1
- package/dist/types.d.ts +15 -4
- package/dist/ui.js +43 -31
- package/package.json +20 -6
package/dist/ui.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { checkFields, createAnnouncer, createDialog, createMenu, createToolbar, createTooltip } from "@rathkit/rte-headless";
|
|
2
2
|
import { createFindBar } from "./findbar.js";
|
|
3
|
+
import { createFloating } from "./floating.js";
|
|
3
4
|
import { setIcon } from "./icon.js";
|
|
4
5
|
import { createShortcuts } from "./shortcuts.js";
|
|
5
6
|
import { createSourceView } from "./source.js";
|
|
@@ -18,7 +19,7 @@ export function createUi(editor, options) {
|
|
|
18
19
|
const appliedClasses = new Map();
|
|
19
20
|
const parts = new Map();
|
|
20
21
|
const part = (el, name) => {
|
|
21
|
-
el.setAttribute("data-
|
|
22
|
+
el.setAttribute("data-rte-part", name);
|
|
22
23
|
let set = parts.get(name);
|
|
23
24
|
if (!set)
|
|
24
25
|
parts.set(name, (set = new Set()));
|
|
@@ -28,7 +29,7 @@ export function createUi(editor, options) {
|
|
|
28
29
|
return el;
|
|
29
30
|
};
|
|
30
31
|
const message = (key, fallback = "", values = {}) => text(style.messages, key, fallback, values);
|
|
31
|
-
root.classList.add("
|
|
32
|
+
root.classList.add("rte-root");
|
|
32
33
|
part(root, "root");
|
|
33
34
|
const toolbarEl = part(document.createElement("div"), "toolbar");
|
|
34
35
|
const contentEl = part(document.createElement("div"), "content");
|
|
@@ -81,9 +82,9 @@ export function createUi(editor, options) {
|
|
|
81
82
|
: given;
|
|
82
83
|
style = next;
|
|
83
84
|
const set = (name, value) => (value === undefined ? root.removeAttribute(name) : root.setAttribute(name, value));
|
|
84
|
-
set("data-
|
|
85
|
-
set("data-
|
|
86
|
-
set("data-
|
|
85
|
+
set("data-rte-theme", next.theme);
|
|
86
|
+
set("data-rte-scheme", next.scheme);
|
|
87
|
+
set("data-rte-density", next.density);
|
|
87
88
|
for (const name of [...appliedTokens])
|
|
88
89
|
if (!(next.tokens && name in next.tokens)) {
|
|
89
90
|
root.style.removeProperty(name);
|
|
@@ -107,6 +108,7 @@ export function createUi(editor, options) {
|
|
|
107
108
|
draw();
|
|
108
109
|
findBar?.refresh();
|
|
109
110
|
shortcuts.refresh();
|
|
111
|
+
floating?.refresh();
|
|
110
112
|
}
|
|
111
113
|
syncDialogs();
|
|
112
114
|
}
|
|
@@ -114,6 +116,7 @@ export function createUi(editor, options) {
|
|
|
114
116
|
return name === undefined ? undefined : style.icons?.[name];
|
|
115
117
|
}
|
|
116
118
|
let unbind;
|
|
119
|
+
let floating;
|
|
117
120
|
function labelOf(item) {
|
|
118
121
|
return message(`item.${item.id}`, toolbar.state(item.id)?.label ?? item.id);
|
|
119
122
|
}
|
|
@@ -127,7 +130,7 @@ export function createUi(editor, options) {
|
|
|
127
130
|
return undefined;
|
|
128
131
|
if (item.kind === "select") {
|
|
129
132
|
const select = part(document.createElement("select"), "select");
|
|
130
|
-
select.setAttribute("data-
|
|
133
|
+
select.setAttribute("data-rte-item", item.id);
|
|
131
134
|
for (const o of item.options) {
|
|
132
135
|
const option = document.createElement("option");
|
|
133
136
|
option.value = String(o.value);
|
|
@@ -141,14 +144,14 @@ export function createUi(editor, options) {
|
|
|
141
144
|
const customize = style.parts?.button;
|
|
142
145
|
if (customize) {
|
|
143
146
|
const el = customize({ item, state, run: (value) => toolbar.activate(item.id, value) });
|
|
144
|
-
el.setAttribute("data-
|
|
145
|
-
el.setAttribute("data-
|
|
147
|
+
el.setAttribute("data-rte-part", "button");
|
|
148
|
+
el.setAttribute("data-rte-item", item.id);
|
|
146
149
|
(parts.get("button") ?? parts.set("button", new Set()).get("button"))?.add(el);
|
|
147
150
|
return el;
|
|
148
151
|
}
|
|
149
152
|
const button = part(document.createElement("button"), "button");
|
|
150
153
|
button.type = "button";
|
|
151
|
-
button.setAttribute("data-
|
|
154
|
+
button.setAttribute("data-rte-item", item.id);
|
|
152
155
|
const icon = part(document.createElement("span"), "icon");
|
|
153
156
|
icon.setAttribute("aria-hidden", "true");
|
|
154
157
|
if (setIcon(icon, iconFor(state.icon))) {
|
|
@@ -168,7 +171,7 @@ export function createUi(editor, options) {
|
|
|
168
171
|
const host = part(document.createElement("span"), "menu-host");
|
|
169
172
|
const trigger = part(document.createElement("button"), "button");
|
|
170
173
|
trigger.type = "button";
|
|
171
|
-
trigger.setAttribute("data-
|
|
174
|
+
trigger.setAttribute("data-rte-item", item.id);
|
|
172
175
|
const icon = part(document.createElement("span"), "icon");
|
|
173
176
|
icon.setAttribute("aria-hidden", "true");
|
|
174
177
|
if (setIcon(icon, iconFor(state.icon))) {
|
|
@@ -197,8 +200,8 @@ export function createUi(editor, options) {
|
|
|
197
200
|
menuItems.set(child.id, child);
|
|
198
201
|
const entry = part(document.createElement("button"), "menu-item");
|
|
199
202
|
entry.type = "button";
|
|
200
|
-
entry.setAttribute("data-
|
|
201
|
-
entry.setAttribute("data-
|
|
203
|
+
entry.setAttribute("data-rte-menuitem", "");
|
|
204
|
+
entry.setAttribute("data-rte-menu-item", child.id);
|
|
202
205
|
const words = part(document.createElement("span"), "label");
|
|
203
206
|
const keys = part(document.createElement("span"), "menu-keys");
|
|
204
207
|
if (child.kind !== "dialog" && child.swatch) {
|
|
@@ -222,7 +225,7 @@ export function createUi(editor, options) {
|
|
|
222
225
|
popup.style.translate = `${Math.round(dx)}px`;
|
|
223
226
|
},
|
|
224
227
|
onSelect: (entry) => {
|
|
225
|
-
const id = entry.getAttribute("data-
|
|
228
|
+
const id = entry.getAttribute("data-rte-menu-item") ?? "";
|
|
226
229
|
const child = menuItems.get(id);
|
|
227
230
|
if (child?.kind === "dialog") {
|
|
228
231
|
openDialog(child, trigger);
|
|
@@ -235,25 +238,25 @@ export function createUi(editor, options) {
|
|
|
235
238
|
editor.focus();
|
|
236
239
|
},
|
|
237
240
|
});
|
|
238
|
-
for (const entry of popup.querySelectorAll("[data-
|
|
239
|
-
if (menuItems.get(entry.getAttribute("data-
|
|
241
|
+
for (const entry of popup.querySelectorAll("[data-rte-menu-item]")) {
|
|
242
|
+
if (menuItems.get(entry.getAttribute("data-rte-menu-item") ?? "")?.kind === "toggle")
|
|
240
243
|
entry.setAttribute("role", "menuitemcheckbox");
|
|
241
244
|
}
|
|
242
245
|
menus.push(menu);
|
|
243
246
|
return host;
|
|
244
247
|
}
|
|
245
248
|
function menuEntries() {
|
|
246
|
-
for (const entry of toolbarEl.querySelectorAll("[data-
|
|
247
|
-
const id = entry.getAttribute("data-
|
|
249
|
+
for (const entry of toolbarEl.querySelectorAll("[data-rte-menu-item]")) {
|
|
250
|
+
const id = entry.getAttribute("data-rte-menu-item") ?? "";
|
|
248
251
|
const child = menuItems.get(id);
|
|
249
252
|
const state = toolbar.state(id);
|
|
250
253
|
if (!child || !state)
|
|
251
254
|
continue;
|
|
252
255
|
const label = labelOf(child);
|
|
253
|
-
const words = entry.querySelector('[data-
|
|
256
|
+
const words = entry.querySelector('[data-rte-part="label"]');
|
|
254
257
|
if (words)
|
|
255
258
|
words.textContent = label;
|
|
256
|
-
const keys = entry.querySelector('[data-
|
|
259
|
+
const keys = entry.querySelector('[data-rte-part="menu-keys"]');
|
|
257
260
|
if (keys)
|
|
258
261
|
keys.textContent = state.shortcutLabel ?? "";
|
|
259
262
|
if (state.shortcut)
|
|
@@ -302,17 +305,17 @@ export function createUi(editor, options) {
|
|
|
302
305
|
menuEntries();
|
|
303
306
|
}
|
|
304
307
|
function names() {
|
|
305
|
-
for (const el of toolbarEl.querySelectorAll("[data-
|
|
306
|
-
const id = el.getAttribute("data-
|
|
308
|
+
for (const el of toolbarEl.querySelectorAll("[data-rte-item]")) {
|
|
309
|
+
const id = el.getAttribute("data-rte-item") ?? "";
|
|
307
310
|
const item = toolbar.items.find((i) => i.id === id);
|
|
308
311
|
const state = toolbar.state(id);
|
|
309
312
|
if (!item || !state)
|
|
310
313
|
continue;
|
|
311
314
|
const label = labelOf(item);
|
|
312
315
|
el.setAttribute("aria-label", label);
|
|
313
|
-
el.setAttribute("data-
|
|
316
|
+
el.setAttribute("data-rte-tip", state.shortcutLabel ? `${label} (${state.shortcutLabel})` : label);
|
|
314
317
|
if (el.tagName === "BUTTON") {
|
|
315
|
-
const word = el.querySelector('[data-
|
|
318
|
+
const word = el.querySelector('[data-rte-part="label"]');
|
|
316
319
|
if (word)
|
|
317
320
|
word.textContent = label;
|
|
318
321
|
}
|
|
@@ -329,10 +332,10 @@ export function createUi(editor, options) {
|
|
|
329
332
|
});
|
|
330
333
|
let drawn = "";
|
|
331
334
|
const onToolbarClick = (e) => {
|
|
332
|
-
const el = e.target?.closest("[data-
|
|
335
|
+
const el = e.target?.closest("[data-rte-item]");
|
|
333
336
|
if (!el)
|
|
334
337
|
return;
|
|
335
|
-
const item = toolbar.items.find((i) => i.id === el.getAttribute("data-
|
|
338
|
+
const item = toolbar.items.find((i) => i.id === el.getAttribute("data-rte-item"));
|
|
336
339
|
const state = item ? toolbar.state(item.id) : undefined;
|
|
337
340
|
if (item?.kind === "toggle" && state && !state.disabled) {
|
|
338
341
|
const group = item.group === "align" || item.group === "lists";
|
|
@@ -353,7 +356,7 @@ export function createUi(editor, options) {
|
|
|
353
356
|
let entry = dialogs.get(item.id);
|
|
354
357
|
if (!entry) {
|
|
355
358
|
const element = part(document.createElement("dialog"), "dialog");
|
|
356
|
-
const titleId = `
|
|
359
|
+
const titleId = `rte-dialog-title-${++counter}`;
|
|
357
360
|
element.setAttribute("aria-labelledby", titleId);
|
|
358
361
|
const form = document.createElement("form");
|
|
359
362
|
form.noValidate = true;
|
|
@@ -361,7 +364,7 @@ export function createUi(editor, options) {
|
|
|
361
364
|
title.id = titleId;
|
|
362
365
|
form.appendChild(title);
|
|
363
366
|
for (const field of item.fields) {
|
|
364
|
-
const inputId = `
|
|
367
|
+
const inputId = `rte-field-${++counter}`;
|
|
365
368
|
const label = part(document.createElement("label"), "field-label");
|
|
366
369
|
label.htmlFor = inputId;
|
|
367
370
|
label.textContent = field.label;
|
|
@@ -385,7 +388,7 @@ export function createUi(editor, options) {
|
|
|
385
388
|
if (field.required)
|
|
386
389
|
input.required = true;
|
|
387
390
|
const error = part(document.createElement("span"), "field-error");
|
|
388
|
-
error.setAttribute("data-
|
|
391
|
+
error.setAttribute("data-rte-error", field.name);
|
|
389
392
|
if (field.type === "checkbox") {
|
|
390
393
|
const row = part(document.createElement("div"), "field-check");
|
|
391
394
|
row.append(input, label);
|
|
@@ -433,7 +436,7 @@ export function createUi(editor, options) {
|
|
|
433
436
|
for (const f of item.fields) {
|
|
434
437
|
const bad = entry.form.querySelector(`[name="${f.name}"]`);
|
|
435
438
|
bad?.removeAttribute("aria-invalid");
|
|
436
|
-
const err = entry.form.querySelector(`[data-
|
|
439
|
+
const err = entry.form.querySelector(`[data-rte-error="${f.name}"]`);
|
|
437
440
|
if (err)
|
|
438
441
|
err.textContent = "";
|
|
439
442
|
}
|
|
@@ -442,6 +445,13 @@ export function createUi(editor, options) {
|
|
|
442
445
|
}
|
|
443
446
|
drawn = toolbar.items.map((i) => i.id).join("\u0000");
|
|
444
447
|
applyStyle(options.style ?? {});
|
|
448
|
+
floating = options.selectionToolbar || options.contextMenu
|
|
449
|
+
? createFloating({
|
|
450
|
+
editor, root, selectionToolbar: options.selectionToolbar === true, contextMenu: options.contextMenu === true,
|
|
451
|
+
part: (el, name) => part(el, name), message: (key, fallback) => message(key, fallback), icon: (name) => iconFor(name),
|
|
452
|
+
openDialog,
|
|
453
|
+
})
|
|
454
|
+
: undefined;
|
|
445
455
|
if (stopStatus)
|
|
446
456
|
showStatus();
|
|
447
457
|
return {
|
|
@@ -456,6 +466,7 @@ export function createUi(editor, options) {
|
|
|
456
466
|
tipEl.remove();
|
|
457
467
|
stopStatus?.();
|
|
458
468
|
findBar?.destroy();
|
|
469
|
+
floating?.destroy();
|
|
459
470
|
sourceView?.destroy();
|
|
460
471
|
removeSourceItem?.();
|
|
461
472
|
shortcuts.destroy();
|
|
@@ -472,8 +483,9 @@ export function createUi(editor, options) {
|
|
|
472
483
|
announcer.destroy();
|
|
473
484
|
toolbar.destroy();
|
|
474
485
|
toolbarEl.remove();
|
|
475
|
-
|
|
476
|
-
|
|
486
|
+
contentEl.replaceWith(...contentEl.childNodes);
|
|
487
|
+
root.classList.remove("rte-root");
|
|
488
|
+
for (const name of ["data-rte-theme", "data-rte-scheme", "data-rte-density", "data-rte-part"])
|
|
477
489
|
root.removeAttribute(name);
|
|
478
490
|
for (const t of appliedTokens)
|
|
479
491
|
root.style.removeProperty(t);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rathkit/rte-ui",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.5",
|
|
4
4
|
"description": "The styled editor interface: a toolbar and dialogs on the headless layer, themeable with tokens, presets, icons and messages.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rich-text",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
},
|
|
25
25
|
"type": "module",
|
|
26
26
|
"sideEffects": [
|
|
27
|
-
"*.css"
|
|
27
|
+
"*.css",
|
|
28
|
+
"./dist/element-define.js"
|
|
28
29
|
],
|
|
29
30
|
"engines": {
|
|
30
31
|
"node": ">=22.14.0"
|
|
@@ -49,13 +50,21 @@
|
|
|
49
50
|
"types": "./dist/standard.d.ts",
|
|
50
51
|
"default": "./dist/standard.js"
|
|
51
52
|
},
|
|
53
|
+
"./element": {
|
|
54
|
+
"types": "./dist/element.d.ts",
|
|
55
|
+
"default": "./dist/element.js"
|
|
56
|
+
},
|
|
57
|
+
"./element/define": {
|
|
58
|
+
"types": "./dist/element-define.d.ts",
|
|
59
|
+
"default": "./dist/element-define.js"
|
|
60
|
+
},
|
|
52
61
|
"./base.css": "./css/base.css"
|
|
53
62
|
},
|
|
54
63
|
"peerDependencies": {
|
|
55
|
-
"@rathkit/rte-core": ">=0.1.0-alpha.
|
|
56
|
-
"@rathkit/rte-headless": ">=0.1.0-alpha.
|
|
57
|
-
"@rathkit/rte-themes": ">=0.1.0-alpha.
|
|
58
|
-
"@rathkit/rte-icons": ">=0.1.0-alpha.
|
|
64
|
+
"@rathkit/rte-core": ">=0.1.0-alpha.5 <0.2.0",
|
|
65
|
+
"@rathkit/rte-headless": ">=0.1.0-alpha.5 <0.2.0",
|
|
66
|
+
"@rathkit/rte-themes": ">=0.1.0-alpha.5 <0.2.0",
|
|
67
|
+
"@rathkit/rte-icons": ">=0.1.0-alpha.5 <0.2.0"
|
|
59
68
|
},
|
|
60
69
|
"peerDependenciesMeta": {
|
|
61
70
|
"@rathkit/rte-core": {
|
|
@@ -93,6 +102,11 @@
|
|
|
93
102
|
"name": "ui with default icons",
|
|
94
103
|
"entry": "dist/standard.js",
|
|
95
104
|
"gzipKB": 30
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"name": "ui element",
|
|
108
|
+
"entry": "dist/element.js",
|
|
109
|
+
"gzipKB": 30
|
|
96
110
|
}
|
|
97
111
|
]
|
|
98
112
|
}
|