@texaryn/web-components 0.0.0 → 0.2.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/LICENSE +190 -0
  3. package/README.md +111 -0
  4. package/dist/binding.d.ts +9 -0
  5. package/dist/binding.d.ts.map +1 -0
  6. package/dist/binding.js +38 -0
  7. package/dist/binding.js.map +1 -0
  8. package/dist/containers.d.ts +11 -0
  9. package/dist/containers.d.ts.map +1 -0
  10. package/dist/containers.js +243 -0
  11. package/dist/containers.js.map +1 -0
  12. package/dist/define.d.ts +3 -0
  13. package/dist/define.d.ts.map +1 -0
  14. package/dist/define.js +11 -0
  15. package/dist/define.js.map +1 -0
  16. package/dist/element.d.ts +26 -0
  17. package/dist/element.d.ts.map +1 -0
  18. package/dist/element.js +140 -0
  19. package/dist/element.js.map +1 -0
  20. package/dist/field-state.d.ts +18 -0
  21. package/dist/field-state.d.ts.map +1 -0
  22. package/dist/field-state.js +51 -0
  23. package/dist/field-state.js.map +1 -0
  24. package/dist/fields.d.ts +8 -0
  25. package/dist/fields.d.ts.map +1 -0
  26. package/dist/fields.js +168 -0
  27. package/dist/fields.js.map +1 -0
  28. package/dist/ids.d.ts +4 -0
  29. package/dist/ids.d.ts.map +1 -0
  30. package/dist/ids.js +10 -0
  31. package/dist/ids.js.map +1 -0
  32. package/dist/index.d.ts +10 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +7 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/mount.d.ts +12 -0
  37. package/dist/mount.d.ts.map +1 -0
  38. package/dist/mount.js +39 -0
  39. package/dist/mount.js.map +1 -0
  40. package/dist/registry.d.ts +9 -0
  41. package/dist/registry.d.ts.map +1 -0
  42. package/dist/registry.js +23 -0
  43. package/dist/registry.js.map +1 -0
  44. package/dist/widget.d.ts +24 -0
  45. package/dist/widget.d.ts.map +1 -0
  46. package/dist/widget.js +2 -0
  47. package/dist/widget.js.map +1 -0
  48. package/package.json +44 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAEA,qGAAqG;AACrG,wBAAgB,iBAAiB,CAAC,OAAO,SAAiB,GAAG,wBAAwB,CAMpF"}
