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