@explita/formly 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +261 -0
- package/README.old.md +141 -0
- package/dist/components/field-error.d.ts +2 -0
- package/dist/components/field-error.js +14 -0
- package/dist/components/field.d.ts +4 -0
- package/dist/components/field.js +120 -0
- package/dist/components/form-spy.d.ts +16 -0
- package/dist/components/form-spy.js +66 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +20 -0
- package/dist/components/label.d.ts +2 -0
- package/dist/components/label.js +46 -0
- package/dist/hooks/use-field.d.ts +21 -0
- package/dist/hooks/use-field.js +66 -0
- package/dist/hooks/use-form-by-id.d.ts +6 -0
- package/dist/hooks/use-form-by-id.js +25 -0
- package/dist/hooks/use-form-context.d.ts +5 -0
- package/dist/hooks/use-form-context.js +17 -0
- package/dist/hooks/use-form.d.ts +43 -0
- package/dist/hooks/use-form.js +961 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +25 -0
- package/dist/lib/array-helpers.d.ts +6 -0
- package/dist/lib/array-helpers.js +281 -0
- package/dist/lib/css.d.ts +1 -0
- package/dist/lib/css.js +45 -0
- package/dist/lib/debounce.d.ts +13 -0
- package/dist/lib/debounce.js +28 -0
- package/dist/lib/deep-path.d.ts +4 -0
- package/dist/lib/deep-path.js +60 -0
- package/dist/lib/drafts-helpter.d.ts +31 -0
- package/dist/lib/drafts-helpter.js +67 -0
- package/dist/lib/form-registry.d.ts +9 -0
- package/dist/lib/form-registry.js +24 -0
- package/dist/lib/group-helpers.d.ts +9 -0
- package/dist/lib/group-helpers.js +29 -0
- package/dist/lib/pub-sub.d.ts +13 -0
- package/dist/lib/pub-sub.js +38 -0
- package/dist/lib/utils.d.ts +17 -0
- package/dist/lib/utils.js +190 -0
- package/dist/lib/validation.d.ts +22 -0
- package/dist/lib/validation.js +46 -0
- package/dist/lib/zod-helpers.d.ts +5 -0
- package/dist/lib/zod-helpers.js +63 -0
- package/dist/providers/form.d.ts +51 -0
- package/dist/providers/form.js +63 -0
- package/dist/types/array.d.ts +197 -0
- package/dist/types/array.js +2 -0
- package/dist/types/field.d.ts +61 -0
- package/dist/types/field.js +2 -0
- package/dist/types/group.d.ts +16 -0
- package/dist/types/group.js +2 -0
- package/dist/types/path.d.ts +8 -0
- package/dist/types/path.js +2 -0
- package/dist/types/pub-sub.d.ts +2 -0
- package/dist/types/pub-sub.js +2 -0
- package/dist/types/utils.d.ts +310 -0
- package/dist/types/utils.js +2 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +14 -0
- package/package.json +53 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { Form } from "./providers/form";
|
|
2
|
+
export * from "./components";
|
|
3
|
+
export * from "./hooks/use-form";
|
|
4
|
+
export * from "./hooks/use-field";
|
|
5
|
+
export * from "./hooks/use-form-context";
|
|
6
|
+
export * from "./hooks/use-form-by-id";
|
|
7
|
+
export * from "./utils";
|
|
8
|
+
export type { HandlerContext, FormShape, FormInstance } from "./types/utils";
|
|
9
|
+
export type * from "./types/array";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.Form = void 0;
|
|
18
|
+
var form_1 = require("./providers/form");
|
|
19
|
+
Object.defineProperty(exports, "Form", { enumerable: true, get: function () { return form_1.Form; } });
|
|
20
|
+
__exportStar(require("./components"), exports);
|
|
21
|
+
__exportStar(require("./hooks/use-form"), exports);
|
|
22
|
+
__exportStar(require("./hooks/use-field"), exports);
|
|
23
|
+
__exportStar(require("./hooks/use-form-context"), exports);
|
|
24
|
+
__exportStar(require("./hooks/use-form-by-id"), exports);
|
|
25
|
+
__exportStar(require("./utils"), exports);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ArrayHelperProps, ArrayHelpers, HandlerArrayHelpers } from "../types/array";
|
|
2
|
+
import { Path } from "../types/path";
|
|
3
|
+
export declare function formArrayHelper<T = any>(props: ArrayHelperProps<T>): ArrayHelpers<T>;
|
|
4
|
+
export declare function handlerArrayHelpers<T>(path: Path<T>, data: T): HandlerArrayHelpers<T>;
|
|
5
|
+
export declare function getArrayKeys(path: string, values: any): number[];
|
|
6
|
+
export declare function extraxtArrayPrefixies(path: string, index: number, deps?: string[]): string[];
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formArrayHelper = formArrayHelper;
|
|
4
|
+
exports.handlerArrayHelpers = handlerArrayHelpers;
|
|
5
|
+
exports.getArrayKeys = getArrayKeys;
|
|
6
|
+
exports.extraxtArrayPrefixies = extraxtArrayPrefixies;
|
|
7
|
+
const deep_path_1 = require("./deep-path");
|
|
8
|
+
const utils_1 = require("./utils");
|
|
9
|
+
function formArrayHelper(props) {
|
|
10
|
+
const { path, formValues, setValues, compute, computed, getCurrentArrayValue, } = props;
|
|
11
|
+
function get() {
|
|
12
|
+
return getCurrentArrayValue() || [];
|
|
13
|
+
}
|
|
14
|
+
let working = [...get()];
|
|
15
|
+
function set(arr) {
|
|
16
|
+
const newFlat = { ...formValues };
|
|
17
|
+
Object.keys(formValues || {}).forEach((key) => {
|
|
18
|
+
if (key.startsWith(path)) {
|
|
19
|
+
delete newFlat[key];
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
// set new array keys
|
|
23
|
+
arr.forEach((v, i) => {
|
|
24
|
+
//@ts-ignore
|
|
25
|
+
newFlat[`${path}.${i}`] = v;
|
|
26
|
+
});
|
|
27
|
+
setValues(newFlat, { overwrite: true });
|
|
28
|
+
}
|
|
29
|
+
function remove(index) {
|
|
30
|
+
removeArrayItem(formValues, setValues, path, index);
|
|
31
|
+
}
|
|
32
|
+
function clear() {
|
|
33
|
+
clearArray(formValues, setValues, path);
|
|
34
|
+
}
|
|
35
|
+
const api = {
|
|
36
|
+
get: () => structuredClone(get()),
|
|
37
|
+
get value() {
|
|
38
|
+
return structuredClone(get());
|
|
39
|
+
},
|
|
40
|
+
get length() {
|
|
41
|
+
return get().length;
|
|
42
|
+
},
|
|
43
|
+
filter(fn) {
|
|
44
|
+
const filtered = get().filter(fn);
|
|
45
|
+
working = filtered;
|
|
46
|
+
set(filtered);
|
|
47
|
+
return api;
|
|
48
|
+
},
|
|
49
|
+
map(fn) {
|
|
50
|
+
const mapped = get().map(fn);
|
|
51
|
+
working = mapped;
|
|
52
|
+
set(mapped);
|
|
53
|
+
return api;
|
|
54
|
+
},
|
|
55
|
+
replaceAll: (value) => {
|
|
56
|
+
set(value);
|
|
57
|
+
working = [...value];
|
|
58
|
+
return api;
|
|
59
|
+
},
|
|
60
|
+
push(items) {
|
|
61
|
+
const newValues = Array.isArray(items) ? items : [items];
|
|
62
|
+
const oldValues = get();
|
|
63
|
+
const combined = [...oldValues, ...newValues];
|
|
64
|
+
working = combined;
|
|
65
|
+
set(combined);
|
|
66
|
+
const startIndex = oldValues.length;
|
|
67
|
+
//@ts-ignore
|
|
68
|
+
generateComputedKeys(path, startIndex, newValues, compute, computed);
|
|
69
|
+
return api;
|
|
70
|
+
},
|
|
71
|
+
insert: (index, item) => {
|
|
72
|
+
working.splice(index, 0, item);
|
|
73
|
+
set(working);
|
|
74
|
+
return api;
|
|
75
|
+
},
|
|
76
|
+
insertFirst: (item) => {
|
|
77
|
+
working.unshift(item);
|
|
78
|
+
set(working);
|
|
79
|
+
return api;
|
|
80
|
+
},
|
|
81
|
+
updateAt: (index, item) => {
|
|
82
|
+
const oldValues = get();
|
|
83
|
+
working = [...oldValues];
|
|
84
|
+
working[index] = item;
|
|
85
|
+
set(working);
|
|
86
|
+
return api;
|
|
87
|
+
},
|
|
88
|
+
swap: (a, b) => {
|
|
89
|
+
[working[a], working[b]] = [working[b], working[a]];
|
|
90
|
+
set(working);
|
|
91
|
+
return api;
|
|
92
|
+
},
|
|
93
|
+
move: (from, to) => {
|
|
94
|
+
const [item] = working.splice(from, 1);
|
|
95
|
+
working.splice(to, 0, item);
|
|
96
|
+
set(working);
|
|
97
|
+
return api;
|
|
98
|
+
},
|
|
99
|
+
moveUp(index) {
|
|
100
|
+
if (index <= 0)
|
|
101
|
+
return api;
|
|
102
|
+
return api.move(index, index - 1);
|
|
103
|
+
},
|
|
104
|
+
moveDown(index) {
|
|
105
|
+
const arr = get();
|
|
106
|
+
if (index >= arr.length - 1)
|
|
107
|
+
return api;
|
|
108
|
+
return api.move(index, index + 1);
|
|
109
|
+
},
|
|
110
|
+
compact() {
|
|
111
|
+
const filtered = get().filter(Boolean);
|
|
112
|
+
working = filtered;
|
|
113
|
+
set(filtered);
|
|
114
|
+
return api;
|
|
115
|
+
},
|
|
116
|
+
replaceWhere(fn, newItem) {
|
|
117
|
+
const arr = get().map((item) => (fn(item) ? newItem : item));
|
|
118
|
+
working = arr;
|
|
119
|
+
set(arr);
|
|
120
|
+
return api;
|
|
121
|
+
},
|
|
122
|
+
merge(fn) {
|
|
123
|
+
const oldValues = get();
|
|
124
|
+
const newValues = fn(oldValues);
|
|
125
|
+
working = newValues;
|
|
126
|
+
set(newValues);
|
|
127
|
+
const startIndex = oldValues.length;
|
|
128
|
+
//@ts-ignore
|
|
129
|
+
generateComputedKeys(path, startIndex, newValues, compute, computed);
|
|
130
|
+
return api;
|
|
131
|
+
},
|
|
132
|
+
sort(fn) {
|
|
133
|
+
const sorted = [...get()].sort(fn);
|
|
134
|
+
working = sorted;
|
|
135
|
+
set(sorted);
|
|
136
|
+
return api;
|
|
137
|
+
},
|
|
138
|
+
remove,
|
|
139
|
+
removeIf(fn) {
|
|
140
|
+
const filtered = get().filter((item, index) => !fn(item, index));
|
|
141
|
+
working = filtered;
|
|
142
|
+
set(filtered);
|
|
143
|
+
return api;
|
|
144
|
+
},
|
|
145
|
+
clear,
|
|
146
|
+
toObject() {
|
|
147
|
+
return get().reduce((acc, item, idx) => {
|
|
148
|
+
acc[idx] = item;
|
|
149
|
+
return acc;
|
|
150
|
+
}, {});
|
|
151
|
+
},
|
|
152
|
+
some: (fn) => get().some(fn),
|
|
153
|
+
every: (fn) => get().every(fn),
|
|
154
|
+
findIndex: (fn) => get().findIndex(fn),
|
|
155
|
+
isFirst: (index) => index === 0,
|
|
156
|
+
isLast: (index) => index === get().length - 1,
|
|
157
|
+
first: () => get()[0],
|
|
158
|
+
last: () => get()[get().length - 1],
|
|
159
|
+
// done() {
|
|
160
|
+
// set(working);
|
|
161
|
+
// },
|
|
162
|
+
};
|
|
163
|
+
return api;
|
|
164
|
+
}
|
|
165
|
+
function generateComputedKeys(path, startIndex, newValues, compute, computed) {
|
|
166
|
+
if (!computed)
|
|
167
|
+
return;
|
|
168
|
+
for (const key in computed) {
|
|
169
|
+
if (key.startsWith(path + "*")) {
|
|
170
|
+
const fieldName = key.split("*")[1];
|
|
171
|
+
//@ts-ignore
|
|
172
|
+
const template = computed[key];
|
|
173
|
+
// compute for each new item
|
|
174
|
+
newValues.forEach((_, i) => {
|
|
175
|
+
const index = startIndex + i;
|
|
176
|
+
const computedKey = `${path}.${index}.${fieldName}`;
|
|
177
|
+
const fieldDeps = extraxtArrayPrefixies(path, index, template.deps);
|
|
178
|
+
compute(computedKey,
|
|
179
|
+
// @ts-ignore
|
|
180
|
+
fieldDeps, (vals) => template.fn(vals, index));
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function handlerArrayHelpers(path, data) {
|
|
186
|
+
const api = {
|
|
187
|
+
get: () => { var _a; return (_a = (0, deep_path_1.getDeepValue)(data, path)) !== null && _a !== void 0 ? _a : []; },
|
|
188
|
+
get value() {
|
|
189
|
+
var _a;
|
|
190
|
+
return (_a = (0, deep_path_1.getDeepValue)(data, path)) !== null && _a !== void 0 ? _a : [];
|
|
191
|
+
},
|
|
192
|
+
snapshot: () => structuredClone(data),
|
|
193
|
+
filter: (fn) => {
|
|
194
|
+
var _a;
|
|
195
|
+
const arr = (_a = (0, deep_path_1.getDeepValue)(data, path)) !== null && _a !== void 0 ? _a : [];
|
|
196
|
+
const filtered = arr.filter(fn);
|
|
197
|
+
(0, deep_path_1.setValueByPath)(data, path, filtered);
|
|
198
|
+
return api;
|
|
199
|
+
},
|
|
200
|
+
removeIf: (fn) => {
|
|
201
|
+
var _a;
|
|
202
|
+
const arr = (_a = (0, deep_path_1.getDeepValue)(data, path)) !== null && _a !== void 0 ? _a : [];
|
|
203
|
+
const filtered = arr.filter((item, index) => !fn(item, index));
|
|
204
|
+
(0, deep_path_1.setValueByPath)(data, path, filtered);
|
|
205
|
+
return api;
|
|
206
|
+
},
|
|
207
|
+
map: (fn) => {
|
|
208
|
+
var _a;
|
|
209
|
+
const arr = (_a = (0, deep_path_1.getDeepValue)(data, path)) !== null && _a !== void 0 ? _a : [];
|
|
210
|
+
const mapped = arr.map(fn);
|
|
211
|
+
(0, deep_path_1.setValueByPath)(data, path, mapped);
|
|
212
|
+
return api;
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
return api;
|
|
216
|
+
}
|
|
217
|
+
function removeArrayItem(formValues, setValues, path, index) {
|
|
218
|
+
const prefix = `${path}.`;
|
|
219
|
+
const flat = { ...formValues };
|
|
220
|
+
const keys = Object.keys(flat || {}).filter((k) => k.startsWith(prefix));
|
|
221
|
+
// Sort descending to avoid index shift issues
|
|
222
|
+
keys.sort((a, b) => {
|
|
223
|
+
const ai = parseInt(a.slice(prefix.length).split(".")[0], 10);
|
|
224
|
+
const bi = parseInt(b.slice(prefix.length).split(".")[0], 10);
|
|
225
|
+
return bi - ai;
|
|
226
|
+
});
|
|
227
|
+
const updated = {};
|
|
228
|
+
for (const key in flat) {
|
|
229
|
+
if (!key.startsWith(prefix)) {
|
|
230
|
+
updated[key] = flat[key];
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
for (const key of keys) {
|
|
234
|
+
const rest = key.slice(prefix.length);
|
|
235
|
+
const [arrayIndexStr] = rest.split(".");
|
|
236
|
+
const currentIndex = parseInt(arrayIndexStr, 10);
|
|
237
|
+
if (Number.isNaN(currentIndex))
|
|
238
|
+
continue;
|
|
239
|
+
if (currentIndex === index)
|
|
240
|
+
continue;
|
|
241
|
+
const newIndex = currentIndex > index ? currentIndex - 1 : currentIndex;
|
|
242
|
+
const newKey = key.replace(new RegExp(`^${prefix}${currentIndex}`), `${prefix}${newIndex}`);
|
|
243
|
+
updated[newKey] = flat[key];
|
|
244
|
+
}
|
|
245
|
+
const nested = (0, utils_1.nestFormValues)(updated);
|
|
246
|
+
// Ensure array still exists
|
|
247
|
+
if (!Array.isArray((0, deep_path_1.getDeepValue)(nested, path))) {
|
|
248
|
+
(0, deep_path_1.setDeepValue)(nested, path, []);
|
|
249
|
+
}
|
|
250
|
+
setValues(nested, { overwrite: true });
|
|
251
|
+
}
|
|
252
|
+
function clearArray(formValues, setValues, path) {
|
|
253
|
+
const updated = (0, utils_1.nestFormValues)(formValues);
|
|
254
|
+
(0, deep_path_1.setDeepValue)(updated, path, []);
|
|
255
|
+
setValues({ ...updated }, { overwrite: true });
|
|
256
|
+
}
|
|
257
|
+
function getArrayKeys(path, values) {
|
|
258
|
+
const indexes = new Set();
|
|
259
|
+
for (const key of Object.keys(values)) {
|
|
260
|
+
if (key.startsWith(path + ".")) {
|
|
261
|
+
const match = key.match(new RegExp(`^${path}\\.(\\d+)\\.`));
|
|
262
|
+
if (match)
|
|
263
|
+
indexes.add(Number(match[1]));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return Array.from(indexes).sort((a, b) => a - b);
|
|
267
|
+
}
|
|
268
|
+
function extraxtArrayPrefixies(path, index, deps) {
|
|
269
|
+
return ((deps === null || deps === void 0 ? void 0 : deps.map((dep) => {
|
|
270
|
+
// If dep starts with the same array path, replace its first numeric index
|
|
271
|
+
const arrayPrefix = path + ".";
|
|
272
|
+
if (dep.startsWith(arrayPrefix)) {
|
|
273
|
+
// extract the remaining path after the first dot
|
|
274
|
+
const rest = dep
|
|
275
|
+
.slice(arrayPrefix.length)
|
|
276
|
+
.replace(/^\d+/, index.toString());
|
|
277
|
+
return `${path}.${rest}`;
|
|
278
|
+
}
|
|
279
|
+
return dep; // global deps stay as-is
|
|
280
|
+
})) || []);
|
|
281
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const css = ".explita-form .form-label {\n display: flex;\n align-items: center;\n gap: 0.5rem; /* gap-2 */\n font-size: 0.875rem; /* text-sm */\n line-height: 1.25rem; /* leading-none */\n font-weight: 500; /* font-medium */\n user-select: none; /* select-none */\n}\n\n/* Disabled group */\n.explita-form .group[data-disabled=\"true\"] .form-label {\n pointer-events: none;\n opacity: 0.5;\n}\n\n/* Disabled peer */\n.explita-form .peer:disabled ~ .form-label {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Required field */\n.explita-form .form-label[data-required=\"true\"]::after {\n content: \"*\";\n color: #ef4444; /* Tailwind red-500 */\n font-size: 1rem; /* text-base */\n margin-left: -0.25rem; /* ml-1 */\n}\n\n/* Error state */\n.explita-form .form-label[data-error=\"true\"] {\n color: #ef4444; /* red-500 */\n}\n\n/* Input error state */\n.explita-form [data-input-error=\"true\"] {\n border-color: #ef4444 !important; /* red-500 */\n // outline: none !important;\n outline-color: #ef4444;\n}\n";
|
package/dist/lib/css.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.css = void 0;
|
|
4
|
+
exports.css = `.explita-form .form-label {
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
gap: 0.5rem; /* gap-2 */
|
|
8
|
+
font-size: 0.875rem; /* text-sm */
|
|
9
|
+
line-height: 1.25rem; /* leading-none */
|
|
10
|
+
font-weight: 500; /* font-medium */
|
|
11
|
+
user-select: none; /* select-none */
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* Disabled group */
|
|
15
|
+
.explita-form .group[data-disabled="true"] .form-label {
|
|
16
|
+
pointer-events: none;
|
|
17
|
+
opacity: 0.5;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* Disabled peer */
|
|
21
|
+
.explita-form .peer:disabled ~ .form-label {
|
|
22
|
+
cursor: not-allowed;
|
|
23
|
+
opacity: 0.5;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Required field */
|
|
27
|
+
.explita-form .form-label[data-required="true"]::after {
|
|
28
|
+
content: "*";
|
|
29
|
+
color: #ef4444; /* Tailwind red-500 */
|
|
30
|
+
font-size: 1rem; /* text-base */
|
|
31
|
+
margin-left: -0.25rem; /* ml-1 */
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Error state */
|
|
35
|
+
.explita-form .form-label[data-error="true"] {
|
|
36
|
+
color: #ef4444; /* red-500 */
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Input error state */
|
|
40
|
+
.explita-form [data-input-error="true"] {
|
|
41
|
+
border-color: #ef4444 !important; /* red-500 */
|
|
42
|
+
// outline: none !important;
|
|
43
|
+
outline-color: #ef4444;
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a debounced function that delays invoking the provided function until
|
|
3
|
+
* after `delay` milliseconds have passed since the last time the debounced
|
|
4
|
+
* function was called. The debounced function returns a function that can be
|
|
5
|
+
* used to cancel the pending call to the underlying function.
|
|
6
|
+
*
|
|
7
|
+
* @param fn The function to debounce.
|
|
8
|
+
* @param delay The number of milliseconds to delay calling the function.
|
|
9
|
+
* @returns A debounced function with an extra `cancel` method to cancel the pending call.
|
|
10
|
+
*/
|
|
11
|
+
export declare function debounce<T extends (...args: any[]) => void>(fn: T, delay: number): T & {
|
|
12
|
+
cancel: () => void;
|
|
13
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.debounce = debounce;
|
|
4
|
+
/**
|
|
5
|
+
* Creates a debounced function that delays invoking the provided function until
|
|
6
|
+
* after `delay` milliseconds have passed since the last time the debounced
|
|
7
|
+
* function was called. The debounced function returns a function that can be
|
|
8
|
+
* used to cancel the pending call to the underlying function.
|
|
9
|
+
*
|
|
10
|
+
* @param fn The function to debounce.
|
|
11
|
+
* @param delay The number of milliseconds to delay calling the function.
|
|
12
|
+
* @returns A debounced function with an extra `cancel` method to cancel the pending call.
|
|
13
|
+
*/
|
|
14
|
+
function debounce(fn, delay) {
|
|
15
|
+
let timeout;
|
|
16
|
+
function debounced(...args) {
|
|
17
|
+
if (timeout)
|
|
18
|
+
clearTimeout(timeout);
|
|
19
|
+
timeout = setTimeout(() => fn.apply(this, args), delay);
|
|
20
|
+
}
|
|
21
|
+
debounced.cancel = () => {
|
|
22
|
+
if (timeout) {
|
|
23
|
+
clearTimeout(timeout);
|
|
24
|
+
timeout = null;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
return debounced;
|
|
28
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function getValueByPath<T extends any>(obj: T, path: string): T;
|
|
2
|
+
export declare function setValueByPath<T extends any>(obj: T, path: string, value: any): void;
|
|
3
|
+
export declare function getDeepValue(obj: any, path: string): any;
|
|
4
|
+
export declare function setDeepValue(obj: any, path: string, value: any): void;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getValueByPath = getValueByPath;
|
|
4
|
+
exports.setValueByPath = setValueByPath;
|
|
5
|
+
exports.getDeepValue = getDeepValue;
|
|
6
|
+
exports.setDeepValue = setDeepValue;
|
|
7
|
+
const utils_1 = require("./utils");
|
|
8
|
+
function getValueByPath(obj, path) {
|
|
9
|
+
return (path === null || path === void 0 ? void 0 : path.split(/[\.\[\]]+/).filter(Boolean).reduce((acc, key) => (acc ? acc[key] : undefined), obj));
|
|
10
|
+
}
|
|
11
|
+
function setValueByPath(obj, path, value) {
|
|
12
|
+
const keys = path.split(/[\.\[\]]+/).filter(Boolean);
|
|
13
|
+
let current = obj;
|
|
14
|
+
keys.forEach((key, idx) => {
|
|
15
|
+
var _a;
|
|
16
|
+
if (idx === keys.length - 1) {
|
|
17
|
+
//@ts-ignore
|
|
18
|
+
current[key] = value;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
//@ts-ignore
|
|
22
|
+
current[key] = (_a = current[key]) !== null && _a !== void 0 ? _a : {};
|
|
23
|
+
//@ts-ignore
|
|
24
|
+
current = current[key];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function getDeepValue(obj, path) {
|
|
29
|
+
if (!obj || !path)
|
|
30
|
+
return undefined;
|
|
31
|
+
const parts = path.split(".");
|
|
32
|
+
let current = (0, utils_1.nestFormValues)(obj);
|
|
33
|
+
for (const part of parts) {
|
|
34
|
+
if (current == null)
|
|
35
|
+
return undefined;
|
|
36
|
+
current = current[part];
|
|
37
|
+
}
|
|
38
|
+
return current;
|
|
39
|
+
}
|
|
40
|
+
function setDeepValue(obj, path, value) {
|
|
41
|
+
if (!obj || !path)
|
|
42
|
+
return;
|
|
43
|
+
const parts = path.split(".");
|
|
44
|
+
let current = obj;
|
|
45
|
+
for (let i = 0; i < parts.length; i++) {
|
|
46
|
+
const part = parts[i];
|
|
47
|
+
const isLast = i === parts.length - 1;
|
|
48
|
+
if (isLast) {
|
|
49
|
+
current[part] = value;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
if (current[part] == null || typeof current[part] !== "object") {
|
|
53
|
+
// Determine if the next part looks like an array index
|
|
54
|
+
const nextIsIndex = /^\d+$/.test(parts[i + 1]);
|
|
55
|
+
current[part] = nextIsIndex ? [] : {};
|
|
56
|
+
}
|
|
57
|
+
current = current[part];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writes a draft to local storage immediately.
|
|
3
|
+
* This function takes a draft key and a draft value as arguments.
|
|
4
|
+
* It will update the local storage with the new draft value.
|
|
5
|
+
*
|
|
6
|
+
* Note: This function is not debounced and will write to local storage immediately, and don't use it for performance critical code.
|
|
7
|
+
*/
|
|
8
|
+
export declare function writeDraftImmediate<T extends unknown>(draftKey: string, data: T): void;
|
|
9
|
+
/**
|
|
10
|
+
* Writes a draft to local storage.
|
|
11
|
+
* This function is debounced to prevent excessive writes to local storage.
|
|
12
|
+
* The function takes a draft key and a draft value as arguments.
|
|
13
|
+
* It will update the local storage with the new draft value.
|
|
14
|
+
*
|
|
15
|
+
* Note: This function is debounced and will write to local storage after a delay of 200ms, good for performance.
|
|
16
|
+
*/
|
|
17
|
+
export declare const writeDraft: typeof writeDraftImmediate & {
|
|
18
|
+
cancel: () => void;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Reads a draft from local storage.
|
|
22
|
+
* This function takes a draft key as an argument and returns the corresponding * draft value.
|
|
23
|
+
* If the draft key does not exist in local storage, the function will return
|
|
24
|
+
* undefined.
|
|
25
|
+
*/
|
|
26
|
+
export declare function readDraft(draftKey: string): unknown;
|
|
27
|
+
/**
|
|
28
|
+
* Deletes a draft from local storage.
|
|
29
|
+
* This function takes a draft key as an argument and removes the corresponding draft from local storage.
|
|
30
|
+
*/
|
|
31
|
+
export declare function deleteDraft(draftKey: string): void;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeDraft = void 0;
|
|
4
|
+
exports.writeDraftImmediate = writeDraftImmediate;
|
|
5
|
+
exports.readDraft = readDraft;
|
|
6
|
+
exports.deleteDraft = deleteDraft;
|
|
7
|
+
const debounce_1 = require("./debounce");
|
|
8
|
+
function getDrafts() {
|
|
9
|
+
const stored = localStorage.getItem("drafts");
|
|
10
|
+
if (!stored)
|
|
11
|
+
return {};
|
|
12
|
+
try {
|
|
13
|
+
return JSON.parse(stored) || {};
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
localStorage.removeItem("drafts"); // corrupted data
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function setDrafts(drafts) {
|
|
21
|
+
if (Object.keys(drafts).length === 0) {
|
|
22
|
+
localStorage.removeItem("drafts");
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
localStorage.setItem("drafts", JSON.stringify(drafts));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Writes a draft to local storage immediately.
|
|
30
|
+
* This function takes a draft key and a draft value as arguments.
|
|
31
|
+
* It will update the local storage with the new draft value.
|
|
32
|
+
*
|
|
33
|
+
* Note: This function is not debounced and will write to local storage immediately, and don't use it for performance critical code.
|
|
34
|
+
*/
|
|
35
|
+
function writeDraftImmediate(draftKey, data) {
|
|
36
|
+
const drafts = getDrafts();
|
|
37
|
+
const newDrafts = { ...drafts, [draftKey]: data };
|
|
38
|
+
setDrafts(newDrafts);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Writes a draft to local storage.
|
|
42
|
+
* This function is debounced to prevent excessive writes to local storage.
|
|
43
|
+
* The function takes a draft key and a draft value as arguments.
|
|
44
|
+
* It will update the local storage with the new draft value.
|
|
45
|
+
*
|
|
46
|
+
* Note: This function is debounced and will write to local storage after a delay of 200ms, good for performance.
|
|
47
|
+
*/
|
|
48
|
+
exports.writeDraft = (0, debounce_1.debounce)(writeDraftImmediate, 200);
|
|
49
|
+
/**
|
|
50
|
+
* Reads a draft from local storage.
|
|
51
|
+
* This function takes a draft key as an argument and returns the corresponding * draft value.
|
|
52
|
+
* If the draft key does not exist in local storage, the function will return
|
|
53
|
+
* undefined.
|
|
54
|
+
*/
|
|
55
|
+
function readDraft(draftKey) {
|
|
56
|
+
const drafts = getDrafts();
|
|
57
|
+
return drafts[draftKey];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Deletes a draft from local storage.
|
|
61
|
+
* This function takes a draft key as an argument and removes the corresponding draft from local storage.
|
|
62
|
+
*/
|
|
63
|
+
function deleteDraft(draftKey) {
|
|
64
|
+
const drafts = getDrafts();
|
|
65
|
+
const newDrafts = Object.fromEntries(Object.entries(drafts).filter(([key]) => key !== draftKey));
|
|
66
|
+
setDrafts(newDrafts);
|
|
67
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FormInstance } from "../types/utils";
|
|
2
|
+
declare class FormRegistry {
|
|
3
|
+
private forms;
|
|
4
|
+
add<T>(id: string, form: FormInstance<T>): () => void;
|
|
5
|
+
get<T extends FormInstance<any>>(id: string): T;
|
|
6
|
+
delete(id: string): void;
|
|
7
|
+
}
|
|
8
|
+
export declare const registry: FormRegistry;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registry = void 0;
|
|
4
|
+
class FormRegistry {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.forms = new Map();
|
|
7
|
+
}
|
|
8
|
+
add(id, form) {
|
|
9
|
+
this.forms.set(id, form);
|
|
10
|
+
return () => {
|
|
11
|
+
this.forms.delete(id);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
get(id) {
|
|
15
|
+
const form = this.forms.get(id);
|
|
16
|
+
if (!form)
|
|
17
|
+
throw new Error(`Form with ID "${id}" not found`);
|
|
18
|
+
return form;
|
|
19
|
+
}
|
|
20
|
+
delete(id) {
|
|
21
|
+
this.forms.delete(id);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.registry = new FormRegistry();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GroupHelpersProps } from "../types/group";
|
|
2
|
+
export declare function groupHelpers<T>(props: GroupHelpersProps<T>): {
|
|
3
|
+
get: () => {};
|
|
4
|
+
set: (vals: any, options?: {
|
|
5
|
+
overwrite?: boolean;
|
|
6
|
+
}) => void;
|
|
7
|
+
reset: (to?: any) => void;
|
|
8
|
+
validate: () => Promise<void>;
|
|
9
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.groupHelpers = groupHelpers;
|
|
4
|
+
const deep_path_1 = require("./deep-path");
|
|
5
|
+
function groupHelpers(props) {
|
|
6
|
+
const { path, formValues, defaultValues, setValues, getCurrentValue, validatePartial, } = props;
|
|
7
|
+
const getGroupValues = () => { var _a; return (_a = getCurrentValue()) !== null && _a !== void 0 ? _a : {}; };
|
|
8
|
+
const setGroupValues = (vals, options) => {
|
|
9
|
+
const current = getGroupValues();
|
|
10
|
+
const merged = (options === null || options === void 0 ? void 0 : options.overwrite) ? vals : { ...current, ...vals };
|
|
11
|
+
(0, deep_path_1.setDeepValue)(formValues, path, merged);
|
|
12
|
+
setValues(formValues, { overwrite: true });
|
|
13
|
+
};
|
|
14
|
+
const reset = (to) => {
|
|
15
|
+
var _a;
|
|
16
|
+
const defaultGroup = (_a = to !== null && to !== void 0 ? to : (0, deep_path_1.getDeepValue)(defaultValues || {}, path)) !== null && _a !== void 0 ? _a : {};
|
|
17
|
+
setGroupValues(defaultGroup);
|
|
18
|
+
};
|
|
19
|
+
const validate = async () => {
|
|
20
|
+
const groupValues = getGroupValues();
|
|
21
|
+
await validatePartial({ [path]: groupValues });
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
get: getGroupValues,
|
|
25
|
+
set: setGroupValues,
|
|
26
|
+
reset,
|
|
27
|
+
validate,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ChannelEvent } from "../types/pub-sub";
|
|
2
|
+
export type Callback<T> = (payload: T) => void;
|
|
3
|
+
export declare function createChannel<T = any>(): {
|
|
4
|
+
emit<T_1>(payload: T_1): void;
|
|
5
|
+
subscribe(cb: Callback<T>): () => void;
|
|
6
|
+
clear(): void;
|
|
7
|
+
};
|
|
8
|
+
export declare function createFormBus<T>(): {
|
|
9
|
+
channel: {
|
|
10
|
+
(name: ChannelEvent<T>): ReturnType<typeof createChannel<T>>;
|
|
11
|
+
clearAll(): void;
|
|
12
|
+
};
|
|
13
|
+
};
|