package/dist/define.js ADDED
@@ -0,0 +1,11 @@
1
+ import { texarynFormElementClass } from './element.js';
2
+ /** Registers the element once; a second call for the same tag returns what is already registered. */
3
+ export function defineTexarynForm(tagName = 'texaryn-form') {
4
+ const existing = customElements.get(tagName);
5
+ if (existing)
6
+ return existing;
7
+ const constructor = texarynFormElementClass();
8
+ customElements.define(tagName, constructor);
9
+ return constructor;
10
+ }
11
+ //# sourceMappingURL=define.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAEtD,qGAAqG;AACrG,MAAM,UAAU,iBAAiB,CAAC,OAAO,GAAG,cAAc;IACxD,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC5C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC7B,MAAM,WAAW,GAAG,uBAAuB,EAAE,CAAA;IAC7C,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;IAC3C,OAAO,WAAW,CAAA;AACpB,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { FormRuntime, FormRuntimeOptions, RendererRegistry, SchemaEvaluationPort } from '@texaryn/core';
2
+ import type { WidgetFactory } from './widget.js';
3
+ /**
4
+ * `runtime` is the primitive input: an external runtime the element renders
5
+ * and never destroys. `port` plus `options` is the managed mode, where the
6
+ * element creates a runtime of its own and destroys it on removal. The two
7
+ * sources are mutually exclusive.
8
+ */
9
+ export interface TexarynFormElement extends HTMLElement {
10
+ /** Borrowed: assigned from outside, rendered, and never destroyed by the element. */
11
+ runtime: FormRuntime | null;
12
+ /** Managed: the element builds a runtime from this and destroys it on removal. */
13
+ port: SchemaEvaluationPort | null;
14
+ /** Read when the managed runtime is created, so set it before `port`. */
15
+ options: FormRuntimeOptions;
16
+ registry: RendererRegistry<WidgetFactory> | null;
17
+ readonly idPrefix: string;
18
+ }
19
+ /**
20
+ * Builds the class on first use rather than at module load. It extends
21
+ * `HTMLElement`, which does not exist outside a browser, and a package that
22
+ * throws on import cannot be loaded by a server rendered application or by any
23
+ * tool that merely resolves it.
24
+ */
25
+ export declare function texarynFormElementClass(): CustomElementConstructor;
26
+ //# sourceMappingURL=element.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element.d.ts","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,eAAe,CAAA;AAItB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD;;;;;GAKG;AACH,MAAM,WAAW,kBAAmB,SAAQ,WAAW;IACrD,qFAAqF;IACrF,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;IAC3B,kFAAkF;IAClF,IAAI,EAAE,oBAAoB,GAAG,IAAI,CAAA;IACjC,yEAAyE;IACzE,OAAO,EAAE,kBAAkB,CAAA;IAC3B,QAAQ,EAAE,gBAAgB,CAAC,aAAa,CAAC,GAAG,IAAI,CAAA;IAChD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAID;;;;;GAKG;AACH,wBAAgB,uBAAuB,IAAI,wBAAwB,CA8IlE"}
@@ -0,0 +1,140 @@
1
+ import { createFormRuntime } from '@texaryn/core';
2
+ import { nextInstancePrefix } from './ids.js';
3
+ import { mountForm } from './mount.js';
4
+ let elementClass = null;
5
+ /**
6
+ * Builds the class on first use rather than at module load. It extends
7
+ * `HTMLElement`, which does not exist outside a browser, and a package that
8
+ * throws on import cannot be loaded by a server rendered application or by any
9
+ * tool that merely resolves it.
10
+ */
11
+ export function texarynFormElementClass() {
12
+ if (elementClass)
13
+ return elementClass;
14
+ class TexarynForm extends HTMLElement {
15
+ #external = null;
16
+ #owned = null;
17
+ #port = null;
18
+ #options = {};
19
+ #registry = null;
20
+ #form = null;
21
+ #mount = null;
22
+ #mountedRuntime = null;
23
+ #mountedRegistry = null;
24
+ #unsubscribe = [];
25
+ #prefix = null;
26
+ /** The element's own id when it has one on first use, else an allocated `texaryn-<n>`; fixed for the element's lifetime. */
27
+ get idPrefix() {
28
+ this.#prefix ??= this.id || nextInstancePrefix();
29
+ return this.#prefix;
30
+ }
31
+ get runtime() {
32
+ return this.#external ?? this.#owned;
33
+ }
34
+ set runtime(runtime) {
35
+ if (runtime && this.#port) {
36
+ throw new Error('<texaryn-form>: runtime and port are mutually exclusive; clear port first');
37
+ }
38
+ this.#external = runtime;
39
+ this.#render();
40
+ }
41
+ get port() {
42
+ return this.#port;
43
+ }
44
+ set port(port) {
45
+ if (port && this.#external) {
46
+ throw new Error('<texaryn-form>: runtime and port are mutually exclusive; clear runtime first');
47
+ }
48
+ if (this.#owned) {
49
+ this.#unmount();
50
+ this.#owned.destroy();
51
+ this.#owned = null;
52
+ }
53
+ this.#port = port;
54
+ this.#render();
55
+ }
56
+ get options() {
57
+ return this.#options;
58
+ }
59
+ /** Read when the managed runtime is created; setting it afterwards changes nothing until `port` is set again. */
60
+ set options(options) {
61
+ this.#options = options ?? {};
62
+ }
63
+ get registry() {
64
+ return this.#registry;
65
+ }
66
+ set registry(registry) {
67
+ this.#registry = registry;
68
+ this.#render();
69
+ }
70
+ connectedCallback() {
71
+ this.#render();
72
+ }
73
+ disconnectedCallback() {
74
+ // A reparent fires disconnected then connected in the same task. Only an
75
+ // element still detached afterwards was removed.
76
+ queueMicrotask(() => {
77
+ if (!this.isConnected)
78
+ this.#dispose();
79
+ });
80
+ }
81
+ #render() {
82
+ if (!this.isConnected)
83
+ return;
84
+ if (!this.#owned && this.#port && !this.#external) {
85
+ this.#owned = createFormRuntime(this.#port, this.#options);
86
+ }
87
+ const runtime = this.runtime;
88
+ if (!runtime || !this.#registry)
89
+ return;
90
+ if (this.#mount && this.#mountedRuntime === runtime && this.#mountedRegistry === this.#registry) {
91
+ return;
92
+ }
93
+ this.#unmount();
94
+ const form = this.#ensureForm();
95
+ this.#mount = mountForm(form, runtime, this.#registry, this.idPrefix);
96
+ this.#mountedRuntime = runtime;
97
+ this.#mountedRegistry = this.#registry;
98
+ this.#unsubscribe.push(runtime.data.subscribe(() => {
99
+ this.dispatchEvent(new CustomEvent('texaryn-data-change', { detail: runtime.data.getSnapshot(), bubbles: true }));
100
+ }), runtime.submission.subscribe(() => {
101
+ this.dispatchEvent(new CustomEvent('texaryn-submission-change', {
102
+ detail: runtime.submission.getSnapshot(),
103
+ bubbles: true,
104
+ }));
105
+ }));
106
+ }
107
+ #ensureForm() {
108
+ if (this.#form)
109
+ return this.#form;
110
+ const form = document.createElement('form');
111
+ form.noValidate = true;
112
+ form.addEventListener('submit', (event) => {
113
+ event.preventDefault();
114
+ this.runtime?.dispatch({ type: 'Submit' });
115
+ });
116
+ this.append(form);
117
+ this.#form = form;
118
+ return form;
119
+ }
120
+ #unmount() {
121
+ for (const off of this.#unsubscribe)
122
+ off();
123
+ this.#unsubscribe = [];
124
+ this.#mount?.unmount();
125
+ this.#mount = null;
126
+ this.#mountedRuntime = null;
127
+ this.#mountedRegistry = null;
128
+ }
129
+ #dispose() {
130
+ this.#unmount();
131
+ if (this.#owned) {
132
+ this.#owned.destroy();
133
+ this.#owned = null;
134
+ }
135
+ }
136
+ }
137
+ elementClass = TexarynForm;
138
+ return elementClass;
139
+ }
140
+ //# sourceMappingURL=element.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element.js","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { FormRuntime, UINode, ValidationError } from '@texaryn/core';
2
+ /**
3
+ * Subscriptions for one field, re-pointable at another node. `getNodeState`
4
+ * is a map lookup and the runtime replaces a node's bundle when its id leaves
5
+ * the document and returns, so every update re-resolves and compares the
6
+ * bundle rather than trusting the id.
7
+ */
8
+ export declare class FieldState {
9
+ #private;
10
+ constructor(runtime: FormRuntime, node: UINode, onChange: () => void);
11
+ rebind(node: UINode): void;
12
+ get value(): unknown;
13
+ get errors(): ValidationError[];
14
+ get showErrors(): boolean;
15
+ get disabled(): boolean;
16
+ destroy(): void;
17
+ }
18
+ //# sourceMappingURL=field-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-state.d.ts","sourceRoot":"","sources":["../src/field-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAa,MAAM,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAEpF;;;;;GAKG;AACH,qBAAa,UAAU;;gBAMT,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI;IAMpE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAW1B,IAAI,KAAK,IAAI,OAAO,CAEnB;IACD,IAAI,MAAM,IAAI,eAAe,EAAE,CAE9B;IACD,IAAI,UAAU,IAAI,OAAO,CAExB;IACD,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAOD,OAAO,IAAI,IAAI;CAIhB"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Subscriptions for one field, re-pointable at another node. `getNodeState`
3
+ * is a map lookup and the runtime replaces a node's bundle when its id leaves
4
+ * the document and returns, so every update re-resolves and compares the
5
+ * bundle rather than trusting the id.
6
+ */
7
+ export class FieldState {
8
+ #runtime;
9
+ #bundle;
10
+ #unsubscribe = [];
11
+ #onChange;
12
+ constructor(runtime, node, onChange) {
13
+ this.#runtime = runtime;
14
+ this.#onChange = onChange;
15
+ this.rebind(node);
16
+ }
17
+ rebind(node) {
18
+ const bundle = this.#runtime.getNodeState(node.id);
19
+ if (bundle === this.#bundle)
20
+ return;
21
+ this.#release();
22
+ this.#bundle = bundle;
23
+ if (!bundle)
24
+ return;
25
+ for (const store of [bundle.value, bundle.errors, bundle.showErrors, bundle.disabled]) {
26
+ this.#unsubscribe.push(store.subscribe(this.#onChange));
27
+ }
28
+ }
29
+ get value() {
30
+ return this.#bundle?.value.getSnapshot();
31
+ }
32
+ get errors() {
33
+ return this.#bundle?.errors.getSnapshot() ?? [];
34
+ }
35
+ get showErrors() {
36
+ return this.#bundle?.showErrors.getSnapshot() ?? false;
37
+ }
38
+ get disabled() {
39
+ return this.#bundle?.disabled.getSnapshot() ?? false;
40
+ }
41
+ #release() {
42
+ for (const off of this.#unsubscribe)
43
+ off();
44
+ this.#unsubscribe = [];
45
+ }
46
+ destroy() {
47
+ this.#release();
48
+ this.#bundle = undefined;
49
+ }
50
+ }
51
+ //# sourceMappingURL=field-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-state.js","sourceRoot":"","sources":["../src/field-state.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,UAAU;IACrB,QAAQ,CAAa;IACrB,OAAO,CAAuB;IAC9B,YAAY,GAAsB,EAAE,CAAA;IACpC,SAAS,CAAY;IAErB,YAAY,OAAoB,EAAE,IAAY,EAAE,QAAoB;QAClE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAA;QACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACnB,CAAC;IAED,MAAM,CAAC,IAAY;QACjB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAClD,IAAI,MAAM,KAAK,IAAI,CAAC,OAAO;YAAE,OAAM;QACnC,IAAI,CAAC,QAAQ,EAAE,CAAA;QACf,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,KAAK,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtF,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAA;QACzD,CAAC;IACH,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,WAAW,EAAE,CAAA;IAC1C,CAAC;IACD,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,CAAA;IACjD,CAAC;IACD,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,WAAW,EAAE,IAAI,KAAK,CAAA;IACxD,CAAC;IACD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,KAAK,CAAA;IACtD,CAAC;IAED,QAAQ;QACN,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,YAAY;YAAE,GAAG,EAAE,CAAA;QAC1C,IAAI,CAAC,YAAY,GAAG,EAAE,CAAA;IACxB,CAAC;IAED,OAAO;QACL,IAAI,CAAC,QAAQ,EAAE,CAAA;QACf,IAAI,CAAC,OAAO,GAAG,SAAS,CAAA;IAC1B,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ import type { UINode } from '@texaryn/core';
2
+ import type { DomWidget, RenderContext } from './widget.js';
3
+ export declare const textInput: (node: UINode, ctx: RenderContext) => DomWidget;
4
+ export declare const numberInput: (node: UINode, ctx: RenderContext) => DomWidget;
5
+ export declare const checkbox: (node: UINode, ctx: RenderContext) => DomWidget;
6
+ export declare const select: (node: UINode, ctx: RenderContext) => DomWidget;
7
+ export declare const textarea: (node: UINode, ctx: RenderContext) => DomWidget;
8
+ //# sourceMappingURL=fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,MAAM,EAAE,MAAM,eAAe,CAAA;AAGtD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAwK3D,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,EAAE,KAAK,aAAa,KAAG,SAA6C,CAAA;AAC1G,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,EAAE,KAAK,aAAa,KAAG,SAA6C,CAAA;AAC5G,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,EAAE,KAAK,aAAa,KAAG,SAA8C,CAAA;AAC1G,eAAO,MAAM,MAAM,GAAI,MAAM,MAAM,EAAE,KAAK,aAAa,KAAG,SAA2C,CAAA;AACrG,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,EAAE,KAAK,aAAa,KAAG,SAA+C,CAAA"}
package/dist/fields.js ADDED
@@ -0,0 +1,168 @@
1
+ import { FieldState } from './field-state.js';
2
+ import { makeId } from './ids.js';
3
+ /** Mirrors the Vue binding's coerce so both renderers write the same data for the same keystrokes. */
4
+ function coerce(kind, node, raw) {
5
+ if (kind === 'number')
6
+ return raw === '' ? undefined : Number(raw);
7
+ if (kind === 'enum') {
8
+ const option = (node.enumValues ?? []).find((o) => String(o.value) === raw);
9
+ return option ? option.value : raw;
10
+ }
11
+ return raw;
12
+ }
13
+ function display(value) {
14
+ return value == null ? '' : String(value);
15
+ }
16
+ /** HTML honours `readonly` on text-like controls only; the rest need ARIA. */
17
+ function hasNativeReadOnly(kind) {
18
+ return kind === 'string' || kind === 'number' || kind === 'textarea';
19
+ }
20
+ function createControl(kind) {
21
+ if (kind === 'enum')
22
+ return document.createElement('select');
23
+ if (kind === 'textarea')
24
+ return document.createElement('textarea');
25
+ const input = document.createElement('input');
26
+ input.type = kind === 'boolean' ? 'checkbox' : kind === 'number' ? 'number' : 'text';
27
+ return input;
28
+ }
29
+ /**
30
+ * Label, control, description and error block for one field, on native
31
+ * elements. Ids carry the instance prefix and the node id; both are rewritten
32
+ * on update because a moved row keeps this widget and changes its node.
33
+ */
34
+ function fieldWidget(kind, initial, ctx) {
35
+ let node = initial;
36
+ const root = document.createElement('div');
37
+ root.className = 'texaryn-field';
38
+ const label = document.createElement('label');
39
+ const control = createControl(kind);
40
+ const description = document.createElement('div');
41
+ const errors = document.createElement('div');
42
+ // Set once and never toggled. Hiding the region while empty took it out of
43
+ // the accessibility tree, so unhiding it with content already in place was
44
+ // the same defect as inserting it populated. Polite rather than alert
45
+ // because validation runs on change, blur and submit.
46
+ errors.setAttribute('aria-live', 'polite');
47
+ errors.setAttribute('aria-atomic', 'true');
48
+ root.append(label, control, description, errors);
49
+ const state = new FieldState(ctx.runtime, node, () => render());
50
+ const commit = () => {
51
+ // Read the node at event time, never captured: a stale id after a move
52
+ // would write into the row that took this one's place.
53
+ if (node.readOnly) {
54
+ // The runtime refuses the write anyway. Re-rendering puts the control
55
+ // back, which native readonly does for a text field but not for a
56
+ // select or a checkbox the user just toggled.
57
+ render();
58
+ return;
59
+ }
60
+ const value = control instanceof HTMLInputElement && kind === 'boolean'
61
+ ? control.checked
62
+ : coerce(kind, node, control.value);
63
+ ctx.runtime.dispatch({ type: 'SetValue', nodeId: node.id, value });
64
+ };
65
+ control.addEventListener(kind === 'boolean' || kind === 'enum' ? 'change' : 'input', commit);
66
+ control.addEventListener('blur', () => {
67
+ ctx.runtime.dispatch({ type: 'SetTouched', nodeId: node.id });
68
+ });
69
+ function renderIds() {
70
+ const inputId = makeId(ctx.idPrefix, node.id, 'input');
71
+ control.id = inputId;
72
+ control.name = node.dataPointer || node.id;
73
+ label.htmlFor = inputId;
74
+ label.id = makeId(ctx.idPrefix, node.id, 'label');
75
+ description.id = makeId(ctx.idPrefix, node.id, 'description');
76
+ errors.id = makeId(ctx.idPrefix, node.id, 'error');
77
+ }
78
+ function renderOptions() {
79
+ if (!(control instanceof HTMLSelectElement))
80
+ return;
81
+ const wanted = [{ value: '', title: '' }].concat((node.enumValues ?? []).map((o) => ({ value: String(o.value), title: o.title ?? String(o.value) })));
82
+ const current = Array.from(control.options).map((o) => o.value);
83
+ if (wanted.map((w) => w.value).join(' ') === current.join(' '))
84
+ return;
85
+ control.replaceChildren(...wanted.map((w) => {
86
+ const option = document.createElement('option');
87
+ option.value = w.value;
88
+ option.textContent = w.title;
89
+ return option;
90
+ }));
91
+ }
92
+ function render() {
93
+ label.textContent = node.annotations.title ?? node.dataPointer ?? node.id;
94
+ renderOptions();
95
+ const value = state.value;
96
+ if (control instanceof HTMLInputElement && kind === 'boolean') {
97
+ control.checked = value === true;
98
+ }
99
+ else {
100
+ // Only write when the DOM disagrees: writing an equal value moves the
101
+ // caret in real browsers, and the DOM already holds what was typed.
102
+ const text = display(value);
103
+ if (control.value !== text)
104
+ control.value = text;
105
+ }
106
+ control.disabled = state.disabled;
107
+ // A control HTML has no readonly for can only say so through ARIA, and is
108
+ // put back by commit above.
109
+ if (hasNativeReadOnly(kind)) {
110
+ ;
111
+ control.readOnly = node.readOnly;
112
+ }
113
+ else if (node.readOnly) {
114
+ control.setAttribute('aria-readonly', 'true');
115
+ }
116
+ else {
117
+ control.removeAttribute('aria-readonly');
118
+ }
119
+ if (node.placeholder && !(control instanceof HTMLSelectElement))
120
+ control.placeholder = node.placeholder;
121
+ if (node.constraints.required)
122
+ control.setAttribute('aria-required', 'true');
123
+ else
124
+ control.removeAttribute('aria-required');
125
+ const helpText = node.helpText ?? node.annotations.description;
126
+ description.textContent = helpText ?? '';
127
+ description.hidden = !helpText;
128
+ const visibleErrors = state.showErrors ? state.errors : [];
129
+ errors.replaceChildren(...visibleErrors.map((error) => {
130
+ const line = document.createElement('div');
131
+ line.textContent = error.message ?? error.keyword;
132
+ return line;
133
+ }));
134
+ const describedBy = [];
135
+ if (helpText)
136
+ describedBy.push(description.id);
137
+ if (visibleErrors.length > 0)
138
+ describedBy.push(errors.id);
139
+ if (describedBy.length > 0)
140
+ control.setAttribute('aria-describedby', describedBy.join(' '));
141
+ else
142
+ control.removeAttribute('aria-describedby');
143
+ if (visibleErrors.length > 0)
144
+ control.setAttribute('aria-invalid', 'true');
145
+ else
146
+ control.removeAttribute('aria-invalid');
147
+ }
148
+ renderIds();
149
+ render();
150
+ return {
151
+ element: root,
152
+ update(next) {
153
+ node = next;
154
+ renderIds();
155
+ state.rebind(node);
156
+ render();
157
+ },
158
+ destroy() {
159
+ state.destroy();
160
+ },
161
+ };
162
+ }
163
+ export const textInput = (node, ctx) => fieldWidget('string', node, ctx);
164
+ export const numberInput = (node, ctx) => fieldWidget('number', node, ctx);
165
+ export const checkbox = (node, ctx) => fieldWidget('boolean', node, ctx);
166
+ export const select = (node, ctx) => fieldWidget('enum', node, ctx);
167
+ export const textarea = (node, ctx) => fieldWidget('textarea', node, ctx);
168
+ //# sourceMappingURL=fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fields.js","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":"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"}
package/dist/ids.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ /** One prefix per element instance, so two forms on a page never share an id. */
2
+ export declare function nextInstancePrefix(): string;
3
+ export declare function makeId(prefix: string, nodeId: string, suffix: string): string;
4
+ //# sourceMappingURL=ids.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAEA,iFAAiF;AACjF,wBAAgB,kBAAkB,IAAI,MAAM,CAG3C;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE7E"}
package/dist/ids.js ADDED
@@ -0,0 +1,10 @@
1
+ let instanceCounter = 0;
2
+ /** One prefix per element instance, so two forms on a page never share an id. */
3
+ export function nextInstancePrefix() {
4
+ instanceCounter += 1;
5
+ return `texaryn-${instanceCounter}`;
6
+ }
7
+ export function makeId(prefix, nodeId, suffix) {
8
+ return `${prefix}-${nodeId}-${suffix}`;
9
+ }
10
+ //# sourceMappingURL=ids.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.js","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,IAAI,eAAe,GAAG,CAAC,CAAA;AAEvB,iFAAiF;AACjF,MAAM,UAAU,kBAAkB;IAChC,eAAe,IAAI,CAAC,CAAA;IACpB,OAAO,WAAW,eAAe,EAAE,CAAA;AACrC,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,MAAc,EAAE,MAAc,EAAE,MAAc;IACnE,OAAO,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,EAAE,CAAA;AACxC,CAAC"}
@@ -0,0 +1,10 @@
1
+ export type { TexarynFormElement } from './element.js';
2
+ export { defineTexarynForm } from './define.js';
3
+ export { mountForm } from './mount.js';
4
+ export type { Mount } from './mount.js';
5
+ export { createDefaultRegistry } from './registry.js';
6
+ export { textInput, numberInput, checkbox, select, textarea } from './fields.js';
7
+ export { objectLayout, arrayControl } from './containers.js';
8
+ export { makeId } from './ids.js';
9
+ export type { DomWidget, NodeBinding, RenderContext, WidgetFactory } from './widget.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { defineTexarynForm } from './define.js';
2
+ export { mountForm } from './mount.js';
3
+ export { createDefaultRegistry } from './registry.js';
4
+ export { textInput, numberInput, checkbox, select, textarea } from './fields.js';
5
+ export { objectLayout, arrayControl } from './containers.js';
6
+ export { makeId } from './ids.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEtC,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,12 @@
1
+ import type { FormRuntime, RendererRegistry } from '@texaryn/core';
2
+ import type { WidgetFactory } from './widget.js';
3
+ export interface Mount {
4
+ unmount(): void;
5
+ }
6
+ /**
7
+ * Renders a runtime's document into a container and follows every recompile
8
+ * by updating the root binding in place. The runtime is borrowed: unmounting
9
+ * releases subscriptions and DOM, never the runtime.
10
+ */
11
+ export declare function mountForm(container: HTMLElement, runtime: FormRuntime, registry: RendererRegistry<WidgetFactory>, idPrefix: string): Mount;
12
+ //# sourceMappingURL=mount.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../src/mount.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAElE,OAAO,KAAK,EAA8B,aAAa,EAAE,MAAM,aAAa,CAAA;AAE5E,MAAM,WAAW,KAAK;IACpB,OAAO,IAAI,IAAI,CAAA;CAChB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,SAAS,EAAE,WAAW,EACtB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,gBAAgB,CAAC,aAAa,CAAC,EACzC,QAAQ,EAAE,MAAM,GACf,KAAK,CAgCP"}
package/dist/mount.js ADDED
@@ -0,0 +1,39 @@
1
+ import { createNodeBinding } from './binding.js';
2
+ /**
3
+ * Renders a runtime's document into a container and follows every recompile
4
+ * by updating the root binding in place. The runtime is borrowed: unmounting
5
+ * releases subscriptions and DOM, never the runtime.
6
+ */
7
+ export function mountForm(container, runtime, registry, idPrefix) {
8
+ const ctx = {
9
+ runtime,
10
+ registry,
11
+ idPrefix,
12
+ mountChild: (node) => createNodeBinding(node, ctx),
13
+ };
14
+ let doc = runtime.document.getSnapshot();
15
+ let root = createNodeBinding(doc.nodes[doc.rootId], ctx);
16
+ container.append(root.element);
17
+ const unsubscribe = runtime.document.subscribe(() => {
18
+ const next = runtime.document.getSnapshot();
19
+ const rootNode = next.nodes[next.rootId];
20
+ if (next.rootId === doc.rootId) {
21
+ root.update(rootNode);
22
+ }
23
+ else {
24
+ const replacement = createNodeBinding(rootNode, ctx);
25
+ root.element.replaceWith(replacement.element);
26
+ root.destroy();
27
+ root = replacement;
28
+ }
29
+ doc = next;
30
+ });
31
+ return {
32
+ unmount() {
33
+ unsubscribe();
34
+ root.destroy();
35
+ root.element.remove();
36
+ },
37
+ };
38
+ }
39
+ //# sourceMappingURL=mount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount.js","sourceRoot":"","sources":["../src/mount.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAOhD;;;;GAIG;AACH,MAAM,UAAU,SAAS,CACvB,SAAsB,EACtB,OAAoB,EACpB,QAAyC,EACzC,QAAgB;IAEhB,MAAM,GAAG,GAAkB;QACzB,OAAO;QACP,QAAQ;QACR,QAAQ;QACR,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,GAAG,CAAC;KACnD,CAAA;IACD,IAAI,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAA;IACxC,IAAI,IAAI,GAAgB,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAA;IACrE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAE9B,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE;QAClD,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAA;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACxC,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACvB,CAAC;aAAM,CAAC;YACN,MAAM,WAAW,GAAG,iBAAiB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;YACpD,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;YAC7C,IAAI,CAAC,OAAO,EAAE,CAAA;YACd,IAAI,GAAG,WAAW,CAAA;QACpB,CAAC;QACD,GAAG,GAAG,IAAI,CAAA;IACZ,CAAC,CAAC,CAAA;IAEF,OAAO;QACL,OAAO;YACL,WAAW,EAAE,CAAA;YACb,IAAI,CAAC,OAAO,EAAE,CAAA;YACd,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAA;QACvB,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { RendererRegistry } from '@texaryn/core';
2
+ import type { WidgetFactory } from './widget.js';
3
+ /**
4
+ * The same tests and ranks as the React and Vue default registries, on
5
+ * purpose. If the three ever disagree about which widget a node resolves to,
6
+ * the difference is a renderer's opinion leaking into what the document means.
7
+ */
8
+ export declare function createDefaultRegistry(): RendererRegistry<WidgetFactory>;
9
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAa,gBAAgB,EAAU,MAAM,eAAe,CAAA;AAGxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAMhD;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,gBAAgB,CAAC,aAAa,CAAC,CAuBvE"}
@@ -0,0 +1,23 @@
1
+ import { createRendererRegistry } from '@texaryn/core';
2
+ import { arrayControl, objectLayout } from './containers.js';
3
+ import { checkbox, numberInput, select, textInput, textarea } from './fields.js';
4
+ function field(node) {
5
+ return node.type === 'field' ? node : null;
6
+ }
7
+ /**
8
+ * The same tests and ranks as the React and Vue default registries, on
9
+ * purpose. If the three ever disagree about which widget a node resolves to,
10
+ * the difference is a renderer's opinion leaking into what the document means.
11
+ */
12
+ export function createDefaultRegistry() {
13
+ const registry = createRendererRegistry();
14
+ registry.register({ rank: 1, test: (n) => field(n)?.fieldType === 'string' && field(n)?.enumValues == null }, textInput);
15
+ registry.register({ rank: 1, test: (n) => field(n)?.fieldType === 'number' || field(n)?.fieldType === 'integer' }, numberInput);
16
+ registry.register({ rank: 1, test: (n) => field(n)?.fieldType === 'boolean' }, checkbox);
17
+ registry.register({ rank: 2, test: (n) => (field(n)?.enumValues?.length ?? 0) > 0 }, select);
18
+ registry.register({ rank: 5, test: (n) => field(n)?.widget === 'textarea' }, textarea);
19
+ registry.register({ rank: 1, test: (n) => n.type === 'container' && n.containerType === 'object' }, objectLayout);
20
+ registry.register({ rank: 1, test: (n) => n.type === 'container' && n.containerType === 'array' }, arrayControl);
21
+ return registry;
22
+ }
23
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAEtD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAGhF,SAAS,KAAK,CAAC,IAAY;IACzB,OAAO,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;AAC5C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,QAAQ,GAAG,sBAAsB,EAAiB,CAAA;IAExD,QAAQ,CAAC,QAAQ,CACf,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,IAAI,IAAI,EAAE,EAC1F,SAAS,CACV,CAAA;IACD,QAAQ,CAAC,QAAQ,CACf,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,KAAK,SAAS,EAAE,EAC/F,WAAW,CACZ,CAAA;IACD,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,KAAK,SAAS,EAAE,EAAE,QAAQ,CAAC,CAAA;IACxF,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;IAC5F,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,UAAU,EAAE,EAAE,QAAQ,CAAC,CAAA;IACtF,QAAQ,CAAC,QAAQ,CACf,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,aAAa,KAAK,QAAQ,EAAE,EAChF,YAAY,CACb,CAAA;IACD,QAAQ,CAAC,QAAQ,CACf,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,aAAa,KAAK,OAAO,EAAE,EAC/E,YAAY,CACb,CAAA;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC"}