formstand 0.12.0 → 0.14.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 +279 -11
- package/README.md +86 -382
- package/dist/chunk-N7WPXYCU.js +144 -0
- package/dist/chunk-N7WPXYCU.js.map +1 -0
- package/dist/createForm-C9hZffCQ.d.cts +190 -0
- package/dist/createForm-C9hZffCQ.d.ts +190 -0
- package/dist/devtools/index.cjs +313 -0
- package/dist/devtools/index.cjs.map +1 -0
- package/dist/devtools/index.d.cts +27 -0
- package/dist/devtools/index.d.ts +27 -0
- package/dist/devtools/index.js +276 -0
- package/dist/devtools/index.js.map +1 -0
- package/dist/index.cjs +18 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -189
- package/dist/index.d.ts +31 -189
- package/dist/index.js +12 -133
- package/dist/index.js.map +1 -1
- package/package.json +14 -4
package/dist/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getAtPath, slotAtPath, setAtPath, isPlainObject, hasOwnSlot, valuesEqual, isFieldDirty, useFormSelector, useFormSelectorShallow, parsePath } from './chunk-N7WPXYCU.js';
|
|
2
|
+
export { getAtPath, parsePath, setAtPath, useFormSelector, useFormSelectorShallow } from './chunk-N7WPXYCU.js';
|
|
1
3
|
import { createStore } from 'zustand/vanilla';
|
|
2
4
|
import { devtools } from 'zustand/middleware';
|
|
3
5
|
import { z } from 'zod';
|
|
@@ -6,8 +8,6 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
6
8
|
import { useStore } from 'zustand/react';
|
|
7
9
|
import { useShallow } from 'zustand/react/shallow';
|
|
8
10
|
|
|
9
|
-
// src/core/createForm.ts
|
|
10
|
-
|
|
11
11
|
// src/core/array.ts
|
|
12
12
|
var removeAt = (i) => (n) => n === i ? null : n > i ? n - 1 : n;
|
|
13
13
|
var insertAt = (i) => (n) => n >= i ? n + 1 : n;
|
|
@@ -101,130 +101,6 @@ var clearArrayOpsUnder = (store, path, keepSelf = false) => {
|
|
|
101
101
|
);
|
|
102
102
|
related.forEach((p) => byPath.delete(p));
|
|
103
103
|
};
|
|
104
|
-
|
|
105
|
-
// src/core/equality.ts
|
|
106
|
-
var isPlainObject = (v) => {
|
|
107
|
-
if (typeof v !== "object" || v === null) return false;
|
|
108
|
-
const proto = Object.getPrototypeOf(v);
|
|
109
|
-
return proto === Object.prototype || proto === null;
|
|
110
|
-
};
|
|
111
|
-
var valuesEqual = (a, b) => {
|
|
112
|
-
if (Object.is(a, b)) return true;
|
|
113
|
-
if (a instanceof Date && b instanceof Date) {
|
|
114
|
-
return a.getTime() === b.getTime();
|
|
115
|
-
}
|
|
116
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
117
|
-
return a.length === b.length && a.every((v, i) => valuesEqual(v, b[i]));
|
|
118
|
-
}
|
|
119
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
120
|
-
const aKeys = Object.keys(a);
|
|
121
|
-
const bKeys = Object.keys(b);
|
|
122
|
-
return aKeys.length === bKeys.length && aKeys.every((k) => Object.hasOwn(b, k) && valuesEqual(a[k], b[k]));
|
|
123
|
-
}
|
|
124
|
-
return false;
|
|
125
|
-
};
|
|
126
|
-
var dirtyCache = /* @__PURE__ */ new WeakMap();
|
|
127
|
-
var MAX_VERDICTS = 4;
|
|
128
|
-
var isFieldDirty = (value, initialValue) => {
|
|
129
|
-
if (Object.is(value, initialValue)) return false;
|
|
130
|
-
if (typeof value !== "object" || value === null) {
|
|
131
|
-
return !valuesEqual(value, initialValue);
|
|
132
|
-
}
|
|
133
|
-
const cached = dirtyCache.get(value) ?? [];
|
|
134
|
-
const hit = cached.find((v) => Object.is(v.initial, initialValue));
|
|
135
|
-
if (hit !== void 0) return hit.dirty;
|
|
136
|
-
const dirty = !valuesEqual(value, initialValue);
|
|
137
|
-
dirtyCache.set(
|
|
138
|
-
value,
|
|
139
|
-
[{ initial: initialValue, dirty }, ...cached].slice(0, MAX_VERDICTS)
|
|
140
|
-
);
|
|
141
|
-
return dirty;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
// src/core/path.ts
|
|
145
|
-
var MAX_ARRAY_INDEX = 1e5;
|
|
146
|
-
var isIndexSegment = (s) => {
|
|
147
|
-
const n = Number(s);
|
|
148
|
-
return Number.isInteger(n) && n >= 0 && String(n) === s;
|
|
149
|
-
};
|
|
150
|
-
var PARSE_CACHE_MAX = 4096;
|
|
151
|
-
var parseCache = /* @__PURE__ */ new Map();
|
|
152
|
-
var parsePath = (path) => {
|
|
153
|
-
const cached = parseCache.get(path);
|
|
154
|
-
if (cached !== void 0) return cached;
|
|
155
|
-
const segments = Object.freeze(
|
|
156
|
-
path === "" ? [] : path.split(".").map((s) => isIndexSegment(s) ? Number(s) : s)
|
|
157
|
-
);
|
|
158
|
-
if (parseCache.size >= PARSE_CACHE_MAX) parseCache.clear();
|
|
159
|
-
parseCache.set(path, segments);
|
|
160
|
-
return segments;
|
|
161
|
-
};
|
|
162
|
-
var isPlainRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
163
|
-
var readSegment = (obj, segment) => {
|
|
164
|
-
if (obj == null) return void 0;
|
|
165
|
-
if (Array.isArray(obj)) {
|
|
166
|
-
return typeof segment === "number" ? obj[segment] : void 0;
|
|
167
|
-
}
|
|
168
|
-
return isPlainRecord(obj) && Object.hasOwn(obj, String(segment)) ? obj[String(segment)] : void 0;
|
|
169
|
-
};
|
|
170
|
-
var getAtPath = (obj, path) => parsePath(path).reduce(readSegment, obj);
|
|
171
|
-
var slotAtPath = (obj, path) => {
|
|
172
|
-
const walked = parsePath(path).reduce(
|
|
173
|
-
(acc, segment) => {
|
|
174
|
-
const container = acc.current;
|
|
175
|
-
const addressable = typeof segment === "number" ? Array.isArray(container) ? segment < container.length : isPlainRecord(container) : isPlainRecord(container);
|
|
176
|
-
return !acc.ok || !addressable ? { ok: false, current: void 0 } : { ok: true, current: readSegment(container, segment) };
|
|
177
|
-
},
|
|
178
|
-
{ ok: true, current: obj }
|
|
179
|
-
);
|
|
180
|
-
return walked.ok ? { exists: true, value: walked.current } : { exists: false };
|
|
181
|
-
};
|
|
182
|
-
var writeIntoArray = (arr, index, rest, value) => {
|
|
183
|
-
const length = Math.max(arr.length, index + 1);
|
|
184
|
-
return Array.from(
|
|
185
|
-
{ length },
|
|
186
|
-
(_, i) => i === index ? writeSegments(arr[i], rest, value) : arr[i]
|
|
187
|
-
);
|
|
188
|
-
};
|
|
189
|
-
var refusesHugeIndex = (index) => {
|
|
190
|
-
if (index > MAX_ARRAY_INDEX) {
|
|
191
|
-
console.warn(
|
|
192
|
-
`[formstand] refusing to write array index ${index} (max ${MAX_ARRAY_INDEX}); value left unchanged.`
|
|
193
|
-
);
|
|
194
|
-
return true;
|
|
195
|
-
}
|
|
196
|
-
return false;
|
|
197
|
-
};
|
|
198
|
-
var writeSegments = (obj, segments, value) => {
|
|
199
|
-
const [head, ...rest] = segments;
|
|
200
|
-
if (head === void 0) return value;
|
|
201
|
-
if (Array.isArray(obj)) {
|
|
202
|
-
if (typeof head !== "number") {
|
|
203
|
-
console.warn(
|
|
204
|
-
`[formstand] cannot write string key "${head}" into an array; value left unchanged.`
|
|
205
|
-
);
|
|
206
|
-
return obj;
|
|
207
|
-
}
|
|
208
|
-
if (refusesHugeIndex(head)) return obj;
|
|
209
|
-
return writeIntoArray(obj, head, rest, value);
|
|
210
|
-
}
|
|
211
|
-
if (isPlainRecord(obj)) {
|
|
212
|
-
if (!isPlainObject(obj)) {
|
|
213
|
-
console.warn(
|
|
214
|
-
`[formstand] cannot write key "${String(head)}" through a non-plain object (Date/Map/Set/class instance); value left unchanged.`
|
|
215
|
-
);
|
|
216
|
-
return obj;
|
|
217
|
-
}
|
|
218
|
-
const key = String(head);
|
|
219
|
-
return { ...obj, [key]: writeSegments(obj[key], rest, value) };
|
|
220
|
-
}
|
|
221
|
-
if (typeof head === "number") {
|
|
222
|
-
if (refusesHugeIndex(head)) return obj;
|
|
223
|
-
return writeIntoArray([], head, rest, value);
|
|
224
|
-
}
|
|
225
|
-
return { [head]: writeSegments(void 0, rest, value) };
|
|
226
|
-
};
|
|
227
|
-
var setAtPath = (obj, path, value) => writeSegments(obj, parsePath(path), value);
|
|
228
104
|
var issuePathToFormPath = (path) => path.filter((segment) => typeof segment !== "symbol").join(".");
|
|
229
105
|
var expandIssue = (issue, prefix) => {
|
|
230
106
|
const at = [...prefix, ...issue.path];
|
|
@@ -881,6 +757,10 @@ var createForm = (schema, options) => {
|
|
|
881
757
|
});
|
|
882
758
|
},
|
|
883
759
|
setValue: (path, value) => {
|
|
760
|
+
const currentValues = store.getState().values;
|
|
761
|
+
if (Object.is(getAtPath(currentValues, path), value) && (value !== void 0 || hasOwnSlot(currentValues, path))) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
884
764
|
clearArrayOpsUnder(store, path);
|
|
885
765
|
store.setState((state) => ({
|
|
886
766
|
...state,
|
|
@@ -1278,8 +1158,10 @@ function useField(form, pathArg, options) {
|
|
|
1278
1158
|
}, [form, path, debounceMs]);
|
|
1279
1159
|
const setValue = useCallback(
|
|
1280
1160
|
(value) => {
|
|
1161
|
+
const before = form.store.getState();
|
|
1281
1162
|
form.setValue(path, value);
|
|
1282
1163
|
const state = form.store.getState();
|
|
1164
|
+
if (state === before) return;
|
|
1283
1165
|
if (shouldValidateOn(
|
|
1284
1166
|
"change",
|
|
1285
1167
|
state.mode,
|
|
@@ -1568,12 +1450,6 @@ function useIsValid(form, path) {
|
|
|
1568
1450
|
}
|
|
1569
1451
|
var useIsSubmitting = (form) => useStore(form.store, (state) => state.isSubmitting);
|
|
1570
1452
|
var useSubmitCount = (form) => useStore(form.store, (state) => state.submitCount);
|
|
1571
|
-
function useFormSelector(form, selector) {
|
|
1572
|
-
return useStore(form.store, selector);
|
|
1573
|
-
}
|
|
1574
|
-
function useFormSelectorShallow(form, selector) {
|
|
1575
|
-
return useStore(form.store, useShallow(selector));
|
|
1576
|
-
}
|
|
1577
1453
|
|
|
1578
1454
|
// src/react/createFormHooks.ts
|
|
1579
1455
|
var capitalize = (name) => name.length === 0 ? name : name.charAt(0).toUpperCase() + name.slice(1);
|
|
@@ -1607,6 +1483,9 @@ var createFormHooks = (form, name) => {
|
|
|
1607
1483
|
[`use${prefix}SubmitCount`]: useBoundSubmitCount
|
|
1608
1484
|
};
|
|
1609
1485
|
};
|
|
1486
|
+
function useFormValues(form) {
|
|
1487
|
+
return useStore(form.store, (state) => state.values);
|
|
1488
|
+
}
|
|
1610
1489
|
|
|
1611
1490
|
// src/react/inputProps.ts
|
|
1612
1491
|
var hasFieldError = (error) => error !== void 0 && error.length > 0;
|
|
@@ -1996,6 +1875,6 @@ var focusField = (path, root) => {
|
|
|
1996
1875
|
return path === "" ? (root !== void 0 || document.querySelectorAll("form").length <= 1) && focusFirstOf(namedControls(scope).filter(isFocusCandidate)) : focusFirstOf(pathCandidates(scope, [path]).filter(isFocusCandidate));
|
|
1997
1876
|
};
|
|
1998
1877
|
|
|
1999
|
-
export { CheckboxField, DateField, NumberField, SelectField, TextField, checkboxProps, createForm, createFormContext, createFormHooks, dateInputProps, dateToInputText, emptyValueForSchema, flattenIssues, focusField, focusFirstError,
|
|
1878
|
+
export { CheckboxField, DateField, NumberField, SelectField, TextField, checkboxProps, createForm, createFormContext, createFormHooks, dateInputProps, dateToInputText, emptyValueForSchema, flattenIssues, focusField, focusFirstError, hasFieldError, isAsyncRequiredError, numberInputProps, numberToInputText, parseDateText, parseNumberText, persistForm, selectProps, shouldValidateOn, textInputProps, useField, useFieldArray, useForm, useFormError, useFormValues, useIsDirty, useIsSubmitting, useIsValid, useNumberInput, useSubmitCount, useVariantField, validateAsync, validateSync };
|
|
2000
1879
|
//# sourceMappingURL=index.js.map
|
|
2001
1880
|
//# sourceMappingURL=index.js.map
|