@idem.agency/form-builder 0.0.10 → 0.0.12

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.
Files changed (77) hide show
  1. package/CHANGELOG.md +2 -26
  2. package/README.md +922 -12
  3. package/dist/index.cjs +509 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +88 -0
  6. package/dist/index.d.mts +88 -0
  7. package/dist/index.mjs +476 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +8 -4
  10. package/{index.html → public/index.html} +1 -2
  11. package/{src/app/debug.tsx → public/main.tsx} +24 -16
  12. package/src/app/index.test.tsx +137 -0
  13. package/src/app/index.tsx +29 -64
  14. package/src/entity/dynamicBuilder/element.tsx +71 -0
  15. package/src/entity/dynamicBuilder/index.tsx +21 -0
  16. package/src/entity/dynamicBuilder/model/createBuilderContext.tsx +52 -0
  17. package/src/entity/dynamicBuilder/model/index.ts +7 -0
  18. package/src/entity/inputs/ui/group/index.test.tsx +46 -0
  19. package/src/{widgets/form → entity/inputs}/ui/group/index.tsx +5 -6
  20. package/src/entity/inputs/ui/input/index.test.tsx +73 -0
  21. package/src/{widgets/form → entity/inputs}/ui/input/index.tsx +5 -3
  22. package/src/index.ts +19 -5
  23. package/src/plugins/validation/index.ts +39 -0
  24. package/src/plugins/validation/rules/confirm.test.ts +23 -0
  25. package/src/plugins/validation/rules/confirm.ts +11 -0
  26. package/src/plugins/validation/rules/email.test.ts +20 -0
  27. package/src/plugins/validation/rules/email.ts +10 -0
  28. package/src/plugins/validation/rules/index.ts +5 -0
  29. package/src/plugins/validation/rules/required.test.ts +24 -0
  30. package/src/plugins/validation/rules/required.ts +9 -0
  31. package/src/plugins/validation/types/index.ts +7 -0
  32. package/src/plugins/validation/validation.test.ts +69 -0
  33. package/src/plugins/validation/validation.ts +57 -0
  34. package/src/{shared/lib/VisibleCore.ts → plugins/visibility/core.ts} +24 -11
  35. package/src/plugins/visibility/index.ts +25 -0
  36. package/src/plugins/visibility/types.ts +20 -0
  37. package/src/shared/model/index.ts +0 -1
  38. package/src/shared/model/plugins/EventBus.ts +15 -0
  39. package/src/shared/model/plugins/FieldRegistry.ts +15 -0
  40. package/src/shared/model/plugins/HookRegistry.ts +21 -0
  41. package/src/shared/model/plugins/MiddlewareRegistry.ts +17 -0
  42. package/src/shared/model/plugins/PipelineRegistry.ts +73 -0
  43. package/src/shared/model/plugins/PluginManager.ts +84 -0
  44. package/src/shared/model/plugins/context.tsx +10 -0
  45. package/src/shared/model/plugins/hooks.ts +22 -0
  46. package/src/shared/model/plugins/index.ts +23 -0
  47. package/src/shared/model/plugins/types.ts +99 -0
  48. package/src/shared/model/store/createStoreContext.tsx +70 -0
  49. package/src/shared/model/store/index.test.tsx +113 -0
  50. package/src/shared/model/store/index.tsx +96 -0
  51. package/src/shared/model/store/store.test.ts +64 -0
  52. package/src/shared/model/store/store.ts +38 -0
  53. package/src/shared/test-utils.tsx +33 -0
  54. package/src/shared/types/common.ts +8 -42
  55. package/src/shared/utils.test.ts +55 -0
  56. package/src/shared/utils.ts +26 -15
  57. package/src/widgets/form/form.tsx +59 -0
  58. package/tsconfig.json +22 -5
  59. package/tsdown.config.ts +10 -0
  60. package/vite.config.ts +8 -16
  61. package/src/main.tsx +0 -9
  62. package/src/shared/lib/VisibleCore.spec.ts +0 -103
  63. package/src/shared/lib/validation/core.spec.ts +0 -103
  64. package/src/shared/lib/validation/core.ts +0 -79
  65. package/src/shared/lib/validation/rules/base.ts +0 -10
  66. package/src/shared/lib/validation/rules/confirm.spec.ts +0 -17
  67. package/src/shared/lib/validation/rules/confirm.ts +0 -32
  68. package/src/shared/lib/validation/rules/email.spec.ts +0 -12
  69. package/src/shared/lib/validation/rules/email.ts +0 -13
  70. package/src/shared/lib/validation/rules/require.spec.ts +0 -13
  71. package/src/shared/lib/validation/rules/require.ts +0 -12
  72. package/src/shared/model/store.tsx +0 -52
  73. package/src/widgets/dynamicBuilder/index.tsx +0 -63
  74. package/tsconfig.app.json +0 -26
  75. package/tsconfig.node.json +0 -24
  76. package/vite-env.d.ts +0 -1
  77. /package/src/{widgets/form → entity/inputs}/index.ts +0 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,509 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) {
14
+ __defProp(to, key, {
15
+ get: ((k) => from[k]).bind(null, key),
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ }
19
+ }
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
24
+ value: mod,
25
+ enumerable: true
26
+ }) : target, mod));
27
+
28
+ //#endregion
29
+ let react = require("react");
30
+ react = __toESM(react);
31
+ let react_jsx_runtime = require("react/jsx-runtime");
32
+ let clsx = require("clsx");
33
+ clsx = __toESM(clsx);
34
+ let zod = require("zod");
35
+
36
+ //#region src/shared/model/store/store.ts
37
+ function createStore(reducer, initialState) {
38
+ let state = initialState;
39
+ const listeners = /* @__PURE__ */ new Set();
40
+ return {
41
+ getState() {
42
+ return state;
43
+ },
44
+ dispatch(action) {
45
+ state = reducer(state, action);
46
+ listeners.forEach((l) => l());
47
+ },
48
+ subscribe(listener) {
49
+ listeners.add(listener);
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
+ });
63
+ }
64
+ };
65
+ }
66
+
67
+ //#endregion
68
+ //#region src/shared/model/store/createStoreContext.tsx
69
+ function createStoreContext(reducer, defaultState) {
70
+ const StoreContext = (0, react.createContext)(null);
71
+ const Provider = ({ children, initialState }) => {
72
+ const storeRef = (0, react.useRef)(createStore(reducer, initialState ?? defaultState));
73
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StoreContext.Provider, {
74
+ value: storeRef.current,
75
+ children
76
+ });
77
+ };
78
+ function useStore(selector) {
79
+ const store = (0, react.useContext)(StoreContext);
80
+ if (!store) throw new Error("StoreProvider missing");
81
+ return (0, react.useSyncExternalStore)(store.subscribe, () => selector(store.getState()), () => selector(store.getState()));
82
+ }
83
+ function useDispatch() {
84
+ const store = (0, react.useContext)(StoreContext);
85
+ if (!store) throw new Error("StoreProvider missing");
86
+ return store.dispatch;
87
+ }
88
+ function useStoreInstance() {
89
+ const store = (0, react.useContext)(StoreContext);
90
+ if (!store) throw new Error("StoreProvider missing");
91
+ return store;
92
+ }
93
+ return {
94
+ Provider,
95
+ useStore,
96
+ useDispatch,
97
+ useStoreInstance
98
+ };
99
+ }
100
+
101
+ //#endregion
102
+ //#region src/shared/utils.ts
103
+ function updateNestedValue(obj, path, value) {
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;
109
+ const newObj = Array.isArray(obj) ? [...obj] : { ...obj };
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;
113
+ else {
114
+ const remainingKeys = keys.slice(1);
115
+ const nestedObj = newObj[currentKey];
116
+ if (typeof nestedObj === "undefined" || nestedObj === null) newObj[currentKey] = typeof remainingKeys[0] === "number" ? [] : {};
117
+ newObj[currentKey] = _updateByKeys(newObj[currentKey], remainingKeys, value);
118
+ }
119
+ return newObj;
120
+ }
121
+ function getNestedValue(obj, path) {
122
+ if (!path) return obj;
123
+ return path.split(".").reduce((acc, key) => acc && acc[key] !== void 0 ? acc[key] : void 0, obj);
124
+ }
125
+
126
+ //#endregion
127
+ //#region src/shared/model/store/index.tsx
128
+ function reducer(state, action) {
129
+ const newData = { ...state };
130
+ switch (action.type) {
131
+ case "setValue":
132
+ newData.formData = updateNestedValue(newData.formData, action.path, action.value);
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;
138
+ case "setError":
139
+ newData.errors = updateNestedValue(newData.errors, action.path, action.value);
140
+ break;
141
+ case "reset":
142
+ newData.formData = {};
143
+ newData.errors = {};
144
+ break;
145
+ case "setErrors":
146
+ newData.errors = { ...action.errors };
147
+ break;
148
+ }
149
+ return newData;
150
+ }
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();
289
+
290
+ //#endregion
291
+ //#region src/entity/dynamicBuilder/element.tsx
292
+ const DynamicBuilderElement = (props) => {
293
+ const Element = props.element;
294
+ const field = props.field;
295
+ const currentFieldPath = props.path ? `${props.path}.${field.name}` : field.name;
296
+ const value = useFormStore(((s) => getNestedValue(s.formData, currentFieldPath)));
297
+ const errors = useFormStore(((s) => s.errors[currentFieldPath]));
298
+ const dispatch = useFormDispatch();
299
+ const store = useFormStoreInstance();
300
+ const validator = useRegister(currentFieldPath, field);
301
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Element, {
302
+ field: { ...field },
303
+ path: currentFieldPath,
304
+ value,
305
+ errors,
306
+ onChange: (value) => {
307
+ const data = store.getState().formData;
308
+ dispatch({
309
+ type: "setFieldValue",
310
+ path: currentFieldPath,
311
+ value,
312
+ errors: validator(value, data)
313
+ });
314
+ }
315
+ });
316
+ };
317
+
318
+ //#endregion
319
+ //#region src/entity/dynamicBuilder/model/createBuilderContext.tsx
320
+ function createBuilderContext() {
321
+ const BuilderContext = (0, react.createContext)(null);
322
+ const Provider = ({ fields, children }) => {
323
+ const builder = (0, react.useCallback)((layout, path, children) => {
324
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DynamicBuilder, {
325
+ layout,
326
+ path,
327
+ children
328
+ });
329
+ }, [fields]);
330
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BuilderContext.Provider, {
331
+ value: {
332
+ builder,
333
+ fields
334
+ },
335
+ children
336
+ });
337
+ };
338
+ function useBuilder() {
339
+ const store = (0, react.useContext)(BuilderContext);
340
+ if (!store) throw new Error("StoreProvider missing");
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;
347
+ }
348
+ return {
349
+ Provider,
350
+ useBuilder,
351
+ useFields
352
+ };
353
+ }
354
+
355
+ //#endregion
356
+ //#region src/entity/dynamicBuilder/model/index.ts
357
+ const { Provider: BuilderProvider, useBuilder, useFields } = createBuilderContext();
358
+
359
+ //#endregion
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}`);
375
+ });
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
+ });
396
+ }
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
+ ]);
407
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
408
+ onSubmit: (e) => {
409
+ e.preventDefault();
410
+ submitHdl();
411
+ },
412
+ className: props?.className,
413
+ children: [
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
+ }),
418
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
419
+ type: "submit",
420
+ style: { display: "none" }
421
+ }),
422
+ props.children
423
+ ]
424
+ });
425
+ });
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
+
443
+ //#endregion
444
+ //#region src/entity/inputs/ui/input/index.tsx
445
+ function isTextFieldConfig(field) {
446
+ return field.type === "text" || field.type === "email" || field.type === "password";
447
+ }
448
+ const TextField = ({ field, value, errors, onChange }) => {
449
+ if (!isTextFieldConfig(field)) {
450
+ console.warn(`TextField received an invalid field config for type: ${field.type}`);
451
+ return null;
452
+ }
453
+ const id = (0, react.useId)();
454
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
455
+ style: { marginBottom: "15px" },
456
+ children: [
457
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
458
+ htmlFor: id,
459
+ children: [field.label, ":"]
460
+ }),
461
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
462
+ type: field.type,
463
+ id,
464
+ name: field.name,
465
+ placeholder: field.placeholder,
466
+ value: value || "",
467
+ onChange: (e) => onChange(e.target.value),
468
+ style: { borderColor: errors ? "red" : "#ccc" }
469
+ }),
470
+ errors && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
471
+ style: {
472
+ color: "red",
473
+ fontSize: "0.8em"
474
+ },
475
+ children: Object.values(errors).join(", ")
476
+ })
477
+ ]
478
+ });
479
+ };
480
+
481
+ //#endregion
482
+ //#region src/entity/inputs/ui/group/index.tsx
483
+ function isGroupConfig(field) {
484
+ return Array.isArray(field.fields);
485
+ }
486
+ const FormGroup = ({ field, path }) => {
487
+ if (!isGroupConfig(field)) return null;
488
+ const Builder = useBuilder()(field.fields, path);
489
+ const className = (field.variant ?? "col") == "col" ? "flex-col" : "flex-row";
490
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: field.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
491
+ className: (0, clsx.default)(className, "flex"),
492
+ children: Builder
493
+ })] });
494
+ };
495
+
496
+ //#endregion
497
+ //#region src/shared/model/index.ts
498
+ const fieldShema = zod.z.object({
499
+ name: zod.z.string(),
500
+ label: zod.z.string().optional(),
501
+ type: zod.z.string()
502
+ });
503
+
504
+ //#endregion
505
+ exports.FormBuilder = FormBuilder;
506
+ exports.FormGroup = FormGroup;
507
+ exports.TextField = TextField;
508
+ exports.fieldShema = fieldShema;
509
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
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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"}
@@ -0,0 +1,88 @@
1
+ import * as react from "react";
2
+ import { FC, ReactNode } from "react";
3
+ import { z } from "zod";
4
+
5
+ //#region src/shared/model/index.d.ts
6
+ declare const fieldShema: z.ZodObject<{
7
+ name: z.ZodString;
8
+ label: z.ZodOptional<z.ZodString>;
9
+ type: z.ZodString;
10
+ }, z.core.$strip>;
11
+ type TField = z.infer<typeof fieldShema>;
12
+ //#endregion
13
+ //#region src/plugins/validation/types/index.d.ts
14
+ interface IUserRule {
15
+ code: string;
16
+ fn: (value: any, data: FormData, args: string[]) => boolean;
17
+ message: string;
18
+ }
19
+ //#endregion
20
+ //#region src/plugins/validation/provider.d.ts
21
+ type TValidator = {
22
+ rules?: IUserRule[];
23
+ onSubmit?: boolean;
24
+ };
25
+ //#endregion
26
+ //#region src/shared/types/common.d.ts
27
+ type ConfigFunctionComponent<P> = FC<P> & {
28
+ fieldProps?: string[];
29
+ };
30
+ type RC<T = {}> = ConfigFunctionComponent<T & {
31
+ className?: string;
32
+ children?: ReactNode;
33
+ }>;
34
+ type FormData = Record<string, any>;
35
+ type FormFieldBase = {
36
+ validation?: string[];
37
+ viewConfig?: TGroupRules;
38
+ } & TField;
39
+ type FormFieldConfig = FormFieldBase & Record<string, any>;
40
+ type FormElementProps<F extends FormFieldConfig = FormFieldConfig> = {
41
+ field: F;
42
+ path: string;
43
+ value: any;
44
+ errors?: Record<string, string>;
45
+ onChange: (value: any) => void;
46
+ };
47
+ type FormElementComponent<F extends FormFieldConfig = FormFieldConfig> = RC<FormElementProps<F>>;
48
+ type FormElementRegistry = Record<string, FormElementComponent<any>>;
49
+ type TFormBuilder = {
50
+ formData?: FormData;
51
+ className?: string;
52
+ layout: FormFieldConfig[];
53
+ fields: FormElementRegistry;
54
+ validator?: TValidator;
55
+ onChange?: (formData: any) => void;
56
+ onSubmit?: (formData: any) => void;
57
+ children?: ReactNode;
58
+ };
59
+ type TCommonRule = {
60
+ operator: string;
61
+ field: string;
62
+ value: any;
63
+ };
64
+ type TGroupRules = {
65
+ logic: 'and' | 'or';
66
+ rules: (TGroupRules | TCommonRule)[];
67
+ };
68
+ type FormBuilderRef = {
69
+ reset: () => void;
70
+ submit: () => void;
71
+ errors: () => Record<string, any>;
72
+ };
73
+ //#endregion
74
+ //#region src/app/index.d.ts
75
+ declare const FormBuilder: react.ForwardRefExoticComponent<TFormBuilder & react.RefAttributes<FormBuilderRef>>;
76
+ //#endregion
77
+ //#region src/entity/inputs/ui/input/index.d.ts
78
+ declare const TextField: RC<FormElementProps>;
79
+ //#endregion
80
+ //#region src/entity/inputs/ui/group/index.d.ts
81
+ type FormGroupConfig = FormFieldBase & {
82
+ variant?: 'row' | 'col';
83
+ fields: FormFieldConfig[];
84
+ };
85
+ declare const FormGroup: RC<FormElementProps<FormGroupConfig>>;
86
+ //#endregion
87
+ export { FormBuilder, type FormBuilderRef, type FormElementProps, type FormElementRegistry, type FormFieldConfig, FormGroup, type TGroupRules, TextField, fieldShema };
88
+ //# sourceMappingURL=index.d.cts.map