@threadlabs/looma 0.9.1 → 0.10.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/components/shared/form-reset.js +21 -0
- package/components/ui-avatar/ui-avatar.html +12 -4
- package/components/ui-avatar-group/ui-avatar-group.html +5 -2
- package/components/ui-badge/ui-badge.html +6 -2
- package/components/ui-button/ui-button.html +6 -2
- package/components/ui-callout/ui-callout.html +3 -1
- package/components/ui-checkbox/ui-checkbox.html +24 -6
- package/components/ui-checkbox/ui-checkbox.js +9 -0
- package/components/ui-cluster/ui-cluster.html +6 -2
- package/components/ui-combobox/ui-combobox.html +54 -20
- package/components/ui-combobox/ui-combobox.js +31 -12
- package/components/ui-container/ui-container.html +5 -2
- package/components/ui-disclosure/ui-disclosure.html +6 -3
- package/components/ui-editable/ui-editable.html +3 -1
- package/components/ui-editable/ui-editable.js +7 -6
- package/components/ui-editor-mention-menu/ui-editor-mention-menu.html +3 -1
- package/components/ui-editor-slash-menu/ui-editor-slash-menu.html +3 -1
- package/components/ui-floating-action-button/ui-floating-action-button.html +5 -3
- package/components/ui-form-field/ui-form-field.html +9 -3
- package/components/ui-grid/ui-grid.html +6 -2
- package/components/ui-icon/ui-icon.html +3 -1
- package/components/ui-icon-button/ui-icon-button.html +11 -4
- package/components/ui-input/ui-input.html +3 -1
- package/components/ui-input/ui-input.js +5 -2
- package/components/ui-menu-item/ui-menu-item.html +5 -2
- package/components/ui-radio/ui-radio.html +12 -5
- package/components/ui-radio/ui-radio.js +11 -0
- package/components/ui-radio-group/ui-radio-group.html +17 -7
- package/components/ui-radio-group/ui-radio-group.js +16 -3
- package/components/ui-reel/ui-reel.html +9 -3
- package/components/ui-search-result-row/ui-search-result-row.html +5 -3
- package/components/ui-select/ui-select.html +3 -1
- package/components/ui-select/ui-select.js +5 -2
- package/components/ui-stack/ui-stack.html +9 -3
- package/components/ui-switch/ui-switch.html +10 -5
- package/components/ui-switch/ui-switch.js +9 -0
- package/components/ui-switcher/ui-switcher.html +9 -3
- package/components/ui-tabs/ui-tabs.html +8 -3
- package/components/ui-textarea/ui-textarea.html +3 -1
- package/components/ui-textarea/ui-textarea.js +5 -2
- package/components/ui-tree/ui-tree.html +7 -3
- package/components/ui-tree-item/ui-tree-item.html +32 -11
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/vanilla/UiCheckbox.d.ts +1 -0
- package/vanilla/UiCheckbox.js +7 -4
- package/vanilla/UiCombobox.js +113 -99
- package/vanilla/UiRadioGroup.js +7 -1
- package/vanilla/UiSearchResultRow.js +4 -1
- package/vanilla/UiSwitch.d.ts +1 -0
- package/vanilla/UiSwitch.js +7 -4
- package/vue/UiCheckbox.d.ts +2 -0
- package/vue/UiCheckbox.vue +3 -0
- package/vue/UiCombobox.vue +27 -4
- package/vue/UiRadioGroup.vue +2 -0
- package/vue/UiSearchResultRow.vue +1 -0
- package/vue/UiSwitch.d.ts +2 -0
- package/vue/UiSwitch.vue +3 -0
- package/vue/chunks/UiCheckbox.js +4 -1
- package/vue/chunks/UiCombobox.js +67 -39
- package/vue/chunks/UiRadioGroup.js +8 -2
- package/vue/chunks/UiSearchResultRow.js +7 -2
- package/vue/chunks/UiSwitch.js +4 -1
- package/vue/components.css +89 -89
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<template component="ui-input" controller="./ui-input.js">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="value" type="string"
|
|
3
|
+
<prop name="value" type="string"
|
|
4
|
+
>The input's text. Setting or changing it replaces the live text; between changes the user's typing stands, so follow input events to keep it in step. It is
|
|
5
|
+
also the input's default, so a form reset returns to it.</prop>
|
|
4
6
|
<prop name="disabled" type="boolean" default="false">Prevents editing and form submission.</prop>
|
|
5
7
|
<prop name="invalid" type="boolean" default="false">Exposes invalid state to assistive technology and styling.</prop>
|
|
6
8
|
<prop name="readonly" type="boolean" default="false">Allows selection without allowing edits.</prop>
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
// The value attribute only sets the default; a controlled value is applied to the live input.
|
|
1
|
+
// The value attribute only sets the default; a controlled value is applied to the live input. The
|
|
2
|
+
// value is also made the native default, so a form reset returns to it.
|
|
2
3
|
export default function controller(host) {
|
|
3
4
|
return host.effect(() => {
|
|
4
5
|
const value = host.state.value;
|
|
5
|
-
if (value
|
|
6
|
+
if (value === undefined || value === null) return;
|
|
7
|
+
host.element.defaultValue = String(value);
|
|
8
|
+
if (host.element.value !== String(value)) host.element.value = String(value);
|
|
6
9
|
});
|
|
7
10
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
<template component="ui-menu-item">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="disabled" type="boolean" default="false"
|
|
4
|
-
|
|
3
|
+
<prop name="disabled" type="boolean" default="false"
|
|
4
|
+
>Makes the item unavailable: it is faded, skipped by the arrow keys, and choosing it does nothing. It stays visible and is announced as disabled.</prop>
|
|
5
|
+
<prop name="value" type="string" default=""
|
|
6
|
+
>The value the enclosing menu reports in its select event when this item is chosen. Give each item a distinct value so one handler can tell them
|
|
7
|
+
apart.</prop>
|
|
5
8
|
</defs>
|
|
6
9
|
<div role="menuitem" tabindex="-1" :aria-disabled="disabled" :data-value="value"><slot></slot></div>
|
|
7
10
|
<style>
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
<template component="ui-radio" controller="./ui-radio.js">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="checked" type="boolean" default="false"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<prop name="
|
|
7
|
-
<prop name="
|
|
3
|
+
<prop name="checked" type="boolean" default="false"
|
|
4
|
+
>Whether the radio is checked initially or when set externally. A form reset returns it to this. Inside a ui-radio-group the group's value decides
|
|
5
|
+
instead.</prop>
|
|
6
|
+
<prop name="disabled" type="boolean" default="false">Disables the native radio, so it cannot be chosen, focused, or reached with the arrow keys.</prop>
|
|
7
|
+
<prop name="name" type="string" default=""
|
|
8
|
+
>The native name that groups radios: of the radios that share a name, only one can be checked, and the arrow keys move between them. Inside a ui-radio-group
|
|
9
|
+
the group sets the name, so leave this empty there.</prop>
|
|
10
|
+
<prop name="required" type="boolean" default="false"
|
|
11
|
+
>Marks the native radio required, so native form validation fails until a radio with the same name is checked.</prop>
|
|
12
|
+
<prop name="value" type="string" default="on"
|
|
13
|
+
>The value this radio stands for: submitted with a form, reported in its change event, and matched against a ui-radio-group's value to decide which radio is
|
|
14
|
+
checked.</prop>
|
|
8
15
|
<state name="internalChecked" :value="false"></state>
|
|
9
16
|
<event name="change" type="object({ checked: boolean, value: string, trigger: keyboard | pointer | programmatic })"></event>
|
|
10
17
|
</defs>
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
import { afterFormReset } from "../shared/form-reset.js";
|
|
1
2
|
import { trackTrigger } from "../shared/trigger.js";
|
|
2
3
|
|
|
3
4
|
// `checked` sets the control initially and whenever it changes; the user's changes update the state.
|
|
5
|
+
// A form reset returns the control to `checked`. Vue writes the checked attribute on every render, so
|
|
6
|
+
// the native default alone cannot hold it there.
|
|
4
7
|
export default function controller(host) {
|
|
5
8
|
const input = host.refs.input;
|
|
6
9
|
const [trigger, stopTracking] = trackTrigger(host);
|
|
7
10
|
let external = host.state.checked;
|
|
8
11
|
host.state.internalChecked = Boolean(external);
|
|
9
12
|
const stop = host.effect(() => {
|
|
13
|
+
input.defaultChecked = Boolean(host.state.checked);
|
|
10
14
|
if (host.state.checked === external) return;
|
|
11
15
|
external = host.state.checked;
|
|
12
16
|
host.state.internalChecked = Boolean(external);
|
|
@@ -17,8 +21,15 @@ export default function controller(host) {
|
|
|
17
21
|
host.dispatch("change", { checked: input.checked, value: String(host.state.value ?? "on"), trigger: trigger() });
|
|
18
22
|
};
|
|
19
23
|
input.addEventListener("change", onChange);
|
|
24
|
+
const stopReset = afterFormReset(input, () => {
|
|
25
|
+
// Inside a ui-radio-group the group's value decides, whichever reset runs first.
|
|
26
|
+
if (input.closest('[data-component~="ui-radio-group"]')) return;
|
|
27
|
+
host.state.internalChecked = Boolean(external);
|
|
28
|
+
input.checked = Boolean(external);
|
|
29
|
+
});
|
|
20
30
|
return () => {
|
|
21
31
|
stop();
|
|
32
|
+
stopReset();
|
|
22
33
|
stopTracking();
|
|
23
34
|
input.removeEventListener("change", onChange);
|
|
24
35
|
};
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
<template component="ui-radio-group" controller="./ui-radio-group.js">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="value" type="string" default=""
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<prop name="
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
<prop name="value" type="string" default=""
|
|
4
|
+
>The value of the checked radio, initially or when set externally; empty checks none. The user's choice updates it from there and is reported as select and
|
|
5
|
+
change events, and a form reset returns the group to it.</prop>
|
|
6
|
+
<prop name="name" type="string" default=""
|
|
7
|
+
>The native name given to every radio in the group, under which a form submits the chosen value. Left empty, the group generates a unique name that keeps
|
|
8
|
+
the radios together, so set it when the choice submits with a form.</prop>
|
|
9
|
+
<prop name="label" type="string" default="Options"
|
|
10
|
+
>The group's legend, shown above the radios and announced as the group's name. Phrase it as the question the radios answer.</prop>
|
|
11
|
+
<prop name="orientation" type="horizontal | vertical" default="horizontal"
|
|
12
|
+
>horizontal lays the radios out in a row; vertical stacks them in a column. The arrow keys move between radios either way.</prop>
|
|
13
|
+
<prop name="disabled" type="boolean" default="false"
|
|
14
|
+
>Disables every radio in the group through the native fieldset, so no choice can be made and the group submits nothing with its form. A radio disabled on
|
|
15
|
+
its own stays disabled when the group is enabled.</prop>
|
|
16
|
+
<prop name="required" type="boolean" default="false"
|
|
17
|
+
>Makes a choice required, as a required native radio does for its group: the group states aria-required, every radio in it is marked required, and native
|
|
18
|
+
form validation fails until one is checked.</prop>
|
|
9
19
|
<state name="internalValue" :value="''"></state>
|
|
10
20
|
<event name="select" type="object({ value: string, previousValue: string, trigger: keyboard | pointer | programmatic })"></event>
|
|
11
21
|
<event name="change" type="object({ checked: boolean, value: string, trigger: keyboard | pointer | programmatic })"></event>
|
|
12
22
|
</defs>
|
|
13
|
-
<fieldset role="radiogroup">
|
|
23
|
+
<fieldset role="radiogroup" :aria-required="required" :disabled="disabled">
|
|
14
24
|
<legend><template $value="label"></template></legend>
|
|
15
25
|
<slot></slot>
|
|
16
26
|
</fieldset>
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
import { afterFormReset } from "../shared/form-reset.js";
|
|
1
2
|
import { trackTrigger } from "../shared/trigger.js";
|
|
2
3
|
|
|
3
4
|
let groups = 0;
|
|
4
5
|
|
|
5
6
|
// Native radios that share a name already move and check with the arrow keys. The group gives its
|
|
6
|
-
// radios that name, applies a controlled value, and reports the user's choice.
|
|
7
|
+
// radios that name, applies a controlled value, and reports the user's choice. Its fieldset disables
|
|
8
|
+
// them, so a radio's own disabled is never overwritten.
|
|
7
9
|
export default function controller(host) {
|
|
8
10
|
const element = host.element;
|
|
9
11
|
const name = String(host.state.name || `ui-radio-group-${++groups}`);
|
|
10
12
|
const [trigger, stopTracking] = trackTrigger(host);
|
|
11
13
|
const inputs = () => Array.from(element.querySelectorAll('[data-component~="ui-radio"] input[type="radio"]'));
|
|
12
14
|
let external = host.state.value;
|
|
15
|
+
// A radio's own required survives until the group's required changes, since either one makes the
|
|
16
|
+
// whole name group required.
|
|
17
|
+
let required = false;
|
|
13
18
|
host.state.internalValue = String(external ?? "");
|
|
14
19
|
const stop = host.effect(() => {
|
|
15
20
|
if (host.state.value !== external) {
|
|
@@ -17,11 +22,14 @@ export default function controller(host) {
|
|
|
17
22
|
host.state.internalValue = String(external ?? "");
|
|
18
23
|
}
|
|
19
24
|
const value = host.state.internalValue;
|
|
20
|
-
const
|
|
25
|
+
const applyRequired = Boolean(host.state.required) !== required;
|
|
26
|
+
required = Boolean(host.state.required);
|
|
21
27
|
for (const input of inputs()) {
|
|
28
|
+
if (applyRequired) input.required = required;
|
|
22
29
|
input.name = name;
|
|
23
30
|
input.checked = input.value === value;
|
|
24
|
-
|
|
31
|
+
// The value prop is the choice a form reset returns to.
|
|
32
|
+
input.defaultChecked = input.value === String(external ?? "");
|
|
25
33
|
}
|
|
26
34
|
});
|
|
27
35
|
const onChange = (event) => {
|
|
@@ -34,8 +42,13 @@ export default function controller(host) {
|
|
|
34
42
|
host.dispatch("change", { checked: true, value: input.value, trigger: how });
|
|
35
43
|
};
|
|
36
44
|
element.addEventListener("change", onChange);
|
|
45
|
+
const stopReset = afterFormReset(element, () => {
|
|
46
|
+
host.state.internalValue = String(external ?? "");
|
|
47
|
+
for (const input of inputs()) input.checked = input.value === host.state.internalValue;
|
|
48
|
+
});
|
|
37
49
|
return () => {
|
|
38
50
|
stop();
|
|
51
|
+
stopReset();
|
|
39
52
|
stopTracking();
|
|
40
53
|
element.removeEventListener("change", onChange);
|
|
41
54
|
};
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
<template component="ui-reel">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="gap" type="xs | s | m | l | xl"
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
<prop name="gap" type="xs | s | m | l | xl"
|
|
4
|
+
>Space between items, on the spacing scale: xs is 0.5rem, s 0.75rem, m 1rem (also the default), l 1.5rem, and xl 2rem. The --ui-reel-gap custom property,
|
|
5
|
+
when set, overrides it.</prop>
|
|
6
|
+
<prop name="itemWidth" type="sm | md | lg"
|
|
7
|
+
>A fixed width for every item: sm is 12rem, md is 16rem, and lg is 20rem. Unset, each item keeps its content's width. Items never shrink to fit, so the reel
|
|
8
|
+
scrolls sideways once they overflow.</prop>
|
|
9
|
+
<prop name="snap" type="start | center"
|
|
10
|
+
>Snaps scrolling to items: start comes to rest with an item's start edge at the reel's start, and center with an item centred in the reel. Unset, the reel
|
|
11
|
+
scrolls freely.</prop>
|
|
6
12
|
</defs>
|
|
7
13
|
<div role="region" tabindex="0"><slot></slot></div>
|
|
8
14
|
<style>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<template component="ui-search-result-row">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="disabled" type="boolean" default="false">
|
|
4
|
-
<prop name="selected" type="boolean" default="false"
|
|
3
|
+
<prop name="disabled" type="boolean" default="false">Disables the row's button, so it cannot be chosen or focused, and fades it to 60% opacity.</prop>
|
|
4
|
+
<prop name="selected" type="boolean" default="false"
|
|
5
|
+
>Marks the row as the current result: it gets the hover surface and aria-current="true", which assistive technology announces as current. Set it on one row
|
|
6
|
+
at a time, such as the result the arrow keys have moved to.</prop>
|
|
5
7
|
</defs>
|
|
6
|
-
<button type="button" :disabled="disabled">
|
|
8
|
+
<button type="button" :disabled="disabled" :aria-current="selected">
|
|
7
9
|
<span class="leading"><slot name="leading"></slot></span>
|
|
8
10
|
<span class="content">
|
|
9
11
|
<span class="title"><slot name="title"></slot></span>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<template component="ui-select" controller="./ui-select.js">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="value" type="string"
|
|
3
|
+
<prop name="value" type="string"
|
|
4
|
+
>The value of the selected option, initially or when set externally. It is also the default, so a form reset returns to it rather than to the first
|
|
5
|
+
option.</prop>
|
|
4
6
|
<prop name="disabled" type="boolean" default="false">Prevents selection and form submission.</prop>
|
|
5
7
|
<prop name="invalid" type="boolean" default="false">Exposes invalid state to assistive technology and styling.</prop>
|
|
6
8
|
<prop name="required" type="boolean" default="false">Requires a non-empty option for form validation.</prop>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
// A controlled value can arrive before its projected <option> elements, so it is applied again
|
|
2
|
-
// whenever the options change.
|
|
2
|
+
// whenever the options change. The value's option is also marked the native default, so a form
|
|
3
|
+
// reset returns to it rather than to the first option.
|
|
3
4
|
export default function controller(host) {
|
|
4
5
|
const select = host.element;
|
|
5
6
|
const apply = () => {
|
|
6
7
|
const value = host.state.value;
|
|
7
|
-
if (value
|
|
8
|
+
if (value === undefined || value === null) return;
|
|
9
|
+
for (const option of select.options) option.defaultSelected = option.value === String(value);
|
|
10
|
+
if (select.value !== String(value)) select.value = String(value);
|
|
8
11
|
};
|
|
9
12
|
const observer = new MutationObserver(apply);
|
|
10
13
|
observer.observe(select, { childList: true, subtree: true });
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
<template component="ui-stack">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="gap" type="xs | s | m | l | xl"
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
<prop name="gap" type="xs | s | m | l | xl"
|
|
4
|
+
>Space between items, on the spacing scale: xs is 0.5rem, s 0.75rem, m 1rem (also the default), l 1.5rem, and xl 2rem. The --ui-stack-gap custom property,
|
|
5
|
+
when set, overrides it.</prop>
|
|
6
|
+
<prop name="align" type="start | center | end | stretch"
|
|
7
|
+
>How items sit across the stack: stretch (the default) makes each fill the stack's width; start, center, and end keep each at its own width, against the
|
|
8
|
+
start, in the middle, or against the end.</prop>
|
|
9
|
+
<prop name="justify" type="start | center | end | between"
|
|
10
|
+
>Where items sit along a stack that is taller than its content: start (the default), center, end, or between, which spreads the spare space between items.
|
|
11
|
+
It has no effect unless the stack is given a height or stretched to one.</prop>
|
|
6
12
|
</defs>
|
|
7
13
|
<div><slot></slot></div>
|
|
8
14
|
<style>
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
<template component="ui-switch" controller="./ui-switch.js">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="checked" type="boolean" default="false">Whether the switch is checked initially or when set externally.</prop>
|
|
4
|
-
<prop name="disabled" type="boolean" default="false">
|
|
5
|
-
<prop name="required" type="boolean" default="false">required
|
|
6
|
-
<prop name="
|
|
3
|
+
<prop name="checked" type="boolean" default="false">Whether the switch is checked initially or when set externally. A form reset returns it to this.</prop>
|
|
4
|
+
<prop name="disabled" type="boolean" default="false">Disables the native switch, so it cannot be toggled or focused.</prop>
|
|
5
|
+
<prop name="required" type="boolean" default="false">Marks the native switch required, so native form validation treats it as invalid until it is on.</prop>
|
|
6
|
+
<prop name="name" type="string" default=""
|
|
7
|
+
>The native name the switch submits under: a form that contains it sends name=value while it is on, and nothing while it is off, as a native checkbox does.
|
|
8
|
+
Left empty, it takes no part in form submission.</prop>
|
|
9
|
+
<prop name="value" type="string" default="on"
|
|
10
|
+
>The value a form submits under name while the switch is on, also reported in the change event's detail so one handler can tell switches apart. on by
|
|
11
|
+
default, as on a native checkbox.</prop>
|
|
7
12
|
<state name="internalChecked" :value="false"></state>
|
|
8
13
|
<event name="change" type="object({ checked: boolean, value: string, trigger: keyboard | pointer | programmatic })"></event>
|
|
9
14
|
</defs>
|
|
10
15
|
<label>
|
|
11
|
-
<input type="checkbox" role="switch" $ref="input" .checked="internalChecked" :disabled="disabled" :required="required" :value="value">
|
|
16
|
+
<input type="checkbox" role="switch" $ref="input" .checked="internalChecked" :disabled="disabled" :required="required" :name="name" :value="value">
|
|
12
17
|
<span class="label"><slot></slot></span>
|
|
13
18
|
</label>
|
|
14
19
|
<style>
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
import { afterFormReset } from "../shared/form-reset.js";
|
|
1
2
|
import { trackTrigger } from "../shared/trigger.js";
|
|
2
3
|
|
|
3
4
|
// `checked` sets the control initially and whenever it changes; the user's changes update the state.
|
|
5
|
+
// A form reset returns the control to `checked`. Vue writes the checked attribute on every render, so
|
|
6
|
+
// the native default alone cannot hold it there.
|
|
4
7
|
export default function controller(host) {
|
|
5
8
|
const input = host.refs.input;
|
|
6
9
|
const [trigger, stopTracking] = trackTrigger(host);
|
|
7
10
|
let external = host.state.checked;
|
|
8
11
|
host.state.internalChecked = Boolean(external);
|
|
9
12
|
const stop = host.effect(() => {
|
|
13
|
+
input.defaultChecked = Boolean(host.state.checked);
|
|
10
14
|
if (host.state.checked === external) return;
|
|
11
15
|
external = host.state.checked;
|
|
12
16
|
host.state.internalChecked = Boolean(external);
|
|
@@ -16,8 +20,13 @@ export default function controller(host) {
|
|
|
16
20
|
host.dispatch("change", { checked: input.checked, value: String(host.state.value ?? "on"), trigger: trigger() });
|
|
17
21
|
};
|
|
18
22
|
input.addEventListener("change", onChange);
|
|
23
|
+
const stopReset = afterFormReset(input, () => {
|
|
24
|
+
host.state.internalChecked = Boolean(external);
|
|
25
|
+
input.checked = Boolean(external);
|
|
26
|
+
});
|
|
19
27
|
return () => {
|
|
20
28
|
stop();
|
|
29
|
+
stopReset();
|
|
21
30
|
stopTracking();
|
|
22
31
|
input.removeEventListener("change", onChange);
|
|
23
32
|
};
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
<template component="ui-switcher">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="gap" type="xs | s | m | l | xl"
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
<prop name="gap" type="xs | s | m | l | xl"
|
|
4
|
+
>Space between items, on the spacing scale: xs is 0.5rem, s 0.75rem, m 1rem (also the default), l 1.5rem, and xl 2rem. The --ui-switcher-gap custom
|
|
5
|
+
property, when set, overrides it.</prop>
|
|
6
|
+
<prop name="threshold" type="xs | sm | md | lg"
|
|
7
|
+
>The container width at which items switch between a row and a stack: wider, they all sit side by side; narrower, each takes the full width. xs is 20rem, sm
|
|
8
|
+
is 30rem (also the default), md is 45rem, and lg is 60rem.</prop>
|
|
9
|
+
<prop name="align" type="start | center | end | stretch"
|
|
10
|
+
>How items line up while they sit in a row: stretch (the default) makes them equally tall; start, center, and end align their tops, middles, or
|
|
11
|
+
bottoms.</prop>
|
|
6
12
|
</defs>
|
|
7
13
|
<div><slot></slot></div>
|
|
8
14
|
<style>
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
<template component="ui-tabs" controller="./ui-tabs.js">
|
|
2
2
|
<defs>
|
|
3
3
|
<prop name="density" type="comfortable | compact" default="comfortable">Compact trades padding and type size for rows that fit more on screen.</prop>
|
|
4
|
-
<prop name="label" type="string" default="Tabs"
|
|
5
|
-
|
|
6
|
-
<prop name="
|
|
4
|
+
<prop name="label" type="string" default="Tabs"
|
|
5
|
+
>The tab list's accessible name, announced when focus enters the list. Name what the tabs switch between.</prop>
|
|
6
|
+
<prop name="value" type="string" default=""
|
|
7
|
+
>The id of the selected panel, initially or when set externally; empty selects the first panel. Choosing a tab updates it from there and reports a select
|
|
8
|
+
event. A panel without an id is given a generated one.</prop>
|
|
9
|
+
<prop name="orientation" type="horizontal | vertical" default="horizontal"
|
|
10
|
+
>horizontal puts the tabs in a row above the panels, moved between with the Left and Right arrow keys; vertical puts them in a column beside the panels,
|
|
11
|
+
moved between with Up and Down.</prop>
|
|
7
12
|
<prop name="stretch" type="boolean" default="false">Share the full width of the tab list equally between tabs instead of sizing each to its label.</prop>
|
|
8
13
|
<state name="internalValue" :value="''"></state>
|
|
9
14
|
<state name="tabs" type="list(object({ id: string, label: string }))" :value="[]"></state>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<template component="ui-textarea" controller="./ui-textarea.js">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="value" type="string"
|
|
3
|
+
<prop name="value" type="string"
|
|
4
|
+
>The textarea's text. Setting or changing it replaces the live text; between changes the user's typing stands, so follow input events to keep it in step. It
|
|
5
|
+
is also the textarea's default, so a form reset returns to it.</prop>
|
|
4
6
|
<prop name="disabled" type="boolean" default="false">Prevents editing and form submission.</prop>
|
|
5
7
|
<prop name="invalid" type="boolean" default="false">Exposes invalid state to assistive technology and styling.</prop>
|
|
6
8
|
<prop name="readonly" type="boolean" default="false">Allows selection without allowing edits.</prop>
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
// The value attribute only sets the default; a controlled value is applied to the live textarea.
|
|
1
|
+
// The value attribute only sets the default; a controlled value is applied to the live textarea. The
|
|
2
|
+
// value is also made the native default, so a form reset returns to it.
|
|
2
3
|
export default function controller(host) {
|
|
3
4
|
return host.effect(() => {
|
|
4
5
|
const value = host.state.value;
|
|
5
|
-
if (value
|
|
6
|
+
if (value === undefined || value === null) return;
|
|
7
|
+
host.element.defaultValue = String(value);
|
|
8
|
+
if (host.element.value !== String(value)) host.element.value = String(value);
|
|
6
9
|
});
|
|
7
10
|
}
|
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
<template component="ui-tree" controller="./ui-tree.js">
|
|
3
3
|
<defs>
|
|
4
4
|
<prop name="density" type="comfortable | compact" default="comfortable">Compact trades padding and type size for rows that fit more on screen.</prop>
|
|
5
|
-
<prop name="label" type="string" default="Tree">
|
|
6
|
-
<prop name="hoverExpandDelay" type="number" default="700"
|
|
7
|
-
|
|
5
|
+
<prop name="label" type="string" default="Tree">The tree's accessible name, announced when focus enters it. Name what the tree holds.</prop>
|
|
6
|
+
<prop name="hoverExpandDelay" type="number" default="700"
|
|
7
|
+
>How long, in milliseconds, a dragged item must hover over the middle of a collapsed branch before the branch opens to receive it. 0 opens it at
|
|
8
|
+
once.</prop>
|
|
9
|
+
<prop name="maxDepth" type="number" default="0"
|
|
10
|
+
>The deepest level a drag may produce, counting the top level as 1. A drop that would place the dragged item, or any item beneath it, deeper than this is
|
|
11
|
+
refused and reported as reorder-rejected. 0 means no limit.</prop>
|
|
8
12
|
<event
|
|
9
13
|
name="reorder"
|
|
10
14
|
type="object({ sourceId: string, targetId: string, position: before | inside | after, sourceType: string, targetType: string, sourceScope: string, targetScope: string, trigger: keyboard | pointer | programmatic })"
|
|
@@ -1,17 +1,38 @@
|
|
|
1
1
|
<template component="ui-tree-item" controller="./ui-tree-item.js">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="itemId" type="string" default=""
|
|
3
|
+
<prop name="itemId" type="string" default=""
|
|
4
|
+
>The item's identifier, reported as sourceId and targetId in the tree's reorder events and as id in its expand event. A sortable item needs one to be
|
|
5
|
+
dragged, and a drop onto an item without one is not reported.</prop>
|
|
4
6
|
<prop name="label" type="string" default="">The item's accessible name, also shown as the row text unless the label slot supplies content.</prop>
|
|
5
|
-
<prop name="dropDepth" type="number"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<prop name="
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<prop name="
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<prop name="
|
|
7
|
+
<prop name="dropDepth" type="number"
|
|
8
|
+
>Overrides the level this item counts as when the tree checks maxDepth for a drop onto it. Unset, its level in the rendered tree is used; set it when the
|
|
9
|
+
item sits deeper in the real hierarchy than the rendered tree shows.</prop>
|
|
10
|
+
<prop name="subtreeDepth" type="number"
|
|
11
|
+
>Overrides how many levels sit beneath this item when the tree checks maxDepth for a drag of it. Unset, the tree counts the rendered descendants; set it
|
|
12
|
+
when some are not rendered, such as children that load later.</prop>
|
|
13
|
+
<prop name="container" type="boolean" default="false"
|
|
14
|
+
>Makes the item a branch even before it has children: it gets the expand button and aria-expanded, and accepts drops inside it. An item with nested items is
|
|
15
|
+
a branch without it.</prop>
|
|
16
|
+
<prop name="sortable" type="boolean" default="false"
|
|
17
|
+
>Gives the item a drag handle, shown on hover, so it can be dragged to a new place in the tree. The tree reports the drop as a reorder event and leaves
|
|
18
|
+
moving the item to you. Needs itemId; a disabled item, and any item under touch input, shows no handle.</prop>
|
|
19
|
+
<prop name="dragType" type="string" default="item"
|
|
20
|
+
>The item's kind, for drag rules: it can be dropped before or after only items of the same type, and inside a branch only if that branch's accepts allows
|
|
21
|
+
it. Reported as sourceType and targetType.</prop>
|
|
22
|
+
<prop name="dropScope" type="string" default=""
|
|
23
|
+
>Names the list the item sits in, such as its parent's id, and is reported as sourceScope and targetScope in the tree's reorder events, so a handler can
|
|
24
|
+
tell a reorder within one list from a move between lists. It never restricts where an item can be dropped; dragType and accepts do that.</prop>
|
|
25
|
+
<prop name="accepts" type="string" default=""
|
|
26
|
+
>A comma-separated list of the dragType values this branch accepts dropped inside it. Empty accepts any type. It does not affect drops before or after the
|
|
27
|
+
item.</prop>
|
|
28
|
+
<prop name="expanded" type="boolean" default="false"
|
|
29
|
+
>Whether the branch shows its children, initially or when set externally. The expand button, a click on the row, and the arrow keys toggle it from there,
|
|
30
|
+
each reported as an expand event. Only meaningful for a branch.</prop>
|
|
31
|
+
<prop name="selected" type="boolean" default="false"
|
|
32
|
+
>Marks the item selected: it sets aria-selected and gives the row the highlighted surface. The tree does not select on click, so drive it from your own
|
|
33
|
+
state.</prop>
|
|
34
|
+
<prop name="disabled" type="boolean" default="false"
|
|
35
|
+
>Makes the item unavailable: faded, skipped by keyboard navigation, unable to expand or be dragged, and closed to drops inside it.</prop>
|
|
15
36
|
<state name="internalExpanded" :value="false"></state>
|
|
16
37
|
<state name="structuralLevel" :value="1"></state>
|
|
17
38
|
<state name="tabStop" :value="false"></state>
|