@loadbare/widgets 0.3.2 → 0.5.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/README.md +4 -4
- package/dist/control.d.ts +57 -0
- package/dist/control.d.ts.map +1 -0
- package/dist/control.js +101 -0
- package/dist/control.js.map +1 -0
- package/dist/lb-input.browser.js +10 -38
- package/dist/lb-input.browser.js.map +1 -1
- package/dist/lb-options.browser.d.ts +14 -6
- package/dist/lb-options.browser.d.ts.map +1 -1
- package/dist/lb-options.browser.js +38 -39
- package/dist/lb-options.browser.js.map +1 -1
- package/dist/lb-options.html +1 -1
- package/dist/lb-picker.browser.js +6 -5
- package/dist/lb-picker.browser.js.map +1 -1
- package/dist/lb-picker.html +2 -2
- package/dist/lb-select.browser.js +10 -39
- package/dist/lb-select.browser.js.map +1 -1
- package/dist/lb-select.html +1 -1
- package/dist/lb-table.browser.js +9 -9
- package/dist/lb-table.browser.js.map +1 -1
- package/dist/lb-table.html +3 -3
- package/dist/lb-unknown-page.html +2 -4
- package/docs/lb-input.md +41 -40
- package/docs/lb-options.md +48 -32
- package/docs/lb-picker.md +24 -23
- package/docs/lb-select.md +37 -19
- package/docs/lb-table.md +26 -24
- package/docs/lb-unknown-page.md +11 -13
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -6,9 +6,9 @@ Inventory:
|
|
|
6
6
|
|
|
7
7
|
| Widget | Is |
|
|
8
8
|
| --- | --- |
|
|
9
|
-
| [`lb-input`](docs/lb-input.md) |
|
|
10
|
-
| [`lb-select`](docs/lb-select.md) | a `<select>` whose options the page writes |
|
|
11
|
-
| [`lb-options`](docs/lb-options.md) | a `<select>` whose options come from a query |
|
|
9
|
+
| [`lb-input`](docs/lb-input.md) | a control wrapping an `<input>` |
|
|
10
|
+
| [`lb-select`](docs/lb-select.md) | a control wrapping a `<select>` whose options the page writes |
|
|
11
|
+
| [`lb-options`](docs/lb-options.md) | a control wrapping a `<select>` whose options come from a query |
|
|
12
12
|
| [`lb-picker`](docs/lb-picker.md) | `lb-options` with the row template built in |
|
|
13
13
|
| [`lb-table`](docs/lb-table.md) | a `<table>` supplying its own scaffolding |
|
|
14
14
|
| [`lb-unknown-page`](docs/lb-unknown-page.md) | the chrome's dialog for a URL that names no page |
|
|
@@ -26,7 +26,7 @@ Then list the package in the application's `imports.ts`:
|
|
|
26
26
|
export default ["@loadbare/widgets"];
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
The application's HTML files can then use the widgets.
|
|
30
30
|
|
|
31
31
|
Apart from the line in `src/imports.ts`, no other import statements
|
|
32
32
|
are required. The loadbare builder automatically bundles the HTML and
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** The native controls a widget wraps. */
|
|
2
|
+
type Inner = HTMLInputElement | HTMLSelectElement;
|
|
3
|
+
/**
|
|
4
|
+
* A form-associated custom element wrapping one native control, which makes
|
|
5
|
+
* the widget itself the control: the hub sets its `value` when a column
|
|
6
|
+
* lands, reads it back when a request gathers, and commits it on `change`
|
|
7
|
+
* when it carries `lb-request`. Nothing about a request is the widget's.
|
|
8
|
+
*
|
|
9
|
+
* The native control inside is an implementation detail. Its `change` is
|
|
10
|
+
* stopped and fired again on the widget, so a listener sees one control and
|
|
11
|
+
* one event per edit.
|
|
12
|
+
*
|
|
13
|
+
* Not a widget itself, so the file carries no `.browser` and no `lb-` name:
|
|
14
|
+
* a consumer's builder passes it over, and each widget that extends it
|
|
15
|
+
* brings it along.
|
|
16
|
+
*/
|
|
17
|
+
export declare abstract class WrappedControl extends HTMLElement {
|
|
18
|
+
static formAssociated: boolean;
|
|
19
|
+
/** `<input>` or `<select>`: what this widget wraps. */
|
|
20
|
+
protected abstract readonly inner: "input" | "select";
|
|
21
|
+
/**
|
|
22
|
+
* Null where the DOM implementation offers no form value, which includes
|
|
23
|
+
* jsdom: the widget still works as a control, and a native form submission
|
|
24
|
+
* leaves it out.
|
|
25
|
+
*/
|
|
26
|
+
private readonly internals;
|
|
27
|
+
/** Whether the widget has connected once. */
|
|
28
|
+
private connected;
|
|
29
|
+
constructor();
|
|
30
|
+
/**
|
|
31
|
+
* A value that landed before this widget's definition did is only a
|
|
32
|
+
* stamp, since the hub sets `value` on a control and the element was not
|
|
33
|
+
* one yet. It is taken up the first time the widget connects, and never
|
|
34
|
+
* again: after that the hub sets `value` itself, and a later move must not
|
|
35
|
+
* undo an edit.
|
|
36
|
+
*
|
|
37
|
+
* The native control follows the widget's `form` attribute, so a form
|
|
38
|
+
* this widget joins by id resets the control inside it too.
|
|
39
|
+
*/
|
|
40
|
+
connectedCallback(): void;
|
|
41
|
+
/** The native control this widget wraps, once it is there. */
|
|
42
|
+
protected get control(): Inner | null;
|
|
43
|
+
get value(): string;
|
|
44
|
+
set value(value: string);
|
|
45
|
+
/**
|
|
46
|
+
* The native control is the form's too, and the form resets it by HTML's
|
|
47
|
+
* own algorithm. This widget comes first in tree order, so it tells the
|
|
48
|
+
* form its value once the control has been reset.
|
|
49
|
+
*/
|
|
50
|
+
formResetCallback(): void;
|
|
51
|
+
/** The inner control changed, before the widget fires its own `change`. */
|
|
52
|
+
protected changed(): void;
|
|
53
|
+
/** Tell the form owner the value, where the implementation allows it. */
|
|
54
|
+
protected formValue(): void;
|
|
55
|
+
}
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=control.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../widgets/control.ts"],"names":[],"mappings":"AAIA,0CAA0C;AAC1C,KAAK,KAAK,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAElD;;;;;;;;;;;;;GAaG;AACH,8BAAsB,cAAe,SAAQ,WAAW;IACtD,MAAM,CAAC,cAAc,UAAQ;IAE7B,uDAAuD;IACvD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAC;IAEtD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;IAEpD,6CAA6C;IAC7C,OAAO,CAAC,SAAS,CAAS;;IAa1B;;;;;;;;;OASG;IACH,iBAAiB,IAAI,IAAI;IASzB,8DAA8D;IAC9D,SAAS,KAAK,OAAO,IAAI,KAAK,GAAG,IAAI,CAEpC;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAUtB;IAED;;;;OAIG;IACH,iBAAiB,IAAI,IAAI;IAIzB,2EAA2E;IAC3E,SAAS,CAAC,OAAO,IAAI,IAAI;IAIzB,yEAAyE;IACzE,SAAS,CAAC,SAAS,IAAI,IAAI;CAG5B"}
|
package/dist/control.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
import { ATTR_COLUMN_VALUE } from "@loadbare/app/constants";
|
|
3
|
+
/**
|
|
4
|
+
* A form-associated custom element wrapping one native control, which makes
|
|
5
|
+
* the widget itself the control: the hub sets its `value` when a column
|
|
6
|
+
* lands, reads it back when a request gathers, and commits it on `change`
|
|
7
|
+
* when it carries `lb-request`. Nothing about a request is the widget's.
|
|
8
|
+
*
|
|
9
|
+
* The native control inside is an implementation detail. Its `change` is
|
|
10
|
+
* stopped and fired again on the widget, so a listener sees one control and
|
|
11
|
+
* one event per edit.
|
|
12
|
+
*
|
|
13
|
+
* Not a widget itself, so the file carries no `.browser` and no `lb-` name:
|
|
14
|
+
* a consumer's builder passes it over, and each widget that extends it
|
|
15
|
+
* brings it along.
|
|
16
|
+
*/
|
|
17
|
+
export class WrappedControl extends HTMLElement {
|
|
18
|
+
static formAssociated = true;
|
|
19
|
+
/**
|
|
20
|
+
* Null where the DOM implementation offers no form value, which includes
|
|
21
|
+
* jsdom: the widget still works as a control, and a native form submission
|
|
22
|
+
* leaves it out.
|
|
23
|
+
*/
|
|
24
|
+
internals;
|
|
25
|
+
/** Whether the widget has connected once. */
|
|
26
|
+
connected = false;
|
|
27
|
+
constructor() {
|
|
28
|
+
super();
|
|
29
|
+
this.internals = internalsOf(this);
|
|
30
|
+
this.addEventListener("change", (e) => {
|
|
31
|
+
if (e.target === this || e.target !== this.control)
|
|
32
|
+
return;
|
|
33
|
+
e.stopPropagation();
|
|
34
|
+
this.changed();
|
|
35
|
+
this.dispatchEvent(new Event("change", { bubbles: true }));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A value that landed before this widget's definition did is only a
|
|
40
|
+
* stamp, since the hub sets `value` on a control and the element was not
|
|
41
|
+
* one yet. It is taken up the first time the widget connects, and never
|
|
42
|
+
* again: after that the hub sets `value` itself, and a later move must not
|
|
43
|
+
* undo an edit.
|
|
44
|
+
*
|
|
45
|
+
* The native control follows the widget's `form` attribute, so a form
|
|
46
|
+
* this widget joins by id resets the control inside it too.
|
|
47
|
+
*/
|
|
48
|
+
connectedCallback() {
|
|
49
|
+
const form = this.getAttribute("form");
|
|
50
|
+
if (form !== null)
|
|
51
|
+
this.control?.setAttribute("form", form);
|
|
52
|
+
if (this.connected)
|
|
53
|
+
return;
|
|
54
|
+
this.connected = true;
|
|
55
|
+
const stamped = this.getAttribute(ATTR_COLUMN_VALUE);
|
|
56
|
+
if (stamped !== null)
|
|
57
|
+
this.value = stamped;
|
|
58
|
+
}
|
|
59
|
+
/** The native control this widget wraps, once it is there. */
|
|
60
|
+
get control() {
|
|
61
|
+
return this.querySelector(this.inner);
|
|
62
|
+
}
|
|
63
|
+
get value() {
|
|
64
|
+
return this.control?.value ?? "";
|
|
65
|
+
}
|
|
66
|
+
set value(value) {
|
|
67
|
+
const control = this.control;
|
|
68
|
+
if (!control) {
|
|
69
|
+
console.error(`${this.localName}: no <${this.inner}> to receive the value`);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
control.value = value;
|
|
73
|
+
this.formValue();
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The native control is the form's too, and the form resets it by HTML's
|
|
77
|
+
* own algorithm. This widget comes first in tree order, so it tells the
|
|
78
|
+
* form its value once the control has been reset.
|
|
79
|
+
*/
|
|
80
|
+
formResetCallback() {
|
|
81
|
+
queueMicrotask(() => this.formValue());
|
|
82
|
+
}
|
|
83
|
+
/** The inner control changed, before the widget fires its own `change`. */
|
|
84
|
+
changed() {
|
|
85
|
+
this.formValue();
|
|
86
|
+
}
|
|
87
|
+
/** Tell the form owner the value, where the implementation allows it. */
|
|
88
|
+
formValue() {
|
|
89
|
+
this.internals?.setFormValue(this.value);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function internalsOf(el) {
|
|
93
|
+
try {
|
|
94
|
+
const internals = el.attachInternals();
|
|
95
|
+
return typeof internals.setFormValue === "function" ? internals : null;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.js","sourceRoot":"","sources":["../widgets/control.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAE3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAK5D;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAgB,cAAe,SAAQ,WAAW;IACtD,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC;IAK7B;;;;OAIG;IACc,SAAS,CAA0B;IAEpD,6CAA6C;IACrC,SAAS,GAAG,KAAK,CAAC;IAE1B;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;YACpC,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,OAAO;gBAAE,OAAO;YAC3D,CAAC,CAAC,eAAe,EAAE,CAAC;YACpB,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;OASG;IACH,iBAAiB;QACf,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,IAAI,KAAK,IAAI;YAAE,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC5D,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;QACrD,IAAI,OAAO,KAAK,IAAI;YAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC;IAC7C,CAAC;IAED,8DAA8D;IAC9D,IAAc,OAAO;QACnB,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC;IACnC,CAAC;IAED,IAAI,KAAK,CAAC,KAAa;QACrB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CACX,GAAG,IAAI,CAAC,SAAS,SAAS,IAAI,CAAC,KAAK,wBAAwB,CAC7D,CAAC;YACF,OAAO;QACT,CAAC;QACD,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,SAAS,EAAE,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,iBAAiB;QACf,cAAc,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,2EAA2E;IACjE,OAAO;QACf,IAAI,CAAC,SAAS,EAAE,CAAC;IACnB,CAAC;IAED,yEAAyE;IAC/D,SAAS;QACjB,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;;AAGH,SAAS,WAAW,CAAC,EAAe;IAClC,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC;QACvC,OAAO,OAAO,SAAS,CAAC,YAAY,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC","sourcesContent":["/// <reference lib=\"dom\" />\n\nimport { ATTR_COLUMN_VALUE } from \"@loadbare/app/constants\";\n\n/** The native controls a widget wraps. */\ntype Inner = HTMLInputElement | HTMLSelectElement;\n\n/**\n * A form-associated custom element wrapping one native control, which makes\n * the widget itself the control: the hub sets its `value` when a column\n * lands, reads it back when a request gathers, and commits it on `change`\n * when it carries `lb-request`. Nothing about a request is the widget's.\n *\n * The native control inside is an implementation detail. Its `change` is\n * stopped and fired again on the widget, so a listener sees one control and\n * one event per edit.\n *\n * Not a widget itself, so the file carries no `.browser` and no `lb-` name:\n * a consumer's builder passes it over, and each widget that extends it\n * brings it along.\n */\nexport abstract class WrappedControl extends HTMLElement {\n static formAssociated = true;\n\n /** `<input>` or `<select>`: what this widget wraps. */\n protected abstract readonly inner: \"input\" | \"select\";\n\n /**\n * Null where the DOM implementation offers no form value, which includes\n * jsdom: the widget still works as a control, and a native form submission\n * leaves it out.\n */\n private readonly internals: ElementInternals | null;\n\n /** Whether the widget has connected once. */\n private connected = false;\n\n constructor() {\n super();\n this.internals = internalsOf(this);\n this.addEventListener(\"change\", (e) => {\n if (e.target === this || e.target !== this.control) return;\n e.stopPropagation();\n this.changed();\n this.dispatchEvent(new Event(\"change\", { bubbles: true }));\n });\n }\n\n /**\n * A value that landed before this widget's definition did is only a\n * stamp, since the hub sets `value` on a control and the element was not\n * one yet. It is taken up the first time the widget connects, and never\n * again: after that the hub sets `value` itself, and a later move must not\n * undo an edit.\n *\n * The native control follows the widget's `form` attribute, so a form\n * this widget joins by id resets the control inside it too.\n */\n connectedCallback(): void {\n const form = this.getAttribute(\"form\");\n if (form !== null) this.control?.setAttribute(\"form\", form);\n if (this.connected) return;\n this.connected = true;\n const stamped = this.getAttribute(ATTR_COLUMN_VALUE);\n if (stamped !== null) this.value = stamped;\n }\n\n /** The native control this widget wraps, once it is there. */\n protected get control(): Inner | null {\n return this.querySelector(this.inner);\n }\n\n get value(): string {\n return this.control?.value ?? \"\";\n }\n\n set value(value: string) {\n const control = this.control;\n if (!control) {\n console.error(\n `${this.localName}: no <${this.inner}> to receive the value`,\n );\n return;\n }\n control.value = value;\n this.formValue();\n }\n\n /**\n * The native control is the form's too, and the form resets it by HTML's\n * own algorithm. This widget comes first in tree order, so it tells the\n * form its value once the control has been reset.\n */\n formResetCallback(): void {\n queueMicrotask(() => this.formValue());\n }\n\n /** The inner control changed, before the widget fires its own `change`. */\n protected changed(): void {\n this.formValue();\n }\n\n /** Tell the form owner the value, where the implementation allows it. */\n protected formValue(): void {\n this.internals?.setFormValue(this.value);\n }\n}\n\nfunction internalsOf(el: HTMLElement): ElementInternals | null {\n try {\n const internals = el.attachInternals();\n return typeof internals.setFormValue === \"function\" ? internals : null;\n } catch {\n return null;\n }\n}\n"]}
|
package/dist/lb-input.browser.js
CHANGED
|
@@ -1,45 +1,17 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
|
-
import {
|
|
2
|
+
import { WrappedControl } from "./control.js";
|
|
3
3
|
/**
|
|
4
|
-
* A
|
|
5
|
-
*
|
|
6
|
-
* forwards it to the control it owns.
|
|
4
|
+
* A control wrapping an `<input>`. The hub sets its `value` from the column
|
|
5
|
+
* its `lb-column` names, and gathers it back under the same name.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* The developer has to ask, because committing per field is one editing model
|
|
15
|
-
* and not the only one. An input inside an `lb-row-insert` or `lb-row-update`
|
|
16
|
-
* form is read again by the form on submit, so a widget that sent on its own
|
|
17
|
-
* would write the same edit twice and defeat the batch the form is for.
|
|
7
|
+
* It issues nothing on its own. With `lb-request` it commits on `change`, and
|
|
8
|
+
* the hub sends that request with this input's column alone: an
|
|
9
|
+
* `lb-row-update` reaches the server with the query and key of the row it
|
|
10
|
+
* sits in. Without `lb-request` an edit waits for the form or row around it,
|
|
11
|
+
* because committing per field is one editing model and not the only one.
|
|
18
12
|
*/
|
|
19
|
-
class LbInput extends
|
|
20
|
-
|
|
21
|
-
attributeChangedCallback(_name, _old, value) {
|
|
22
|
-
const input = this.querySelector("input");
|
|
23
|
-
if (!input) {
|
|
24
|
-
console.error(`lb-input: no <input> to receive the value`);
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
input.value = value;
|
|
28
|
-
}
|
|
29
|
-
connectedCallback() {
|
|
30
|
-
this.addEventListener("change", () => {
|
|
31
|
-
const action = this.getAttribute(ATTR_ACTION);
|
|
32
|
-
if (!action)
|
|
33
|
-
return;
|
|
34
|
-
const input = this.querySelector("input");
|
|
35
|
-
if (!input) {
|
|
36
|
-
console.error(`lb-input: change with no <input>, ignoring`);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
const detail = { action, value: input.value };
|
|
40
|
-
this.dispatchEvent(new CustomEvent(LB_EVENT_NAME, { bubbles: true, detail }));
|
|
41
|
-
});
|
|
42
|
-
}
|
|
13
|
+
class LbInput extends WrappedControl {
|
|
14
|
+
inner = "input";
|
|
43
15
|
}
|
|
44
16
|
customElements.define("lb-input", LbInput);
|
|
45
17
|
//# sourceMappingURL=lb-input.browser.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lb-input.browser.js","sourceRoot":"","sources":["../widgets/lb-input.browser.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAE3B,OAAO,
|
|
1
|
+
{"version":3,"file":"lb-input.browser.js","sourceRoot":"","sources":["../widgets/lb-input.browser.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAE3B,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;;;;;GASG;AACH,MAAM,OAAQ,SAAQ,cAAc;IACf,KAAK,GAAG,OAAO,CAAC;CACpC;AAED,cAAc,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC","sourcesContent":["/// <reference lib=\"dom\" />\n\nimport { WrappedControl } from \"./control.js\";\n\n/**\n * A control wrapping an `<input>`. The hub sets its `value` from the column\n * its `lb-column` names, and gathers it back under the same name.\n *\n * It issues nothing on its own. With `lb-request` it commits on `change`, and\n * the hub sends that request with this input's column alone: an\n * `lb-row-update` reaches the server with the query and key of the row it\n * sits in. Without `lb-request` an edit waits for the form or row around it,\n * because committing per field is one editing model and not the only one.\n */\nclass LbInput extends WrappedControl {\n protected readonly inner = \"input\";\n}\n\ncustomElements.define(\"lb-input\", LbInput);\n"]}
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type { Row, RowsHost } from "@loadbare/app/types";
|
|
2
|
+
import { WrappedControl } from "./control.js";
|
|
3
|
+
export declare class LbOptions extends WrappedControl implements RowsHost {
|
|
4
|
+
protected readonly inner = "select";
|
|
5
5
|
/**
|
|
6
|
-
* The
|
|
6
|
+
* The value last set or chosen, which the options may not include yet.
|
|
7
|
+
* Null when nothing chose one, so the select's own default stands.
|
|
8
|
+
*/
|
|
9
|
+
private chosen;
|
|
10
|
+
get value(): string;
|
|
11
|
+
set value(value: string);
|
|
12
|
+
formResetCallback(): void;
|
|
13
|
+
protected changed(): void;
|
|
14
|
+
/**
|
|
15
|
+
* The hub reconciles the rows and calls this for placement only, so this
|
|
7
16
|
* widget carries no copy of what a row is or when one arrives.
|
|
8
17
|
*/
|
|
9
18
|
lbPlaceRow(el: Element, row: Row, template: HTMLTemplateElement): void;
|
|
@@ -11,6 +20,5 @@ export declare class LbOptions extends HTMLElement implements ListHost {
|
|
|
11
20
|
lbRowsLanded(): void;
|
|
12
21
|
/** The group with this label, or a new one in front of the template. */
|
|
13
22
|
private groupFor;
|
|
14
|
-
connectedCallback(): void;
|
|
15
23
|
}
|
|
16
24
|
//# sourceMappingURL=lb-options.browser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lb-options.browser.d.ts","sourceRoot":"","sources":["../widgets/lb-options.browser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"lb-options.browser.d.ts","sourceRoot":"","sources":["../widgets/lb-options.browser.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AA8B9C,qBAAa,SAAU,SAAQ,cAAe,YAAW,QAAQ;IAC/D,SAAS,CAAC,QAAQ,CAAC,KAAK,YAAY;IAEpC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAuB;IAErC,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAGtB;IAED,iBAAiB,IAAI,IAAI;IAKzB,SAAS,CAAC,OAAO,IAAI,IAAI;IAKzB;;;OAGG;IACH,UAAU,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,mBAAmB,GAAG,IAAI;IAUtE,0EAA0E;IAC1E,YAAY,IAAI,IAAI;IAgBpB,wEAAwE;IACxE,OAAO,CAAC,QAAQ;CASjB"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
|
-
import {
|
|
2
|
+
import { ATTR_KEY_VALUE } from "@loadbare/app/constants";
|
|
3
|
+
import { WrappedControl } from "./control.js";
|
|
3
4
|
/**
|
|
4
|
-
* A `<select>` whose choices
|
|
5
|
-
* placement belongs to the widget rather than to the framework.
|
|
5
|
+
* A `<select>` whose choices are the rows of a query, and the case that
|
|
6
|
+
* shows why placement belongs to the widget rather than to the framework.
|
|
6
7
|
*
|
|
7
8
|
* The rows arrive flat and keyed. Nothing on the wire knows about
|
|
8
9
|
* `<optgroup>`, and nothing needs to: a group is a column like any other, and
|
|
@@ -13,12 +14,13 @@ import { ATTR_ACTION, ATTR_KEY_VALUE, ATTR_QUERY_PARM, ATTR_VALUE, LB_EVENT_NAME
|
|
|
13
14
|
* does read.
|
|
14
15
|
*
|
|
15
16
|
* The identity of a row is the value of the option, so the `lb-key-value`
|
|
16
|
-
* the hub stamps on each option is copied to its `value
|
|
17
|
-
*
|
|
17
|
+
* the hub stamps on each option is copied to its `value`. The server declares
|
|
18
|
+
* the key, and the page never names it.
|
|
18
19
|
*
|
|
19
|
-
* It
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* It is a control like `lb-select`: `lb-column` sets which option is
|
|
21
|
+
* selected, from the row around it, and `lb-request` commits the choice on
|
|
22
|
+
* `change`. A value can arrive before the options it names, so the widget
|
|
23
|
+
* keeps the value it was last given and selects it again whenever rows land.
|
|
22
24
|
*
|
|
23
25
|
* Exported because `lb-picker` is this widget with its row template
|
|
24
26
|
* supplied by the definition instead of by the page. Nothing about the
|
|
@@ -26,15 +28,30 @@ import { ATTR_ACTION, ATTR_KEY_VALUE, ATTR_QUERY_PARM, ATTR_VALUE, LB_EVENT_NAME
|
|
|
26
28
|
*/
|
|
27
29
|
/** Named on the row template: the column whose distinct values become groups. */
|
|
28
30
|
const GROUP_COLUMN = "data-group";
|
|
29
|
-
export class LbOptions extends
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
export class LbOptions extends WrappedControl {
|
|
32
|
+
inner = "select";
|
|
33
|
+
/**
|
|
34
|
+
* The value last set or chosen, which the options may not include yet.
|
|
35
|
+
* Null when nothing chose one, so the select's own default stands.
|
|
36
|
+
*/
|
|
37
|
+
chosen = null;
|
|
38
|
+
get value() {
|
|
39
|
+
return this.chosen ?? super.value;
|
|
40
|
+
}
|
|
41
|
+
set value(value) {
|
|
42
|
+
this.chosen = value === null || value === undefined ? null : String(value);
|
|
43
|
+
super.value = value;
|
|
44
|
+
}
|
|
45
|
+
formResetCallback() {
|
|
46
|
+
this.chosen = null;
|
|
47
|
+
super.formResetCallback();
|
|
48
|
+
}
|
|
49
|
+
changed() {
|
|
50
|
+
this.chosen = this.control?.value ?? null;
|
|
51
|
+
super.changed();
|
|
35
52
|
}
|
|
36
53
|
/**
|
|
37
|
-
* The hub reconciles the
|
|
54
|
+
* The hub reconciles the rows and calls this for placement only, so this
|
|
38
55
|
* widget carries no copy of what a row is or when one arrives.
|
|
39
56
|
*/
|
|
40
57
|
lbPlaceRow(el, row, template) {
|
|
@@ -49,7 +66,7 @@ export class LbOptions extends HTMLElement {
|
|
|
49
66
|
/** Everything derived from the rows, once the whole result has landed. */
|
|
50
67
|
lbRowsLanded() {
|
|
51
68
|
// The identity of the row is the value of the option, so nothing on the
|
|
52
|
-
// page has to say so
|
|
69
|
+
// page has to say so.
|
|
53
70
|
for (const option of this.querySelectorAll(`option[${ATTR_KEY_VALUE}]`)) {
|
|
54
71
|
option.setAttribute("value", option.getAttribute(ATTR_KEY_VALUE));
|
|
55
72
|
}
|
|
@@ -58,10 +75,11 @@ export class LbOptions extends HTMLElement {
|
|
|
58
75
|
if (!group.querySelector("option"))
|
|
59
76
|
group.remove();
|
|
60
77
|
}
|
|
61
|
-
// A value that
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
64
|
-
|
|
78
|
+
// A value that arrived before its option selects it now.
|
|
79
|
+
const select = this.querySelector("select");
|
|
80
|
+
if (select && this.chosen !== null)
|
|
81
|
+
select.value = this.chosen;
|
|
82
|
+
this.formValue();
|
|
65
83
|
}
|
|
66
84
|
/** The group with this label, or a new one in front of the template. */
|
|
67
85
|
groupFor(select, template, label) {
|
|
@@ -74,25 +92,6 @@ export class LbOptions extends HTMLElement {
|
|
|
74
92
|
select.insertBefore(group, template);
|
|
75
93
|
return group;
|
|
76
94
|
}
|
|
77
|
-
connectedCallback() {
|
|
78
|
-
this.addEventListener("change", () => {
|
|
79
|
-
const select = this.querySelector("select");
|
|
80
|
-
if (!select) {
|
|
81
|
-
console.error(`lb-options: change with no <select>, ignoring`);
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const name = this.getAttribute(ATTR_ACTION);
|
|
85
|
-
if (!name && this.hasAttribute(ATTR_QUERY_PARM))
|
|
86
|
-
return;
|
|
87
|
-
if (!name) {
|
|
88
|
-
console.error(`lb-options: no ${ATTR_ACTION}, nothing to send`);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
// The hub scopes it, so a choice inside a row says which row.
|
|
92
|
-
const detail = { action: name, value: select.value };
|
|
93
|
-
this.dispatchEvent(new CustomEvent(LB_EVENT_NAME, { bubbles: true, detail }));
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
95
|
}
|
|
97
96
|
customElements.define("lb-options", LbOptions);
|
|
98
97
|
//# sourceMappingURL=lb-options.browser.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lb-options.browser.js","sourceRoot":"","sources":["../widgets/lb-options.browser.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAE3B,OAAO,
|
|
1
|
+
{"version":3,"file":"lb-options.browser.js","sourceRoot":"","sources":["../widgets/lb-options.browser.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"dom\" />\n\nimport { ATTR_KEY_VALUE } from \"@loadbare/app/constants\";\nimport type { Row, RowsHost } from \"@loadbare/app/types\";\n\nimport { WrappedControl } from \"./control.js\";\n\n/**\n * A `<select>` whose choices are the rows of a query, and the case that\n * shows why placement belongs to the widget rather than to the framework.\n *\n * The rows arrive flat and keyed. Nothing on the wire knows about\n * `<optgroup>`, and nothing needs to: a group is a column like any other, and\n * turning a repeated column value into an element is exactly the local\n * knowledge a widget has and the hub does not. So the attribute that names\n * the column is this widget's own, in HTML's `data-` namespace rather than\n * the hub's: the hub never reads it, and `lb-` is reserved for what the hub\n * does read.\n *\n * The identity of a row is the value of the option, so the `lb-key-value`\n * the hub stamps on each option is copied to its `value`. The server declares\n * the key, and the page never names it.\n *\n * It is a control like `lb-select`: `lb-column` sets which option is\n * selected, from the row around it, and `lb-request` commits the choice on\n * `change`. A value can arrive before the options it names, so the widget\n * keeps the value it was last given and selects it again whenever rows land.\n *\n * Exported because `lb-picker` is this widget with its row template\n * supplied by the definition instead of by the page. Nothing about the\n * behavior changes, so nothing about the behavior is written twice.\n */\n/** Named on the row template: the column whose distinct values become groups. */\nconst GROUP_COLUMN = \"data-group\";\n\nexport class LbOptions extends WrappedControl implements RowsHost {\n protected readonly inner = \"select\";\n\n /**\n * The value last set or chosen, which the options may not include yet.\n * Null when nothing chose one, so the select's own default stands.\n */\n private chosen: string | null = null;\n\n get value(): string {\n return this.chosen ?? super.value;\n }\n\n set value(value: string) {\n this.chosen = value === null || value === undefined ? null : String(value);\n super.value = value;\n }\n\n formResetCallback(): void {\n this.chosen = null;\n super.formResetCallback();\n }\n\n protected changed(): void {\n this.chosen = this.control?.value ?? null;\n super.changed();\n }\n\n /**\n * The hub reconciles the rows and calls this for placement only, so this\n * widget carries no copy of what a row is or when one arrives.\n */\n lbPlaceRow(el: Element, row: Row, template: HTMLTemplateElement): void {\n const select = this.querySelector(\"select\")!;\n const groupColumn = template.getAttribute(GROUP_COLUMN);\n if (!groupColumn) {\n select.insertBefore(el, template);\n return;\n }\n this.groupFor(select, template, String(row[groupColumn] ?? \"\")).append(el);\n }\n\n /** Everything derived from the rows, once the whole result has landed. */\n lbRowsLanded(): void {\n // The identity of the row is the value of the option, so nothing on the\n // page has to say so.\n for (const option of this.querySelectorAll(`option[${ATTR_KEY_VALUE}]`)) {\n option.setAttribute(\"value\", option.getAttribute(ATTR_KEY_VALUE)!);\n }\n // A group is derived, so it goes when its last row does.\n for (const group of this.querySelectorAll(\"optgroup\")) {\n if (!group.querySelector(\"option\")) group.remove();\n }\n // A value that arrived before its option selects it now.\n const select = this.querySelector(\"select\");\n if (select && this.chosen !== null) select.value = this.chosen;\n this.formValue();\n }\n\n /** The group with this label, or a new one in front of the template. */\n private groupFor(select: Element, template: Element, label: string): Element {\n for (const group of select.querySelectorAll(\"optgroup\")) {\n if (group.label === label) return group;\n }\n const group = document.createElement(\"optgroup\");\n group.label = label;\n select.insertBefore(group, template);\n return group;\n }\n}\n\ncustomElements.define(\"lb-options\", LbOptions);\n"]}
|
package/dist/lb-options.html
CHANGED
|
@@ -6,9 +6,10 @@ import { LbOptions } from "./lb-options.browser.js";
|
|
|
6
6
|
*
|
|
7
7
|
* A row template is markup, so writing it is the page author's job — until
|
|
8
8
|
* every row is one option and the only thing that varies is which columns it
|
|
9
|
-
* reads. Those are words, and words are parameters: `exp-
|
|
9
|
+
* reads. Those are words, and words are parameters: `exp-column` and
|
|
10
10
|
* `exp-group` fill the placeholders in the template the definition already
|
|
11
|
-
* has, at build time, and the page writes one tag with no children.
|
|
11
|
+
* has, at build time, and the page writes one tag with no children. The key
|
|
12
|
+
* is the server's, declared with the query, so the page names none.
|
|
12
13
|
*
|
|
13
14
|
* It is the same trade as anywhere else in expansion. A page author who wants
|
|
14
15
|
* a second element in the row, or an option built from two columns, writes
|
|
@@ -16,9 +17,9 @@ import { LbOptions } from "./lb-options.browser.js";
|
|
|
16
17
|
* not.
|
|
17
18
|
*
|
|
18
19
|
* The behavior is inherited whole, because it is the same behavior: rows land
|
|
19
|
-
* in groups, the key becomes the value, and
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* in groups, the key becomes the value, and the widget is a control. A
|
|
21
|
+
* distinct class exists only because `customElements.define` requires one
|
|
22
|
+
* constructor per name.
|
|
22
23
|
*/
|
|
23
24
|
class LbPicker extends LbOptions {
|
|
24
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lb-picker.browser.js","sourceRoot":"","sources":["../widgets/lb-picker.browser.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAE3B,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD
|
|
1
|
+
{"version":3,"file":"lb-picker.browser.js","sourceRoot":"","sources":["../widgets/lb-picker.browser.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAE3B,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,QAAS,SAAQ,SAAS;CAAG;AAEnC,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC","sourcesContent":["/// <reference lib=\"dom\" />\n\nimport { LbOptions } from \"./lb-options.browser.js\";\n\n/**\n * The same `<select>` as `lb-options`, with the row template supplied by\n * the definition instead of by the page.\n *\n * A row template is markup, so writing it is the page author's job — until\n * every row is one option and the only thing that varies is which columns it\n * reads. Those are words, and words are parameters: `exp-column` and\n * `exp-group` fill the placeholders in the template the definition already\n * has, at build time, and the page writes one tag with no children. The key\n * is the server's, declared with the query, so the page names none.\n *\n * It is the same trade as anywhere else in expansion. A page author who wants\n * a second element in the row, or an option built from two columns, writes\n * `lb-options` and the template themselves. This one is for when they do\n * not.\n *\n * The behavior is inherited whole, because it is the same behavior: rows land\n * in groups, the key becomes the value, and the widget is a control. A\n * distinct class exists only because `customElements.define` requires one\n * constructor per name.\n */\nclass LbPicker extends LbOptions {}\n\ncustomElements.define(\"lb-picker\", LbPicker);\n"]}
|
package/dist/lb-picker.html
CHANGED
|
@@ -1,46 +1,17 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
|
-
import {
|
|
2
|
+
import { WrappedControl } from "./control.js";
|
|
3
3
|
/**
|
|
4
|
-
* A
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* one widget.
|
|
4
|
+
* A control wrapping a `<select>` whose options the page writes. The hub
|
|
5
|
+
* sets its `value` from the column its `lb-column` names, and gathers it back
|
|
6
|
+
* under the same name.
|
|
8
7
|
*
|
|
9
|
-
* The choice is the interaction, so this is the
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* off the bubbling `change` and puts it in the address bar.
|
|
8
|
+
* The choice is the interaction, so this is the control that most often
|
|
9
|
+
* carries `lb-request`: it commits on `change`, and the hub sends that request
|
|
10
|
+
* with this select's column alone. The server still decides what the choice
|
|
11
|
+
* means.
|
|
14
12
|
*/
|
|
15
|
-
class LbSelect extends
|
|
16
|
-
|
|
17
|
-
attributeChangedCallback(_name, _old, value) {
|
|
18
|
-
const select = this.querySelector("select");
|
|
19
|
-
if (!select) {
|
|
20
|
-
console.error(`lb-select: no <select> to receive the value`);
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
select.value = value;
|
|
24
|
-
}
|
|
25
|
-
connectedCallback() {
|
|
26
|
-
this.addEventListener("change", () => {
|
|
27
|
-
const select = this.querySelector("select");
|
|
28
|
-
if (!select) {
|
|
29
|
-
console.error(`lb-select: change with no <select>, ignoring`);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
const name = this.getAttribute(ATTR_ACTION);
|
|
33
|
-
if (!name && this.hasAttribute(ATTR_QUERY_PARM))
|
|
34
|
-
return;
|
|
35
|
-
if (!name) {
|
|
36
|
-
console.error(`lb-select: no ${ATTR_ACTION}, nothing to send`);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
// The hub scopes it, so a choice inside a row says which row.
|
|
40
|
-
const detail = { action: name, value: select.value };
|
|
41
|
-
this.dispatchEvent(new CustomEvent(LB_EVENT_NAME, { bubbles: true, detail }));
|
|
42
|
-
});
|
|
43
|
-
}
|
|
13
|
+
class LbSelect extends WrappedControl {
|
|
14
|
+
inner = "select";
|
|
44
15
|
}
|
|
45
16
|
customElements.define("lb-select", LbSelect);
|
|
46
17
|
//# sourceMappingURL=lb-select.browser.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lb-select.browser.js","sourceRoot":"","sources":["../widgets/lb-select.browser.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAE3B,OAAO,
|
|
1
|
+
{"version":3,"file":"lb-select.browser.js","sourceRoot":"","sources":["../widgets/lb-select.browser.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAE3B,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;;;;;GASG;AACH,MAAM,QAAS,SAAQ,cAAc;IAChB,KAAK,GAAG,QAAQ,CAAC;CACrC;AAED,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC","sourcesContent":["/// <reference lib=\"dom\" />\n\nimport { WrappedControl } from \"./control.js\";\n\n/**\n * A control wrapping a `<select>` whose options the page writes. The hub\n * sets its `value` from the column its `lb-column` names, and gathers it back\n * under the same name.\n *\n * The choice is the interaction, so this is the control that most often\n * carries `lb-request`: it commits on `change`, and the hub sends that request\n * with this select's column alone. The server still decides what the choice\n * means.\n */\nclass LbSelect extends WrappedControl {\n protected readonly inner = \"select\";\n}\n\ncustomElements.define(\"lb-select\", LbSelect);\n"]}
|
package/dist/lb-select.html
CHANGED