react-store-input 0.2.6 → 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/CHANGELOG.md +136 -0
- package/README.md +211 -199
- package/dist/index.d.mts +127 -11
- package/dist/index.d.ts +127 -11
- package/dist/index.js +542 -280
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +529 -272
- package/dist/index.mjs.map +1 -0
- package/dist/text-editor.d.mts +11 -0
- package/dist/text-editor.d.ts +11 -0
- package/dist/text-editor.js +203 -0
- package/dist/text-editor.js.map +1 -0
- package/dist/text-editor.mjs +178 -0
- package/dist/text-editor.mjs.map +1 -0
- package/package.json +78 -18
- package/dist/create_render.d.mts +0 -9
- package/dist/create_render.d.ts +0 -9
- package/dist/create_render.js +0 -51
- package/dist/create_render.mjs +0 -25
- package/dist/text_editor.d.mts +0 -13
- package/dist/text_editor.d.ts +0 -13
- package/dist/text_editor.js +0 -135
- package/dist/text_editor.mjs +0 -112
- package/dist/use_form_store.d.mts +0 -16
- package/dist/use_form_store.d.ts +0 -16
- package/dist/use_form_store.js +0 -365
- package/dist/use_form_store.mjs +0 -340
- package/dist/use_store_component.d.mts +0 -23
- package/dist/use_store_component.d.ts +0 -23
- package/dist/use_store_component.js +0 -337
- package/dist/use_store_component.mjs +0 -311
- package/dist/use_store_controller.d.mts +0 -11
- package/dist/use_store_controller.d.ts +0 -11
- package/dist/use_store_controller.js +0 -57
- package/dist/use_store_controller.mjs +0 -32
- package/dist/use_store_input.d.mts +0 -22
- package/dist/use_store_input.d.ts +0 -22
- package/dist/use_store_input.js +0 -151
- package/dist/use_store_input.mjs +0 -126
- package/dist/use_store_input_with_name.d.mts +0 -17
- package/dist/use_store_input_with_name.d.ts +0 -17
- package/dist/use_store_input_with_name.js +0 -177
- package/dist/use_store_input_with_name.mjs +0 -150
- package/tsup.config.ts +0 -9
package/dist/index.js
CHANGED
|
@@ -15,368 +15,630 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
15
|
}
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
|
-
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
19
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
19
|
|
|
21
20
|
// src/index.tsx
|
|
22
|
-
var
|
|
23
|
-
__export(
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
24
23
|
Input: () => Input,
|
|
25
24
|
Select: () => Select,
|
|
26
|
-
TextEditor: () => TextEditor,
|
|
27
25
|
Textarea: () => Textarea,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
assertCodecLaws: () => assertCodecLaws,
|
|
27
|
+
assertLensLaws: () => assertLensLaws,
|
|
28
|
+
createRender: () => createRender,
|
|
29
|
+
createRenderWithStore: () => createRenderWithStore,
|
|
30
|
+
defineBinding: () => defineBinding,
|
|
31
|
+
defineCodec: () => defineCodec,
|
|
32
|
+
defineLens: () => defineLens,
|
|
33
|
+
err: () => import_gw_result2.err,
|
|
34
|
+
ok: () => import_gw_result2.ok,
|
|
35
|
+
stateLens: () => stateLens,
|
|
36
|
+
useStoreBinding: () => useStoreBinding,
|
|
37
|
+
useStoreHTMLElement: () => useStoreHTMLElement,
|
|
31
38
|
useStoreInput: () => useStoreInput,
|
|
32
39
|
useStoreInputWithName: () => useStoreInputWithName
|
|
33
40
|
});
|
|
34
|
-
module.exports = __toCommonJS(
|
|
41
|
+
module.exports = __toCommonJS(src_exports);
|
|
35
42
|
|
|
36
|
-
// src/
|
|
37
|
-
var
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
(state) => {
|
|
54
|
-
props.onDispatch(state);
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
key: dispatchKey
|
|
58
|
-
}
|
|
59
|
-
);
|
|
43
|
+
// src/store/create_render.tsx
|
|
44
|
+
var import_gw_store = require("gw-store");
|
|
45
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
46
|
+
function createRender(store, selector, compare) {
|
|
47
|
+
function Component() {
|
|
48
|
+
const result = (0, import_gw_store.useSelector)(store, (state) => state, compare);
|
|
49
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: selector(result) });
|
|
50
|
+
}
|
|
51
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, {});
|
|
52
|
+
}
|
|
53
|
+
function createRenderWithStore(store) {
|
|
54
|
+
return function createRender2(selector, compare) {
|
|
55
|
+
function Component() {
|
|
56
|
+
const result = (0, import_gw_store.useSelector)(store, (state) => state, compare);
|
|
57
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: selector(result) });
|
|
58
|
+
}
|
|
59
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, {});
|
|
60
60
|
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/binding/lens.ts
|
|
64
|
+
function defineLens(lens) {
|
|
65
|
+
return lens;
|
|
66
|
+
}
|
|
67
|
+
function readPath(value, path) {
|
|
68
|
+
return path.reduce((current, key) => current[key], value);
|
|
69
|
+
}
|
|
70
|
+
function writePath(state, path, value) {
|
|
71
|
+
const parent = path.slice(0, -1).reduce((current, key) => current[key], state);
|
|
72
|
+
parent[path.at(-1)] = value;
|
|
73
|
+
}
|
|
74
|
+
function createPathLens(path) {
|
|
75
|
+
return {
|
|
76
|
+
get: (state) => readPath(state, path),
|
|
77
|
+
set: (state, value) => writePath(state, path, value),
|
|
78
|
+
prop: (key) => createPathLens([...path, key])
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function stateLens() {
|
|
61
82
|
return {
|
|
62
|
-
|
|
83
|
+
prop: (key) => createPathLens([key])
|
|
63
84
|
};
|
|
64
85
|
}
|
|
65
86
|
|
|
66
|
-
// src/
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
87
|
+
// src/binding/codec.ts
|
|
88
|
+
function defineCodec(codec) {
|
|
89
|
+
return codec;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/binding/binding.ts
|
|
93
|
+
function defineBinding(binding) {
|
|
94
|
+
return binding;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/binding/laws.ts
|
|
98
|
+
var import_immer = require("immer");
|
|
99
|
+
function structuralEqual(previous, next) {
|
|
100
|
+
if (Object.is(previous, next)) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
if (previous instanceof Date && next instanceof Date) {
|
|
104
|
+
return previous.getTime() === next.getTime();
|
|
105
|
+
}
|
|
106
|
+
if (Array.isArray(previous) && Array.isArray(next)) {
|
|
107
|
+
return previous.length === next.length && previous.every((value, index) => structuralEqual(value, next[index]));
|
|
108
|
+
}
|
|
109
|
+
if (previous !== null && next !== null && typeof previous === "object" && typeof next === "object") {
|
|
110
|
+
const previousRecord = previous;
|
|
111
|
+
const nextRecord = next;
|
|
112
|
+
const previousKeys = Reflect.ownKeys(previousRecord);
|
|
113
|
+
const nextKeys = Reflect.ownKeys(nextRecord);
|
|
114
|
+
return previousKeys.length === nextKeys.length && previousKeys.every(
|
|
115
|
+
(key) => Object.prototype.hasOwnProperty.call(nextRecord, key) && structuralEqual(previousRecord[key], nextRecord[key])
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
function assertLensLaws(lens, options) {
|
|
121
|
+
const equalsState = options.equalsState ?? structuralEqual;
|
|
122
|
+
const equalsValue = options.equalsValue ?? structuralEqual;
|
|
123
|
+
const set = (state, value) => (0, import_immer.produce)(state, (draft) => lens.set(draft, value));
|
|
124
|
+
if (!equalsState(set(options.state, lens.get(options.state)), options.state)) {
|
|
125
|
+
throw new Error("Lens law failed: setting the current value changed state.");
|
|
126
|
+
}
|
|
127
|
+
for (const value of options.values) {
|
|
128
|
+
const updated = set(options.state, value);
|
|
129
|
+
if (!equalsValue(lens.get(updated), value)) {
|
|
130
|
+
throw new Error("Lens law failed: get(set(state, value)) !== value.");
|
|
72
131
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
132
|
+
}
|
|
133
|
+
for (const previous of options.values) {
|
|
134
|
+
for (const next of options.values) {
|
|
135
|
+
if (!equalsState(set(set(options.state, previous), next), set(options.state, next))) {
|
|
136
|
+
throw new Error("Lens law failed: the last set did not win.");
|
|
77
137
|
}
|
|
78
138
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return toInputValue(props.getter(store.state));
|
|
89
|
-
};
|
|
90
|
-
const toInputChecked = (value) => {
|
|
91
|
-
if (props.type === "radio") {
|
|
92
|
-
return value !== void 0 && value === props.value;
|
|
93
|
-
}
|
|
94
|
-
return Boolean(value);
|
|
95
|
-
};
|
|
96
|
-
const getDefaultChecked = () => {
|
|
97
|
-
if (props.defaultChecked) {
|
|
98
|
-
return props.defaultChecked;
|
|
99
|
-
}
|
|
100
|
-
if (props.type !== "checkbox" && props.type !== "radio") {
|
|
101
|
-
return void 0;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function assertCodecLaws(codec, options) {
|
|
142
|
+
const equals = options.equals ?? codec.equals ?? structuralEqual;
|
|
143
|
+
const equalsInput = options.equalsInput ?? structuralEqual;
|
|
144
|
+
for (const value of options.values) {
|
|
145
|
+
const result = codec.parse(codec.format(value));
|
|
146
|
+
if (result.isErr) {
|
|
147
|
+
throw new Error("Codec law failed: parse(format(value)) returned Err.");
|
|
102
148
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const toStateValue = props.toStateValue || ((value) => {
|
|
106
|
-
if (props.type === "number" || props.type === "range") {
|
|
107
|
-
return Number(value);
|
|
149
|
+
if (!equals(result.value, value)) {
|
|
150
|
+
throw new Error("Codec law failed: parse(format(value)) !== value.");
|
|
108
151
|
}
|
|
109
|
-
|
|
110
|
-
|
|
152
|
+
}
|
|
153
|
+
for (const input of options.inputs ?? []) {
|
|
154
|
+
const result = codec.parse(input);
|
|
155
|
+
if (result.isOk && !equalsInput(codec.format(result.value), input)) {
|
|
156
|
+
throw new Error("Codec law failed: format(parse(input).value) !== input.");
|
|
111
157
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/binding/use_store_binding.tsx
|
|
162
|
+
var import_react = require("react");
|
|
163
|
+
function equalStoreValue(previous, next) {
|
|
164
|
+
if (Object.is(previous, next)) {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
if (previous instanceof Date && next instanceof Date) {
|
|
168
|
+
return Object.is(previous.getTime(), next.getTime());
|
|
169
|
+
}
|
|
170
|
+
if (Array.isArray(previous) && Array.isArray(next)) {
|
|
171
|
+
return previous.length === next.length && previous.every((value, index) => Object.is(value, next[index]));
|
|
172
|
+
}
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
function useStoreBinding(store, binding, options = {}) {
|
|
176
|
+
const dispatchKey = (0, import_react.useId)();
|
|
177
|
+
const [initialValue] = (0, import_react.useState)(() => binding.codec.format(binding.lens.get(store.state)));
|
|
178
|
+
const [meta, setMeta] = (0, import_react.useState)({ valid: true });
|
|
179
|
+
const metaRef = (0, import_react.useRef)(meta);
|
|
180
|
+
const optionsRef = (0, import_react.useRef)(options);
|
|
181
|
+
const subscribedStoreRef = (0, import_react.useRef)(null);
|
|
182
|
+
const subscribedBindingRef = (0, import_react.useRef)(binding);
|
|
183
|
+
(0, import_react.useEffect)(() => {
|
|
184
|
+
optionsRef.current = options;
|
|
185
|
+
}, [options]);
|
|
186
|
+
(0, import_react.useEffect)(() => {
|
|
187
|
+
const isReplacement = subscribedStoreRef.current !== null && (subscribedStoreRef.current !== store || subscribedBindingRef.current !== binding);
|
|
188
|
+
subscribedStoreRef.current = store;
|
|
189
|
+
subscribedBindingRef.current = binding;
|
|
190
|
+
const sync = (state) => {
|
|
191
|
+
if (!metaRef.current.valid) {
|
|
118
192
|
return;
|
|
119
193
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
} else {
|
|
127
|
-
const value = toInputValue(props.getter(state));
|
|
128
|
-
if (element.value === value) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
element.value = value;
|
|
194
|
+
const value = binding.lens.get(state);
|
|
195
|
+
optionsRef.current.onStoreChange?.(binding.codec.format(value), value);
|
|
196
|
+
};
|
|
197
|
+
const unsubscribe = store.subscribe((state, key) => {
|
|
198
|
+
if (key !== dispatchKey) {
|
|
199
|
+
sync(state);
|
|
132
200
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
201
|
+
});
|
|
202
|
+
if (isReplacement) {
|
|
203
|
+
sync(store.state);
|
|
204
|
+
}
|
|
205
|
+
return unsubscribe;
|
|
206
|
+
}, [binding, dispatchKey, store]);
|
|
207
|
+
const setValue = (0, import_react.useCallback)(
|
|
208
|
+
(value) => {
|
|
209
|
+
const currentValue = binding.lens.get(store.state);
|
|
210
|
+
const equals = binding.codec.equals ?? equalStoreValue;
|
|
211
|
+
if (equals(currentValue, value)) {
|
|
139
212
|
return;
|
|
140
213
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
214
|
+
store.dispatch((state) => binding.lens.set(state, value), { key: dispatchKey });
|
|
215
|
+
},
|
|
216
|
+
[binding, dispatchKey, store]
|
|
217
|
+
);
|
|
218
|
+
const commit = (0, import_react.useCallback)(
|
|
219
|
+
(input) => {
|
|
220
|
+
const result = binding.codec.parse(input);
|
|
221
|
+
if (result.isErr) {
|
|
222
|
+
const invalidMeta = {
|
|
223
|
+
valid: false,
|
|
224
|
+
error: result.error
|
|
225
|
+
};
|
|
226
|
+
metaRef.current = invalidMeta;
|
|
227
|
+
setMeta(invalidMeta);
|
|
228
|
+
return result;
|
|
145
229
|
}
|
|
146
|
-
|
|
147
|
-
|
|
230
|
+
const validMeta = { valid: true };
|
|
231
|
+
metaRef.current = validMeta;
|
|
232
|
+
setMeta((current) => current.valid ? current : validMeta);
|
|
233
|
+
setValue(result.value);
|
|
234
|
+
return result;
|
|
235
|
+
},
|
|
236
|
+
[binding, setValue]
|
|
237
|
+
);
|
|
238
|
+
const reset = (0, import_react.useCallback)(
|
|
239
|
+
(value) => {
|
|
240
|
+
const validMeta = { valid: true };
|
|
241
|
+
metaRef.current = validMeta;
|
|
242
|
+
setMeta((current) => current.valid ? current : validMeta);
|
|
243
|
+
setValue(value);
|
|
244
|
+
},
|
|
245
|
+
[setValue]
|
|
246
|
+
);
|
|
148
247
|
return {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
props.onChange?.(event);
|
|
154
|
-
}
|
|
248
|
+
initialValue,
|
|
249
|
+
meta,
|
|
250
|
+
commit,
|
|
251
|
+
reset
|
|
155
252
|
};
|
|
156
253
|
}
|
|
157
254
|
|
|
158
|
-
// src/
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
255
|
+
// src/html_element/use_store_html_element.tsx
|
|
256
|
+
var import_react2 = require("react");
|
|
257
|
+
|
|
258
|
+
// src/html_element/dom_value.ts
|
|
259
|
+
function pad(value) {
|
|
260
|
+
return String(value).padStart(2, "0");
|
|
261
|
+
}
|
|
262
|
+
function formatDateTimeLocal(value) {
|
|
263
|
+
const date = new Date(value);
|
|
264
|
+
if (Number.isNaN(date.getTime())) {
|
|
265
|
+
return "";
|
|
266
|
+
}
|
|
267
|
+
return [
|
|
268
|
+
date.getFullYear(),
|
|
269
|
+
"-",
|
|
270
|
+
pad(date.getMonth() + 1),
|
|
271
|
+
"-",
|
|
272
|
+
pad(date.getDate()),
|
|
273
|
+
"T",
|
|
274
|
+
pad(date.getHours()),
|
|
275
|
+
":",
|
|
276
|
+
pad(date.getMinutes()),
|
|
277
|
+
":",
|
|
278
|
+
pad(date.getSeconds())
|
|
279
|
+
].join("");
|
|
280
|
+
}
|
|
281
|
+
function readElementValue(element) {
|
|
282
|
+
if ("options" in element && element.multiple) {
|
|
283
|
+
return Array.from(element.selectedOptions, (option) => option.value);
|
|
284
|
+
}
|
|
285
|
+
return element.value;
|
|
286
|
+
}
|
|
287
|
+
function writeElementValue(element, value) {
|
|
288
|
+
if ("files" in element && element.type === "file") {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if ("options" in element && element.multiple) {
|
|
292
|
+
const selectedValues = new Set((Array.isArray(value) ? value : [value]).map(String));
|
|
293
|
+
for (const option of element.options) {
|
|
294
|
+
const selected = selectedValues.has(option.value);
|
|
295
|
+
if (option.selected !== selected) {
|
|
296
|
+
option.selected = selected;
|
|
172
297
|
}
|
|
173
|
-
state[props.name] = value;
|
|
174
298
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const nextValue = String(value);
|
|
302
|
+
if (element.value !== nextValue) {
|
|
303
|
+
element.value = nextValue;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// src/html_element/reset_coordinator.ts
|
|
308
|
+
var resettingForms = /* @__PURE__ */ new WeakSet();
|
|
309
|
+
var resetCoordinators = /* @__PURE__ */ new WeakMap();
|
|
310
|
+
function isFormResetting(form) {
|
|
311
|
+
return resettingForms.has(form);
|
|
312
|
+
}
|
|
313
|
+
function registerResetBinding(form, batch, reset) {
|
|
314
|
+
let coordinator = resetCoordinators.get(form);
|
|
315
|
+
if (!coordinator) {
|
|
316
|
+
const groups = /* @__PURE__ */ new Map();
|
|
317
|
+
const handleReset = () => {
|
|
318
|
+
resettingForms.add(form);
|
|
319
|
+
const groupSnapshots = Array.from(groups, ([groupBatch, bindings2]) => [groupBatch, [...bindings2]]);
|
|
320
|
+
setTimeout(() => {
|
|
321
|
+
try {
|
|
322
|
+
for (const [groupBatch, bindings2] of groupSnapshots) {
|
|
323
|
+
groupBatch(() => {
|
|
324
|
+
for (const binding of bindings2) {
|
|
325
|
+
binding();
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
} finally {
|
|
330
|
+
setTimeout(() => resettingForms.delete(form), 0);
|
|
331
|
+
}
|
|
332
|
+
}, 0);
|
|
333
|
+
};
|
|
334
|
+
coordinator = { groups, handleReset };
|
|
335
|
+
resetCoordinators.set(form, coordinator);
|
|
336
|
+
form.addEventListener("reset", handleReset);
|
|
337
|
+
}
|
|
338
|
+
let bindings = coordinator.groups.get(batch);
|
|
339
|
+
if (!bindings) {
|
|
340
|
+
bindings = /* @__PURE__ */ new Set();
|
|
341
|
+
coordinator.groups.set(batch, bindings);
|
|
342
|
+
}
|
|
343
|
+
bindings.add(reset);
|
|
344
|
+
return () => {
|
|
345
|
+
const currentCoordinator = resetCoordinators.get(form);
|
|
346
|
+
if (!currentCoordinator) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const currentBindings = currentCoordinator.groups.get(batch);
|
|
350
|
+
currentBindings?.delete(reset);
|
|
351
|
+
if (currentBindings?.size === 0) {
|
|
352
|
+
currentCoordinator.groups.delete(batch);
|
|
353
|
+
}
|
|
354
|
+
if (currentCoordinator.groups.size === 0) {
|
|
355
|
+
form.removeEventListener("reset", currentCoordinator.handleReset);
|
|
356
|
+
resetCoordinators.delete(form);
|
|
357
|
+
}
|
|
179
358
|
};
|
|
180
359
|
}
|
|
181
360
|
|
|
182
|
-
// src/
|
|
183
|
-
|
|
361
|
+
// src/html_element/value_conversion.ts
|
|
362
|
+
function convertToInputValue(value, type) {
|
|
363
|
+
if (value === void 0 || value === null) {
|
|
364
|
+
return "";
|
|
365
|
+
}
|
|
366
|
+
if (type === "datetime-local") {
|
|
367
|
+
return formatDateTimeLocal(value);
|
|
368
|
+
}
|
|
369
|
+
return Array.isArray(value) ? value.map(String) : String(value);
|
|
370
|
+
}
|
|
371
|
+
function convertToStateValue(value, type) {
|
|
372
|
+
if (Array.isArray(value)) {
|
|
373
|
+
return value;
|
|
374
|
+
}
|
|
375
|
+
if (type === "number" || type === "range") {
|
|
376
|
+
return value === "" ? void 0 : Number(value);
|
|
377
|
+
}
|
|
378
|
+
if (type === "datetime-local") {
|
|
379
|
+
if (value === "") {
|
|
380
|
+
return void 0;
|
|
381
|
+
}
|
|
382
|
+
const date = new Date(value);
|
|
383
|
+
return Number.isNaN(date.getTime()) ? void 0 : date;
|
|
384
|
+
}
|
|
385
|
+
return value;
|
|
386
|
+
}
|
|
387
|
+
function resolveDefaultValue(props, stateValue, format) {
|
|
388
|
+
if (props.type !== "radio" && props.value !== void 0) {
|
|
389
|
+
return void 0;
|
|
390
|
+
}
|
|
391
|
+
if (props.defaultValue !== void 0) {
|
|
392
|
+
return props.defaultValue;
|
|
393
|
+
}
|
|
394
|
+
if (props.type === "checkbox" || props.type === "radio" || props.type === "file") {
|
|
395
|
+
return void 0;
|
|
396
|
+
}
|
|
397
|
+
return format(stateValue);
|
|
398
|
+
}
|
|
399
|
+
function resolveDefaultChecked(props, stateValue, toChecked) {
|
|
400
|
+
if (props.checked !== void 0) {
|
|
401
|
+
return void 0;
|
|
402
|
+
}
|
|
403
|
+
if (props.defaultChecked !== void 0) {
|
|
404
|
+
return props.defaultChecked;
|
|
405
|
+
}
|
|
406
|
+
return props.type === "checkbox" || props.type === "radio" ? toChecked(stateValue) : void 0;
|
|
407
|
+
}
|
|
408
|
+
function resolveResetStateValue(props, stateValue, parse) {
|
|
409
|
+
if (props.type === "checkbox" && props.defaultChecked !== void 0) {
|
|
410
|
+
return props.defaultChecked;
|
|
411
|
+
}
|
|
412
|
+
if (props.type === "radio" && props.defaultChecked) {
|
|
413
|
+
if (props.value !== void 0) {
|
|
414
|
+
return props.value;
|
|
415
|
+
}
|
|
416
|
+
return convertToStateValue(String(props.defaultValue ?? ""), props.type);
|
|
417
|
+
}
|
|
418
|
+
if (props.type !== "file" && props.type !== "checkbox" && props.type !== "radio" && props.defaultValue !== void 0) {
|
|
419
|
+
const defaultValue = Array.isArray(props.defaultValue) ? props.defaultValue.map(String) : String(props.defaultValue);
|
|
420
|
+
return parse(defaultValue);
|
|
421
|
+
}
|
|
422
|
+
return stateValue;
|
|
423
|
+
}
|
|
184
424
|
|
|
185
|
-
// src/
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
function
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
425
|
+
// src/html_element/use_store_html_element.tsx
|
|
426
|
+
function isDisplayValue(value) {
|
|
427
|
+
return typeof value === "string" || typeof value === "number" || Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
428
|
+
}
|
|
429
|
+
function readControlValue(element, type, radioValue) {
|
|
430
|
+
if ("files" in element && type === "file") {
|
|
431
|
+
return element.files?.length ? element.files : null;
|
|
432
|
+
}
|
|
433
|
+
if ("checked" in element && type === "checkbox") {
|
|
434
|
+
return element.checked;
|
|
435
|
+
}
|
|
436
|
+
if ("checked" in element && type === "radio") {
|
|
437
|
+
return element.checked ? radioValue ?? element.value : void 0;
|
|
438
|
+
}
|
|
439
|
+
return readElementValue(element);
|
|
440
|
+
}
|
|
441
|
+
function useStoreHTMLElement(ref, store, binding, options = {}) {
|
|
442
|
+
const props = options;
|
|
443
|
+
const getStateValue = binding.lens.get;
|
|
444
|
+
const formatValue = (0, import_react2.useCallback)((value) => binding.codec.format(value), [binding]);
|
|
445
|
+
const toChecked = (0, import_react2.useCallback)(
|
|
446
|
+
(value) => props.type === "radio" ? Object.is(formatValue(value), props.value) : Boolean(formatValue(value)),
|
|
447
|
+
[formatValue, props.type, props.value]
|
|
203
448
|
);
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
449
|
+
const initialStateValue = getStateValue(store.state);
|
|
450
|
+
const resetValueRef = (0, import_react2.useRef)(
|
|
451
|
+
Object.prototype.hasOwnProperty.call(options, "resetValue") ? options.resetValue : initialStateValue
|
|
452
|
+
);
|
|
453
|
+
const writeValue = (0, import_react2.useCallback)(
|
|
454
|
+
(element, value) => {
|
|
455
|
+
if ("checked" in element && (props.type === "checkbox" || props.type === "radio")) {
|
|
456
|
+
element.checked = toChecked(value);
|
|
208
457
|
return;
|
|
209
458
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
return "";
|
|
218
|
-
};
|
|
219
|
-
const result = getResult();
|
|
220
|
-
if (controller.value !== result) {
|
|
221
|
-
controller.value = result;
|
|
459
|
+
if ("files" in element && props.type === "file") {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const formatted = formatValue(value);
|
|
463
|
+
if (isDisplayValue(formatted)) {
|
|
464
|
+
writeElementValue(element, formatted);
|
|
222
465
|
}
|
|
223
466
|
},
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
467
|
+
[formatValue, props.type, toChecked]
|
|
468
|
+
);
|
|
469
|
+
const { commit, meta, reset } = useStoreBinding(store, binding, {
|
|
470
|
+
onStoreChange: (_input, value) => {
|
|
471
|
+
const element = ref.current;
|
|
472
|
+
if (!element || element.form && isFormResetting(element.form) || props.type !== "radio" && props.value !== void 0) {
|
|
227
473
|
return;
|
|
228
474
|
}
|
|
229
|
-
if (
|
|
230
|
-
setter(state, controller.value);
|
|
475
|
+
if ("checked" in element && (props.type === "checkbox" || props.type === "radio") && props.checked !== void 0) {
|
|
231
476
|
return;
|
|
232
477
|
}
|
|
233
|
-
|
|
234
|
-
state[name] = controller.value;
|
|
235
|
-
}
|
|
478
|
+
writeValue(element, value);
|
|
236
479
|
}
|
|
237
480
|
});
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
return store.state[name];
|
|
481
|
+
(0, import_react2.useEffect)(() => {
|
|
482
|
+
const element = ref.current;
|
|
483
|
+
const form = element?.form;
|
|
484
|
+
if (!element || !form) {
|
|
485
|
+
return;
|
|
244
486
|
}
|
|
245
|
-
return
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
487
|
+
return registerResetBinding(form, store.batch, () => {
|
|
488
|
+
if (!element.isConnected) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
const resetValue = resetValueRef.current;
|
|
492
|
+
const writeResetValue = () => writeValue(element, resetValue);
|
|
493
|
+
writeResetValue();
|
|
494
|
+
reset(resetValue);
|
|
495
|
+
setTimeout(() => {
|
|
496
|
+
if (element.isConnected) {
|
|
497
|
+
writeResetValue();
|
|
498
|
+
}
|
|
499
|
+
}, 0);
|
|
500
|
+
});
|
|
501
|
+
}, [ref, reset, store.batch, writeValue]);
|
|
502
|
+
const inputProps = {
|
|
503
|
+
defaultValue: resolveDefaultValue(props, initialStateValue, (value) => {
|
|
504
|
+
const formatted = formatValue(value);
|
|
505
|
+
return isDisplayValue(formatted) ? formatted : "";
|
|
506
|
+
}),
|
|
507
|
+
defaultChecked: resolveDefaultChecked(props, initialStateValue, toChecked),
|
|
508
|
+
onChange: (event) => {
|
|
509
|
+
const element = ref.current;
|
|
510
|
+
if (element) {
|
|
511
|
+
const controlValue = readControlValue(element, props.type, props.value);
|
|
512
|
+
if (controlValue !== void 0) {
|
|
513
|
+
commit(controlValue);
|
|
514
|
+
}
|
|
256
515
|
}
|
|
516
|
+
props.onChange?.(event);
|
|
257
517
|
}
|
|
258
|
-
|
|
518
|
+
};
|
|
519
|
+
return { inputProps, meta };
|
|
259
520
|
}
|
|
260
521
|
|
|
261
|
-
// src/
|
|
262
|
-
var
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
522
|
+
// src/html_element/use_store_input_with_name.tsx
|
|
523
|
+
var import_react3 = require("react");
|
|
524
|
+
var import_gw_result = require("gw-result");
|
|
525
|
+
function formatControlValue(value, type) {
|
|
526
|
+
if (type === "checkbox") {
|
|
527
|
+
return Boolean(value);
|
|
528
|
+
}
|
|
529
|
+
if (type === "radio" || type === "file") {
|
|
530
|
+
return value;
|
|
531
|
+
}
|
|
532
|
+
return convertToInputValue(value, type);
|
|
533
|
+
}
|
|
534
|
+
function parseControlValue(value, type) {
|
|
535
|
+
if (typeof value === "string" || Array.isArray(value)) {
|
|
536
|
+
const stateInputValue = Array.isArray(value) ? [...value] : value;
|
|
537
|
+
return convertToStateValue(stateInputValue, type);
|
|
538
|
+
}
|
|
539
|
+
return value;
|
|
540
|
+
}
|
|
541
|
+
function useStoreInputWithName(ref, store, props) {
|
|
542
|
+
const binding = (0, import_react3.useMemo)(
|
|
543
|
+
() => ({
|
|
544
|
+
lens: {
|
|
545
|
+
get: (state) => state[props.name],
|
|
546
|
+
set: (state, value) => {
|
|
547
|
+
state[props.name] = value;
|
|
548
|
+
}
|
|
549
|
+
},
|
|
550
|
+
codec: {
|
|
551
|
+
format: (value) => formatControlValue(value, props.type),
|
|
552
|
+
parse: (value) => (0, import_gw_result.ok)(parseControlValue(value, props.type))
|
|
553
|
+
}
|
|
554
|
+
}),
|
|
555
|
+
[props.name, props.type]
|
|
556
|
+
);
|
|
557
|
+
const initialStateValue = binding.lens.get(store.state);
|
|
558
|
+
const resetValue = resolveResetStateValue(
|
|
559
|
+
props,
|
|
560
|
+
initialStateValue,
|
|
561
|
+
(value) => parseControlValue(value, props.type)
|
|
562
|
+
);
|
|
563
|
+
const { inputProps } = useStoreHTMLElement(ref, store, binding, {
|
|
564
|
+
...props,
|
|
565
|
+
resetValue
|
|
566
|
+
});
|
|
276
567
|
return {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
textarea,
|
|
280
|
-
textEditor
|
|
568
|
+
...inputProps,
|
|
569
|
+
name: String(props.name)
|
|
281
570
|
};
|
|
282
571
|
}
|
|
572
|
+
|
|
573
|
+
// src/input/store_input.tsx
|
|
574
|
+
var import_react4 = require("react");
|
|
575
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
283
576
|
function Input({
|
|
284
577
|
store,
|
|
285
|
-
getter,
|
|
286
|
-
setter,
|
|
287
|
-
toInputValue,
|
|
288
|
-
toStateValue,
|
|
289
578
|
...props
|
|
290
579
|
}) {
|
|
291
|
-
const ref = (0,
|
|
292
|
-
const storeProps = useStoreInputWithName(ref, store,
|
|
293
|
-
...props,
|
|
294
|
-
getter,
|
|
295
|
-
setter,
|
|
296
|
-
toInputValue,
|
|
297
|
-
toStateValue
|
|
298
|
-
});
|
|
580
|
+
const ref = (0, import_react4.useRef)(null);
|
|
581
|
+
const storeProps = useStoreInputWithName(ref, store, props);
|
|
299
582
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { ref, ...props, ...storeProps });
|
|
300
583
|
}
|
|
301
584
|
function Select({
|
|
302
585
|
store,
|
|
303
|
-
getter,
|
|
304
|
-
setter,
|
|
305
|
-
toInputValue,
|
|
306
|
-
toStateValue,
|
|
307
586
|
...props
|
|
308
587
|
}) {
|
|
309
|
-
const ref = (0,
|
|
310
|
-
const storeProps = useStoreInputWithName(ref, store,
|
|
311
|
-
...props,
|
|
312
|
-
getter,
|
|
313
|
-
setter,
|
|
314
|
-
toInputValue,
|
|
315
|
-
toStateValue
|
|
316
|
-
});
|
|
588
|
+
const ref = (0, import_react4.useRef)(null);
|
|
589
|
+
const storeProps = useStoreInputWithName(ref, store, props);
|
|
317
590
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("select", { ref, ...props, ...storeProps });
|
|
318
591
|
}
|
|
319
592
|
function Textarea({
|
|
320
593
|
store,
|
|
321
|
-
getter,
|
|
322
|
-
setter,
|
|
323
|
-
toInputValue,
|
|
324
|
-
toStateValue,
|
|
325
594
|
...props
|
|
326
595
|
}) {
|
|
327
|
-
const ref = (0,
|
|
328
|
-
const storeProps = useStoreInputWithName(ref, store,
|
|
329
|
-
...props,
|
|
330
|
-
getter,
|
|
331
|
-
setter,
|
|
332
|
-
toInputValue,
|
|
333
|
-
toStateValue
|
|
334
|
-
});
|
|
596
|
+
const ref = (0, import_react4.useRef)(null);
|
|
597
|
+
const storeProps = useStoreInputWithName(ref, store, props);
|
|
335
598
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("textarea", { ref, ...props, ...storeProps });
|
|
336
599
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
function createRenderWithStore(store) {
|
|
342
|
-
return function createRender(selector, compare) {
|
|
343
|
-
function Component() {
|
|
344
|
-
const result = (0, import_gw_store.useSelector)(store, (state) => state, compare);
|
|
345
|
-
const content = selector(result);
|
|
346
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: content });
|
|
347
|
-
}
|
|
348
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Component, {});
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// src/use_form_store.tsx
|
|
353
|
-
var import_gw_store2 = require("gw-store");
|
|
354
|
-
function useFormStore(initialState) {
|
|
355
|
-
const store = (0, import_gw_store2.useStore)(initialState);
|
|
356
|
-
const storeComponent = useStoreComponent(store);
|
|
357
|
-
return {
|
|
358
|
-
get state() {
|
|
359
|
-
return store.state;
|
|
600
|
+
function useStoreInput(store) {
|
|
601
|
+
const input = (0, import_react4.useCallback)(
|
|
602
|
+
function Component(props) {
|
|
603
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Input, { store, ...props });
|
|
360
604
|
},
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
605
|
+
[store]
|
|
606
|
+
);
|
|
607
|
+
const select = (0, import_react4.useCallback)(
|
|
608
|
+
function Component(props) {
|
|
609
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Select, { store, ...props });
|
|
610
|
+
},
|
|
611
|
+
[store]
|
|
612
|
+
);
|
|
613
|
+
const textarea = (0, import_react4.useCallback)(
|
|
614
|
+
function Component(props) {
|
|
615
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Textarea, { store, ...props });
|
|
616
|
+
},
|
|
617
|
+
[store]
|
|
618
|
+
);
|
|
619
|
+
return { input, select, textarea };
|
|
366
620
|
}
|
|
367
621
|
|
|
368
622
|
// src/index.tsx
|
|
369
|
-
|
|
623
|
+
var import_gw_result2 = require("gw-result");
|
|
370
624
|
// Annotate the CommonJS export names for ESM import in node:
|
|
371
625
|
0 && (module.exports = {
|
|
372
626
|
Input,
|
|
373
627
|
Select,
|
|
374
|
-
TextEditor,
|
|
375
628
|
Textarea,
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
629
|
+
assertCodecLaws,
|
|
630
|
+
assertLensLaws,
|
|
631
|
+
createRender,
|
|
632
|
+
createRenderWithStore,
|
|
633
|
+
defineBinding,
|
|
634
|
+
defineCodec,
|
|
635
|
+
defineLens,
|
|
636
|
+
err,
|
|
637
|
+
ok,
|
|
638
|
+
stateLens,
|
|
639
|
+
useStoreBinding,
|
|
640
|
+
useStoreHTMLElement,
|
|
379
641
|
useStoreInput,
|
|
380
|
-
useStoreInputWithName
|
|
381
|
-
...require("gw-store")
|
|
642
|
+
useStoreInputWithName
|
|
382
643
|
});
|
|
644
|
+
//# sourceMappingURL=index.js.map
|