react-store-input 0.2.6 → 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 +127 -10
- package/dist/index.d.ts +127 -10
- package/dist/index.js +554 -249
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +549 -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
|
@@ -19,337 +19,630 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
|
|
|
19
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
20
|
|
|
21
21
|
// src/index.tsx
|
|
22
|
-
var
|
|
23
|
-
__export(
|
|
22
|
+
var src_exports = {};
|
|
23
|
+
__export(src_exports, {
|
|
24
24
|
Input: () => Input,
|
|
25
25
|
Select: () => Select,
|
|
26
|
-
TextEditor: () => TextEditor,
|
|
27
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,
|
|
28
37
|
useFormStore: () => useFormStore,
|
|
29
38
|
useStoreComponent: () => useStoreComponent,
|
|
30
39
|
useStoreController: () => useStoreController,
|
|
31
40
|
useStoreInput: () => useStoreInput,
|
|
32
41
|
useStoreInputWithName: () => useStoreInputWithName
|
|
33
42
|
});
|
|
34
|
-
module.exports = __toCommonJS(
|
|
43
|
+
module.exports = __toCommonJS(src_exports);
|
|
35
44
|
|
|
36
|
-
// src/use_store_controller.tsx
|
|
45
|
+
// src/store/use_store_controller.tsx
|
|
37
46
|
var import_react = require("react");
|
|
38
47
|
function useStoreController(store, props) {
|
|
39
48
|
const dispatchKey = (0, import_react.useId)();
|
|
49
|
+
const propsRef = (0, import_react.useRef)(props);
|
|
50
|
+
const subscribedStoreRef = (0, import_react.useRef)(null);
|
|
40
51
|
(0, import_react.useEffect)(() => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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);
|
|
44
60
|
}
|
|
45
|
-
props.onSubscribe(state);
|
|
46
61
|
});
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
62
|
+
if (isReplacement) {
|
|
63
|
+
propsRef.current.onSubscribe(store.state);
|
|
64
|
+
}
|
|
65
|
+
return unsubscribe;
|
|
66
|
+
}, [dispatchKey, store]);
|
|
67
|
+
const dispatch = (0, import_react.useCallback)(() => {
|
|
52
68
|
store.dispatch(
|
|
53
|
-
(state) =>
|
|
54
|
-
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
key: dispatchKey
|
|
58
|
-
}
|
|
69
|
+
(state) => propsRef.current.onDispatch(state),
|
|
70
|
+
{ key: dispatchKey }
|
|
59
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, {});
|
|
60
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() {
|
|
61
121
|
return {
|
|
62
|
-
|
|
122
|
+
prop: (key) => createPathLens([key])
|
|
63
123
|
};
|
|
64
124
|
}
|
|
65
125
|
|
|
66
|
-
// src/
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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.");
|
|
72
173
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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.");
|
|
77
182
|
}
|
|
78
183
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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.");
|
|
84
193
|
}
|
|
85
|
-
if (
|
|
86
|
-
|
|
194
|
+
if (!equals(result.value, value)) {
|
|
195
|
+
throw new Error("Codec law failed: parse(format(value)) !== value.");
|
|
87
196
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (
|
|
92
|
-
|
|
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
|
+
);
|
|
93
204
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
+
}
|
|
99
253
|
}
|
|
100
|
-
|
|
101
|
-
|
|
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;
|
|
102
318
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return Number(value);
|
|
319
|
+
const currentBindings = currentCoordinator.groups.get(batch);
|
|
320
|
+
currentBindings?.delete(reset);
|
|
321
|
+
if (currentBindings?.size === 0) {
|
|
322
|
+
currentCoordinator.groups.delete(batch);
|
|
108
323
|
}
|
|
109
|
-
if (
|
|
110
|
-
|
|
324
|
+
if (currentCoordinator.groups.size === 0) {
|
|
325
|
+
form.removeEventListener("reset", currentCoordinator.handleReset);
|
|
326
|
+
resetCoordinators.delete(form);
|
|
111
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)) {
|
|
112
343
|
return value;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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)) {
|
|
118
440
|
return;
|
|
119
441
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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;
|
|
132
457
|
}
|
|
133
|
-
const
|
|
134
|
-
|
|
458
|
+
const validMeta = { valid: true };
|
|
459
|
+
metaRef.current = validMeta;
|
|
460
|
+
setMeta((current) => current.valid ? current : validMeta);
|
|
461
|
+
setStateValue(state, result.value);
|
|
135
462
|
},
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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);
|
|
139
469
|
return;
|
|
140
470
|
}
|
|
141
|
-
if ("
|
|
142
|
-
|
|
143
|
-
} else {
|
|
144
|
-
props.setter(state, toStateValue(element.value));
|
|
471
|
+
if ("files" in element && props.type === "file") {
|
|
472
|
+
return;
|
|
145
473
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
defaultValue: getDefaultValue(),
|
|
150
|
-
defaultChecked: getDefaultChecked(),
|
|
151
|
-
onChange: (event) => {
|
|
152
|
-
inputProps.dispatch();
|
|
153
|
-
props.onChange?.(event);
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// src/use_store_input_with_name.tsx
|
|
159
|
-
function useStoreInputWithName(ref, store, props) {
|
|
160
|
-
const inputProps = useStoreInput(ref, store, {
|
|
161
|
-
...props,
|
|
162
|
-
getter: (state) => {
|
|
163
|
-
if (props.getter) {
|
|
164
|
-
return props.getter(state);
|
|
474
|
+
const formatted = formatValue(value);
|
|
475
|
+
if (isDisplayValue(formatted)) {
|
|
476
|
+
writeElementValue(element, formatted);
|
|
165
477
|
}
|
|
166
|
-
return state[props.name];
|
|
167
478
|
},
|
|
168
|
-
|
|
169
|
-
if (props.setter) {
|
|
170
|
-
props.setter(state, value);
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
state[props.name] = value;
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
return {
|
|
177
|
-
...inputProps,
|
|
178
|
-
name: "name" in props ? String(props.name) : void 0
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// src/use_store_component.tsx
|
|
183
|
-
var import_react3 = require("react");
|
|
184
|
-
|
|
185
|
-
// src/text_editor.tsx
|
|
186
|
-
var import_gw_react_text_editor = require("gw-react-text-editor");
|
|
187
|
-
var import_react2 = require("react");
|
|
188
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
189
|
-
function TextEditor({
|
|
190
|
-
store,
|
|
191
|
-
name,
|
|
192
|
-
getter,
|
|
193
|
-
setter,
|
|
194
|
-
defaultValue,
|
|
195
|
-
ref,
|
|
196
|
-
...props
|
|
197
|
-
}) {
|
|
198
|
-
const controllerRef = (0, import_react2.useRef)(null);
|
|
199
|
-
(0, import_react2.useImperativeHandle)(
|
|
200
|
-
ref,
|
|
201
|
-
() => controllerRef.current,
|
|
202
|
-
[]
|
|
479
|
+
[formatValue, props.type, toChecked]
|
|
203
480
|
);
|
|
204
481
|
const { dispatch } = useStoreController(store, {
|
|
205
482
|
onSubscribe: (state) => {
|
|
206
|
-
const
|
|
207
|
-
if (!
|
|
483
|
+
const element = ref.current;
|
|
484
|
+
if (!element || !metaRef.current.valid || element.form && isFormResetting(element.form) || props.type !== "radio" && props.value !== void 0) {
|
|
208
485
|
return;
|
|
209
486
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return getter(state) || "";
|
|
213
|
-
}
|
|
214
|
-
if (name) {
|
|
215
|
-
return state[name] || "";
|
|
216
|
-
}
|
|
217
|
-
return "";
|
|
218
|
-
};
|
|
219
|
-
const result = getResult();
|
|
220
|
-
if (controller.value !== result) {
|
|
221
|
-
controller.value = result;
|
|
487
|
+
if ("checked" in element && (props.type === "checkbox" || props.type === "radio") && props.checked !== void 0) {
|
|
488
|
+
return;
|
|
222
489
|
}
|
|
490
|
+
writeValue(element, getStateValue(state));
|
|
223
491
|
},
|
|
224
492
|
onDispatch: (state) => {
|
|
225
|
-
const
|
|
226
|
-
if (!
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
if (setter) {
|
|
230
|
-
setter(state, controller.value);
|
|
493
|
+
const element = ref.current;
|
|
494
|
+
if (!element) {
|
|
231
495
|
return;
|
|
232
496
|
}
|
|
233
|
-
|
|
234
|
-
|
|
497
|
+
const controlValue = readControlValue(element, props.type, props.value);
|
|
498
|
+
if (controlValue !== void 0) {
|
|
499
|
+
commitValue(state, controlValue);
|
|
235
500
|
}
|
|
236
501
|
}
|
|
237
502
|
});
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
503
|
+
(0, import_react2.useEffect)(() => {
|
|
504
|
+
const element = ref.current;
|
|
505
|
+
const form = element?.form;
|
|
506
|
+
if (!element || !form) {
|
|
507
|
+
return;
|
|
241
508
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return void 0;
|
|
246
|
-
};
|
|
247
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
248
|
-
import_gw_react_text_editor.TextEditor,
|
|
249
|
-
{
|
|
250
|
-
...props,
|
|
251
|
-
ref: controllerRef,
|
|
252
|
-
defaultValue: defaultValue ?? getDefaultValue(),
|
|
253
|
-
onChange: (e) => {
|
|
254
|
-
dispatch();
|
|
255
|
-
props.onChange?.(e);
|
|
509
|
+
return registerResetBinding(form, store.batch, () => {
|
|
510
|
+
if (!element.isConnected) {
|
|
511
|
+
return;
|
|
256
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);
|
|
257
540
|
}
|
|
258
|
-
|
|
541
|
+
};
|
|
542
|
+
return { inputProps, meta };
|
|
259
543
|
}
|
|
260
544
|
|
|
261
|
-
// src/
|
|
262
|
-
var
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
+
});
|
|
276
590
|
return {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
textarea,
|
|
280
|
-
textEditor
|
|
591
|
+
...inputProps,
|
|
592
|
+
name: String(props.name)
|
|
281
593
|
};
|
|
282
594
|
}
|
|
595
|
+
|
|
596
|
+
// src/form/store_components.tsx
|
|
597
|
+
var import_react4 = require("react");
|
|
598
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
283
599
|
function Input({
|
|
284
600
|
store,
|
|
285
|
-
getter,
|
|
286
|
-
setter,
|
|
287
|
-
toInputValue,
|
|
288
|
-
toStateValue,
|
|
289
601
|
...props
|
|
290
602
|
}) {
|
|
291
|
-
const ref = (0,
|
|
292
|
-
const storeProps = useStoreInputWithName(ref, store,
|
|
293
|
-
...props,
|
|
294
|
-
getter,
|
|
295
|
-
setter,
|
|
296
|
-
toInputValue,
|
|
297
|
-
toStateValue
|
|
298
|
-
});
|
|
603
|
+
const ref = (0, import_react4.useRef)(null);
|
|
604
|
+
const storeProps = useStoreInputWithName(ref, store, props);
|
|
299
605
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { ref, ...props, ...storeProps });
|
|
300
606
|
}
|
|
301
607
|
function Select({
|
|
302
608
|
store,
|
|
303
|
-
getter,
|
|
304
|
-
setter,
|
|
305
|
-
toInputValue,
|
|
306
|
-
toStateValue,
|
|
307
609
|
...props
|
|
308
610
|
}) {
|
|
309
|
-
const ref = (0,
|
|
310
|
-
const storeProps = useStoreInputWithName(ref, store,
|
|
311
|
-
...props,
|
|
312
|
-
getter,
|
|
313
|
-
setter,
|
|
314
|
-
toInputValue,
|
|
315
|
-
toStateValue
|
|
316
|
-
});
|
|
611
|
+
const ref = (0, import_react4.useRef)(null);
|
|
612
|
+
const storeProps = useStoreInputWithName(ref, store, props);
|
|
317
613
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("select", { ref, ...props, ...storeProps });
|
|
318
614
|
}
|
|
319
615
|
function Textarea({
|
|
320
616
|
store,
|
|
321
|
-
getter,
|
|
322
|
-
setter,
|
|
323
|
-
toInputValue,
|
|
324
|
-
toStateValue,
|
|
325
617
|
...props
|
|
326
618
|
}) {
|
|
327
|
-
const ref = (0,
|
|
328
|
-
const storeProps = useStoreInputWithName(ref, store,
|
|
329
|
-
...props,
|
|
330
|
-
getter,
|
|
331
|
-
setter,
|
|
332
|
-
toInputValue,
|
|
333
|
-
toStateValue
|
|
334
|
-
});
|
|
619
|
+
const ref = (0, import_react4.useRef)(null);
|
|
620
|
+
const storeProps = useStoreInputWithName(ref, store, props);
|
|
335
621
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("textarea", { ref, ...props, ...storeProps });
|
|
336
622
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
return /* @__PURE__ */ (0,
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
|
|
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 };
|
|
350
643
|
}
|
|
351
644
|
|
|
352
|
-
// src/use_form_store.tsx
|
|
645
|
+
// src/form/use_form_store.tsx
|
|
353
646
|
var import_gw_store2 = require("gw-store");
|
|
354
647
|
function useFormStore(initialState) {
|
|
355
648
|
const store = (0, import_gw_store2.useStore)(initialState);
|
|
@@ -359,6 +652,7 @@ function useFormStore(initialState) {
|
|
|
359
652
|
return store.state;
|
|
360
653
|
},
|
|
361
654
|
dispatch: store.dispatch,
|
|
655
|
+
batch: store.batch,
|
|
362
656
|
subscribe: store.subscribe,
|
|
363
657
|
render: createRenderWithStore(store),
|
|
364
658
|
...storeComponent
|
|
@@ -366,13 +660,23 @@ function useFormStore(initialState) {
|
|
|
366
660
|
}
|
|
367
661
|
|
|
368
662
|
// src/index.tsx
|
|
369
|
-
|
|
663
|
+
var import_gw_result2 = require("gw-result");
|
|
664
|
+
__reExport(src_exports, require("gw-store"), module.exports);
|
|
370
665
|
// Annotate the CommonJS export names for ESM import in node:
|
|
371
666
|
0 && (module.exports = {
|
|
372
667
|
Input,
|
|
373
668
|
Select,
|
|
374
|
-
TextEditor,
|
|
375
669
|
Textarea,
|
|
670
|
+
assertCodecLaws,
|
|
671
|
+
assertLensLaws,
|
|
672
|
+
createRender,
|
|
673
|
+
createRenderWithStore,
|
|
674
|
+
defineBinding,
|
|
675
|
+
defineCodec,
|
|
676
|
+
defineLens,
|
|
677
|
+
err,
|
|
678
|
+
ok,
|
|
679
|
+
stateLens,
|
|
376
680
|
useFormStore,
|
|
377
681
|
useStoreComponent,
|
|
378
682
|
useStoreController,
|
|
@@ -380,3 +684,4 @@ __reExport(index_exports, require("gw-store"), module.exports);
|
|
|
380
684
|
useStoreInputWithName,
|
|
381
685
|
...require("gw-store")
|
|
382
686
|
});
|
|
687
|
+
//# sourceMappingURL=index.js.map
|