@idem.agency/form-builder 0.0.12 → 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.
Files changed (56) hide show
  1. package/package.json +5 -2
  2. package/CHANGELOG.md +0 -16
  3. package/eslint.config.js +0 -23
  4. package/public/index.html +0 -13
  5. package/public/main.tsx +0 -97
  6. package/src/app/index.test.tsx +0 -137
  7. package/src/app/index.tsx +0 -34
  8. package/src/app/test.css +0 -1
  9. package/src/entity/dynamicBuilder/element.tsx +0 -71
  10. package/src/entity/dynamicBuilder/index.tsx +0 -21
  11. package/src/entity/dynamicBuilder/model/createBuilderContext.tsx +0 -52
  12. package/src/entity/dynamicBuilder/model/index.ts +0 -7
  13. package/src/entity/inputs/index.ts +0 -2
  14. package/src/entity/inputs/ui/group/index.test.tsx +0 -46
  15. package/src/entity/inputs/ui/group/index.tsx +0 -26
  16. package/src/entity/inputs/ui/input/index.test.tsx +0 -73
  17. package/src/entity/inputs/ui/input/index.tsx +0 -31
  18. package/src/plugins/validation/index.ts +0 -39
  19. package/src/plugins/validation/rules/confirm.test.ts +0 -23
  20. package/src/plugins/validation/rules/confirm.ts +0 -11
  21. package/src/plugins/validation/rules/email.test.ts +0 -20
  22. package/src/plugins/validation/rules/email.ts +0 -10
  23. package/src/plugins/validation/rules/index.ts +0 -5
  24. package/src/plugins/validation/rules/required.test.ts +0 -24
  25. package/src/plugins/validation/rules/required.ts +0 -9
  26. package/src/plugins/validation/types/index.ts +0 -7
  27. package/src/plugins/validation/validation.test.ts +0 -69
  28. package/src/plugins/validation/validation.ts +0 -57
  29. package/src/plugins/visibility/core.ts +0 -56
  30. package/src/plugins/visibility/index.ts +0 -25
  31. package/src/plugins/visibility/types.ts +0 -20
  32. package/src/shared/hook/useUpdateEffect.tsx +0 -23
  33. package/src/shared/model/index.ts +0 -12
  34. package/src/shared/model/plugins/EventBus.ts +0 -15
  35. package/src/shared/model/plugins/FieldRegistry.ts +0 -15
  36. package/src/shared/model/plugins/HookRegistry.ts +0 -21
  37. package/src/shared/model/plugins/MiddlewareRegistry.ts +0 -17
  38. package/src/shared/model/plugins/PipelineRegistry.ts +0 -73
  39. package/src/shared/model/plugins/PluginManager.ts +0 -84
  40. package/src/shared/model/plugins/context.tsx +0 -10
  41. package/src/shared/model/plugins/hooks.ts +0 -22
  42. package/src/shared/model/plugins/index.ts +0 -23
  43. package/src/shared/model/plugins/types.ts +0 -99
  44. package/src/shared/model/store/createStoreContext.tsx +0 -70
  45. package/src/shared/model/store/index.test.tsx +0 -113
  46. package/src/shared/model/store/index.tsx +0 -96
  47. package/src/shared/model/store/store.test.ts +0 -64
  48. package/src/shared/model/store/store.ts +0 -38
  49. package/src/shared/test-utils.tsx +0 -33
  50. package/src/shared/types/common.ts +0 -45
  51. package/src/shared/utils.test.ts +0 -55
  52. package/src/shared/utils.ts +0 -36
  53. package/src/widgets/form/form.tsx +0 -59
  54. package/tsconfig.json +0 -24
  55. package/tsdown.config.ts +0 -10
  56. package/vite.config.ts +0 -12
