@rathkit/rte-headless 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 +3 -3
- package/dist/dialog.d.ts +1 -1
- package/dist/dialog.js +2 -2
- package/dist/disclosure.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/menu.js +3 -3
- package/dist/toolbar.d.ts +1 -1
- package/dist/toolbar.js +5 -5
- package/dist/tooltip.js +3 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @rathkit/rte-headless
|
|
2
2
|
|
|
3
|
-
> **Alpha
|
|
3
|
+
> **Alpha.** Not for production: the APIs will change between releases. Published to the `next` tag only.
|
|
4
4
|
|
|
5
5
|
How a toolbar, menu, dialog, tooltip and live announcement should behave for the keyboard and assistive technology, with no markup or CSS of its own. Draw the elements yourself and this makes them behave (roving focus, ARIA state, focus returned to the editor); also external stores for any framework.
|
|
6
6
|
|
|
@@ -23,12 +23,12 @@ surface.setAttribute("aria-label", "Body");
|
|
|
23
23
|
document.body.append(surface);
|
|
24
24
|
const editor = createEditor({ element: surface, html: "<p>Hello</p>" });
|
|
25
25
|
|
|
26
|
-
// Draw the controls yourself and mark each with data-
|
|
26
|
+
// Draw the controls yourself and mark each with data-rte-item="<id>"; the toolbar makes them behave.
|
|
27
27
|
const bar = document.createElement("div");
|
|
28
28
|
const toolbar = createToolbar(editor, { label: "Formatting" });
|
|
29
29
|
for (const item of toolbar.items.filter((i) => i.kind === "button" || i.kind === "toggle")) {
|
|
30
30
|
const button = document.createElement("button");
|
|
31
|
-
button.setAttribute("data-
|
|
31
|
+
button.setAttribute("data-rte-item", item.id);
|
|
32
32
|
button.textContent = toolbar.state(item.id).label;
|
|
33
33
|
bar.append(button);
|
|
34
34
|
}
|
package/dist/dialog.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export interface FormCheck {
|
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Checks a dialog's form against the fields an item asked for. Each field that is missing or wrong gets `aria-invalid` and is tied to
|
|
27
|
-
* its message by `aria-describedby`; put an element marked `data-
|
|
27
|
+
* its message by `aria-describedby`; put an element marked `data-rte-error="<field name>"` where the message should appear. The first
|
|
28
28
|
* bad field takes the focus, and the messages are announced when an announcer is given.
|
|
29
29
|
*/
|
|
30
30
|
export declare function checkFields(form: HTMLElement, fields: readonly Field[], messages?: {
|
package/dist/dialog.js
CHANGED
|
@@ -104,14 +104,14 @@ export function checkFields(form, fields, messages = {}, announce) {
|
|
|
104
104
|
problem = messages.required ?? `${field.label} is required.`;
|
|
105
105
|
else if (value !== "" && field.type === "url" && /^\s*(javascript|vbscript|data):/i.test(value))
|
|
106
106
|
problem = messages.url ?? `${field.label} must be a web, mail or phone address.`;
|
|
107
|
-
const slot = form.querySelector(`[data-
|
|
107
|
+
const slot = form.querySelector(`[data-rte-error="${field.name}"]`);
|
|
108
108
|
if (slot)
|
|
109
109
|
slot.textContent = problem;
|
|
110
110
|
if (problem) {
|
|
111
111
|
input.setAttribute("aria-invalid", "true");
|
|
112
112
|
if (slot) {
|
|
113
113
|
if (!slot.id)
|
|
114
|
-
slot.id = uniqueId("
|
|
114
|
+
slot.id = uniqueId("rte-error");
|
|
115
115
|
input.setAttribute("aria-describedby", slot.id);
|
|
116
116
|
}
|
|
117
117
|
problems.push(problem);
|
package/dist/disclosure.js
CHANGED
|
@@ -3,7 +3,7 @@ export const uniqueId = (prefix) => `${prefix}-${++counter}`;
|
|
|
3
3
|
export function createDisclosure(options) {
|
|
4
4
|
const { trigger, popup } = options;
|
|
5
5
|
if (!popup.id)
|
|
6
|
-
popup.id = uniqueId("
|
|
6
|
+
popup.id = uniqueId("rte-popup");
|
|
7
7
|
trigger.setAttribute("aria-haspopup", options.kind ?? "true");
|
|
8
8
|
trigger.setAttribute("aria-controls", popup.id);
|
|
9
9
|
let isOpen = false;
|
package/dist/index.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ export { createDisclosure, type Disclosure, type DisclosureOptions } from "./dis
|
|
|
4
4
|
export { createMenu, type Menu, type MenuOptions } from "./menu.ts";
|
|
5
5
|
export { checkFields, createDialog, type Dialog, type DialogOptions, type FormCheck } from "./dialog.ts";
|
|
6
6
|
export { commandStore, selectStore, snapshotStore, toReadable, type ExternalStore, type Readable } from "./stores.ts";
|
|
7
|
-
export type { HeadlessEditor
|
|
7
|
+
export type { HeadlessEditor } from "./types.ts";
|
|
8
8
|
export { createTooltip, type Tooltip, type TooltipOptions } from "./tooltip.ts";
|
package/dist/menu.js
CHANGED
|
@@ -2,10 +2,10 @@ import { createDisclosure, uniqueId } from "./disclosure.js";
|
|
|
2
2
|
export function createMenu(options) {
|
|
3
3
|
const { trigger, menu } = options;
|
|
4
4
|
if (!trigger.id)
|
|
5
|
-
trigger.id = uniqueId("
|
|
5
|
+
trigger.id = uniqueId("rte-menu-button");
|
|
6
6
|
menu.setAttribute("role", "menu");
|
|
7
7
|
menu.setAttribute("aria-labelledby", trigger.id);
|
|
8
|
-
const items = () => [...menu.querySelectorAll("[data-
|
|
8
|
+
const items = () => [...menu.querySelectorAll("[data-rte-menuitem]")];
|
|
9
9
|
let typed = "";
|
|
10
10
|
let typedTimer;
|
|
11
11
|
const disclosure = createDisclosure({
|
|
@@ -82,7 +82,7 @@ export function createMenu(options) {
|
|
|
82
82
|
}
|
|
83
83
|
};
|
|
84
84
|
const onClick = (e) => {
|
|
85
|
-
const item = e.target?.closest("[data-
|
|
85
|
+
const item = e.target?.closest("[data-rte-menuitem]");
|
|
86
86
|
if (item && menu.contains(item))
|
|
87
87
|
choose(item);
|
|
88
88
|
};
|
package/dist/toolbar.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface Toolbar {
|
|
|
37
37
|
activate(id: string, value?: unknown): boolean;
|
|
38
38
|
/** Called, once per turn, when the items or the state of any of them change. */
|
|
39
39
|
subscribe(callback: () => void): Unsubscribe;
|
|
40
|
-
/** Makes the elements a person's own interface drew behave. Mark each with `data-
|
|
40
|
+
/** Makes the elements a person's own interface drew behave. Mark each with `data-rte-item="<id>"`. */
|
|
41
41
|
bind(root: HTMLElement, options?: BindOptions): Unsubscribe;
|
|
42
42
|
destroy(): void;
|
|
43
43
|
}
|
package/dist/toolbar.js
CHANGED
|
@@ -78,12 +78,12 @@ export function createToolbar(editor, options = {}) {
|
|
|
78
78
|
root.setAttribute("aria-orientation", options.orientation ?? "horizontal");
|
|
79
79
|
if (options.label)
|
|
80
80
|
root.setAttribute("aria-label", options.label);
|
|
81
|
-
const controls = () => [...root.querySelectorAll("[data-
|
|
81
|
+
const controls = () => [...root.querySelectorAll("[data-rte-item]")];
|
|
82
82
|
let current = 0;
|
|
83
83
|
const sync = () => {
|
|
84
84
|
const all = controls();
|
|
85
85
|
all.forEach((control, index) => {
|
|
86
|
-
const s = state(control.getAttribute("data-
|
|
86
|
+
const s = state(control.getAttribute("data-rte-item") ?? "");
|
|
87
87
|
if (!s)
|
|
88
88
|
return;
|
|
89
89
|
control.setAttribute("aria-disabled", String(s.disabled));
|
|
@@ -110,9 +110,9 @@ export function createToolbar(editor, options = {}) {
|
|
|
110
110
|
all.forEach((c, i) => { c.tabIndex = i === current ? 0 : -1; });
|
|
111
111
|
all[current]?.focus();
|
|
112
112
|
};
|
|
113
|
-
const control = (target) => (target instanceof Element ? target.closest("[data-
|
|
113
|
+
const control = (target) => (target instanceof Element ? target.closest("[data-rte-item]") : null);
|
|
114
114
|
const press = (el) => {
|
|
115
|
-
const id = el.getAttribute("data-
|
|
115
|
+
const id = el.getAttribute("data-rte-item") ?? "";
|
|
116
116
|
const item = find(id);
|
|
117
117
|
if (!item || el.getAttribute("aria-disabled") === "true")
|
|
118
118
|
return;
|
|
@@ -137,7 +137,7 @@ export function createToolbar(editor, options = {}) {
|
|
|
137
137
|
const el = control(e.target);
|
|
138
138
|
if (!el || el.tagName !== "SELECT")
|
|
139
139
|
return;
|
|
140
|
-
const item = find(el.getAttribute("data-
|
|
140
|
+
const item = find(el.getAttribute("data-rte-item") ?? "");
|
|
141
141
|
if (item?.kind !== "select")
|
|
142
142
|
return;
|
|
143
143
|
const chosen = item.options.find((o) => String(o.value) === el.value);
|
package/dist/tooltip.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { uniqueId } from "./disclosure.js";
|
|
2
|
-
const TIP = "[data-
|
|
2
|
+
const TIP = "[data-rte-tip]";
|
|
3
3
|
export function createTooltip(options) {
|
|
4
4
|
const { container, popup } = options;
|
|
5
5
|
const delay = options.delay ?? 500;
|
|
6
6
|
const grace = options.grace ?? 150;
|
|
7
7
|
if (!popup.id)
|
|
8
|
-
popup.id = uniqueId("
|
|
8
|
+
popup.id = uniqueId("rte-tooltip");
|
|
9
9
|
popup.setAttribute("role", "tooltip");
|
|
10
10
|
popup.hidden = true;
|
|
11
11
|
let shown;
|
|
@@ -25,7 +25,7 @@ export function createTooltip(options) {
|
|
|
25
25
|
};
|
|
26
26
|
const show = (target) => {
|
|
27
27
|
clear();
|
|
28
|
-
const text = target.getAttribute("data-
|
|
28
|
+
const text = target.getAttribute("data-rte-tip");
|
|
29
29
|
if (!text)
|
|
30
30
|
return;
|
|
31
31
|
shown = target;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rathkit/rte-headless",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.5",
|
|
4
4
|
"description": "How a toolbar, menu, dialog or announcement should behave for keyboard and assistive technology, with no markup or CSS of its own.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rich-text",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"@rathkit/rte-core": ">=0.1.0-alpha.
|
|
48
|
+
"@rathkit/rte-core": ">=0.1.0-alpha.5 <0.2.0"
|
|
49
49
|
},
|
|
50
50
|
"peerDependenciesMeta": {
|
|
51
51
|
"@rathkit/rte-core": {
|