@idem.agency/form-builder 0.0.9 → 0.0.11

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 (37) hide show
  1. package/CHANGELOG.md +1 -25
  2. package/dist/index.cjs +325 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +86 -0
  5. package/dist/index.d.mts +86 -0
  6. package/dist/index.mjs +292 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/package.json +12 -4
  9. package/{index.html → public/index.html} +1 -2
  10. package/public/main.tsx +90 -0
  11. package/src/app/debug.tsx +0 -89
  12. package/src/app/index.tsx +51 -40
  13. package/src/{widgets/form → entity/inputs}/ui/group/index.tsx +4 -3
  14. package/src/{widgets/form → entity/inputs}/ui/input/index.tsx +5 -3
  15. package/src/index.ts +2 -2
  16. package/src/shared/lib/validation/core.ts +3 -3
  17. package/src/shared/lib/validation/rules/confirm.ts +2 -2
  18. package/src/shared/lib/validation/rules/email.ts +1 -1
  19. package/src/shared/lib/validation/rules/require.ts +1 -1
  20. package/src/shared/model/builder/createContext.tsx +40 -0
  21. package/src/shared/model/builder/index.ts +6 -0
  22. package/src/shared/model/index.ts +0 -1
  23. package/src/shared/model/store/createStoreContext.tsx +74 -0
  24. package/src/shared/model/store/index.ts +46 -0
  25. package/src/shared/model/store/store.ts +27 -0
  26. package/src/shared/types/common.ts +1 -1
  27. package/src/widgets/dynamicBuilder/element.tsx +31 -0
  28. package/src/widgets/dynamicBuilder/index.tsx +28 -58
  29. package/tsconfig.json +22 -5
  30. package/tsdown.config.ts +10 -0
  31. package/vite.config.ts +7 -16
  32. package/src/main.tsx +0 -9
  33. package/src/shared/model/store.tsx +0 -52
  34. package/tsconfig.app.json +0 -26
  35. package/tsconfig.node.json +0 -24
  36. package/vite-env.d.ts +0 -1
  37. /package/src/{widgets/form → entity/inputs}/index.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -3,30 +3,6 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ## [0.0.9](https://gitlab.idem.agency/idem-project/front-package/compare/@idem.agency/form-builder@0.0.8...@idem.agency/form-builder@0.0.9) (2026-01-13)
7
-
8
- **Note:** Version bump only for package @idem.agency/form-builder
9
-
10
-
11
-
12
-
13
-
14
- ## [0.0.8](https://gitlab.idem.agency/idem-project/front-package/compare/@idem.agency/form-builder@0.0.7...@idem.agency/form-builder@0.0.8) (2026-01-13)
15
-
16
- **Note:** Version bump only for package @idem.agency/form-builder
17
-
18
-
19
-
20
-
21
-
22
- ## 0.0.7 (2026-01-13)
23
-
24
- **Note:** Version bump only for package @idem.agency/form-builder
25
-
26
-
27
-
28
-
29
-
30
- ## 0.0.6 (2026-01-13)
6
+ ## [0.0.11](https://gitlab.idem.agency/idem-project/front-package/compare/@idem.agency/form-builder@0.0.10...@idem.agency/form-builder@0.0.11) (2026-02-09)
31
7
 
32
8
  **Note:** Version bump only for package @idem.agency/form-builder