@@ -1,45 +0,0 @@
1
- import {type FC, type ReactNode} from "react";
2
- import type { TField } from '@/shared/model';
3
- import type { IPlugin } from '@/shared/model/plugins/types';
4
-
5
- export type ConfigFunctionComponent<P> = FC<P> & {
6
- fieldProps?: string[];
7
- }
8
- export type RC<T = {}> = ConfigFunctionComponent<T & { className?: string, children?: ReactNode, }>;
9
- export type FormData = Record<string, any>;
10
-
11
- export type FormFieldConfig = TField & Record<string, any>;
12
-
13
- export type FormElementProps<F extends FormFieldConfig = FormFieldConfig> = {
14
- field: F;
15
- path: string;
16
- value: any;
17
- errors?: Record<string, string>;
18
- onChange: (value: any) => void;
19
- };
20
-
21
- export type FormElementComponent<F extends FormFieldConfig = FormFieldConfig> = RC<FormElementProps<F>>;
22
- export type FormElementRegistry = Record<string, FormElementComponent<any>>;
23
-
24
-
25
- export type TFormBuilder = {
26
- formData?: FormData,
27
- className?: string,
28
- layout: FormFieldConfig[],
29
- fields: FormElementRegistry,
30
- plugins?: IPlugin[],
31
- onChange?: (formData: any) => void,
32
- onSubmit?: (formData: any) => void,
33
- children?: ReactNode,
34
- }
35
-
36
- export type TDynamicBuilder = RC<{
37
- layout: FormFieldConfig[],
38
- path?: string,
39
- }>;
40
-
41
- export type FormBuilderRef = {
42
- reset: () => void;
43
- submit: () => Promise<void>;
44
- errors: () => Record<string, any>
45
- }
@@ -1,55 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { updateNestedValue, getNestedValue } from './utils'
3
-
4
- describe('updateNestedValue', () => {
5
- it('updates top-level key', () => {
6
- const result = updateNestedValue({ a: 1 }, 'a', 2)
7
- expect(result).toEqual({ a: 2 })
8
- })
9
-
10
- it('updates nested key (a.b.c)', () => {
11
- const result = updateNestedValue({ a: { b: { c: 1 } } }, 'a.b.c', 42)
12
- expect(result).toEqual({ a: { b: { c: 42 } } })
13
- })
14
-
15
- it('returns value directly when path is empty', () => {
16
- const result = updateNestedValue({ a: 1 }, '', 'newValue')
17
- expect(result).toBe('newValue')
18
- })
19
-
20
- it('auto-creates intermediate objects', () => {
21
- const result = updateNestedValue({}, 'a.b.c', 'val')
22
- expect(result).toEqual({ a: { b: { c: 'val' } } })
23
- })
24
-
25
- it('throws on __proto__ path', () => {
26
- expect(() => updateNestedValue({}, '__proto__.x', 1)).toThrow()
27
- })
28
-
29
- it('throws on constructor path', () => {
30
- expect(() => updateNestedValue({}, 'constructor', 1)).toThrow()
31
- })
32
-
33
- it('throws on prototype path', () => {
34
- expect(() => updateNestedValue({}, 'prototype', 1)).toThrow()
35
- })
36
- })
37
-
38
- describe('getNestedValue', () => {
39
- it('gets top-level key', () => {
40
- expect(getNestedValue({ a: 1 }, 'a')).toBe(1)
41
- })
42
-
43
- it('gets nested key (a.b.c)', () => {
44
- expect(getNestedValue({ a: { b: { c: 42 } } }, 'a.b.c')).toBe(42)
45
- })
46
-
47
- it('returns undefined for missing key', () => {
48
- expect(getNestedValue({ a: 1 }, 'b')).toBeUndefined()
49
- })
50
-
51
- it('returns obj when path is empty', () => {
52
- const obj = { a: 1 }
53
- expect(getNestedValue(obj, '')).toBe(obj)
54
- })
55
- })
@@ -1,36 +0,0 @@
1
- export function updateNestedValue(obj: any, path: string, value: any): any {
2
- if (!path) return value;
3
- return _updateByKeys(obj, path.split('.'), value);
4
- }
5
-
6
- function _updateByKeys(obj: any, keys: string[], value: any): any {
7
- if (keys.length === 0) return value;
8
-
9
- const newObj = Array.isArray(obj) ? [...obj] : { ...obj };
10
- const currentKey = keys[0];
11
-
12
- if (currentKey === '__proto__' || currentKey === 'constructor' || currentKey === 'prototype') {
13
- throw new Error(`Forbidden path key: ${currentKey}`);
14
- }
15
-
16
- if (keys.length === 1) {
17
- newObj[currentKey] = value;
18
- } else {
19
- const remainingKeys = keys.slice(1);
20
- const nestedObj = newObj[currentKey];
21
-
22
- if (typeof nestedObj === 'undefined' || nestedObj === null) {
23
- newObj[currentKey] = typeof remainingKeys[0] === 'number' ? [] : {};
24
- }
25
- newObj[currentKey] = _updateByKeys(newObj[currentKey], remainingKeys, value);
26
- }
27
- return newObj;
28
- }
29
-
30
- export function getNestedValue(obj: any, path: string): any {
31
- if (!path) return obj;
32
- return path.split('.').reduce(
33
- (acc, key) => (acc && acc[key] !== undefined ? acc[key] : undefined),
34
- obj
35
- );
36
- }
@@ -1,59 +0,0 @@
1
- 'use client';
2
-
3
- import { DynamicBuilder, BuilderProvider } from "@/entity/dynamicBuilder";
4
- import { forwardRef, useCallback, useEffect, useImperativeHandle } from "react";
5
- import { useFormDispatch, useFormStoreInstance } from "@/shared/model/store";
6
- import type { FormBuilderRef, TFormBuilder } from "@/shared/types/common";
7
- import { useCallEvents, useRunPipeline } from '@/shared/model/plugins/hooks';
8
-
9
- export const Form = forwardRef<FormBuilderRef, TFormBuilder>((props, ref) => {
10
- const dispatch = useFormDispatch();
11
- const store = useFormStoreInstance();
12
- const callEvents = useCallEvents();
13
- const runPipeline = useRunPipeline();
14
-
15
- useEffect(() => {
16
- return store.subscribeSelector(
17
- (s) => s.formData,
18
- (formData) => props.onChange ? props.onChange?.(formData): null
19
- );
20
- }, [props.onChange]);
21
-
22
- const submitHdl = useCallback(async () => {
23
- if (props.onSubmit) {
24
- const currentFormData = store.getState().formData;
25
- await callEvents('form:submit:before', { formData: currentFormData });
26
- const { formData: transformed } = await runPipeline('form:submit', { formData: currentFormData });
27
- const { errors } = await runPipeline('form:validate', { formData: transformed, errors: {} });
28
-
29
- if (Object.keys(errors).length === 0) {
30
- props.onSubmit(transformed);
31
- } else {
32
- dispatch({ type: 'setErrors', errors });
33
- }
34
- await callEvents('form:submit:after', { formData: transformed, errors });
35
- }
36
- }, [props.onSubmit, callEvents, runPipeline, store, dispatch]);
37
-
38
- useImperativeHandle(ref, () => ({
39
- reset: () => dispatch({ type: 'reset' }),
40
- submit: () => submitHdl(),
41
- errors: () => store.getState().errors,
42
- }), [submitHdl, dispatch, store]);
43
-
44
- return (
45
- <form
46
- onSubmit={async (e) => {
47
- e.preventDefault();
48
- await submitHdl();
49
- }}
50
- className={props?.className}
51
- >
52
- <BuilderProvider fields={props.fields}>
53
- <DynamicBuilder layout={props.layout} />
54
- </BuilderProvider>
55
- <input type="submit" style={{ display: 'none' }} />
56
- {props.children}
57
- </form>
58
- );
59
- });
package/tsconfig.json DELETED
@@ -1,24 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "declaration": true,
4
- "jsx": "react-jsx",
5
- "emitDeclarationOnly": true,
6
- "outDir": "dist",
7
- "module": "ESNext",
8
- "target": "ESNext",
9
- "moduleResolution": "bundler",
10
- "verbatimModuleSyntax": true,
11
- "moduleDetection": "force",
12
- "baseUrl": ".",
13
- "paths": {
14
- "@/*": ["./src/*"],
15
- "~/*": ["./*"]
16
- },
17
- "strict": true,
18
- "noUnusedLocals": true,
19
- "noUnusedParameters": true,
20
- "noFallthroughCasesInSwitch": true,
21
- "noUncheckedSideEffectImports": true
22
- },
23
- "include": ["src/**/*", "./*.ts", "./public/*.tsx"]
24
- }
package/tsdown.config.ts DELETED
@@ -1,10 +0,0 @@
1
- import { defineConfig } from "tsdown";
2
-
3
- export default defineConfig({
4
- entry: ["src/index.ts"],
5
- format: ["esm", "cjs"],
6
- dts: true,
7
- sourcemap: true,
8
- clean: true,
9
- skipNodeModulesBundle: true
10
- });
package/vite.config.ts DELETED
@@ -1,12 +0,0 @@
1
- import { defineConfig } from 'vitest/config'
2
- import tsconfigPaths from 'vite-tsconfig-paths'
3
-
4
- export default defineConfig({
5
- root: "./public",
6
- plugins: [tsconfigPaths({ root: __dirname })],
7
- test: {
8
- globals: true,
9
- environment: 'jsdom',
10
- include: ['../src/**/*.{test,spec}.?(c|m)[jt]s?(x)'],
11
- }
12
- })