@takazudo/zfb 2.22.1 → 3.0.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 +5 -9
- package/dist/config.d.ts +62 -19
- package/dist/config.js +27 -6
- package/dist/config.js.map +1 -1
- package/dist/content.d.ts +8 -22
- package/dist/content.js +6 -28
- package/dist/content.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/island-boundary.d.ts +4 -0
- package/dist/island-boundary.js +42 -0
- package/dist/island-boundary.js.map +1 -0
- package/dist/island.d.ts +2 -118
- package/dist/island.js +4 -284
- package/dist/island.js.map +1 -1
- package/dist/jsx-types.d.ts +2 -38
- package/dist/jsx-types.js +3 -10
- package/dist/jsx-types.js.map +1 -1
- package/dist/plugins.d.ts +40 -0
- package/dist/plugins.js.map +1 -1
- package/dist/runtime.d.ts +23 -77
- package/dist/runtime.js +149 -320
- package/dist/runtime.js.map +1 -1
- package/dist/zudo-react/client.d.ts +3 -0
- package/dist/zudo-react/client.js +3 -0
- package/dist/zudo-react/client.js.map +1 -0
- package/dist/zudo-react/description.d.ts +16 -0
- package/dist/zudo-react/description.js +64 -0
- package/dist/zudo-react/description.js.map +1 -0
- package/dist/zudo-react/dom-bindings.d.ts +13 -0
- package/dist/zudo-react/dom-bindings.js +58 -0
- package/dist/zudo-react/dom-bindings.js.map +1 -0
- package/dist/zudo-react/escape.d.ts +2 -0
- package/dist/zudo-react/escape.js +7 -0
- package/dist/zudo-react/escape.js.map +1 -0
- package/dist/zudo-react/forms.d.ts +29 -0
- package/dist/zudo-react/forms.js +371 -0
- package/dist/zudo-react/forms.js.map +1 -0
- package/dist/zudo-react/hydrate.d.ts +4 -0
- package/dist/zudo-react/hydrate.js +909 -0
- package/dist/zudo-react/hydrate.js.map +1 -0
- package/dist/zudo-react/index.d.ts +47 -0
- package/dist/zudo-react/index.js +13 -0
- package/dist/zudo-react/index.js.map +1 -0
- package/dist/zudo-react/island-root-type.d.ts +1 -0
- package/dist/zudo-react/island-root-type.js +2 -0
- package/dist/zudo-react/island-root-type.js.map +1 -0
- package/dist/zudo-react/jsx-dev-runtime.d.ts +8 -0
- package/dist/zudo-react/jsx-dev-runtime.js +6 -0
- package/dist/zudo-react/jsx-dev-runtime.js.map +1 -0
- package/dist/zudo-react/jsx-runtime.d.ts +5 -0
- package/dist/zudo-react/jsx-runtime.js +7 -0
- package/dist/zudo-react/jsx-runtime.js.map +1 -0
- package/dist/zudo-react/jsx-types.d.ts +203 -0
- package/dist/zudo-react/jsx-types.js +2 -0
- package/dist/zudo-react/jsx-types.js.map +1 -0
- package/dist/zudo-react/props-transport.d.ts +2 -0
- package/dist/zudo-react/props-transport.js +95 -0
- package/dist/zudo-react/props-transport.js.map +1 -0
- package/dist/zudo-react/reactive-types.d.ts +8 -0
- package/dist/zudo-react/reactive-types.js +2 -0
- package/dist/zudo-react/reactive-types.js.map +1 -0
- package/dist/zudo-react/reactive.d.ts +20 -0
- package/dist/zudo-react/reactive.js +176 -0
- package/dist/zudo-react/reactive.js.map +1 -0
- package/dist/zudo-react/render-html.d.ts +3 -0
- package/dist/zudo-react/render-html.js +537 -0
- package/dist/zudo-react/render-html.js.map +1 -0
- package/dist/zudo-react/root.d.ts +20 -0
- package/dist/zudo-react/root.js +74 -0
- package/dist/zudo-react/root.js.map +1 -0
- package/dist/zudo-react/scheduler.d.ts +12 -0
- package/dist/zudo-react/scheduler.js +113 -0
- package/dist/zudo-react/scheduler.js.map +1 -0
- package/dist/zudo-react/scope.d.ts +42 -0
- package/dist/zudo-react/scope.js +220 -0
- package/dist/zudo-react/scope.js.map +1 -0
- package/dist/zudo-react/server.d.ts +15 -0
- package/dist/zudo-react/server.js +11 -0
- package/dist/zudo-react/server.js.map +1 -0
- package/dist/zudo-react/structure.d.ts +14 -0
- package/dist/zudo-react/structure.js +35 -0
- package/dist/zudo-react/structure.js.map +1 -0
- package/package.json +28 -24
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { batch } from "./scheduler.js";
|
|
2
|
+
import { isReactive } from "./dom-bindings.js";
|
|
3
|
+
import { subscribe } from "./reactive.js";
|
|
4
|
+
import { diagnostic, report, rootPath } from "./root.js";
|
|
5
|
+
const compositionKey = Symbol.for("@takazudo/zfb/zudo-react/composition-v1");
|
|
6
|
+
const radioOwners = new WeakMap();
|
|
7
|
+
export class FormError extends TypeError {
|
|
8
|
+
code;
|
|
9
|
+
path;
|
|
10
|
+
detail;
|
|
11
|
+
constructor(code, path, detail) {
|
|
12
|
+
super(`${code}: ${detail} at ${path}`);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.path = path;
|
|
15
|
+
this.detail = detail;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function error(code, path, detail) {
|
|
19
|
+
throw new FormError(code, path, detail);
|
|
20
|
+
}
|
|
21
|
+
function writable(value, path) {
|
|
22
|
+
if (!value ||
|
|
23
|
+
typeof value !== "object" ||
|
|
24
|
+
!("$$zudoReactive" in value) ||
|
|
25
|
+
value.$$zudoReactive !== "zudo-react.reactive.v1" ||
|
|
26
|
+
!("$$zudoWritable" in value) ||
|
|
27
|
+
value.$$zudoWritable !== "zudo-react.writable.v1")
|
|
28
|
+
error("ZR_MODEL_READONLY", path, "model requires a writable signal");
|
|
29
|
+
let proto = value;
|
|
30
|
+
while (proto) {
|
|
31
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, "value");
|
|
32
|
+
if (descriptor) {
|
|
33
|
+
if (typeof descriptor.set !== "function")
|
|
34
|
+
error("ZR_MODEL_READONLY", path, "model requires a writable signal");
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
proto = Object.getPrototypeOf(proto);
|
|
38
|
+
}
|
|
39
|
+
return error("ZR_MODEL_READONLY", path, "model requires a writable signal");
|
|
40
|
+
}
|
|
41
|
+
function kind(node, props) {
|
|
42
|
+
if (node.localName === "textarea")
|
|
43
|
+
return "textarea";
|
|
44
|
+
if (node.localName === "select")
|
|
45
|
+
return "select";
|
|
46
|
+
if (node.localName !== "input")
|
|
47
|
+
return null;
|
|
48
|
+
const type = String(props.type ?? "text");
|
|
49
|
+
if (type === "checkbox")
|
|
50
|
+
return "checkbox";
|
|
51
|
+
if (type === "radio")
|
|
52
|
+
return "radio";
|
|
53
|
+
return ["text", "search", "email", "url", "tel", "password"].includes(type) ? "text" : null;
|
|
54
|
+
}
|
|
55
|
+
// Text input: read/write string .value; listen to input.
|
|
56
|
+
function textAdapter(node, path) {
|
|
57
|
+
return {
|
|
58
|
+
event: "input",
|
|
59
|
+
read: () => node.value,
|
|
60
|
+
write: (value) => {
|
|
61
|
+
if (typeof value !== "string")
|
|
62
|
+
error("ZR_MODEL_VALUE", path, "text requires string");
|
|
63
|
+
if (node.value !== value)
|
|
64
|
+
node.value = value;
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// Textarea: read/write string .value; listen to input.
|
|
69
|
+
function textareaAdapter(node, path) {
|
|
70
|
+
return {
|
|
71
|
+
event: "input",
|
|
72
|
+
read: () => node.value,
|
|
73
|
+
write: (value) => {
|
|
74
|
+
if (typeof value !== "string")
|
|
75
|
+
error("ZR_MODEL_VALUE", path, "textarea requires string");
|
|
76
|
+
if (node.value !== value)
|
|
77
|
+
node.value = value;
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
// Checkbox: read/write boolean .checked; listen to change.
|
|
82
|
+
function checkboxAdapter(node, path) {
|
|
83
|
+
return {
|
|
84
|
+
event: "change",
|
|
85
|
+
read: () => node.checked,
|
|
86
|
+
write: (value) => {
|
|
87
|
+
if (typeof value !== "boolean")
|
|
88
|
+
error("ZR_MODEL_VALUE", path, "checkbox requires boolean");
|
|
89
|
+
if (node.checked !== value)
|
|
90
|
+
node.checked = value;
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Single select: read/write string .value after options exist; listen to change.
|
|
95
|
+
function selectAdapter(node, path) {
|
|
96
|
+
return {
|
|
97
|
+
event: "change",
|
|
98
|
+
read: () => node.value,
|
|
99
|
+
write: (value) => {
|
|
100
|
+
if (typeof value !== "string")
|
|
101
|
+
error("ZR_MODEL_VALUE", path, "select requires string");
|
|
102
|
+
if (!values(node).includes(value) && !(value === "" && node.selectedIndex === -1))
|
|
103
|
+
error("ZR_MODEL_VALUE", path, `select has no option ${value}`);
|
|
104
|
+
if (node.value !== value)
|
|
105
|
+
node.value = value;
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// Radio group: read selected option or null; write checked; listen to change.
|
|
110
|
+
function radioAdapter(node) {
|
|
111
|
+
return {
|
|
112
|
+
event: "change",
|
|
113
|
+
read: () => (node.checked ? node.value : null),
|
|
114
|
+
write: (value) => {
|
|
115
|
+
const checked = value === node.value;
|
|
116
|
+
if (node.checked !== checked)
|
|
117
|
+
node.checked = checked;
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function adapterFor(kind, node, path) {
|
|
122
|
+
switch (kind) {
|
|
123
|
+
case "text":
|
|
124
|
+
return textAdapter(node, path);
|
|
125
|
+
case "textarea":
|
|
126
|
+
return textareaAdapter(node, path);
|
|
127
|
+
case "checkbox":
|
|
128
|
+
return checkboxAdapter(node, path);
|
|
129
|
+
case "select":
|
|
130
|
+
return selectAdapter(node, path);
|
|
131
|
+
case "radio":
|
|
132
|
+
return radioAdapter(node);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function values(node) {
|
|
136
|
+
return [...node.options].map((option) => option.value);
|
|
137
|
+
}
|
|
138
|
+
function optionValuesFor(group) {
|
|
139
|
+
return group.map((binding) => binding.node.value);
|
|
140
|
+
}
|
|
141
|
+
export function prepareForms(plans, map, mode, container) {
|
|
142
|
+
const bindings = [];
|
|
143
|
+
const groupByModel = new Map();
|
|
144
|
+
const namedRadios = new Map();
|
|
145
|
+
for (const plan of plans) {
|
|
146
|
+
const { props, path } = plan;
|
|
147
|
+
const node = map.get(plan.element);
|
|
148
|
+
const controlKind = kind(node, props);
|
|
149
|
+
const modelValue = props.modelValue;
|
|
150
|
+
const modelChecked = props.modelChecked;
|
|
151
|
+
const hasValue = modelValue !== undefined;
|
|
152
|
+
const hasChecked = modelChecked !== undefined;
|
|
153
|
+
if (hasValue && hasChecked)
|
|
154
|
+
error("ZR_MODEL_CONFLICT", path, "modelValue with modelChecked");
|
|
155
|
+
if ((props.defaultValue !== undefined && props.value !== undefined) ||
|
|
156
|
+
(props.defaultChecked !== undefined && props.checked !== undefined))
|
|
157
|
+
error("ZR_MODEL_CONFLICT", path, "default with static value or checked");
|
|
158
|
+
if ((hasValue &&
|
|
159
|
+
(props.defaultValue !== undefined ||
|
|
160
|
+
(controlKind !== "radio" && props.value !== undefined))) ||
|
|
161
|
+
(hasChecked && (props.defaultChecked !== undefined || props.checked !== undefined)))
|
|
162
|
+
error("ZR_MODEL_CONFLICT", path, "model with default or static value");
|
|
163
|
+
if (props.defaultValue !== undefined &&
|
|
164
|
+
!["text", "textarea", "select"].includes(controlKind ?? ""))
|
|
165
|
+
error("ZR_MODEL_UNSUPPORTED", path, "defaultValue on unsupported control");
|
|
166
|
+
if (props.defaultChecked !== undefined && !["checkbox", "radio"].includes(controlKind ?? ""))
|
|
167
|
+
error("ZR_MODEL_UNSUPPORTED", path, "defaultChecked on unsupported control");
|
|
168
|
+
if (node.localName === "select" && node.multiple)
|
|
169
|
+
error("ZR_MODEL_UNSUPPORTED", path, "select[multiple]");
|
|
170
|
+
if (hasValue || hasChecked) {
|
|
171
|
+
for (const name of ["type", "multiple", "name", "form"])
|
|
172
|
+
if (isReactive(props[name]))
|
|
173
|
+
error("ZR_MODEL_UNSUPPORTED", path, `reactive ${name} shape`);
|
|
174
|
+
if (!controlKind ||
|
|
175
|
+
node.hasAttribute("contenteditable") ||
|
|
176
|
+
(hasChecked && controlKind !== "checkbox") ||
|
|
177
|
+
(hasValue && controlKind === "checkbox"))
|
|
178
|
+
error("ZR_MODEL_UNSUPPORTED", path, node.localName);
|
|
179
|
+
const model = writable(hasValue ? modelValue : modelChecked, path);
|
|
180
|
+
const initial = model.value;
|
|
181
|
+
if (controlKind === "checkbox"
|
|
182
|
+
? typeof initial !== "boolean"
|
|
183
|
+
: controlKind === "radio"
|
|
184
|
+
? initial !== null && typeof initial !== "string"
|
|
185
|
+
: typeof initial !== "string")
|
|
186
|
+
error("ZR_MODEL_VALUE", path, "model has wrong value type");
|
|
187
|
+
if (controlKind === "select") {
|
|
188
|
+
const options = [...node.options].map((option) => option.value);
|
|
189
|
+
if (new Set(options).size !== options.length)
|
|
190
|
+
error("ZR_MODEL_CONFLICT", path, "duplicate select option value");
|
|
191
|
+
}
|
|
192
|
+
if (controlKind === "radio") {
|
|
193
|
+
const radio = node;
|
|
194
|
+
if (!radio.name || typeof props.value !== "string")
|
|
195
|
+
error("ZR_MODEL_UNSUPPORTED", path, "radio requires static name and value");
|
|
196
|
+
const owners = radioOwners.get(node.ownerDocument);
|
|
197
|
+
if ([...(owners ?? [])].some((entry) => entry.root !== container && entry.name === radio.name && entry.form === radio.form))
|
|
198
|
+
error("ZR_MODEL_CONFLICT", path, "same-name radio owned by another root");
|
|
199
|
+
const key = `${radio.name}\u0000${radio.getAttribute("form") ?? ""}`;
|
|
200
|
+
const prior = namedRadios.get(key);
|
|
201
|
+
if (prior && prior !== model)
|
|
202
|
+
error("ZR_MODEL_CONFLICT", path, "same-name radios use different models");
|
|
203
|
+
namedRadios.set(key, model);
|
|
204
|
+
}
|
|
205
|
+
const binding = {
|
|
206
|
+
node: node,
|
|
207
|
+
model,
|
|
208
|
+
kind: controlKind,
|
|
209
|
+
path,
|
|
210
|
+
...adapterFor(controlKind, node, path),
|
|
211
|
+
};
|
|
212
|
+
bindings.push(binding);
|
|
213
|
+
const group = groupByModel.get(model) ?? [];
|
|
214
|
+
group.push(binding);
|
|
215
|
+
groupByModel.set(model, group);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
for (const [model, group] of groupByModel) {
|
|
219
|
+
const radios = group.every((binding) => binding.kind === "radio");
|
|
220
|
+
if (group.some((binding) => binding.kind === "radio") && !radios)
|
|
221
|
+
error("ZR_MODEL_CONFLICT", group[0].path, "radio and non-radio share model");
|
|
222
|
+
if (radios) {
|
|
223
|
+
const nodes = group.map((binding) => binding.node);
|
|
224
|
+
const names = new Set(nodes.map((node) => `${node.name}\u0000${node.getAttribute("form") ?? ""}`));
|
|
225
|
+
const optionValues = nodes.map((node) => node.value);
|
|
226
|
+
if (names.size !== 1 ||
|
|
227
|
+
new Set(nodes.map((node) => node.form)).size !== 1 ||
|
|
228
|
+
new Set(optionValues).size !== optionValues.length)
|
|
229
|
+
error("ZR_MODEL_CONFLICT", group[0].path, "radio group membership or duplicate value");
|
|
230
|
+
if (mode === "mount" && model.value !== null && !optionValues.includes(model.value))
|
|
231
|
+
error("ZR_MODEL_VALUE", group[0].path, "radio model has no option");
|
|
232
|
+
if (mode === "hydrate" && nodes.filter((node) => node.checked).length > 1)
|
|
233
|
+
error("ZR_MODEL_CONFLICT", group[0].path, "multiple checked radios");
|
|
234
|
+
}
|
|
235
|
+
else if (mode === "hydrate" &&
|
|
236
|
+
group.some((binding) => !Object.is(binding.read(), group[0].read())))
|
|
237
|
+
error("ZR_MODEL_CONFLICT", group[0].path, "shared model controls disagree");
|
|
238
|
+
if (radios) {
|
|
239
|
+
for (const binding of group) {
|
|
240
|
+
const originalWrite = binding.write;
|
|
241
|
+
binding.write = (value) => {
|
|
242
|
+
if (value !== null && !optionValuesFor(group).includes(value))
|
|
243
|
+
error("ZR_MODEL_VALUE", binding.path, "radio model has no option");
|
|
244
|
+
originalWrite(value);
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return bindings;
|
|
250
|
+
}
|
|
251
|
+
export function reconcileForms(bindings, mode) {
|
|
252
|
+
const groups = new Map();
|
|
253
|
+
for (const binding of bindings)
|
|
254
|
+
groups.set(binding.model, [...(groups.get(binding.model) ?? []), binding]);
|
|
255
|
+
if (mode === "hydrate")
|
|
256
|
+
batch(() => {
|
|
257
|
+
for (const [model, group] of groups) {
|
|
258
|
+
model.value =
|
|
259
|
+
group[0].kind === "radio"
|
|
260
|
+
? (group.find((binding) => binding.read() !== null)?.read() ?? null)
|
|
261
|
+
: group[0].read();
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
else
|
|
265
|
+
for (const [model, group] of groups)
|
|
266
|
+
for (const binding of group)
|
|
267
|
+
binding.write(model.value);
|
|
268
|
+
}
|
|
269
|
+
export function activateForms(bindings, scope, cleanups, options, container) {
|
|
270
|
+
const byForm = new Map();
|
|
271
|
+
const owned = radioOwners.get(container.ownerDocument) ??
|
|
272
|
+
new Set();
|
|
273
|
+
radioOwners.set(container.ownerDocument, owned);
|
|
274
|
+
const registrations = [];
|
|
275
|
+
for (const binding of bindings)
|
|
276
|
+
if (binding.kind === "radio") {
|
|
277
|
+
const node = binding.node;
|
|
278
|
+
const registration = { root: container, name: node.name, form: node.form };
|
|
279
|
+
registrations.push(registration);
|
|
280
|
+
owned.add(registration);
|
|
281
|
+
}
|
|
282
|
+
cleanups.push(() => {
|
|
283
|
+
for (const registration of registrations)
|
|
284
|
+
owned.delete(registration);
|
|
285
|
+
});
|
|
286
|
+
for (const binding of bindings) {
|
|
287
|
+
const { node, model } = binding;
|
|
288
|
+
const textual = binding.kind === "text" || binding.kind === "textarea";
|
|
289
|
+
let composing = textual && node[compositionKey] === "active";
|
|
290
|
+
let unknown = textual &&
|
|
291
|
+
node.ownerDocument.activeElement === node &&
|
|
292
|
+
node[compositionKey] === undefined;
|
|
293
|
+
const update = () => {
|
|
294
|
+
model.value = binding.read();
|
|
295
|
+
};
|
|
296
|
+
const onInput = (event) => {
|
|
297
|
+
if (binding.kind === "radio" && !node.checked)
|
|
298
|
+
return;
|
|
299
|
+
if (textual && event.isComposing)
|
|
300
|
+
composing = true;
|
|
301
|
+
update();
|
|
302
|
+
};
|
|
303
|
+
const onStart = () => {
|
|
304
|
+
composing = true;
|
|
305
|
+
unknown = false;
|
|
306
|
+
};
|
|
307
|
+
const onFinish = () => {
|
|
308
|
+
composing = false;
|
|
309
|
+
unknown = false;
|
|
310
|
+
update();
|
|
311
|
+
};
|
|
312
|
+
node.addEventListener(binding.event, onInput);
|
|
313
|
+
if (textual) {
|
|
314
|
+
node.addEventListener("compositionstart", onStart);
|
|
315
|
+
node.addEventListener("compositionend", onFinish);
|
|
316
|
+
node.addEventListener("blur", onFinish);
|
|
317
|
+
}
|
|
318
|
+
cleanups.push(() => {
|
|
319
|
+
node.removeEventListener(binding.event, onInput);
|
|
320
|
+
if (textual) {
|
|
321
|
+
node.removeEventListener("compositionstart", onStart);
|
|
322
|
+
node.removeEventListener("compositionend", onFinish);
|
|
323
|
+
node.removeEventListener("blur", onFinish);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
const subscription = subscribe(() => {
|
|
327
|
+
const value = model.value;
|
|
328
|
+
if (!composing && !unknown) {
|
|
329
|
+
try {
|
|
330
|
+
binding.write(value);
|
|
331
|
+
}
|
|
332
|
+
catch (failure) {
|
|
333
|
+
if (!(failure instanceof FormError))
|
|
334
|
+
throw failure;
|
|
335
|
+
report(options, diagnostic(options, failure.code, "update", `${rootPath(container)}${binding.path}`, "valid model update", failure.detail));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}, {
|
|
339
|
+
active: () => scope.active,
|
|
340
|
+
report: (code, actual) => report(options, diagnostic(options, code, "update", `${rootPath(container)}${binding.path}`, "valid model update", actual)),
|
|
341
|
+
});
|
|
342
|
+
subscription.run();
|
|
343
|
+
cleanups.push(() => subscription.dispose());
|
|
344
|
+
const form = node.form;
|
|
345
|
+
if (form)
|
|
346
|
+
byForm.set(form, [...(byForm.get(form) ?? []), binding]);
|
|
347
|
+
}
|
|
348
|
+
for (const [form, members] of byForm) {
|
|
349
|
+
let active = true;
|
|
350
|
+
const onReset = (event) => queueMicrotask(() => {
|
|
351
|
+
if (!active || event.defaultPrevented)
|
|
352
|
+
return;
|
|
353
|
+
batch(() => {
|
|
354
|
+
const groups = new Map();
|
|
355
|
+
for (const binding of members)
|
|
356
|
+
groups.set(binding.model, [...(groups.get(binding.model) ?? []), binding]);
|
|
357
|
+
for (const [model, group] of groups)
|
|
358
|
+
model.value =
|
|
359
|
+
group[0].kind === "radio"
|
|
360
|
+
? (group.find((binding) => binding.read() !== null)?.read() ?? null)
|
|
361
|
+
: group[0].read();
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
form.addEventListener("reset", onReset);
|
|
365
|
+
cleanups.push(() => {
|
|
366
|
+
active = false;
|
|
367
|
+
form.removeEventListener("reset", onReset);
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
//# sourceMappingURL=forms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forms.js","sourceRoot":"","sources":["../../src/zudo-react/forms.ts"],"names":[],"mappings":"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","sourcesContent":["import { batch } from \"./scheduler.js\";\nimport { isReactive } from \"./dom-bindings.js\";\nimport { subscribe } from \"./reactive.js\";\nimport type { Signal } from \"./reactive-types.js\";\nimport type { RuntimeScope } from \"./scope.js\";\nimport { diagnostic, report, rootPath, type RootOptions } from \"./root.js\";\n\nconst compositionKey = Symbol.for(\"@takazudo/zfb/zudo-react/composition-v1\");\nconst radioOwners = new WeakMap<\n Document,\n Set<{ root: Element; name: string; form: HTMLFormElement | null }>\n>();\ntype Control = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\ntype Model = Signal<string | boolean | null>;\nexport interface FormPlan {\n element: Element;\n props: Readonly<Record<string, unknown>>;\n path: string;\n}\ninterface Binding {\n node: Control;\n model: Model;\n kind: \"text\" | \"textarea\" | \"checkbox\" | \"select\" | \"radio\";\n read(): string | boolean | null;\n write(value: string | boolean | null): void;\n event: \"input\" | \"change\";\n path: string;\n}\nexport class FormError extends TypeError {\n constructor(\n readonly code: string,\n readonly path: string,\n readonly detail: string,\n ) {\n super(`${code}: ${detail} at ${path}`);\n }\n}\nfunction error(code: string, path: string, detail: string): never {\n throw new FormError(code, path, detail);\n}\nfunction writable(value: unknown, path: string): Model {\n if (\n !value ||\n typeof value !== \"object\" ||\n !(\"$$zudoReactive\" in value) ||\n value.$$zudoReactive !== \"zudo-react.reactive.v1\" ||\n !(\"$$zudoWritable\" in value) ||\n value.$$zudoWritable !== \"zudo-react.writable.v1\"\n )\n error(\"ZR_MODEL_READONLY\", path, \"model requires a writable signal\");\n let proto = value;\n while (proto) {\n const descriptor = Object.getOwnPropertyDescriptor(proto, \"value\");\n if (descriptor) {\n if (typeof descriptor.set !== \"function\")\n error(\"ZR_MODEL_READONLY\", path, \"model requires a writable signal\");\n return value as Model;\n }\n proto = Object.getPrototypeOf(proto);\n }\n return error(\"ZR_MODEL_READONLY\", path, \"model requires a writable signal\");\n}\nfunction kind(node: Element, props: Readonly<Record<string, unknown>>): Binding[\"kind\"] | null {\n if (node.localName === \"textarea\") return \"textarea\";\n if (node.localName === \"select\") return \"select\";\n if (node.localName !== \"input\") return null;\n const type = String(props.type ?? \"text\");\n if (type === \"checkbox\") return \"checkbox\";\n if (type === \"radio\") return \"radio\";\n return [\"text\", \"search\", \"email\", \"url\", \"tel\", \"password\"].includes(type) ? \"text\" : null;\n}\n// Text input: read/write string .value; listen to input.\nfunction textAdapter(\n node: HTMLInputElement,\n path: string,\n): Pick<Binding, \"read\" | \"write\" | \"event\"> {\n return {\n event: \"input\",\n read: () => node.value,\n write: (value) => {\n if (typeof value !== \"string\") error(\"ZR_MODEL_VALUE\", path, \"text requires string\");\n if (node.value !== value) node.value = value;\n },\n };\n}\n// Textarea: read/write string .value; listen to input.\nfunction textareaAdapter(\n node: HTMLTextAreaElement,\n path: string,\n): Pick<Binding, \"read\" | \"write\" | \"event\"> {\n return {\n event: \"input\",\n read: () => node.value,\n write: (value) => {\n if (typeof value !== \"string\") error(\"ZR_MODEL_VALUE\", path, \"textarea requires string\");\n if (node.value !== value) node.value = value;\n },\n };\n}\n// Checkbox: read/write boolean .checked; listen to change.\nfunction checkboxAdapter(\n node: HTMLInputElement,\n path: string,\n): Pick<Binding, \"read\" | \"write\" | \"event\"> {\n return {\n event: \"change\",\n read: () => node.checked,\n write: (value) => {\n if (typeof value !== \"boolean\") error(\"ZR_MODEL_VALUE\", path, \"checkbox requires boolean\");\n if (node.checked !== value) node.checked = value;\n },\n };\n}\n// Single select: read/write string .value after options exist; listen to change.\nfunction selectAdapter(\n node: HTMLSelectElement,\n path: string,\n): Pick<Binding, \"read\" | \"write\" | \"event\"> {\n return {\n event: \"change\",\n read: () => node.value,\n write: (value) => {\n if (typeof value !== \"string\") error(\"ZR_MODEL_VALUE\", path, \"select requires string\");\n if (!values(node).includes(value) && !(value === \"\" && node.selectedIndex === -1))\n error(\"ZR_MODEL_VALUE\", path, `select has no option ${value}`);\n if (node.value !== value) node.value = value;\n },\n };\n}\n// Radio group: read selected option or null; write checked; listen to change.\nfunction radioAdapter(node: HTMLInputElement): Pick<Binding, \"read\" | \"write\" | \"event\"> {\n return {\n event: \"change\",\n read: () => (node.checked ? node.value : null),\n write: (value) => {\n const checked = value === node.value;\n if (node.checked !== checked) node.checked = checked;\n },\n };\n}\nfunction adapterFor(\n kind: Binding[\"kind\"],\n node: Control,\n path: string,\n): Pick<Binding, \"read\" | \"write\" | \"event\"> {\n switch (kind) {\n case \"text\":\n return textAdapter(node as HTMLInputElement, path);\n case \"textarea\":\n return textareaAdapter(node as HTMLTextAreaElement, path);\n case \"checkbox\":\n return checkboxAdapter(node as HTMLInputElement, path);\n case \"select\":\n return selectAdapter(node as HTMLSelectElement, path);\n case \"radio\":\n return radioAdapter(node as HTMLInputElement);\n }\n}\nfunction values(node: HTMLSelectElement): string[] {\n return [...node.options].map((option) => option.value);\n}\nfunction optionValuesFor(group: Binding[]): string[] {\n return group.map((binding) => (binding.node as HTMLInputElement).value);\n}\nexport function prepareForms(\n plans: FormPlan[],\n map: Map<Node, Node>,\n mode: \"hydrate\" | \"mount\",\n container: Element,\n): Binding[] {\n const bindings: Binding[] = [];\n const groupByModel = new Map<Model, Binding[]>();\n const namedRadios = new Map<string, Model>();\n for (const plan of plans) {\n const { props, path } = plan;\n const node = map.get(plan.element) as Element;\n const controlKind = kind(node, props);\n const modelValue = props.modelValue;\n const modelChecked = props.modelChecked;\n const hasValue = modelValue !== undefined;\n const hasChecked = modelChecked !== undefined;\n if (hasValue && hasChecked) error(\"ZR_MODEL_CONFLICT\", path, \"modelValue with modelChecked\");\n if (\n (props.defaultValue !== undefined && props.value !== undefined) ||\n (props.defaultChecked !== undefined && props.checked !== undefined)\n )\n error(\"ZR_MODEL_CONFLICT\", path, \"default with static value or checked\");\n if (\n (hasValue &&\n (props.defaultValue !== undefined ||\n (controlKind !== \"radio\" && props.value !== undefined))) ||\n (hasChecked && (props.defaultChecked !== undefined || props.checked !== undefined))\n )\n error(\"ZR_MODEL_CONFLICT\", path, \"model with default or static value\");\n if (\n props.defaultValue !== undefined &&\n ![\"text\", \"textarea\", \"select\"].includes(controlKind ?? \"\")\n )\n error(\"ZR_MODEL_UNSUPPORTED\", path, \"defaultValue on unsupported control\");\n if (props.defaultChecked !== undefined && ![\"checkbox\", \"radio\"].includes(controlKind ?? \"\"))\n error(\"ZR_MODEL_UNSUPPORTED\", path, \"defaultChecked on unsupported control\");\n if (node.localName === \"select\" && (node as HTMLSelectElement).multiple)\n error(\"ZR_MODEL_UNSUPPORTED\", path, \"select[multiple]\");\n if (hasValue || hasChecked) {\n for (const name of [\"type\", \"multiple\", \"name\", \"form\"])\n if (isReactive(props[name])) error(\"ZR_MODEL_UNSUPPORTED\", path, `reactive ${name} shape`);\n if (\n !controlKind ||\n node.hasAttribute(\"contenteditable\") ||\n (hasChecked && controlKind !== \"checkbox\") ||\n (hasValue && controlKind === \"checkbox\")\n )\n error(\"ZR_MODEL_UNSUPPORTED\", path, node.localName);\n const model = writable(hasValue ? modelValue : modelChecked, path);\n const initial = model.value;\n if (\n controlKind === \"checkbox\"\n ? typeof initial !== \"boolean\"\n : controlKind === \"radio\"\n ? initial !== null && typeof initial !== \"string\"\n : typeof initial !== \"string\"\n )\n error(\"ZR_MODEL_VALUE\", path, \"model has wrong value type\");\n if (controlKind === \"select\") {\n const options = [...(node as HTMLSelectElement).options].map((option) => option.value);\n if (new Set(options).size !== options.length)\n error(\"ZR_MODEL_CONFLICT\", path, \"duplicate select option value\");\n }\n if (controlKind === \"radio\") {\n const radio = node as HTMLInputElement;\n if (!radio.name || typeof props.value !== \"string\")\n error(\"ZR_MODEL_UNSUPPORTED\", path, \"radio requires static name and value\");\n const owners = radioOwners.get(node.ownerDocument);\n if (\n [...(owners ?? [])].some(\n (entry) =>\n entry.root !== container && entry.name === radio.name && entry.form === radio.form,\n )\n )\n error(\"ZR_MODEL_CONFLICT\", path, \"same-name radio owned by another root\");\n const key = `${radio.name}\\u0000${radio.getAttribute(\"form\") ?? \"\"}`;\n const prior = namedRadios.get(key);\n if (prior && prior !== model)\n error(\"ZR_MODEL_CONFLICT\", path, \"same-name radios use different models\");\n namedRadios.set(key, model);\n }\n const binding: Binding = {\n node: node as Control,\n model,\n kind: controlKind!,\n path,\n ...adapterFor(controlKind!, node as Control, path),\n };\n bindings.push(binding);\n const group = groupByModel.get(model) ?? [];\n group.push(binding);\n groupByModel.set(model, group);\n }\n }\n for (const [model, group] of groupByModel) {\n const radios = group.every((binding) => binding.kind === \"radio\");\n if (group.some((binding) => binding.kind === \"radio\") && !radios)\n error(\"ZR_MODEL_CONFLICT\", group[0]!.path, \"radio and non-radio share model\");\n if (radios) {\n const nodes = group.map((binding) => binding.node as HTMLInputElement);\n const names = new Set(\n nodes.map((node) => `${node.name}\\u0000${node.getAttribute(\"form\") ?? \"\"}`),\n );\n const optionValues = nodes.map((node) => node.value);\n if (\n names.size !== 1 ||\n new Set(nodes.map((node) => node.form)).size !== 1 ||\n new Set(optionValues).size !== optionValues.length\n )\n error(\"ZR_MODEL_CONFLICT\", group[0]!.path, \"radio group membership or duplicate value\");\n if (mode === \"mount\" && model.value !== null && !optionValues.includes(model.value as string))\n error(\"ZR_MODEL_VALUE\", group[0]!.path, \"radio model has no option\");\n if (mode === \"hydrate\" && nodes.filter((node) => node.checked).length > 1)\n error(\"ZR_MODEL_CONFLICT\", group[0]!.path, \"multiple checked radios\");\n } else if (\n mode === \"hydrate\" &&\n group.some((binding) => !Object.is(binding.read(), group[0]!.read()))\n )\n error(\"ZR_MODEL_CONFLICT\", group[0]!.path, \"shared model controls disagree\");\n if (radios) {\n for (const binding of group) {\n const originalWrite = binding.write;\n binding.write = (value) => {\n if (value !== null && !optionValuesFor(group).includes(value as string))\n error(\"ZR_MODEL_VALUE\", binding.path, \"radio model has no option\");\n originalWrite(value);\n };\n }\n }\n }\n return bindings;\n}\nexport function reconcileForms(bindings: Binding[], mode: \"hydrate\" | \"mount\"): void {\n const groups = new Map<Model, Binding[]>();\n for (const binding of bindings)\n groups.set(binding.model, [...(groups.get(binding.model) ?? []), binding]);\n if (mode === \"hydrate\")\n batch(() => {\n for (const [model, group] of groups) {\n model.value =\n group[0]!.kind === \"radio\"\n ? (group.find((binding) => binding.read() !== null)?.read() ?? null)\n : group[0]!.read();\n }\n });\n else for (const [model, group] of groups) for (const binding of group) binding.write(model.value);\n}\nexport function activateForms(\n bindings: Binding[],\n scope: RuntimeScope,\n cleanups: Array<() => void>,\n options: RootOptions,\n container: Element,\n): void {\n const byForm = new Map<HTMLFormElement, Binding[]>();\n const owned =\n radioOwners.get(container.ownerDocument) ??\n new Set<{ root: Element; name: string; form: HTMLFormElement | null }>();\n radioOwners.set(container.ownerDocument, owned);\n const registrations: Array<{ root: Element; name: string; form: HTMLFormElement | null }> = [];\n for (const binding of bindings)\n if (binding.kind === \"radio\") {\n const node = binding.node as HTMLInputElement;\n const registration = { root: container, name: node.name, form: node.form };\n registrations.push(registration);\n owned.add(registration);\n }\n cleanups.push(() => {\n for (const registration of registrations) owned.delete(registration);\n });\n for (const binding of bindings) {\n const { node, model } = binding;\n const textual = binding.kind === \"text\" || binding.kind === \"textarea\";\n let composing =\n textual && (node as unknown as Record<symbol, unknown>)[compositionKey] === \"active\";\n let unknown =\n textual &&\n node.ownerDocument.activeElement === node &&\n (node as unknown as Record<symbol, unknown>)[compositionKey] === undefined;\n const update = () => {\n model.value = binding.read();\n };\n const onInput = (event: Event) => {\n if (binding.kind === \"radio\" && !(node as HTMLInputElement).checked) return;\n if (textual && (event as InputEvent).isComposing) composing = true;\n update();\n };\n const onStart = () => {\n composing = true;\n unknown = false;\n };\n const onFinish = () => {\n composing = false;\n unknown = false;\n update();\n };\n node.addEventListener(binding.event, onInput);\n if (textual) {\n node.addEventListener(\"compositionstart\", onStart);\n node.addEventListener(\"compositionend\", onFinish);\n node.addEventListener(\"blur\", onFinish);\n }\n cleanups.push(() => {\n node.removeEventListener(binding.event, onInput);\n if (textual) {\n node.removeEventListener(\"compositionstart\", onStart);\n node.removeEventListener(\"compositionend\", onFinish);\n node.removeEventListener(\"blur\", onFinish);\n }\n });\n const subscription = subscribe(\n () => {\n const value = model.value;\n if (!composing && !unknown) {\n try {\n binding.write(value);\n } catch (failure) {\n if (!(failure instanceof FormError)) throw failure;\n report(\n options,\n diagnostic(\n options,\n failure.code,\n \"update\",\n `${rootPath(container)}${binding.path}`,\n \"valid model update\",\n failure.detail,\n ),\n );\n }\n }\n },\n {\n active: () => scope.active,\n report: (code, actual) =>\n report(\n options,\n diagnostic(\n options,\n code,\n \"update\",\n `${rootPath(container)}${binding.path}`,\n \"valid model update\",\n actual,\n ),\n ),\n },\n );\n subscription.run();\n cleanups.push(() => subscription.dispose());\n const form = node.form;\n if (form) byForm.set(form, [...(byForm.get(form) ?? []), binding]);\n }\n for (const [form, members] of byForm) {\n let active = true;\n const onReset = (event: Event) =>\n queueMicrotask(() => {\n if (!active || event.defaultPrevented) return;\n batch(() => {\n const groups = new Map<Model, Binding[]>();\n for (const binding of members)\n groups.set(binding.model, [...(groups.get(binding.model) ?? []), binding]);\n for (const [model, group] of groups)\n model.value =\n group[0]!.kind === \"radio\"\n ? (group.find((binding) => binding.read() !== null)?.read() ?? null)\n : group[0]!.read();\n });\n });\n form.addEventListener(\"reset\", onReset);\n cleanups.push(() => {\n active = false;\n form.removeEventListener(\"reset\", onReset);\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type Child } from "./description.js";
|
|
2
|
+
import { type RootHandle, type RootOptions } from "./root.js";
|
|
3
|
+
export declare function hydrate(node: Child, container: Element, options: RootOptions): RootHandle | null;
|
|
4
|
+
export declare function mount(node: Child, container: Element, options: RootOptions): RootHandle | null;
|