package/dist/index.cjs ADDED
@@ -0,0 +1,325 @@
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 () => listeners.delete(listener);
51
+ }
52
+ };
53
+ }
54
+
55
+ //#endregion
56
+ //#region src/shared/model/store/createStoreContext.tsx
57
+ function createStoreContext$1(reducer, initialState) {
58
+ const StoreContext = (0, react.createContext)(null);
59
+ const Provider = ({ children }) => {
60
+ const storeRef = (0, react.useRef)(null);
61
+ if (!storeRef.current) storeRef.current = createStore(reducer, initialState);
62
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StoreContext.Provider, {
63
+ value: storeRef.current,
64
+ children
65
+ });
66
+ };
67
+ function useStore(selector) {
68
+ const store = (0, react.useContext)(StoreContext);
69
+ if (!store) throw new Error("StoreProvider missing");
70
+ return (0, react.useSyncExternalStore)(store.subscribe, () => selector(store.getState()), () => selector(store.getState()));
71
+ }
72
+ function useDispatch() {
73
+ const store = (0, react.useContext)(StoreContext);
74
+ if (!store) throw new Error("StoreProvider missing");
75
+ return store.dispatch;
76
+ }
77
+ function useSubmit(onSubmit) {
78
+ const store = (0, react.useContext)(StoreContext);
79
+ return () => {
80
+ if (store) onSubmit(store.getState());
81
+ };
82
+ }
83
+ return {
84
+ Provider,
85
+ useStore,
86
+ useSubmit,
87
+ useDispatch
88
+ };
89
+ }
90
+
91
+ //#endregion
92
+ //#region src/shared/utils.ts
93
+ function updateNestedValue(obj, path, value) {
94
+ if (path.length === 0) return value;
95
+ const newObj = Array.isArray(obj) ? [...obj] : { ...obj };
96
+ const currentKey = path[0];
97
+ if (path.length === 1) newObj[currentKey] = value;
98
+ else {
99
+ const remainingPath = path.slice(1);
100
+ const nestedObj = newObj[currentKey];
101
+ if (typeof nestedObj === "undefined" || nestedObj === null) newObj[currentKey] = typeof remainingPath[0] === "number" ? [] : {};
102
+ newObj[currentKey] = updateNestedValue(newObj[currentKey], remainingPath, value);
103
+ }
104
+ return newObj;
105
+ }
106
+ function getNestedValue(obj, path) {
107
+ return path.reduce((acc, key) => acc && acc[key] !== void 0 ? acc[key] : void 0, obj);
108
+ }
109
+
110
+ //#endregion
111
+ //#region src/shared/model/store/index.ts
112
+ const initialState = {
113
+ formData: {},
114
+ errors: {}
115
+ };
116
+ function reducer(state, action) {
117
+ const newData = { ...state };
118
+ switch (action.type) {
119
+ case "setValue":
120
+ newData.formData = updateNestedValue(newData.formData, action.path, action.value);
121
+ break;
122
+ case "setError":
123
+ newData.errors = updateNestedValue(newData.errors, action.path, action.value);
124
+ break;
125
+ case "reset":
126
+ newData.formData = {};
127
+ newData.errors = {};
128
+ break;
129
+ case "setErrors":
130
+ newData.errors = { ...action.errors };
131
+ break;
132
+ }
133
+ return newData;
134
+ }
135
+ const { Provider: FormStoreProvider, useStore: useFormStore, useDispatch: useFormDispatch, useSubmit } = createStoreContext$1(reducer, initialState);
136
+
137
+ //#endregion
138
+ //#region src/widgets/dynamicBuilder/element.tsx
139
+ const BuilderElement = (props) => {
140
+ const Element = props.element;
141
+ const field = props.field;
142
+ const currentFieldPath = [...props.path, field.name];
143
+ const value = useFormStore(((s) => getNestedValue(s.formData, currentFieldPath)));
144
+ const errors = useFormStore(((s) => getNestedValue(s.errors, currentFieldPath)));
145
+ const dispatch = useFormDispatch();
146
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Element, {
147
+ field: { ...field },
148
+ builder: props.DynamicBuilder,
149
+ path: currentFieldPath,
150
+ plugins: props.plugins,
151
+ value,
152
+ errors,
153
+ onChange: (value) => {
154
+ dispatch({
155
+ type: "setValue",
156
+ path: currentFieldPath,
157
+ value
158
+ });
159
+ dispatch({
160
+ type: "setError",
161
+ path: currentFieldPath,
162
+ value: ""
163
+ });
164
+ }
165
+ });
166
+ };
167
+
168
+ //#endregion
169
+ //#region src/widgets/dynamicBuilder/index.tsx
170
+ const DynamicBuilder = (props) => {
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() {
189
+ const BuilderContext = (0, react.createContext)(null);
190
+ const Provider = ({ plugins, children }) => {
191
+ const storeRef = (0, react.useRef)(null);
192
+ if (!storeRef.current) storeRef.current = (layout, path, children) => {
193
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DynamicBuilder, {
194
+ layout,
195
+ path,
196
+ plugins,
197
+ children
198
+ });
199
+ };
200
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BuilderContext.Provider, {
201
+ value: storeRef.current,
202
+ children
203
+ });
204
+ };
205
+ function useBuilder() {
206
+ const store = (0, react.useContext)(BuilderContext);
207
+ if (!store) throw new Error("StoreProvider missing");
208
+ return store;
209
+ }
210
+ return {
211
+ Provider,
212
+ useBuilder
213
+ };
214
+ }
215
+
216
+ //#endregion
217
+ //#region src/shared/model/builder/index.ts
218
+ const { Provider: BuilderProvider, useBuilder } = createStoreContext();
219
+
220
+ //#endregion
221
+ //#region src/app/index.tsx
222
+ const FormBuilder = (0, react.forwardRef)((props, ref) => {
223
+ const submitHdl = useSubmit((data) => {
224
+ if (props.onSubmit) props.onSubmit(data);
225
+ });
226
+ (0, react.useImperativeHandle)(ref, () => ({
227
+ reset: () => {},
228
+ submit: () => {
229
+ submitHdl();
230
+ },
231
+ errors: () => {
232
+ return {};
233
+ }
234
+ }), [props.onSubmit]);
235
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
236
+ onSubmit: (e) => {
237
+ e.preventDefault();
238
+ submitHdl();
239
+ },
240
+ className: props?.className,
241
+ children: [
242
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormStoreProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BuilderProvider, {
243
+ plugins: props.plugins,
244
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DynamicBuilder, {
245
+ layout: props.layout,
246
+ plugins: props.plugins
247
+ })
248
+ }) }),
249
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
250
+ type: "submit",
251
+ style: { display: "none" }
252
+ }),
253
+ props.children
254
+ ]
255
+ });
256
+ });
257
+
258
+ //#endregion
259
+ //#region src/entity/inputs/ui/input/index.tsx
260
+ function isTextFieldConfig(field) {
261
+ return field.type === "text" || field.type === "email" || field.type === "password";
262
+ }
263
+ const TextField = ({ field, value, errors, onChange }) => {
264
+ if (!isTextFieldConfig(field)) {
265
+ console.warn(`TextField received an invalid field config for type: ${field.type}`);
266
+ return null;
267
+ }
268
+ const id = (0, react.useId)();
269
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
270
+ style: { marginBottom: "15px" },
271
+ children: [
272
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
273
+ htmlFor: id,
274
+ children: [field.label, ":"]
275
+ }),
276
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
277
+ type: field.type,
278
+ id,
279
+ name: field.name,
280
+ placeholder: field.placeholder,
281
+ value: value || "",
282
+ onChange: (e) => onChange(e.target.value),
283
+ style: { borderColor: errors ? "red" : "#ccc" }
284
+ }),
285
+ errors && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
286
+ style: {
287
+ color: "red",
288
+ fontSize: "0.8em"
289
+ },
290
+ children: Object.values(errors).join(", ")
291
+ })
292
+ ]
293
+ });
294
+ };
295
+
296
+ //#endregion
297
+ //#region src/entity/inputs/ui/group/index.tsx
298
+ function isGroupConfig(field) {
299
+ return field.fields;
300
+ }
301
+ const FormGroup = ({ field, path }) => {
302
+ if (!isGroupConfig(field)) return null;
303
+ const Builder = useBuilder()(field.fields, path);
304
+ const className = (field.variant ?? "col") == "col" ? "flex-col" : "flex-row";
305
+ 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", {
306
+ className: (0, clsx.default)(className, "flex"),
307
+ children: Builder
308
+ })] });
309
+ };
310
+ FormGroup.fieldProps = ["fields"];
311
+
312
+ //#endregion
313
+ //#region src/shared/model/index.ts
314
+ const fieldShema = zod.z.object({
315
+ name: zod.z.string(),
316
+ label: zod.z.string().optional(),
317
+ type: zod.z.string()
318
+ });
319
+
320
+ //#endregion
321
+ exports.FormBuilder = FormBuilder;
322
+ exports.FormGroup = FormGroup;
323
+ exports.TextField = TextField;
324
+ exports.fieldShema = fieldShema;
325
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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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"}
@@ -0,0 +1,86 @@
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/shared/types/common.d.ts
14
+ type ConfigFunctionComponent<P> = FC<P> & {
15
+ fieldProps?: string[];
16
+ };
17
+ type RC<T = {}> = ConfigFunctionComponent<T & {
18
+ className?: string;
19
+ children?: ReactNode;
20
+ }>;
21
+ type FormData = Record<string, any>;
22
+ interface IRule {
23
+ getName: () => string;
24
+ validate: (value: string, formData: FormData) => boolean;
25
+ message: () => string;
26
+ }
27
+ type FormFieldBase = {
28
+ validation?: (string | IRule)[];
29
+ viewConfig?: TGroupRules;
30
+ } & TField;
31
+ type FormFieldConfig = FormFieldBase & Record<string, any>;
32
+ type FormElementProps<F extends FormFieldConfig = FormFieldConfig> = {
33
+ field: F;
34
+ builder: TDynamicBuilder;
35
+ plugins: FormElementRegistry;
36
+ path: string[];
37
+ value: any;
38
+ errors?: Record<string, string>;
39
+ onChange: (value: any) => void;
40
+ };
41
+ type FormElementComponent<F extends FormFieldConfig = FormFieldConfig> = RC<FormElementProps<F>>;
42
+ type FormElementRegistry = Record<string, FormElementComponent<any>>;
43
+ type TFormBuilder = {
44
+ formData?: FormData;
45
+ className?: string;
46
+ layout: FormFieldConfig[];
47
+ plugins: FormElementRegistry;
48
+ onChange?: (formData: any) => void;
49
+ onSubmit?: (formData: any) => void;
50
+ children?: ReactNode;
51
+ };
52
+ type TDynamicBuilder = RC<{
53
+ layout: FormFieldConfig[];
54
+ plugins: FormElementRegistry;
55
+ path?: string[];
56
+ }>;
57
+ type TCommonRule = {
58
+ operator: string;
59
+ field: string;
60
+ value: any;
61
+ };
62
+ type TGroupRules = {
63
+ logic: 'and' | 'or';
64
+ rules: (TGroupRules | TCommonRule)[];
65
+ };
66
+ type FormBuilderRef = {
67
+ reset: () => void;
68
+ submit: () => void;
69
+ errors: () => Record<string, any>;
70
+ };
71
+ //#endregion
72
+ //#region src/app/index.d.ts
73
+ declare const FormBuilder: react.ForwardRefExoticComponent<TFormBuilder & react.RefAttributes<FormBuilderRef>>;
74
+ //#endregion
75
+ //#region src/entity/inputs/ui/input/index.d.ts
76
+ declare const TextField: RC<FormElementProps>;
77
+ //#endregion
78
+ //#region src/entity/inputs/ui/group/index.d.ts
79
+ type FormGroupConfig = FormFieldBase & {
80
+ variant?: 'row' | 'col';
81
+ fields: FormFieldConfig[];
82
+ };
83
+ declare const FormGroup: RC<FormElementProps<FormGroupConfig>>;
84
+ //#endregion
85
+ export { FormBuilder, type FormBuilderRef, type FormElementProps, type FormElementRegistry, type FormFieldConfig, FormGroup, type IRule, type TGroupRules, TextField, fieldShema };
86
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,86 @@
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/shared/types/common.d.ts
14
+ type ConfigFunctionComponent<P> = FC<P> & {
15
+ fieldProps?: string[];
16
+ };
17
+ type RC<T = {}> = ConfigFunctionComponent<T & {
18
+ className?: string;
19
+ children?: ReactNode;
20
+ }>;
21
+ type FormData = Record<string, any>;
22
+ interface IRule {
23
+ getName: () => string;
24
+ validate: (value: string, formData: FormData) => boolean;
25
+ message: () => string;
26
+ }
27
+ type FormFieldBase = {
28
+ validation?: (string | IRule)[];
29
+ viewConfig?: TGroupRules;
30
+ } & TField;
31
+ type FormFieldConfig = FormFieldBase & Record<string, any>;
32
+ type FormElementProps<F extends FormFieldConfig = FormFieldConfig> = {
33
+ field: F;
34
+ builder: TDynamicBuilder;
35
+ plugins: FormElementRegistry;
36
+ path: string[];
37
+ value: any;
38
+ errors?: Record<string, string>;
39
+ onChange: (value: any) => void;
40
+ };
41
+ type FormElementComponent<F extends FormFieldConfig = FormFieldConfig> = RC<FormElementProps<F>>;
42
+ type FormElementRegistry = Record<string, FormElementComponent<any>>;
43
+ type TFormBuilder = {
44
+ formData?: FormData;
45
+ className?: string;
46
+ layout: FormFieldConfig[];
47
+ plugins: FormElementRegistry;
48
+ onChange?: (formData: any) => void;
49
+ onSubmit?: (formData: any) => void;
50
+ children?: ReactNode;
51
+ };
52
+ type TDynamicBuilder = RC<{
53
+ layout: FormFieldConfig[];
54
+ plugins: FormElementRegistry;
55
+ path?: string[];
56
+ }>;
57
+ type TCommonRule = {
58
+ operator: string;
59
+ field: string;
60
+ value: any;
61
+ };
62
+ type TGroupRules = {
63
+ logic: 'and' | 'or';
64
+ rules: (TGroupRules | TCommonRule)[];
65
+ };
66
+ type FormBuilderRef = {
67
+ reset: () => void;
68
+ submit: () => void;
69
+ errors: () => Record<string, any>;
70
+ };
71
+ //#endregion
72
+ //#region src/app/index.d.ts
73
+ declare const FormBuilder: react.ForwardRefExoticComponent<TFormBuilder & react.RefAttributes<FormBuilderRef>>;
74
+ //#endregion
75
+ //#region src/entity/inputs/ui/input/index.d.ts
76
+ declare const TextField: RC<FormElementProps>;
77
+ //#endregion
78
+ //#region src/entity/inputs/ui/group/index.d.ts
79
+ type FormGroupConfig = FormFieldBase & {
80
+ variant?: 'row' | 'col';
81
+ fields: FormFieldConfig[];
82
+ };
83
+ declare const FormGroup: RC<FormElementProps<FormGroupConfig>>;
84
+ //#endregion
85
+ export { FormBuilder, type FormBuilderRef, type FormElementProps, type FormElementRegistry, type FormFieldConfig, FormGroup, type IRule, type TGroupRules, TextField, fieldShema };
86
+ //# sourceMappingURL=index.d.mts.map