@idem.agency/form-builder 0.0.11 → 0.0.13
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 +922 -12
- package/dist/index.cjs +272 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -16
- package/dist/index.d.mts +18 -16
- package/dist/index.mjs +273 -89
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -2
- package/src/index.ts +19 -5
- package/CHANGELOG.md +0 -8
- package/eslint.config.js +0 -23
- package/public/index.html +0 -13
- package/public/main.tsx +0 -90
- package/src/app/debug.tsx +0 -0
- package/src/app/index.tsx +0 -80
- package/src/app/test.css +0 -1
- package/src/entity/inputs/index.ts +0 -2
- package/src/entity/inputs/ui/group/index.tsx +0 -28
- package/src/entity/inputs/ui/input/index.tsx +0 -31
- package/src/shared/hook/useUpdateEffect.tsx +0 -23
- package/src/shared/lib/VisibleCore.spec.ts +0 -103
- package/src/shared/lib/VisibleCore.ts +0 -43
- package/src/shared/lib/validation/core.spec.ts +0 -103
- package/src/shared/lib/validation/core.ts +0 -79
- package/src/shared/lib/validation/rules/base.ts +0 -10
- package/src/shared/lib/validation/rules/confirm.spec.ts +0 -17
- package/src/shared/lib/validation/rules/confirm.ts +0 -32
- package/src/shared/lib/validation/rules/email.spec.ts +0 -12
- package/src/shared/lib/validation/rules/email.ts +0 -13
- package/src/shared/lib/validation/rules/require.spec.ts +0 -13
- package/src/shared/lib/validation/rules/require.ts +0 -12
- package/src/shared/model/builder/createContext.tsx +0 -40
- package/src/shared/model/builder/index.ts +0 -6
- package/src/shared/model/index.ts +0 -12
- package/src/shared/model/store/createStoreContext.tsx +0 -74
- package/src/shared/model/store/index.ts +0 -46
- package/src/shared/model/store/store.ts +0 -27
- package/src/shared/types/common.ts +0 -79
- package/src/shared/utils.ts +0 -25
- package/src/widgets/dynamicBuilder/element.tsx +0 -31
- package/src/widgets/dynamicBuilder/index.tsx +0 -33
- package/tsconfig.json +0 -24
- package/tsdown.config.ts +0 -10
- package/vite.config.ts +0 -11
package/dist/index.cjs
CHANGED
|
@@ -47,18 +47,29 @@ function createStore(reducer, initialState) {
|
|
|
47
47
|
},
|
|
48
48
|
subscribe(listener) {
|
|
49
49
|
listeners.add(listener);
|
|
50
|
-
return () =>
|
|
50
|
+
return () => {
|
|
51
|
+
listeners.delete(listener);
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
subscribeSelector(selector, listener) {
|
|
55
|
+
let prev = selector(state);
|
|
56
|
+
return this.subscribe(() => {
|
|
57
|
+
const next = selector(state);
|
|
58
|
+
if (next !== prev) {
|
|
59
|
+
prev = next;
|
|
60
|
+
listener(next);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
51
63
|
}
|
|
52
64
|
};
|
|
53
65
|
}
|
|
54
66
|
|
|
55
67
|
//#endregion
|
|
56
68
|
//#region src/shared/model/store/createStoreContext.tsx
|
|
57
|
-
function createStoreContext
|
|
69
|
+
function createStoreContext(reducer, defaultState) {
|
|
58
70
|
const StoreContext = (0, react.createContext)(null);
|
|
59
|
-
const Provider = ({ children }) => {
|
|
60
|
-
const storeRef = (0, react.useRef)(
|
|
61
|
-
if (!storeRef.current) storeRef.current = createStore(reducer, initialState);
|
|
71
|
+
const Provider = ({ children, initialState }) => {
|
|
72
|
+
const storeRef = (0, react.useRef)(createStore(reducer, initialState ?? defaultState));
|
|
62
73
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StoreContext.Provider, {
|
|
63
74
|
value: storeRef.current,
|
|
64
75
|
children
|
|
@@ -74,51 +85,56 @@ function createStoreContext$1(reducer, initialState) {
|
|
|
74
85
|
if (!store) throw new Error("StoreProvider missing");
|
|
75
86
|
return store.dispatch;
|
|
76
87
|
}
|
|
77
|
-
function
|
|
88
|
+
function useStoreInstance() {
|
|
78
89
|
const store = (0, react.useContext)(StoreContext);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
};
|
|
90
|
+
if (!store) throw new Error("StoreProvider missing");
|
|
91
|
+
return store;
|
|
82
92
|
}
|
|
83
93
|
return {
|
|
84
94
|
Provider,
|
|
85
95
|
useStore,
|
|
86
|
-
|
|
87
|
-
|
|
96
|
+
useDispatch,
|
|
97
|
+
useStoreInstance
|
|
88
98
|
};
|
|
89
99
|
}
|
|
90
100
|
|
|
91
101
|
//#endregion
|
|
92
102
|
//#region src/shared/utils.ts
|
|
93
103
|
function updateNestedValue(obj, path, value) {
|
|
94
|
-
if (path
|
|
104
|
+
if (!path) return value;
|
|
105
|
+
return _updateByKeys(obj, path.split("."), value);
|
|
106
|
+
}
|
|
107
|
+
function _updateByKeys(obj, keys, value) {
|
|
108
|
+
if (keys.length === 0) return value;
|
|
95
109
|
const newObj = Array.isArray(obj) ? [...obj] : { ...obj };
|
|
96
|
-
const currentKey =
|
|
97
|
-
if (
|
|
110
|
+
const currentKey = keys[0];
|
|
111
|
+
if (currentKey === "__proto__" || currentKey === "constructor" || currentKey === "prototype") throw new Error(`Forbidden path key: ${currentKey}`);
|
|
112
|
+
if (keys.length === 1) newObj[currentKey] = value;
|
|
98
113
|
else {
|
|
99
|
-
const
|
|
114
|
+
const remainingKeys = keys.slice(1);
|
|
100
115
|
const nestedObj = newObj[currentKey];
|
|
101
|
-
if (typeof nestedObj === "undefined" || nestedObj === null) newObj[currentKey] = typeof
|
|
102
|
-
newObj[currentKey] =
|
|
116
|
+
if (typeof nestedObj === "undefined" || nestedObj === null) newObj[currentKey] = typeof remainingKeys[0] === "number" ? [] : {};
|
|
117
|
+
newObj[currentKey] = _updateByKeys(newObj[currentKey], remainingKeys, value);
|
|
103
118
|
}
|
|
104
119
|
return newObj;
|
|
105
120
|
}
|
|
106
121
|
function getNestedValue(obj, path) {
|
|
107
|
-
|
|
122
|
+
if (!path) return obj;
|
|
123
|
+
return path.split(".").reduce((acc, key) => acc && acc[key] !== void 0 ? acc[key] : void 0, obj);
|
|
108
124
|
}
|
|
109
125
|
|
|
110
126
|
//#endregion
|
|
111
|
-
//#region src/shared/model/store/index.
|
|
112
|
-
const initialState = {
|
|
113
|
-
formData: {},
|
|
114
|
-
errors: {}
|
|
115
|
-
};
|
|
127
|
+
//#region src/shared/model/store/index.tsx
|
|
116
128
|
function reducer(state, action) {
|
|
117
129
|
const newData = { ...state };
|
|
118
130
|
switch (action.type) {
|
|
119
131
|
case "setValue":
|
|
120
132
|
newData.formData = updateNestedValue(newData.formData, action.path, action.value);
|
|
121
133
|
break;
|
|
134
|
+
case "setFieldValue":
|
|
135
|
+
newData.formData = updateNestedValue(newData.formData, action.path, action.value);
|
|
136
|
+
newData.errors = updateNestedValue(newData.errors, action.path, action?.errors?.length ? action.errors : null);
|
|
137
|
+
break;
|
|
122
138
|
case "setError":
|
|
123
139
|
newData.errors = updateNestedValue(newData.errors, action.path, action.value);
|
|
124
140
|
break;
|
|
@@ -132,106 +148,262 @@ function reducer(state, action) {
|
|
|
132
148
|
}
|
|
133
149
|
return newData;
|
|
134
150
|
}
|
|
135
|
-
const { Provider
|
|
151
|
+
const { Provider, useStore: useFormStore, useDispatch: useFormDispatch, useStoreInstance: useFormStoreInstance } = createStoreContext(reducer, {
|
|
152
|
+
formData: {},
|
|
153
|
+
errors: {}
|
|
154
|
+
});
|
|
155
|
+
const FormStoreProvider = ({ children, formData }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Provider, {
|
|
156
|
+
initialState: {
|
|
157
|
+
formData: formData ?? {},
|
|
158
|
+
errors: {}
|
|
159
|
+
},
|
|
160
|
+
children
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
//#endregion
|
|
164
|
+
//#region src/plugins/validation/rules/confirm.ts
|
|
165
|
+
const confirm = {
|
|
166
|
+
code: "confirm",
|
|
167
|
+
fn: (value, data, args) => {
|
|
168
|
+
const attr = args[0] ?? false;
|
|
169
|
+
return attr ? value == getNestedValue(data, attr) : false;
|
|
170
|
+
},
|
|
171
|
+
message: "Поле не совпадает с ::attr(1)"
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
//#endregion
|
|
175
|
+
//#region src/plugins/validation/rules/required.ts
|
|
176
|
+
const required = {
|
|
177
|
+
code: "required",
|
|
178
|
+
fn: (value) => {
|
|
179
|
+
return value !== void 0 && value !== null && value.length > 0;
|
|
180
|
+
},
|
|
181
|
+
message: "Поле обязательно для заполнения"
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region src/plugins/validation/rules/email.ts
|
|
186
|
+
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
187
|
+
const email = {
|
|
188
|
+
code: "email",
|
|
189
|
+
fn: (value) => {
|
|
190
|
+
return emailRegex.test(value);
|
|
191
|
+
},
|
|
192
|
+
message: "Поле не является email"
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region src/plugins/validation/rules/index.ts
|
|
197
|
+
var rules_default = [
|
|
198
|
+
confirm,
|
|
199
|
+
required,
|
|
200
|
+
email
|
|
201
|
+
];
|
|
202
|
+
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region src/plugins/validation/validation.ts
|
|
205
|
+
var Validation = class {
|
|
206
|
+
registry = [];
|
|
207
|
+
registerFields = {};
|
|
208
|
+
constructor(onSubmit, rules = []) {
|
|
209
|
+
this.onSubmit = onSubmit;
|
|
210
|
+
this.registry = [...rules, ...rules_default];
|
|
211
|
+
}
|
|
212
|
+
validateRule(rule, data, formData) {
|
|
213
|
+
const [code, rawArgs] = rule.split(":");
|
|
214
|
+
const args = rawArgs ? rawArgs.split(",") : [];
|
|
215
|
+
const userRule = this.registry.find((i) => i.code == code);
|
|
216
|
+
if (!userRule) return null;
|
|
217
|
+
return !userRule.fn(data, formData, args) ? this.replaceMessageArgs(userRule.message, args) : null;
|
|
218
|
+
}
|
|
219
|
+
replaceMessageArgs(message, args = []) {
|
|
220
|
+
const replaceArgs = args.reduce((acc, arg, index) => {
|
|
221
|
+
acc[`::attr(${index})`] = arg;
|
|
222
|
+
return acc;
|
|
223
|
+
}, {});
|
|
224
|
+
return message.replace(/::attr\(\d\)/g, (i) => replaceArgs[i]);
|
|
225
|
+
}
|
|
226
|
+
registerField(path, validators) {
|
|
227
|
+
this.registerFields[path] = validators;
|
|
228
|
+
}
|
|
229
|
+
_validate(rules, data, formData) {
|
|
230
|
+
return rules.map((rule) => {
|
|
231
|
+
return this.validateRule(rule, data, formData);
|
|
232
|
+
}).filter((i) => i !== null);
|
|
233
|
+
}
|
|
234
|
+
validate(rules, data, formData) {
|
|
235
|
+
return !this.onSubmit ? this._validate(rules, data, formData) : [];
|
|
236
|
+
}
|
|
237
|
+
validateAll(formData) {
|
|
238
|
+
return Object.entries(this.registerFields).reduce((acc, [path, rules]) => {
|
|
239
|
+
const value = getNestedValue(formData, path);
|
|
240
|
+
const validationMessage = this._validate(rules, value, formData);
|
|
241
|
+
if (validationMessage.length) acc[path] = validationMessage;
|
|
242
|
+
return acc;
|
|
243
|
+
}, {});
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/plugins/validation/provider.tsx
|
|
249
|
+
function createValidationProvider() {
|
|
250
|
+
const Context = (0, react.createContext)(null);
|
|
251
|
+
const Provider = ({ validator = {
|
|
252
|
+
onSubmit: false,
|
|
253
|
+
rules: []
|
|
254
|
+
}, children }) => {
|
|
255
|
+
const core = (0, react.useMemo)(() => new Validation(validator.onSubmit ?? false, validator.rules ?? []), [validator]);
|
|
256
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Context.Provider, {
|
|
257
|
+
value: core,
|
|
258
|
+
children
|
|
259
|
+
});
|
|
260
|
+
};
|
|
261
|
+
const useValidate = (rules) => {
|
|
262
|
+
const core = (0, react.useContext)(Context);
|
|
263
|
+
if (!core) throw new Error("ValidationProvider missing");
|
|
264
|
+
return (data, formData) => {
|
|
265
|
+
return core.validate(rules ?? [], data, formData);
|
|
266
|
+
};
|
|
267
|
+
};
|
|
268
|
+
const useRegister = (currentFieldPath, field) => {
|
|
269
|
+
const core = (0, react.useContext)(Context);
|
|
270
|
+
if (!core) throw new Error("ValidationProvider missing");
|
|
271
|
+
core.registerField(currentFieldPath, field.validation ?? []);
|
|
272
|
+
return useValidate(field.validation);
|
|
273
|
+
};
|
|
274
|
+
const useSubmitValidation = () => {
|
|
275
|
+
const core = (0, react.useContext)(Context);
|
|
276
|
+
if (!core) throw new Error("ValidationProvider missing");
|
|
277
|
+
return (formData) => core.validateAll(formData);
|
|
278
|
+
};
|
|
279
|
+
return {
|
|
280
|
+
Provider,
|
|
281
|
+
useRegister,
|
|
282
|
+
useSubmitValidation
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
//#endregion
|
|
287
|
+
//#region src/plugins/validation/index.ts
|
|
288
|
+
const { Provider: ValidationProvider, useRegister, useSubmitValidation } = createValidationProvider();
|
|
136
289
|
|
|
137
290
|
//#endregion
|
|
138
|
-
//#region src/
|
|
139
|
-
const
|
|
291
|
+
//#region src/entity/dynamicBuilder/element.tsx
|
|
292
|
+
const DynamicBuilderElement = (props) => {
|
|
140
293
|
const Element = props.element;
|
|
141
294
|
const field = props.field;
|
|
142
|
-
const currentFieldPath =
|
|
295
|
+
const currentFieldPath = props.path ? `${props.path}.${field.name}` : field.name;
|
|
143
296
|
const value = useFormStore(((s) => getNestedValue(s.formData, currentFieldPath)));
|
|
144
|
-
const errors = useFormStore(((s) =>
|
|
297
|
+
const errors = useFormStore(((s) => s.errors[currentFieldPath]));
|
|
145
298
|
const dispatch = useFormDispatch();
|
|
299
|
+
const store = useFormStoreInstance();
|
|
300
|
+
const validator = useRegister(currentFieldPath, field);
|
|
146
301
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Element, {
|
|
147
302
|
field: { ...field },
|
|
148
|
-
builder: props.DynamicBuilder,
|
|
149
303
|
path: currentFieldPath,
|
|
150
|
-
plugins: props.plugins,
|
|
151
304
|
value,
|
|
152
305
|
errors,
|
|
153
306
|
onChange: (value) => {
|
|
307
|
+
const data = store.getState().formData;
|
|
154
308
|
dispatch({
|
|
155
|
-
type: "
|
|
309
|
+
type: "setFieldValue",
|
|
156
310
|
path: currentFieldPath,
|
|
157
|
-
value
|
|
158
|
-
|
|
159
|
-
dispatch({
|
|
160
|
-
type: "setError",
|
|
161
|
-
path: currentFieldPath,
|
|
162
|
-
value: ""
|
|
311
|
+
value,
|
|
312
|
+
errors: validator(value, data)
|
|
163
313
|
});
|
|
164
314
|
}
|
|
165
315
|
});
|
|
166
316
|
};
|
|
167
317
|
|
|
168
318
|
//#endregion
|
|
169
|
-
//#region src/
|
|
170
|
-
|
|
171
|
-
const path = props.path ?? [];
|
|
172
|
-
return props.layout.map((field, index) => {
|
|
173
|
-
const FormElement = props.plugins[field.type];
|
|
174
|
-
if (!FormElement) {
|
|
175
|
-
console.warn(`Неизвестный тип поля: ${field.type}. Проверьте formRegistry.`);
|
|
176
|
-
return null;
|
|
177
|
-
}
|
|
178
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BuilderElement, {
|
|
179
|
-
element: FormElement,
|
|
180
|
-
path,
|
|
181
|
-
field
|
|
182
|
-
}, `${field.name}${index}`);
|
|
183
|
-
});
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
//#endregion
|
|
187
|
-
//#region src/shared/model/builder/createContext.tsx
|
|
188
|
-
function createStoreContext() {
|
|
319
|
+
//#region src/entity/dynamicBuilder/model/createBuilderContext.tsx
|
|
320
|
+
function createBuilderContext() {
|
|
189
321
|
const BuilderContext = (0, react.createContext)(null);
|
|
190
|
-
const Provider = ({
|
|
191
|
-
const
|
|
192
|
-
if (!storeRef.current) storeRef.current = (layout, path, children) => {
|
|
322
|
+
const Provider = ({ fields, children }) => {
|
|
323
|
+
const builder = (0, react.useCallback)((layout, path, children) => {
|
|
193
324
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DynamicBuilder, {
|
|
194
325
|
layout,
|
|
195
326
|
path,
|
|
196
|
-
plugins,
|
|
197
327
|
children
|
|
198
328
|
});
|
|
199
|
-
};
|
|
329
|
+
}, [fields]);
|
|
200
330
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BuilderContext.Provider, {
|
|
201
|
-
value:
|
|
331
|
+
value: {
|
|
332
|
+
builder,
|
|
333
|
+
fields
|
|
334
|
+
},
|
|
202
335
|
children
|
|
203
336
|
});
|
|
204
337
|
};
|
|
205
338
|
function useBuilder() {
|
|
206
339
|
const store = (0, react.useContext)(BuilderContext);
|
|
207
340
|
if (!store) throw new Error("StoreProvider missing");
|
|
208
|
-
return store;
|
|
341
|
+
return store.builder;
|
|
342
|
+
}
|
|
343
|
+
function useFields() {
|
|
344
|
+
const store = (0, react.useContext)(BuilderContext);
|
|
345
|
+
if (!store) throw new Error("StoreProvider missing");
|
|
346
|
+
return store.fields;
|
|
209
347
|
}
|
|
210
348
|
return {
|
|
211
349
|
Provider,
|
|
212
|
-
useBuilder
|
|
350
|
+
useBuilder,
|
|
351
|
+
useFields
|
|
213
352
|
};
|
|
214
353
|
}
|
|
215
354
|
|
|
216
355
|
//#endregion
|
|
217
|
-
//#region src/
|
|
218
|
-
const { Provider: BuilderProvider, useBuilder } =
|
|
356
|
+
//#region src/entity/dynamicBuilder/model/index.ts
|
|
357
|
+
const { Provider: BuilderProvider, useBuilder, useFields } = createBuilderContext();
|
|
219
358
|
|
|
220
359
|
//#endregion
|
|
221
|
-
//#region src/
|
|
222
|
-
const
|
|
223
|
-
const
|
|
224
|
-
|
|
360
|
+
//#region src/entity/dynamicBuilder/index.tsx
|
|
361
|
+
const DynamicBuilder = (props) => {
|
|
362
|
+
const path = props.path ?? "";
|
|
363
|
+
const fields = useFields();
|
|
364
|
+
return props.layout.map((field, index) => {
|
|
365
|
+
const FormElement = fields[field.type];
|
|
366
|
+
if (!FormElement) {
|
|
367
|
+
console.warn(`Неизвестный тип поля: ${field.type}. Проверьте formRegistry.`);
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DynamicBuilderElement, {
|
|
371
|
+
element: FormElement,
|
|
372
|
+
path,
|
|
373
|
+
field
|
|
374
|
+
}, `${field.name}-${index}`);
|
|
225
375
|
});
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
//#endregion
|
|
379
|
+
//#region src/widgets/form/form.tsx
|
|
380
|
+
const Form = (0, react.forwardRef)((props, ref) => {
|
|
381
|
+
const dispatch = useFormDispatch();
|
|
382
|
+
const store = useFormStoreInstance();
|
|
383
|
+
const changeRef = (0, react.useRef)(props.onChange);
|
|
384
|
+
(0, react.useEffect)(() => {
|
|
385
|
+
return store.subscribeSelector((s) => s.formData, (formData) => changeRef.current?.(formData));
|
|
386
|
+
}, [store]);
|
|
387
|
+
const validation = useSubmitValidation();
|
|
388
|
+
const submitHdl = (0, react.useCallback)(() => {
|
|
389
|
+
if (props.onSubmit) {
|
|
390
|
+
const errors = validation(store.getState().formData);
|
|
391
|
+
if (Object.keys(errors).length == 0) props.onSubmit(store.getState().formData);
|
|
392
|
+
else dispatch({
|
|
393
|
+
type: "setErrors",
|
|
394
|
+
errors
|
|
395
|
+
});
|
|
233
396
|
}
|
|
234
|
-
}
|
|
397
|
+
}, [props.onSubmit, validation]);
|
|
398
|
+
(0, react.useImperativeHandle)(ref, () => ({
|
|
399
|
+
reset: () => dispatch({ type: "reset" }),
|
|
400
|
+
submit: () => submitHdl(),
|
|
401
|
+
errors: () => store.getState().errors
|
|
402
|
+
}), [
|
|
403
|
+
submitHdl,
|
|
404
|
+
dispatch,
|
|
405
|
+
store
|
|
406
|
+
]);
|
|
235
407
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
236
408
|
onSubmit: (e) => {
|
|
237
409
|
e.preventDefault();
|
|
@@ -239,13 +411,10 @@ const FormBuilder = (0, react.forwardRef)((props, ref) => {
|
|
|
239
411
|
},
|
|
240
412
|
className: props?.className,
|
|
241
413
|
children: [
|
|
242
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
243
|
-
|
|
244
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DynamicBuilder, {
|
|
245
|
-
|
|
246
|
-
plugins: props.plugins
|
|
247
|
-
})
|
|
248
|
-
}) }),
|
|
414
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(BuilderProvider, {
|
|
415
|
+
fields: props.fields,
|
|
416
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DynamicBuilder, { layout: props.layout })
|
|
417
|
+
}),
|
|
249
418
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
250
419
|
type: "submit",
|
|
251
420
|
style: { display: "none" }
|
|
@@ -255,6 +424,22 @@ const FormBuilder = (0, react.forwardRef)((props, ref) => {
|
|
|
255
424
|
});
|
|
256
425
|
});
|
|
257
426
|
|
|
427
|
+
//#endregion
|
|
428
|
+
//#region src/app/index.tsx
|
|
429
|
+
const FormBuilder = (0, react.forwardRef)((props, ref) => {
|
|
430
|
+
const { formData, ...innerProps } = props;
|
|
431
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormStoreProvider, {
|
|
432
|
+
formData,
|
|
433
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValidationProvider, {
|
|
434
|
+
validator: props.validator,
|
|
435
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Form, {
|
|
436
|
+
...innerProps,
|
|
437
|
+
ref
|
|
438
|
+
})
|
|
439
|
+
})
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
|
|
258
443
|
//#endregion
|
|
259
444
|
//#region src/entity/inputs/ui/input/index.tsx
|
|
260
445
|
function isTextFieldConfig(field) {
|
|
@@ -296,7 +481,7 @@ const TextField = ({ field, value, errors, onChange }) => {
|
|
|
296
481
|
//#endregion
|
|
297
482
|
//#region src/entity/inputs/ui/group/index.tsx
|
|
298
483
|
function isGroupConfig(field) {
|
|
299
|
-
return field.fields;
|
|
484
|
+
return Array.isArray(field.fields);
|
|
300
485
|
}
|
|
301
486
|
const FormGroup = ({ field, path }) => {
|
|
302
487
|
if (!isGroupConfig(field)) return null;
|
|
@@ -307,7 +492,6 @@ const FormGroup = ({ field, path }) => {
|
|
|
307
492
|
children: Builder
|
|
308
493
|
})] });
|
|
309
494
|
};
|
|
310
|
-
FormGroup.fieldProps = ["fields"];
|
|
311
495
|
|
|
312
496
|
//#endregion
|
|
313
497
|
//#region src/shared/model/index.ts
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["createStoreContext","createStoreContext","z"],"sources":["../src/shared/model/store/store.ts","../src/shared/model/store/createStoreContext.tsx","../src/shared/utils.ts","../src/shared/model/store/index.ts","../src/widgets/dynamicBuilder/element.tsx","../src/widgets/dynamicBuilder/index.tsx","../src/shared/model/builder/createContext.tsx","../src/shared/model/builder/index.ts","../src/app/index.tsx","../src/entity/inputs/ui/input/index.tsx","../src/entity/inputs/ui/group/index.tsx","../src/shared/model/index.ts"],"sourcesContent":["export type Reducer<S, A> = (state: S, action: A) => S;\n\nexport function createStore<S, A>(\n reducer: Reducer<S, A>,\n initialState: S\n) {\n let state = initialState;\n const listeners = new Set<() => void>();\n \n return {\n getState(): S {\n return state;\n },\n \n dispatch(action: A) {\n state = reducer(state, action);\n listeners.forEach(l => l());\n },\n \n subscribe(listener: () => void) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n }\n };\n}\n\nexport type Store<S, A> = ReturnType<typeof createStore<S, A>>;\n","import {\n createContext,\n useContext,\n useRef,\n useSyncExternalStore\n} from \"react\";\nimport { createStore, type Reducer, type Store } from \"./store\";\n\nexport function createStoreContext<S, A>(\n reducer: Reducer<S, A>,\n initialState: S\n) {\n const StoreContext = createContext<Store<S, A> | null>(null);\n \n const Provider: React.FC<{ children: React.ReactNode }> = ({\n children\n }) => {\n const storeRef = useRef<Store<S, A>>(null);\n \n if (!storeRef.current) {\n storeRef.current = createStore(reducer, initialState);\n }\n\n return (\n <StoreContext.Provider value={storeRef.current}>\n {children}\n </StoreContext.Provider>\n );\n };\n \n function useStore<T>(\n selector: (state: S) => T\n ): T {\n const store = useContext(StoreContext);\n\n if (!store) {\n throw new Error(\"StoreProvider missing\");\n }\n \n return useSyncExternalStore(\n store.subscribe,\n () => selector(store.getState()),\n () => selector(store.getState())\n );\n }\n \n function useDispatch() {\n const store = useContext(StoreContext);\n \n if (!store) {\n throw new Error(\"StoreProvider missing\");\n }\n \n return store.dispatch;\n }\n \n function useSubmit(onSubmit: (state: S) => void) {\n const store = useContext(StoreContext);\n \n return () => {\n if (store) {\n const state = store.getState();\n onSubmit(state);\n }\n };\n }\n \n return {\n Provider,\n useStore,\n useSubmit,\n useDispatch\n };\n}\n","export function updateNestedValue(obj: any, path: string[], value: any): any {\n if (path.length === 0) {\n return value;\n }\n \n const newObj = Array.isArray(obj) ? [...obj] : { ...obj }; // Создаем копию\n const currentKey = path[0];\n \n if (path.length === 1) {\n // Последний элемент пути, просто обновляем значение\n newObj[currentKey] = value;\n } else {\n const remainingPath = path.slice(1);\n const nestedObj = newObj[currentKey];\n \n if (typeof nestedObj === 'undefined' || nestedObj === null) {\n newObj[currentKey] = typeof remainingPath[0] === 'number' ? [] : {};\n }\n newObj[currentKey] = updateNestedValue(newObj[currentKey], remainingPath, value);\n }\n return newObj;\n}\nexport function getNestedValue(obj: any, path: string[]): any {\n return path.reduce((acc, key) => (acc && acc[key] !== undefined ? acc[key] : undefined), obj);\n}\n","import { createStoreContext } from \"./createStoreContext\";\nimport type {FormData} from \"@/shared/types/common\";\nimport {updateNestedValue} from \"@/shared/utils\";\n\ntype State = {\n formData: FormData\n errors: Record<string, any>\n};\n\ntype Action =\n | { type: \"setValue\"; path: string[]; value: unknown }\n | { type: \"setError\"; path: string[]; value?: string }\n | { type: \"reset\"; }\n | { type: \"setErrors\"; errors?: object };\n\nconst initialState: State = {\n formData: {},\n errors: {}\n};\n\nfunction reducer(state: State, action: Action): State {\n const newData = {...state};\n switch (action.type) {\n case 'setValue':\n newData.formData = updateNestedValue(newData.formData, action.path, action.value);\n break;\n case 'setError':\n newData.errors = updateNestedValue(newData.errors, action.path, action.value);\n break;\n case 'reset':\n newData.formData = {};\n newData.errors = {};\n break;\n case 'setErrors':\n newData.errors = {...action.errors};\n break;\n }\n return newData;\n}\n\nexport const {\n Provider: FormStoreProvider,\n useStore: useFormStore,\n useDispatch: useFormDispatch,\n useSubmit,\n} = createStoreContext(reducer, initialState);\n","import {useFormStore, useFormDispatch} from \"@/shared/model/store\";\nimport {getNestedValue} from \"@/shared/utils\";\n\nexport const BuilderElement = (props: any) => {\n const Element = props.element;\n const field = props.field;\n const currentFieldPath = [...props.path, field.name];\n const value = useFormStore((s=> getNestedValue(s.formData, currentFieldPath)));\n const errors = useFormStore((s=> getNestedValue(s.errors, currentFieldPath)));\n const dispatch= useFormDispatch();\n return <Element\n field={{...field}}\n builder={props.DynamicBuilder}\n path={currentFieldPath}\n plugins={props.plugins}\n value={value}\n errors={errors}\n onChange={(value: any) => {\n dispatch({\n type: 'setValue',\n path: currentFieldPath,\n value\n });\n dispatch({\n type: 'setError',\n path: currentFieldPath,\n value: ''\n });\n }}\n />;\n}\n","import type {TDynamicBuilder} from \"@/shared/types/common\";\nimport {BuilderElement} from \"@/widgets/dynamicBuilder/element\";\n// import {getNestedValue} from \"@/shared/utils\";\n// import {useCallback} from \"react\";\n// import {VisibleCore} from \"@/shared/lib/VisibleCore\";\n// import {use} from \"@/shared/model/store\";\n\nexport const DynamicBuilder: TDynamicBuilder = (props) => {\n const path = props.path ?? [];\n \n // const isShow = useCallback((field: FormFieldConfig) => {\n // let result = true;\n //\n // if (field.viewConfig) {\n // result = VisibleCore.isVisible(field.viewConfig, state.formData);\n // }\n // return result;\n // }, [state]);\n \n \n return props.layout.map((field, index) => {\n const FormElement = props.plugins[field.type];\n \n if (!FormElement) {\n console.warn(`Неизвестный тип поля: ${field.type}. Проверьте formRegistry.`);\n return null;\n }\n \n // const currentValue = getNestedValue(state.formData, currentFieldPath);\n // const currentErrors = getNestedValue(state.errors, currentFieldPath) as (Record<string, string> | undefined);\n return <BuilderElement key={`${field.name}${index}`} element={FormElement} path={path} field={field}/>\n })\n}\n","import React, {createContext, type ReactNode, useContext, useRef,} from \"react\";\nimport {DynamicBuilder} from \"@/widgets/dynamicBuilder\";\n\nexport function createStoreContext() {\n const BuilderContext = createContext<((layout: any, path: string[]|undefined, children?: ReactNode) => ReactNode) | null>(null);\n \n const Provider: React.FC<{ children: React.ReactNode, plugins: any }> = ({\n plugins,\n children\n }) => {\n const storeRef = useRef<(layout: any, path: string[]|undefined, children?: ReactNode) => ReactNode>(null);\n \n if (!storeRef.current) {\n storeRef.current = (layout: any, path: string[]|undefined, children?: ReactNode) => {\n return <DynamicBuilder layout={layout} path={path} plugins={plugins}>{children}</DynamicBuilder>\n };\n }\n \n return (\n <BuilderContext.Provider value={storeRef.current}>\n {children}\n </BuilderContext.Provider>\n );\n };\n \n function useBuilder(): (layout: any, path: string[]|undefined, children?: ReactNode) => ReactNode {\n const store = useContext(BuilderContext);\n \n if (!store) {\n throw new Error(\"StoreProvider missing\");\n }\n \n return store\n }\n \n return {\n Provider,\n useBuilder\n };\n}\n","import {createStoreContext} from \"@/shared/model/builder/createContext\";\n\nexport const {\n Provider: BuilderProvider,\n useBuilder,\n} = createStoreContext();\n","'use client';\n\nimport type {FormBuilderRef, TFormBuilder} from \"../shared/types/common\";\n// import {StoreContext, storeReducer,} from \"@/shared/model\";\n\nimport {DynamicBuilder} from \"../widgets/dynamicBuilder\";\nimport { forwardRef, useImperativeHandle} from \"react\";\n// import {ValidationCore} from \"@/shared/lib/validation/core\";\n// import { useUpdateEffect } from '@/shared/hook/useUpdateEffect';\nimport {FormStoreProvider, useSubmit} from \"@/shared/model/store\";\nimport {BuilderProvider} from \"@/shared/model/builder\";\n\nexport const FormBuilder = forwardRef<FormBuilderRef, TFormBuilder>((props, ref) => {\n // const validator = useMemo(() => {\n // return (new ValidationCore(props.layout, props.plugins))\n // }, [props.layout, props.plugins]);\n\n // const [state, dispatch] = useReducer(storeReducer, {\n // formData: props.formData ?? {},\n // errors: {},\n // });\n //\n // useUpdateEffect(() => {\n // if (props.onChange) {\n // props.onChange(state.formData);\n // }\n // }, [state.formData, props.onChange]);\n const submitHdl = useSubmit((data) => {\n if (props.onSubmit) {\n props.onSubmit(data);\n }\n });\n \n // const submit = () => {\n //\n // // const errors = validator.validate(state.formData);\n // // if (Object.keys(errors).length == 0) {\n // // if (props.onSubmit) {\n // // props.onSubmit(state.formData)\n // // }\n // // } else {\n // // dispatch({\n // // type: 'setErrors',\n // // payload: {\n // // errors\n // // }\n // // });\n // // }\n // }\n\n useImperativeHandle(ref, () => ({\n reset: () => {\n // dispatch({type: 'reset'})\n },\n submit: () => {\n submitHdl();\n },\n errors: () => {\n return {}\n // return state?.errors ?? {};\n }\n }), [props.onSubmit]);\n\n return <form onSubmit={(e) => {\n e.preventDefault();\n submitHdl();\n }}\n className={props?.className}\n >\n <FormStoreProvider>\n <BuilderProvider plugins={props.plugins}>\n <DynamicBuilder layout={props.layout} plugins={props.plugins} />\n </BuilderProvider>\n </FormStoreProvider>\n <input type=\"submit\" style={{ display: 'none' }}/>\n {props.children}\n </form>\n});\n\nexport default FormBuilder;\n","import type { FormElementProps, FormFieldConfig, FormFieldBase, RC } from '../../../../shared/types/common';\nimport { useId } from \"react\";\n\nexport type TextFieldConfig = FormFieldBase & { type: 'text' | 'email' | 'password'; placeholder?: string; };\n\nfunction isTextFieldConfig(field: FormFieldConfig): field is TextFieldConfig {\n return field.type === 'text' || field.type === 'email' || field.type === 'password';\n}\n\nexport const TextField: RC<FormElementProps> = ({ field, value, errors, onChange }) => {\n if (!isTextFieldConfig(field)) {\n console.warn(`TextField received an invalid field config for type: ${field.type}`);\n return null;\n }\n const id = useId();\n return (\n <div style={{ marginBottom: '15px' }}>\n <label htmlFor={id}>{field.label}:</label>\n <input\n type={field.type}\n id={id}\n name={field.name}\n placeholder={field.placeholder}\n value={value || ''}\n onChange={(e) => onChange(e.target.value)}\n style={{ borderColor: errors ? 'red' : '#ccc' }}\n />\n {errors && <p style={{ color: 'red', fontSize: '0.8em' }}>{Object.values(errors).join(', ')}</p>}\n </div>\n );\n};\n","import type {FormElementProps, FormFieldBase, FormFieldConfig, RC} from \"../../../../shared/types/common.ts\";\nimport clsx from \"clsx\";\nimport {useBuilder} from \"@/shared/model/builder\";\nexport type FormGroupConfig = FormFieldBase & { variant?: 'row' | 'col', fields: FormFieldConfig[] };\n\nfunction isGroupConfig(field: FormFieldConfig): field is FormGroupConfig {\n return field.fields;\n}\n\n\nexport const FormGroup: RC<FormElementProps<FormGroupConfig>> = ({field, path}) => {\n if (!isGroupConfig(field)) {\n return null;\n }\n const Builder = useBuilder()(field.fields, path);\n const variant = field.variant ?? 'col';\n \n const className = variant == 'col' ? 'flex-col' : 'flex-row';\n\n return <div>\n <div>{field.label}</div>\n <div className={clsx(className, 'flex')}>\n {Builder}\n </div>\n </div>;\n};\n\nFormGroup.fieldProps = ['fields'];\n","import { z } from 'zod';\n\nconst fieldShema = z.object({\n name: z.string(),\n label: z.string().optional(),\n type: z.string(),\n});\n\ntype TField = z.infer<typeof fieldShema>;\n\nexport type { TField };\nexport { fieldShema };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["base","z"],"sources":["../src/shared/model/store/store.ts","../src/shared/model/store/createStoreContext.tsx","../src/shared/utils.ts","../src/shared/model/store/index.tsx","../src/plugins/validation/rules/confirm.ts","../src/plugins/validation/rules/required.ts","../src/plugins/validation/rules/email.ts","../src/plugins/validation/rules/index.ts","../src/plugins/validation/validation.ts","../src/plugins/validation/provider.tsx","../src/plugins/validation/index.ts","../src/entity/dynamicBuilder/element.tsx","../src/entity/dynamicBuilder/model/createBuilderContext.tsx","../src/entity/dynamicBuilder/model/index.ts","../src/entity/dynamicBuilder/index.tsx","../src/widgets/form/form.tsx","../src/app/index.tsx","../src/entity/inputs/ui/input/index.tsx","../src/entity/inputs/ui/group/index.tsx","../src/shared/model/index.ts"],"sourcesContent":["export type Reducer<S, A> = (state: S, action: A) => S;\n\nexport function createStore<S, A>(\n reducer: Reducer<S, A>,\n initialState: S\n) {\n let state = initialState;\n const listeners = new Set<() => void>();\n \n return {\n getState(): S {\n return state;\n },\n \n dispatch(action: A) {\n state = reducer(state, action);\n listeners.forEach(l => l());\n },\n \n subscribe(listener: () => void) {\n listeners.add(listener);\n return () => { listeners.delete(listener) };\n },\n\n subscribeSelector<T>(selector: (state: S) => T, listener: (value: T) => void) {\n let prev = selector(state);\n return this.subscribe(() => {\n const next = selector(state);\n if (next !== prev) {\n prev = next;\n listener(next);\n }\n });\n }\n };\n}\n\nexport type Store<S, A> = ReturnType<typeof createStore<S, A>>;\n","import {\n createContext,\n useContext,\n useRef,\n useSyncExternalStore\n} from \"react\";\n\nimport { createStore, type Reducer, type Store } from \"./store\";\n\nexport function createStoreContext<S, A>(\n reducer: Reducer<S, A>,\n defaultState: S\n) {\n const StoreContext = createContext<Store<S, A> | null>(null);\n const Provider: React.FC<{ children: React.ReactNode, initialState?: S }> = ({\n children,\n initialState\n }) => {\n const storeRef = useRef<Store<S, A>>(createStore(reducer, initialState ?? defaultState));\n\n return (\n <StoreContext.Provider value={storeRef.current}>\n {children}\n </StoreContext.Provider>\n );\n };\n \n function useStore<T>(\n selector: (state: S) => T\n ): T {\n const store = useContext(StoreContext);\n\n if (!store) {\n throw new Error(\"StoreProvider missing\");\n }\n \n return useSyncExternalStore(\n store.subscribe,\n () => selector(store.getState()),\n () => selector(store.getState())\n );\n }\n \n function useDispatch() {\n const store = useContext(StoreContext);\n \n if (!store) {\n throw new Error(\"StoreProvider missing\");\n }\n \n return store.dispatch;\n }\n \n function useStoreInstance(): Store<S, A> {\n const store = useContext(StoreContext);\n\n if (!store) {\n throw new Error(\"StoreProvider missing\");\n }\n\n return store;\n }\n \n return {\n Provider,\n useStore,\n useDispatch,\n useStoreInstance,\n };\n}\n","export function updateNestedValue(obj: any, path: string, value: any): any {\n if (!path) return value;\n return _updateByKeys(obj, path.split('.'), value);\n}\n\nfunction _updateByKeys(obj: any, keys: string[], value: any): any {\n if (keys.length === 0) return value;\n\n const newObj = Array.isArray(obj) ? [...obj] : { ...obj };\n const currentKey = keys[0];\n\n if (currentKey === '__proto__' || currentKey === 'constructor' || currentKey === 'prototype') {\n throw new Error(`Forbidden path key: ${currentKey}`);\n }\n\n if (keys.length === 1) {\n newObj[currentKey] = value;\n } else {\n const remainingKeys = keys.slice(1);\n const nestedObj = newObj[currentKey];\n\n if (typeof nestedObj === 'undefined' || nestedObj === null) {\n newObj[currentKey] = typeof remainingKeys[0] === 'number' ? [] : {};\n }\n newObj[currentKey] = _updateByKeys(newObj[currentKey], remainingKeys, value);\n }\n return newObj;\n}\n\nexport function getNestedValue(obj: any, path: string): any {\n if (!path) return obj;\n return path.split('.').reduce(\n (acc, key) => (acc && acc[key] !== undefined ? acc[key] : undefined),\n obj\n );\n}\n","import { createStoreContext } from \"./createStoreContext\";\nimport type {FormData} from \"@/shared/types/common\";\nimport {updateNestedValue} from \"@/shared/utils\";\nimport type {Provider, ReactNode} from \"react\";\n\ntype State = {\n formData: FormData\n errors: Record<string, any>\n};\n\ntype Action =\n | { type: \"setValue\"; path: string; value: unknown }\n | { type: \"setFieldValue\"; path: string; value: unknown, errors?: string[] }\n | { type: \"setError\"; path: string; value?: string }\n | { type: \"reset\"; }\n | { type: \"setErrors\"; errors?: object };\n\n\nfunction reducer(state: State, action: Action): State {\n const newData = {...state};\n switch (action.type) {\n case 'setValue':\n newData.formData = updateNestedValue(newData.formData, action.path, action.value);\n break;\n case 'setFieldValue':\n newData.formData = updateNestedValue(newData.formData, action.path, action.value);\n newData.errors = updateNestedValue(newData.errors, action.path, action?.errors?.length ? action.errors : null);\n break;\n case 'setError':\n newData.errors = updateNestedValue(newData.errors, action.path, action.value);\n break;\n case 'reset':\n newData.formData = {};\n newData.errors = {};\n break;\n case 'setErrors':\n newData.errors = {...action.errors};\n break;\n }\n return newData;\n}\n\nconst {\n Provider,\n useStore: useFormStore,\n useDispatch: useFormDispatch,\n useStoreInstance: useFormStoreInstance,\n} = createStoreContext(reducer, { formData: {}, errors: {} });\n\nconst FormStoreProvider: React.FC<{ children: ReactNode; formData?: FormData }> = ({children, formData}) =>\n (<Provider initialState={{ formData: formData ?? {}, errors: {} }}>{children}</Provider>);\n\n\nexport { FormStoreProvider, useFormStore, useFormDispatch, useFormStoreInstance };\n","import type {IUserRule} from \"@/plugins/validation/types\";\nimport {getNestedValue} from \"@/shared/utils\";\n\nexport const confirm: IUserRule = {\n code: 'confirm',\n fn: (value, data, args) => {\n const attr = args[0] ?? false;\n return attr ? value == getNestedValue(data, attr) : false;\n },\n message: 'Поле не совпадает с ::attr(1)'\n};\n","import type {IUserRule} from \"@/plugins/validation/types\";\n\nexport const required: IUserRule = {\n code: 'required',\n fn: (value) => {\n return value !== undefined && value !== null && value.length > 0;\n },\n message: 'Поле обязательно для заполнения'\n};\n","import type {IUserRule} from \"@/plugins/validation/types\";\n\nconst emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/;\nexport const email: IUserRule = {\n code: 'email',\n fn: (value) => {\n return emailRegex.test(value);\n },\n message: 'Поле не является email'\n};\n","import { confirm } from \"@/plugins/validation/rules/confirm\";\nimport { required } from \"@/plugins/validation/rules/required\";\nimport {email} from \"@/plugins/validation/rules/email\";\n\nexport default [confirm, required, email]\n","import type {FormData} from \"@/shared/types/common\";\nimport base from './rules';\nimport type {IUserRule} from \"@/plugins/validation/types\";\nimport {getNestedValue} from \"@/shared/utils\";\n\nexport class Validation {\n private readonly registry: IUserRule[] = [];\n private registerFields: Record<string, string[]> = {};\n constructor(public readonly onSubmit: boolean, rules: IUserRule[] = []) {\n this.registry = [...rules, ...base];\n }\n \n \n private validateRule(rule: string, data: unknown, formData: FormData): string|null {\n const [code, rawArgs] = rule.split(':');\n const args = rawArgs ? rawArgs.split(',') : [];\n const userRule = this.registry.find(i => i.code == code);\n if (!userRule) {\n return null;\n }\n const validateStatus = userRule.fn(data, formData, args);\n return !validateStatus ? this.replaceMessageArgs(userRule.message, args) : null;\n }\n \n private replaceMessageArgs(message: string, args: string[] = []): string {\n const replaceArgs = args.reduce<Record<string, string>>((acc, arg, index) => {\n acc[`::attr(${index})`] = arg;\n return acc;\n }, {});\n\n return message.replace(/::attr\\(\\d\\)/g, i => replaceArgs[i]);\n }\n \n public registerField(path: string, validators: string[]): void {\n this.registerFields[path] = validators;\n }\n\n private _validate(rules: string[], data: unknown, formData: FormData): string[] {\n return rules.map((rule) => {\n return this.validateRule(rule, data, formData);\n }).filter(i => i !== null)\n }\n validate(rules: string[], data: unknown, formData: FormData): string[] {\n return !this.onSubmit ? this._validate(rules, data, formData) : [];\n }\n \n public validateAll(formData: FormData): Record<string, string[]> {\n return Object.entries(this.registerFields).reduce<Record<string, string[]>>((acc, [path, rules]) => {\n const value = getNestedValue(formData, path);\n const validationMessage = this._validate(rules, value, formData);\n if (validationMessage.length) {\n acc[path] = validationMessage;\n }\n return acc;\n } , {});\n }\n}\n","import React, {createContext, useContext, useMemo} from \"react\";\nimport type {IUserRule} from \"@/plugins/validation/types\";\nimport {Validation} from \"@/plugins/validation/validation\";\nimport type {FormData, FormFieldConfig} from \"@/shared/types/common\";\n\nexport type TValidator = {\n rules?: IUserRule[],\n onSubmit?: boolean,\n}\n\nexport function createValidationProvider() {\n const Context = createContext<Validation | null>(null);\n const Provider: React.FC<{\n children: React.ReactNode,\n validator?: TValidator,\n }> = ({\n validator = {\n onSubmit: false,\n rules: []\n },\n children\n }) => {\n const core = useMemo(() => new Validation(validator.onSubmit ?? false, validator.rules ?? []), [validator]);\n \n return (\n <Context.Provider value={core}>\n {children}\n </Context.Provider>\n );\n }\n \n const useValidate = (rules ?: string[]) => {\n const core = useContext(Context);\n if (!core) {\n throw new Error(\"ValidationProvider missing\");\n }\n return (data: unknown, formData: FormData) => {\n return core.validate(rules ?? [], data, formData);\n }\n }\n \n const useRegister = (currentFieldPath: string, field: FormFieldConfig) => {\n const core = useContext(Context);\n if (!core) {\n throw new Error(\"ValidationProvider missing\");\n }\n \n core.registerField(currentFieldPath, field.validation ?? []);\n\n return useValidate(field.validation);\n }\n \n const useSubmitValidation = () => {\n const core = useContext(Context);\n if (!core) {\n throw new Error(\"ValidationProvider missing\");\n }\n \n return (formData: FormData) => core.validateAll(formData);\n }\n \n return {\n Provider,\n useRegister,\n useSubmitValidation,\n }\n}\n","import {createValidationProvider } from \"./provider\";\nexport { type TValidator } from \"./provider\";\n\nexport const {\n Provider: ValidationProvider,\n useRegister,\n useSubmitValidation\n} = createValidationProvider();\n","import {useFormStore, useFormDispatch, useFormStoreInstance} from \"@/shared/model/store\";\nimport {getNestedValue} from \"@/shared/utils\";\n\nimport type { FormFieldConfig, FormElementComponent} from \"@/shared/types/common\";\nimport {useRegister} from \"@/plugins/validation\";\n\ntype BuilderElementProps = {\n element: FormElementComponent;\n field: FormFieldConfig;\n path: string;\n};\n\n\nexport const DynamicBuilderElement = (props: BuilderElementProps) => {\n const Element = props.element;\n const field = props.field;\n const currentFieldPath = props.path ? `${props.path}.${field.name}` : field.name;\n const value = useFormStore((s=> getNestedValue(s.formData, currentFieldPath)));\n const errors = useFormStore((s=> s.errors[currentFieldPath]));\n const dispatch= useFormDispatch();\n const store = useFormStoreInstance();\n const validator = useRegister(currentFieldPath, field);\n return <Element\n field={{...field}}\n path={currentFieldPath}\n value={value}\n errors={errors}\n onChange={(value: any) => {\n const data = store.getState().formData;\n const errors = validator(value, data);\n dispatch({\n type: 'setFieldValue',\n path: currentFieldPath,\n value,\n errors\n });\n }}\n />;\n}\n","import React, {createContext, type ReactNode, useCallback, useContext} from \"react\";\nimport {DynamicBuilder} from \"@/entity/dynamicBuilder\";\nimport type {FormElementRegistry} from \"~/src\";\n\nexport type TFnBuilder = (layout: any, path: string | undefined, children?: ReactNode) => ReactNode;\nexport function createBuilderContext() {\n const BuilderContext = createContext<{\n builder: TFnBuilder,\n fields: FormElementRegistry,\n } | null>(null);\n \n const Provider: React.FC<{ children: React.ReactNode, fields: FormElementRegistry }> = ({\n fields,\n children\n }) => {\n const builder = useCallback<TFnBuilder>((layout, path, children) => {\n return <DynamicBuilder layout={layout} path={path}>{children}</DynamicBuilder>\n }, [fields]);\n \n return (\n <BuilderContext.Provider value={{builder, fields}}>\n {children}\n </BuilderContext.Provider>\n );\n };\n \n function useBuilder(): TFnBuilder {\n const store = useContext(BuilderContext);\n \n if (!store) {\n throw new Error(\"StoreProvider missing\");\n }\n \n return store.builder\n }\n \n function useFields(): FormElementRegistry {\n const store = useContext(BuilderContext);\n \n if (!store) {\n throw new Error(\"StoreProvider missing\");\n }\n \n return store.fields\n }\n \n return {\n Provider,\n useBuilder,\n useFields,\n };\n}\n","import { createBuilderContext } from \"./createBuilderContext\";\n\nexport const {\n Provider: BuilderProvider,\n useBuilder,\n useFields,\n} = createBuilderContext();\n","import type {TDynamicBuilder} from \"@/shared/types/common\";\nimport {DynamicBuilderElement} from \"./element\";\nimport { useFields } from \"@/entity/dynamicBuilder/model\";\n\nexport const DynamicBuilder: TDynamicBuilder = (props) => {\n const path = props.path ?? '';\n const fields = useFields();\n\n return props.layout.map((field, index) => {\n const FormElement = fields[field.type];\n \n if (!FormElement) {\n console.warn(`Неизвестный тип поля: ${field.type}. Проверьте formRegistry.`);\n return null;\n }\n\n return <DynamicBuilderElement key={`${field.name}-${index}`} element={FormElement} path={path} field={field}/>\n })\n}\n\nexport * from './model';\n","'use client';\n\nimport {DynamicBuilder, BuilderProvider} from \"@/entity/dynamicBuilder\";\nimport {forwardRef, useCallback, useEffect, useImperativeHandle, useRef} from \"react\";\nimport {useFormDispatch, useFormStoreInstance} from \"@/shared/model/store\";\nimport type {FormBuilderRef, TFormBuilder} from \"@/shared/types/common\";\nimport { useSubmitValidation } from \"@/plugins/validation\";\n\nexport const Form = forwardRef<FormBuilderRef, TFormBuilder>((props, ref) => {\n const dispatch = useFormDispatch();\n const store = useFormStoreInstance();\n const changeRef = useRef(props.onChange);\n \n useEffect(() => {\n return store.subscribeSelector(\n (s) => s.formData,\n (formData) => changeRef.current?.(formData)\n );\n }, [store]);\n \n const validation = useSubmitValidation();\n \n const submitHdl = useCallback(() => {\n if (props.onSubmit) {\n const errors = validation(store.getState().formData);\n if (Object.keys(errors).length == 0) {\n props.onSubmit(store.getState().formData);\n } else {\n dispatch({type: 'setErrors', errors })\n }\n }\n }, [props.onSubmit, validation]);\n \n useImperativeHandle(ref, () => ({\n reset: () => dispatch({type: 'reset'}),\n submit: () => submitHdl(),\n errors: () => store.getState().errors,\n }), [submitHdl, dispatch, store]);\n \n return (\n <form onSubmit={(e) => {\n e.preventDefault();\n submitHdl();\n }}\n className={props?.className}\n >\n <BuilderProvider fields={props.fields}>\n <DynamicBuilder layout={props.layout}/>\n </BuilderProvider>\n <input type=\"submit\" style={{display: 'none'}}/>\n {props.children}\n </form>\n );\n});\n","import type {FormBuilderRef, TFormBuilder} from \"../shared/types/common\";\nimport {forwardRef} from \"react\";\nimport {FormStoreProvider} from \"@/shared/model/store\";\n\nimport { Form } from \"@/widgets/form/form\";\nimport {ValidationProvider} from \"@/plugins/validation\";\n\nexport const FormBuilder = forwardRef<FormBuilderRef, TFormBuilder>((props, ref) => {\n const {formData, ...innerProps} = props;\n\n return <FormStoreProvider formData={formData}>\n <ValidationProvider validator={props.validator}>\n <Form {...innerProps} ref={ref}></Form>\n </ValidationProvider>\n </FormStoreProvider>\n});\n\nexport default FormBuilder;\n","import type { FormElementProps, FormFieldConfig, FormFieldBase, RC } from '../../../../shared/types/common';\nimport { useId } from \"react\";\n\nexport type TextFieldConfig = FormFieldBase & { type: 'text' | 'email' | 'password'; placeholder?: string; };\n\nfunction isTextFieldConfig(field: FormFieldConfig): field is TextFieldConfig {\n return field.type === 'text' || field.type === 'email' || field.type === 'password';\n}\n\nexport const TextField: RC<FormElementProps> = ({ field, value, errors, onChange }) => {\n if (!isTextFieldConfig(field)) {\n console.warn(`TextField received an invalid field config for type: ${field.type}`);\n return null;\n }\n const id = useId();\n return (\n <div style={{ marginBottom: '15px' }}>\n <label htmlFor={id}>{field.label}:</label>\n <input\n type={field.type}\n id={id}\n name={field.name}\n placeholder={field.placeholder}\n value={value || ''}\n onChange={(e) => onChange(e.target.value)}\n style={{ borderColor: errors ? 'red' : '#ccc' }}\n />\n {errors && <p style={{ color: 'red', fontSize: '0.8em' }}>{Object.values(errors).join(', ')}</p>}\n </div>\n );\n};\n","import type {FormElementProps, FormFieldBase, FormFieldConfig, RC} from \"../../../../shared/types/common.ts\";\nimport clsx from \"clsx\";\nimport {useBuilder} from \"@/entity/dynamicBuilder\";\nexport type FormGroupConfig = FormFieldBase & { variant?: 'row' | 'col', fields: FormFieldConfig[] };\n\nfunction isGroupConfig(field: FormFieldConfig): field is FormGroupConfig {\n return Array.isArray(field.fields);\n}\n\n\nexport const FormGroup: RC<FormElementProps<FormGroupConfig>> = ({field, path}) => {\n if (!isGroupConfig(field)) {\n return null;\n }\n const Builder = useBuilder()(field.fields, path);\n const variant = field.variant ?? 'col';\n \n const className = variant == 'col' ? 'flex-col' : 'flex-row';\n\n return <div>\n <div>{field.label}</div>\n <div className={clsx(className, 'flex')}>\n {Builder}\n </div>\n </div>;\n};\n","import { z } from 'zod';\n\nconst fieldShema = z.object({\n name: z.string(),\n label: z.string().optional(),\n type: z.string(),\n});\n\ntype TField = z.infer<typeof fieldShema>;\n\nexport type { TField };\nexport { fieldShema };\n"],"mappings":"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"}
|