@threadlabs/looma 0.28.11 → 0.28.13
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/components/ui-editor-chip-editor/ui-editor-chip-editor.html +32 -0
- package/components/ui-editor-chip-editor/ui-editor-chip-editor.js +33 -0
- package/components/ui-radio-group/ui-radio-group.html +13 -1
- package/components/ui-swatch/ui-swatch.html +69 -0
- package/dist/index.js +38 -37
- package/editor/formatting-selection.d.ts +49 -0
- package/package.json +1 -1
- package/styles/ui-editor-chip-editor.css +1 -0
- package/styles/ui-radio-group.css +9 -0
- package/styles/ui-swatch.css +76 -0
- package/vanilla/UiEditorChipEditor.d.ts +18 -0
- package/vanilla/UiEditorChipEditor.js +45 -0
- package/vanilla/UiRadioGroup.d.ts +1 -0
- package/vanilla/UiRadioGroup.js +18 -13
- package/vanilla/UiSwatch.d.ts +14 -0
- package/vanilla/UiSwatch.js +54 -0
- package/vanilla/index.js +2 -0
- package/vue/UiEditorChipEditor.d.ts +45 -0
- package/vue/UiEditorChipEditor.js +2 -0
- package/vue/UiEditorChipEditor.vue +163 -0
- package/vue/UiRadioGroup.d.ts +9 -0
- package/vue/UiRadioGroup.vue +44 -2
- package/vue/UiSwatch.d.ts +16 -0
- package/vue/UiSwatch.js +2 -0
- package/vue/UiSwatch.vue +150 -0
- package/vue/chunks/UiEditorChipEditor.js +157 -0
- package/vue/chunks/UiEditorImageToolbar.js +2 -2
- package/vue/chunks/UiEditorLinkCard.js +1 -1
- package/vue/chunks/UiEditorLinkForm.js +2 -2
- package/vue/chunks/UiRadioGroup.js +26 -3
- package/vue/chunks/UiSwatch.js +78 -0
- package/vue/components.css +461 -443
- package/vue/editor/index.js +132 -109
- package/vue/editor/primitives.d.ts +9 -1
- package/vue/index.d.ts +2 -0
- package/vue/index.js +6 -4
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/core";
|
|
2
|
+
import { TextSelection, type Selection } from "@tiptap/pm/state";
|
|
3
|
+
export interface LoomaFormattingSelectionOptions {
|
|
4
|
+
editor: Editor;
|
|
5
|
+
/** Whether a press held on the text may open the tools: floating tools, an editable document, no resize in progress. */
|
|
6
|
+
canHold: () => boolean;
|
|
7
|
+
/** Whether a slash or mention menu is open, which a completed hold leaves alone. */
|
|
8
|
+
menuOpen: () => boolean;
|
|
9
|
+
/** Whether something other than a selection, such as a range action at the caret, shows the tools. */
|
|
10
|
+
shownAtCaret: () => boolean;
|
|
11
|
+
/** Opens the tools at the caret a press was held on. */
|
|
12
|
+
onHold: (selection: TextSelection) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Which selection the editor's floating formatting tools belong to: a text selection, a caret the
|
|
16
|
+
* reader pressed and held, never one the reader dismissed with Escape.
|
|
17
|
+
*
|
|
18
|
+
* @ownership The host owns the tools' surface and the document listeners that feed `press`; this
|
|
19
|
+
* owns the dismissed and held selections and the hold gesture's timer.
|
|
20
|
+
* @lifecycle `destroy()` cancels a pending hold.
|
|
21
|
+
*/
|
|
22
|
+
export interface LoomaFormattingSelection {
|
|
23
|
+
/** Whether the current selection shows the tools. */
|
|
24
|
+
active(): boolean;
|
|
25
|
+
/** Whether `selection` is the one the reader dismissed. */
|
|
26
|
+
dismissed(selection: Selection): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Hides the tools for the current selection, or for `selection`, until the reader selects again.
|
|
29
|
+
* Without an argument only a text or whole-document selection is remembered.
|
|
30
|
+
*/
|
|
31
|
+
dismiss(selection?: Selection | null): void;
|
|
32
|
+
/** Forgets a dismissal, as when the reader clicks a link. */
|
|
33
|
+
undismiss(): void;
|
|
34
|
+
/** Forgets a held caret. */
|
|
35
|
+
release(): void;
|
|
36
|
+
/** Forgets a dismissed or held selection that no longer matches the editor's. */
|
|
37
|
+
selectionChanged(): void;
|
|
38
|
+
/** Feeds the hold gesture: a still press for half a second on the text opens the tools at its caret. */
|
|
39
|
+
readonly press: {
|
|
40
|
+
down(event: PointerEvent): void;
|
|
41
|
+
move(event: PointerEvent): void;
|
|
42
|
+
end(event: PointerEvent): void;
|
|
43
|
+
cancel(): void;
|
|
44
|
+
/** A viewport change after the press began cancels it; the shared pass may report one from before. */
|
|
45
|
+
viewportChanged(event?: Event): void;
|
|
46
|
+
};
|
|
47
|
+
destroy(): void;
|
|
48
|
+
}
|
|
49
|
+
export declare function createFormattingSelection(options: LoomaFormattingSelectionOptions): LoomaFormattingSelection;
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/* Generated by HTML Next 1.0.0-alpha.51. Do not edit. */
|
|
@@ -36,6 +36,15 @@
|
|
|
36
36
|
clear: both;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
legend.sr-only {
|
|
40
|
+
position: absolute;
|
|
41
|
+
inline-size: 1px;
|
|
42
|
+
block-size: 1px;
|
|
43
|
+
overflow: hidden;
|
|
44
|
+
clip-path: inset(50%);
|
|
45
|
+
white-space: nowrap;
|
|
46
|
+
}
|
|
47
|
+
|
|
39
48
|
:scope:where([data-component~="ui-radio-group"])[data-ui-radio-group-state~="invalid"] legend {
|
|
40
49
|
color: var(--_ui-radio-group-invalid-text);
|
|
41
50
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* Generated by HTML Next 1.0.0-alpha.51. Do not edit. */
|
|
2
|
+
@supports (-moz-appearance: none) {
|
|
3
|
+
:where([data-component], [data-slotted]) { --html-next-scope-owner: boundary; }
|
|
4
|
+
:where([data-slotted]:not([data-component])) { --html-next-scope-owner: projected !important; }
|
|
5
|
+
}
|
|
6
|
+
@supports (-moz-appearance: none) {
|
|
7
|
+
[data-component~="ui-swatch"] { --html-next-scope-owner: "ui-swatch" !important; }
|
|
8
|
+
}
|
|
9
|
+
@scope ([data-component~="ui-swatch"]) to ([data-component], [data-slotted]) {
|
|
10
|
+
@property --ui-swatch-size {
|
|
11
|
+
syntax: "*";
|
|
12
|
+
inherits: false;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* A native radio drawn as a round dot. Inside a ui-radio-group the group names it, applies its
|
|
16
|
+
value, and moves between swatches with the arrow keys. */
|
|
17
|
+
:scope:where([data-component~="ui-swatch"]) {
|
|
18
|
+
--_surface: var(--ui-surface-subtle);
|
|
19
|
+
--_text: var(--ui-text-secondary);
|
|
20
|
+
|
|
21
|
+
appearance: none;
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
flex: 0 0 auto;
|
|
24
|
+
inline-size: var(--ui-swatch-size, 1.65rem);
|
|
25
|
+
block-size: var(--ui-swatch-size, 1.65rem);
|
|
26
|
+
margin: 0;
|
|
27
|
+
border: var(--ui-border-width) solid color-mix(in srgb, var(--_surface) 75%, var(--_text) 25%);
|
|
28
|
+
border-radius: 50%;
|
|
29
|
+
background: var(--_surface);
|
|
30
|
+
cursor: pointer;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
:scope:where([data-component~="ui-swatch"])[data-ui-swatch-state~="tone=blue"] {
|
|
34
|
+
--_surface: var(--ui-info-soft);
|
|
35
|
+
--_text: var(--ui-info-subtle-text);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
:scope:where([data-component~="ui-swatch"])[data-ui-swatch-state~="tone=green"] {
|
|
39
|
+
--_surface: var(--ui-success-soft);
|
|
40
|
+
--_text: var(--ui-success-subtle-text);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
:scope:where([data-component~="ui-swatch"])[data-ui-swatch-state~="tone=yellow"] {
|
|
44
|
+
--_surface: var(--ui-warning-soft);
|
|
45
|
+
--_text: var(--ui-warning-subtle-text);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
:scope:where([data-component~="ui-swatch"])[data-ui-swatch-state~="tone=red"] {
|
|
49
|
+
--_surface: var(--ui-danger-soft);
|
|
50
|
+
--_text: var(--ui-danger-subtle-text);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
:scope:where([data-component~="ui-swatch"])[data-ui-swatch-state~="tone=purple"] {
|
|
54
|
+
--_surface: var(--ui-accent-soft);
|
|
55
|
+
--_text: var(--ui-accent-subtle-text);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* The chosen swatch and the focused one share one ring at the focus width (2px by default), in
|
|
59
|
+
the tone or the focus colour. */
|
|
60
|
+
:scope:where([data-component~="ui-swatch"]):checked {
|
|
61
|
+
outline: var(--ui-focus-width) solid var(--_text);
|
|
62
|
+
outline-offset: var(--ui-focus-width);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
:scope:where([data-component~="ui-swatch"]):focus-visible {
|
|
66
|
+
outline: var(--ui-focus-width) solid var(--ui-focus-ring, var(--ui-accent-solid));
|
|
67
|
+
outline-offset: var(--ui-focus-width);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
@scope ([data-component~="ui-swatch"]) to ([data-component]) {
|
|
71
|
+
/* A native radio drawn as a round dot. Inside a ui-radio-group the group names it, applies its
|
|
72
|
+
value, and moves between swatches with the arrow keys. */
|
|
73
|
+
|
|
74
|
+
/* The chosen swatch and the focused one share one ring at the focus width (2px by default), in
|
|
75
|
+
the tone or the focus colour. */
|
|
76
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Generated by HTML Next 1.0.0-alpha.51 for Vanilla DOM. Do not edit.
|
|
2
|
+
export interface UiEditorChipEditorEventMap {
|
|
3
|
+
label: CustomEvent<{ readonly label: string }>;
|
|
4
|
+
color: CustomEvent<{ readonly color: "neutral" | "blue" | "green" | "yellow" | "red" | "purple" }>;
|
|
5
|
+
done: CustomEvent<Readonly<Record<string, unknown>>>;
|
|
6
|
+
}
|
|
7
|
+
export interface UiEditorChipEditorElement extends HTMLDivElement {
|
|
8
|
+
addEventListener<K extends keyof UiEditorChipEditorEventMap>(type: K, listener: (this: UiEditorChipEditorElement, event: UiEditorChipEditorEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
9
|
+
removeEventListener<K extends keyof UiEditorChipEditorEventMap>(type: K, listener: (this: UiEditorChipEditorElement, event: UiEditorChipEditorEventMap[K]) => unknown, options?: boolean | EventListenerOptions): void;
|
|
10
|
+
}
|
|
11
|
+
export interface UiEditorChipEditorProps {
|
|
12
|
+
color?: "neutral" | "blue" | "green" | "yellow" | "red" | "purple" | null;
|
|
13
|
+
label?: string | null;
|
|
14
|
+
attributes?: Readonly<Record<string, string | number | boolean | null | undefined>>;
|
|
15
|
+
children?: readonly (string | Node)[];
|
|
16
|
+
slots?: Readonly<Record<string, readonly (string | Node)[]>>;
|
|
17
|
+
}
|
|
18
|
+
export declare function createUiEditorChipEditor(props?: UiEditorChipEditorProps): UiEditorChipEditorElement;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Generated by HTML Next 1.0.0-alpha.51 for Vanilla DOM. Do not edit.
|
|
2
|
+
import { attachGeneratedController, buildTemplate, toAttribute, writeAttribute, dispatchDeclared, detailCheck, formatOf, keywordFormat, acceptProps, manageProps, checkConstrained, checkFormat, checkObject, checkRecord, checkString, checkUnknown } from "@nextwebwg/html-next/generated-runtime";
|
|
3
|
+
import * as controller from "../components/ui-editor-chip-editor/ui-editor-chip-editor.js";
|
|
4
|
+
import "../styles/ui-editor-chip-editor.css";
|
|
5
|
+
|
|
6
|
+
const T0 = ["",[],["ui-stack",["gap","s"],["ui-input",["data-chip-label","","size","sm","placeholder","Set a label","aria-label","Chip text"]],["ui-radio-group",["label","Chip color","label-visibility","sr-only"],["ui-swatch",["tone","neutral"]],["ui-swatch",["tone","blue"]],["ui-swatch",["tone","green"]],["ui-swatch",["tone","yellow"]],["ui-swatch",["tone","red"]],["ui-swatch",["tone","purple"]]]]];
|
|
7
|
+
let P0;
|
|
8
|
+
const S = { n: [], t: [], f: import.meta.url, g: "ui-editor-chip-editor", d: { "label": [detailCheck(checkObject([["label", checkString, false]], false)), true, true, false], "color": [detailCheck(checkObject([["color", checkConstrained(checkFormat("keyword", keywordFormat), "keyword", {"values":["neutral","blue","green","yellow","red","purple"]}), false]], false)), true, true, false], "done": [detailCheck(checkRecord(checkUnknown)), true, true, false] }, x: dispatchDeclared };
|
|
9
|
+
const D = { props: { "color": { "required":false,"values":["neutral","blue","green","yellow","red","purple"],"default":"neutral", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "label": { "required":false,"default":"", c: checkString, t: "string", j: 0, m: "s" } } };
|
|
10
|
+
const C = (host) => controller.default(host);
|
|
11
|
+
|
|
12
|
+
export function createUiEditorChipEditor(options = {}, html) {
|
|
13
|
+
const { attributes = {}, children = [], slots = {}, ...componentProps } = options;
|
|
14
|
+
const element = document.createElement("div");
|
|
15
|
+
for (const [name, value] of Object.entries(attributes)) {
|
|
16
|
+
if (value === null || value === undefined || value === false) continue;
|
|
17
|
+
element.setAttribute(name, value === true ? "" : String(value));
|
|
18
|
+
}
|
|
19
|
+
if (!element.hasAttribute("role")) element.setAttribute("role", "dialog");
|
|
20
|
+
if (!element.hasAttribute("aria-label")) element.setAttribute("aria-label", "Edit chip");
|
|
21
|
+
element.setAttribute("data-component", "ui-editor-chip-editor");
|
|
22
|
+
element.append((P0 ??= buildTemplate(T0)).cloneNode(true));
|
|
23
|
+
const v = [null, null];
|
|
24
|
+
const B = acceptProps(element, D, S.n, v, componentProps, [], html);
|
|
25
|
+
const p0 = (r, c, d) => {
|
|
26
|
+
if (c & 2) {
|
|
27
|
+
const x0 = v[1];
|
|
28
|
+
const s0 = toAttribute(x0, "value");
|
|
29
|
+
if (s0 !== r.v0) writeAttribute(r.a0, "value", r.v0 = s0);
|
|
30
|
+
}
|
|
31
|
+
if (c & 1073741825) {
|
|
32
|
+
const x1 = v[0];
|
|
33
|
+
const s1 = toAttribute(x1, "value");
|
|
34
|
+
if (s1 !== r.v1) writeAttribute(r.a1, "value", r.v1 = s1);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const t0 = element.firstChild;
|
|
38
|
+
const t1 = t0.firstChild;
|
|
39
|
+
const t2 = t1.nextSibling;
|
|
40
|
+
const R = { a0: t1, a1: t2, v0: null, v1: null };
|
|
41
|
+
const I = { B };
|
|
42
|
+
attachGeneratedController(element, S, v, ((c, d) => p0(R, c, d)), C, undefined, I);
|
|
43
|
+
manageProps(I);
|
|
44
|
+
return element;
|
|
45
|
+
}
|
|
@@ -11,6 +11,7 @@ export interface UiRadioGroupProps {
|
|
|
11
11
|
disabled?: boolean | null;
|
|
12
12
|
invalid?: boolean | null;
|
|
13
13
|
label?: string | null;
|
|
14
|
+
labelVisibility?: "visible" | "sr-only" | null;
|
|
14
15
|
name?: string | null;
|
|
15
16
|
orientation?: "horizontal" | "vertical" | null;
|
|
16
17
|
required?: boolean | null;
|
package/vanilla/UiRadioGroup.js
CHANGED
|
@@ -7,7 +7,7 @@ const T0 = ["",[],["legend",[],0],4];
|
|
|
7
7
|
const T1 = ["",[]];
|
|
8
8
|
let P0, P1;
|
|
9
9
|
const S = { n: ["internalValue"], t: ["s"], f: import.meta.url, g: "ui-radio-group", d: { "select": [detailCheck(checkObject([["value", checkString, false], ["previousValue", checkString, false], ["trigger", checkConstrained(checkFormat("keyword", keywordFormat), "keyword", {"values":["keyboard","pointer","programmatic"]}), false]], false)), true, true, false], "change": [detailCheck(checkObject([["checked", checkBoolean, false], ["value", checkString, false], ["trigger", checkConstrained(checkFormat("keyword", keywordFormat), "keyword", {"values":["keyboard","pointer","programmatic"]}), false]], false)), true, true, false] }, x: dispatchDeclared };
|
|
10
|
-
const D = { props: { "disabled": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "invalid": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "label": { "required":false,"default":"Options", c: checkString, t: "string", j: 0, m: "s" }, "name": { "required":false,"default":"", c: checkString, t: "string", j: 0, m: "s" }, "orientation": { "required":false,"values":["horizontal","vertical"],"default":"horizontal", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "required": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "value": { "required":false,"default":"", c: checkString, t: "string", j: 0, m: "s" } } };
|
|
10
|
+
const D = { props: { "disabled": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "invalid": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "label": { "required":false,"default":"Options", c: checkString, t: "string", j: 0, m: "s" }, "labelVisibility": { "required":false,"values":["visible","sr-only"],"default":"visible", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "name": { "required":false,"default":"", c: checkString, t: "string", j: 0, m: "s" }, "orientation": { "required":false,"values":["horizontal","vertical"],"default":"horizontal", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "required": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "value": { "required":false,"default":"", c: checkString, t: "string", j: 0, m: "s" } } };
|
|
11
11
|
const C = (host) => controller.default(host);
|
|
12
12
|
|
|
13
13
|
export function createUiRadioGroup(options = {}, html) {
|
|
@@ -20,7 +20,7 @@ export function createUiRadioGroup(options = {}, html) {
|
|
|
20
20
|
if (!element.hasAttribute("role")) element.setAttribute("role", "radiogroup");
|
|
21
21
|
element.setAttribute("data-component", "ui-radio-group");
|
|
22
22
|
element.append((P0 ??= buildTemplate(T0)).cloneNode(true));
|
|
23
|
-
const v = ["", null, null, null, null, null, null, null];
|
|
23
|
+
const v = ["", null, null, null, null, null, null, null, null];
|
|
24
24
|
const B = acceptProps(element, D, S.n, v, componentProps, [], html);
|
|
25
25
|
const m1 = (d) => {
|
|
26
26
|
const n = (P1 ??= buildTemplate(T1)).cloneNode(true);
|
|
@@ -31,8 +31,8 @@ export function createUiRadioGroup(options = {}, html) {
|
|
|
31
31
|
const p1 = (r, c, d) => {
|
|
32
32
|
};
|
|
33
33
|
const p0 = (r, c, d) => {
|
|
34
|
-
if (c &
|
|
35
|
-
const x0 = v[
|
|
34
|
+
if (c & 128) {
|
|
35
|
+
const x0 = v[7];
|
|
36
36
|
const s0 = toAttribute(x0, "aria-required");
|
|
37
37
|
if (s0 !== r.v0) writeAttribute(r.n, "aria-required", r.v0 = s0);
|
|
38
38
|
}
|
|
@@ -46,24 +46,29 @@ export function createUiRadioGroup(options = {}, html) {
|
|
|
46
46
|
const s2 = toAttribute(x2, "disabled");
|
|
47
47
|
if (s2 !== r.v2) writeAttribute(r.n, "disabled", r.v2 = s2);
|
|
48
48
|
}
|
|
49
|
+
if (c & 16) {
|
|
50
|
+
const x3 = (v[4] === "sr-only");
|
|
51
|
+
const s3 = x3;
|
|
52
|
+
if (s3 !== r.v3) r.a1.classList.toggle("sr-only", r.v3 = s3);
|
|
53
|
+
}
|
|
49
54
|
if (c & 8) {
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
if (
|
|
55
|
+
const x4 = v[3];
|
|
56
|
+
const s4 = toText(x4);
|
|
57
|
+
if (s4 !== r.v4) r.a2.data = r.v4 = s4;
|
|
53
58
|
}
|
|
54
|
-
if (c &
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
if (
|
|
59
|
+
if (c & 68) {
|
|
60
|
+
const x5 = hostState(["invalid","orientation"], [v[2], v[6]]);
|
|
61
|
+
const s5 = x5;
|
|
62
|
+
if (s5 !== r.v5) writeAttribute(r.n, "data-ui-radio-group-state", (r.v5 = s5) === "" ? null : s5);
|
|
58
63
|
}
|
|
59
|
-
if (r.f0 === undefined) { r.f0 = 1; const at = fillSlot(r.
|
|
64
|
+
if (r.f0 === undefined) { r.f0 = 1; const at = fillSlot(r.a3, r.e0, "", J, false, undefined, d);
|
|
60
65
|
if (Array.isArray(at)) (r.z ??= []).push(() => { at[0].l.delete(at[1]); dispose(at[1]); }); else if (at !== undefined) { r.b0 = m1(d); at.before(r.b0.n); } }
|
|
61
66
|
else if (r.b0 !== undefined) p1(r.b0, c, d);
|
|
62
67
|
};
|
|
63
68
|
const t0 = element.firstChild;
|
|
64
69
|
const t1 = t0.firstChild;
|
|
65
70
|
const t2 = t0.nextSibling;
|
|
66
|
-
const R = { n: element, a1: t1, v0: undefined, v1: undefined, v2: undefined, v3: "",
|
|
71
|
+
const R = { n: element, a1: t0, a2: t1, v0: undefined, v1: undefined, v2: undefined, v3: false, v4: "", v5: undefined, a3: t2, e0: t2.nextSibling, b0: undefined, f0: undefined };
|
|
67
72
|
const I = { B };
|
|
68
73
|
const J = project(I, children, slots);
|
|
69
74
|
I.R = new Set();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Generated by HTML Next 1.0.0-alpha.51 for Vanilla DOM. Do not edit.
|
|
2
|
+
export interface UiSwatchEventMap {
|
|
3
|
+
}
|
|
4
|
+
export interface UiSwatchElement extends HTMLInputElement {
|
|
5
|
+
addEventListener<K extends keyof UiSwatchEventMap>(type: K, listener: (this: UiSwatchElement, event: UiSwatchEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
6
|
+
removeEventListener<K extends keyof UiSwatchEventMap>(type: K, listener: (this: UiSwatchElement, event: UiSwatchEventMap[K]) => unknown, options?: boolean | EventListenerOptions): void;
|
|
7
|
+
}
|
|
8
|
+
export interface UiSwatchProps {
|
|
9
|
+
tone?: "neutral" | "blue" | "green" | "yellow" | "red" | "purple" | null;
|
|
10
|
+
attributes?: Readonly<Record<string, string | number | boolean | null | undefined>>;
|
|
11
|
+
children?: readonly (string | Node)[];
|
|
12
|
+
slots?: Readonly<Record<string, readonly (string | Node)[]>>;
|
|
13
|
+
}
|
|
14
|
+
export declare function createUiSwatch(props?: UiSwatchProps): UiSwatchElement;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Generated by HTML Next 1.0.0-alpha.51 for Vanilla DOM. Do not edit.
|
|
2
|
+
import { attachGeneratedController, readIndex, toAttribute, writeAttribute, computedCycle, formatOf, keywordFormat, hostState, acceptProps, manageProps, readonlyView, checkFormat } from "@nextwebwg/html-next/generated-runtime";
|
|
3
|
+
import "../styles/ui-swatch.css";
|
|
4
|
+
|
|
5
|
+
const S = { n: ["toneName"], t: ["?"], f: import.meta.url, g: "ui-swatch", k: 0, r: readonlyView };
|
|
6
|
+
const D = { props: { "tone": { "required":false,"values":["neutral","blue","green","yellow","red","purple"],"default":"neutral", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] } } };
|
|
7
|
+
|
|
8
|
+
export function createUiSwatch(options = {}, html) {
|
|
9
|
+
const { attributes = {}, children = [], slots = {}, ...componentProps } = options;
|
|
10
|
+
const element = document.createElement("input");
|
|
11
|
+
for (const [name, value] of Object.entries(attributes)) {
|
|
12
|
+
if (value === null || value === undefined || value === false) continue;
|
|
13
|
+
element.setAttribute(name, value === true ? "" : String(value));
|
|
14
|
+
}
|
|
15
|
+
if (!element.hasAttribute("type")) element.setAttribute("type", "radio");
|
|
16
|
+
element.setAttribute("data-component", "ui-swatch");
|
|
17
|
+
const v = [undefined, null];
|
|
18
|
+
const B = acceptProps(element, D, S.n, v, componentProps, [], html);
|
|
19
|
+
const X = { e: 0, g: (j) => g(j), w: new Set() };
|
|
20
|
+
const ke = [];
|
|
21
|
+
const K = [() => readIndex({ "neutral": "Neutral", "blue": "Blue", "green": "Green", "yellow": "Yellow", "red": "Red", "purple": "Purple" }, v[1])];
|
|
22
|
+
const g = (j) => {
|
|
23
|
+
const i = j - 0;
|
|
24
|
+
if (ke[i] === X.e) return v[j];
|
|
25
|
+
if (ke[i] === -1) computedCycle();
|
|
26
|
+
ke[i] = -1;
|
|
27
|
+
let next;
|
|
28
|
+
try { next = K[i](); } catch (error) { ke[i] = undefined; throw error; }
|
|
29
|
+
ke[i] = X.e;
|
|
30
|
+
const previous = v[j];
|
|
31
|
+
if (!Object.is(previous, next)) { v[j] = next; X.n?.(j, previous, next); }
|
|
32
|
+
return next;
|
|
33
|
+
};
|
|
34
|
+
const p0 = (r, c, d) => {
|
|
35
|
+
if (c & 1073741826) {
|
|
36
|
+
const x0 = v[1];
|
|
37
|
+
const s0 = toAttribute(x0, "value");
|
|
38
|
+
if (s0 !== r.v0) writeAttribute(r.n, "value", r.v0 = s0);
|
|
39
|
+
const x1 = g(0);
|
|
40
|
+
const s1 = toAttribute(x1, "aria-label");
|
|
41
|
+
if (s1 !== r.v1) writeAttribute(r.n, "aria-label", r.v1 = s1);
|
|
42
|
+
}
|
|
43
|
+
if (c & 2) {
|
|
44
|
+
const x2 = hostState(["tone"], [v[1]]);
|
|
45
|
+
const s2 = x2;
|
|
46
|
+
if (s2 !== r.v2) writeAttribute(r.n, "data-ui-swatch-state", (r.v2 = s2) === "" ? null : s2);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const R = { n: element, v0: undefined, v1: undefined, v2: undefined };
|
|
50
|
+
const I = { B };
|
|
51
|
+
attachGeneratedController(element, S, v, ((c, d) => p0(R, c, d)), undefined, X, I);
|
|
52
|
+
manageProps(I);
|
|
53
|
+
return element;
|
|
54
|
+
}
|
package/vanilla/index.js
CHANGED
|
@@ -20,6 +20,7 @@ export * from "./UiDialog.js";
|
|
|
20
20
|
export * from "./UiDisclosure.js";
|
|
21
21
|
export * from "./UiEditable.js";
|
|
22
22
|
export * from "./UiEditorBlockActions.js";
|
|
23
|
+
export * from "./UiEditorChipEditor.js";
|
|
23
24
|
export * from "./UiEditorCodeLanguage.js";
|
|
24
25
|
export * from "./UiEditorImageToolbar.js";
|
|
25
26
|
export * from "./UiEditorInsertTableGrid.js";
|
|
@@ -66,6 +67,7 @@ export * from "./UiSidebar.js";
|
|
|
66
67
|
export * from "./UiSpinner.js";
|
|
67
68
|
export * from "./UiStack.js";
|
|
68
69
|
export * from "./UiStatusMessage.js";
|
|
70
|
+
export * from "./UiSwatch.js";
|
|
69
71
|
export * from "./UiSwitch.js";
|
|
70
72
|
export * from "./UiSwitcher.js";
|
|
71
73
|
export * from "./UiTable.js";
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { PropType } from 'vue';
|
|
2
|
+
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
3
|
+
color: {
|
|
4
|
+
type: PropType<"neutral" | "blue" | "green" | "yellow" | "red" | "purple" | null>;
|
|
5
|
+
default: string;
|
|
6
|
+
};
|
|
7
|
+
label: {
|
|
8
|
+
type: PropType<string | null>;
|
|
9
|
+
default: string;
|
|
10
|
+
};
|
|
11
|
+
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
12
|
+
done: (event: CustomEvent<Readonly<Record<string, unknown>>>) => any;
|
|
13
|
+
label: (event: CustomEvent<{
|
|
14
|
+
readonly label: string;
|
|
15
|
+
}>) => any;
|
|
16
|
+
color: (event: CustomEvent<{
|
|
17
|
+
readonly color: "neutral" | "blue" | "green" | "yellow" | "red" | "purple";
|
|
18
|
+
}>) => any;
|
|
19
|
+
"update:color": (value: string) => any;
|
|
20
|
+
"update:label": (value: string) => any;
|
|
21
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
22
|
+
color: {
|
|
23
|
+
type: PropType<"neutral" | "blue" | "green" | "yellow" | "red" | "purple" | null>;
|
|
24
|
+
default: string;
|
|
25
|
+
};
|
|
26
|
+
label: {
|
|
27
|
+
type: PropType<string | null>;
|
|
28
|
+
default: string;
|
|
29
|
+
};
|
|
30
|
+
}>> & Readonly<{
|
|
31
|
+
onDone?: ((event: CustomEvent<Readonly<Record<string, unknown>>>) => any) | undefined;
|
|
32
|
+
onLabel?: ((event: CustomEvent<{
|
|
33
|
+
readonly label: string;
|
|
34
|
+
}>) => any) | undefined;
|
|
35
|
+
onColor?: ((event: CustomEvent<{
|
|
36
|
+
readonly color: "neutral" | "blue" | "green" | "yellow" | "red" | "purple";
|
|
37
|
+
}>) => any) | undefined;
|
|
38
|
+
"onUpdate:color"?: ((value: string) => any) | undefined;
|
|
39
|
+
"onUpdate:label"?: ((value: string) => any) | undefined;
|
|
40
|
+
}>, {
|
|
41
|
+
label: string | null;
|
|
42
|
+
color: "blue" | "green" | "purple" | "red" | "yellow" | "neutral" | null;
|
|
43
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
44
|
+
declare const _default: typeof __VLS_export;
|
|
45
|
+
export default _default;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
<!-- Generated by HTML Next 1.0.0-alpha.51 for Vue 3.5. Do not edit. -->
|
|
2
|
+
<script setup lang="ts">
|
|
3
|
+
import { computed, getCurrentInstance, ref, watchSyncEffect } from 'vue'
|
|
4
|
+
import type { PropType } from 'vue'
|
|
5
|
+
import {
|
|
6
|
+
checkHydratedRoot,
|
|
7
|
+
createDispatch,
|
|
8
|
+
nativeAttrs,
|
|
9
|
+
useComponentHost,
|
|
10
|
+
useReflectedProp,
|
|
11
|
+
} from './host'
|
|
12
|
+
import { checkedProp, propValidityState, vPropValidity } from './props'
|
|
13
|
+
import UiInput from './UiInput.vue'
|
|
14
|
+
import UiRadioGroup from './UiRadioGroup.vue'
|
|
15
|
+
import UiStack from './UiStack.vue'
|
|
16
|
+
import UiSwatch from './UiSwatch.vue'
|
|
17
|
+
|
|
18
|
+
defineOptions({ inheritAttrs: false })
|
|
19
|
+
|
|
20
|
+
const propValidityContract = {
|
|
21
|
+
props: {
|
|
22
|
+
color: {
|
|
23
|
+
type: { kind: 'terminal', name: 'keyword' },
|
|
24
|
+
required: false,
|
|
25
|
+
target: { attribute: 'value' },
|
|
26
|
+
description: 'The chip\'s colour, checked among the swatches.',
|
|
27
|
+
values: ['neutral', 'blue', 'green', 'yellow', 'red', 'purple'],
|
|
28
|
+
default: 'neutral',
|
|
29
|
+
},
|
|
30
|
+
label: {
|
|
31
|
+
type: { kind: 'terminal', name: 'string' },
|
|
32
|
+
required: false,
|
|
33
|
+
target: { attribute: 'value' },
|
|
34
|
+
description: 'The chip\'s text, shown in the field as the reader edits it.',
|
|
35
|
+
default: '',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
} as const
|
|
39
|
+
const props = defineProps({
|
|
40
|
+
color: {
|
|
41
|
+
type: null as unknown as PropType<
|
|
42
|
+
'neutral' | 'blue' | 'green' | 'yellow' | 'red' | 'purple' | null
|
|
43
|
+
>,
|
|
44
|
+
default: 'neutral',
|
|
45
|
+
},
|
|
46
|
+
label: { type: null as unknown as PropType<string | null>, default: '' },
|
|
47
|
+
})
|
|
48
|
+
const acceptedProps: Record<string, unknown> = { color: 'neutral', label: '' }
|
|
49
|
+
const checkedProps = computed(() => ({
|
|
50
|
+
color: checkedProp<'neutral' | 'blue' | 'green' | 'yellow' | 'red' | 'purple'>(
|
|
51
|
+
props['color'],
|
|
52
|
+
{ kind: 'terminal', name: 'keyword' },
|
|
53
|
+
false,
|
|
54
|
+
'color',
|
|
55
|
+
acceptedProps,
|
|
56
|
+
) as 'neutral' | 'blue' | 'green' | 'yellow' | 'red' | 'purple',
|
|
57
|
+
label: checkedProp<string>(
|
|
58
|
+
props['label'],
|
|
59
|
+
{ kind: 'terminal', name: 'string' },
|
|
60
|
+
false,
|
|
61
|
+
'label',
|
|
62
|
+
acceptedProps,
|
|
63
|
+
) as string,
|
|
64
|
+
}))
|
|
65
|
+
void checkedProps.value
|
|
66
|
+
watchSyncEffect(() => {
|
|
67
|
+
void checkedProps.value
|
|
68
|
+
})
|
|
69
|
+
const reflectedProp = useReflectedProp()
|
|
70
|
+
const hydrationInstance = getCurrentInstance()
|
|
71
|
+
const emit = defineEmits<{
|
|
72
|
+
'update:color': [value: string]
|
|
73
|
+
'update:label': [value: string]
|
|
74
|
+
label: [event: CustomEvent<{ readonly label: string }>]
|
|
75
|
+
color: [
|
|
76
|
+
event: CustomEvent<
|
|
77
|
+
{ readonly color: 'neutral' | 'blue' | 'green' | 'yellow' | 'red' | 'purple' }
|
|
78
|
+
>,
|
|
79
|
+
]
|
|
80
|
+
done: [event: CustomEvent<Readonly<Record<string, unknown>>>]
|
|
81
|
+
}>()
|
|
82
|
+
|
|
83
|
+
const root = ref<HTMLElement | null>(null)
|
|
84
|
+
checkHydratedRoot('div', 'ui-editor-chip-editor')
|
|
85
|
+
|
|
86
|
+
const isLabelDetail = (
|
|
87
|
+
detail: unknown,
|
|
88
|
+
): boolean => (detail !== null && typeof detail === 'object' && !Array.isArray(detail)
|
|
89
|
+
&& typeof (detail as Record<string, unknown>)['label'] === 'string'
|
|
90
|
+
&& Object.keys(detail as object).every((key) => ['label'].includes(key)))
|
|
91
|
+
const isColorDetail = (
|
|
92
|
+
detail: unknown,
|
|
93
|
+
): boolean => (detail !== null && typeof detail === 'object' && !Array.isArray(detail)
|
|
94
|
+
&& ((detail as Record<string, unknown>)['color'] === 'neutral'
|
|
95
|
+
|| (detail as Record<string, unknown>)['color'] === 'blue'
|
|
96
|
+
|| (detail as Record<string, unknown>)['color'] === 'green'
|
|
97
|
+
|| (detail as Record<string, unknown>)['color'] === 'yellow'
|
|
98
|
+
|| (detail as Record<string, unknown>)['color'] === 'red'
|
|
99
|
+
|| (detail as Record<string, unknown>)['color'] === 'purple')
|
|
100
|
+
&& Object.keys(detail as object).every((key) => ['color'].includes(key)))
|
|
101
|
+
const isDoneDetail = (
|
|
102
|
+
detail: unknown,
|
|
103
|
+
): boolean => (detail !== null && typeof detail === 'object' && !Array.isArray(detail)
|
|
104
|
+
&& Object.values(detail as object).every((item: unknown) => true))
|
|
105
|
+
const dispatch = createDispatch(root, emit as (name: string, detail: unknown) => void, {
|
|
106
|
+
checks: {
|
|
107
|
+
label: isLabelDetail,
|
|
108
|
+
color: isColorDetail,
|
|
109
|
+
done: isDoneDetail,
|
|
110
|
+
},
|
|
111
|
+
modeled: ['color', 'label'],
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
useComponentHost(() => import('../components/ui-editor-chip-editor/ui-editor-chip-editor.js'), {
|
|
115
|
+
root,
|
|
116
|
+
dispatch,
|
|
117
|
+
controllerSource: {
|
|
118
|
+
specifier: '../components/ui-editor-chip-editor/ui-editor-chip-editor.js',
|
|
119
|
+
definition: './components/ui-editor-chip-editor/ui-editor-chip-editor.html',
|
|
120
|
+
},
|
|
121
|
+
props: checkedProps,
|
|
122
|
+
propInputs: (name: string) => {
|
|
123
|
+
const incoming = hydrationInstance?.vnode.props
|
|
124
|
+
const kebab = name.replace(/[A-Z]/g, (letter) => '-' + letter.toLowerCase())
|
|
125
|
+
return incoming !== null && incoming !== undefined
|
|
126
|
+
? (incoming[name] ?? incoming[kebab] ?? null)
|
|
127
|
+
: null
|
|
128
|
+
},
|
|
129
|
+
propNames: ['color', 'label'],
|
|
130
|
+
propValidity: (name: string) =>
|
|
131
|
+
propValidityState({ contract: propValidityContract, values: { ...props } }, name),
|
|
132
|
+
})
|
|
133
|
+
</script>
|
|
134
|
+
|
|
135
|
+
<template>
|
|
136
|
+
<div
|
|
137
|
+
role="dialog"
|
|
138
|
+
aria-label="Edit chip"
|
|
139
|
+
v-bind="nativeAttrs($attrs)"
|
|
140
|
+
v-prop-validity="{ contract: propValidityContract, values: { ...props } }"
|
|
141
|
+
:data-color="reflectedProp('color', 'color', checkedProps.color, undefined, false)"
|
|
142
|
+
:data-label="reflectedProp('label', 'label', checkedProps.label, undefined, false)"
|
|
143
|
+
ref="root"
|
|
144
|
+
>
|
|
145
|
+
<UiStack gap="s"><UiInput
|
|
146
|
+
data-chip-label=""
|
|
147
|
+
size="sm"
|
|
148
|
+
placeholder="Set a label"
|
|
149
|
+
aria-label="Chip text"
|
|
150
|
+
:value="checkedProps.label"
|
|
151
|
+
/>
|
|
152
|
+
<UiRadioGroup
|
|
153
|
+
label="Chip color"
|
|
154
|
+
label-visibility="sr-only"
|
|
155
|
+
:value="checkedProps.color"
|
|
156
|
+
><UiSwatch tone="neutral" />
|
|
157
|
+
<UiSwatch tone="blue" />
|
|
158
|
+
<UiSwatch tone="green" />
|
|
159
|
+
<UiSwatch tone="yellow" />
|
|
160
|
+
<UiSwatch tone="red" />
|
|
161
|
+
<UiSwatch tone="purple" /></UiRadioGroup></UiStack>
|
|
162
|
+
</div>
|
|
163
|
+
</template>
|
package/vue/UiRadioGroup.d.ts
CHANGED
|
@@ -16,6 +16,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
16
16
|
type: PropType<string | null>;
|
|
17
17
|
default: string;
|
|
18
18
|
};
|
|
19
|
+
labelVisibility: {
|
|
20
|
+
type: PropType<"visible" | "sr-only" | null>;
|
|
21
|
+
default: string;
|
|
22
|
+
};
|
|
19
23
|
name: {
|
|
20
24
|
type: PropType<string | null>;
|
|
21
25
|
default: string;
|
|
@@ -57,6 +61,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
57
61
|
type: PropType<string | null>;
|
|
58
62
|
default: string;
|
|
59
63
|
};
|
|
64
|
+
labelVisibility: {
|
|
65
|
+
type: PropType<"visible" | "sr-only" | null>;
|
|
66
|
+
default: string;
|
|
67
|
+
};
|
|
60
68
|
name: {
|
|
61
69
|
type: PropType<string | null>;
|
|
62
70
|
default: string;
|
|
@@ -92,6 +100,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
92
100
|
label: string | null;
|
|
93
101
|
invalid: boolean | null;
|
|
94
102
|
disabled: boolean | null;
|
|
103
|
+
labelVisibility: "visible" | "sr-only" | null;
|
|
95
104
|
orientation: "vertical" | "horizontal" | null;
|
|
96
105
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
97
106
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|