@bgroup/wise-form 1.0.2 → 1.0.5
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 +1 -1
- package/package.json +23 -4
- package/postcss.config.js +6 -0
- package/src/form/styles.css +11 -37
- package/src/form/view/components/containers/index.tsx +33 -4
- package/src/form/view/components/error.tsx +0 -3
- package/src/form/view/components/field/container.tsx +1 -1
- package/src/form/view/components/field/index.tsx +42 -7
- package/src/form/view/components/rows/row-container.tsx +37 -9
- package/src/form/view/components/rows/wrapper.tsx +17 -6
- package/src/form/view/components/wrapped-form.tsx +38 -5
- package/src/form/view/hooks/use-model.ts +91 -25
- package/src/form/view/index.tsx +15 -3
- package/src/models/field.ts +504 -458
- package/tailwind.config.js +11 -0
- package/tsconfig.json +2 -0
- package/vite.config.ts +59 -0
- package/dist/components/ui/Checkbox.d.ts +0 -14
- package/dist/components/ui/Checkbox.d.ts.map +0 -1
- package/dist/components/ui/Checkbox.js +0 -43
- package/dist/components/ui/Checkbox.js.map +0 -1
- package/dist/components/ui/CheckboxGroup.d.ts +0 -15
- package/dist/components/ui/CheckboxGroup.d.ts.map +0 -1
- package/dist/components/ui/CheckboxGroup.js +0 -33
- package/dist/components/ui/CheckboxGroup.js.map +0 -1
- package/dist/components/ui/Input.d.ts +0 -14
- package/dist/components/ui/Input.d.ts.map +0 -1
- package/dist/components/ui/Input.js +0 -49
- package/dist/components/ui/Input.js.map +0 -1
- package/dist/components/ui/Radio.d.ts +0 -14
- package/dist/components/ui/Radio.d.ts.map +0 -1
- package/dist/components/ui/Radio.js +0 -43
- package/dist/components/ui/Radio.js.map +0 -1
- package/dist/components/ui/Select.d.ts +0 -18
- package/dist/components/ui/Select.d.ts.map +0 -1
- package/dist/components/ui/Select.js +0 -44
- package/dist/components/ui/Select.js.map +0 -1
- package/dist/components/ui/Textarea.d.ts +0 -13
- package/dist/components/ui/Textarea.d.ts.map +0 -1
- package/dist/components/ui/Textarea.js +0 -42
- package/dist/components/ui/Textarea.js.map +0 -1
- package/dist/components/ui/index.d.ts +0 -13
- package/dist/components/ui/index.d.ts.map +0 -1
- package/dist/components/ui/index.js +0 -7
- package/dist/components/ui/index.js.map +0 -1
- package/dist/form/index.d.ts +0 -10
- package/dist/form/index.d.ts.map +0 -1
- package/dist/form/index.js +0 -5
- package/dist/form/index.js.map +0 -1
- package/dist/form/interfaces/field-container.d.ts +0 -8
- package/dist/form/interfaces/field-container.d.ts.map +0 -1
- package/dist/form/interfaces/field-container.js +0 -2
- package/dist/form/interfaces/field-container.js.map +0 -1
- package/dist/form/interfaces/interfaces.d.ts +0 -8
- package/dist/form/interfaces/interfaces.d.ts.map +0 -1
- package/dist/form/interfaces/interfaces.js +0 -2
- package/dist/form/interfaces/interfaces.js.map +0 -1
- package/dist/form/interfaces/settings.d.ts +0 -10
- package/dist/form/interfaces/settings.d.ts.map +0 -1
- package/dist/form/interfaces/settings.js +0 -2
- package/dist/form/interfaces/settings.js.map +0 -1
- package/dist/form/interfaces/template.d.ts +0 -6
- package/dist/form/interfaces/template.d.ts.map +0 -1
- package/dist/form/interfaces/template.js +0 -2
- package/dist/form/interfaces/template.js.map +0 -1
- package/dist/form/interfaces/wise-form-specs.d.ts +0 -9
- package/dist/form/interfaces/wise-form-specs.d.ts.map +0 -1
- package/dist/form/interfaces/wise-form-specs.js +0 -2
- package/dist/form/interfaces/wise-form-specs.js.map +0 -1
- package/dist/form/view/components/containers/index.d.ts +0 -3
- package/dist/form/view/components/containers/index.d.ts.map +0 -1
- package/dist/form/view/components/containers/index.js +0 -12
- package/dist/form/view/components/containers/index.js.map +0 -1
- package/dist/form/view/components/error.d.ts +0 -5
- package/dist/form/view/components/error.d.ts.map +0 -1
- package/dist/form/view/components/error.js +0 -8
- package/dist/form/view/components/error.js.map +0 -1
- package/dist/form/view/components/field/container.d.ts +0 -5
- package/dist/form/view/components/field/container.d.ts.map +0 -1
- package/dist/form/view/components/field/container.js +0 -5
- package/dist/form/view/components/field/container.js.map +0 -1
- package/dist/form/view/components/field/index.d.ts +0 -18
- package/dist/form/view/components/field/index.d.ts.map +0 -1
- package/dist/form/view/components/field/index.js +0 -89
- package/dist/form/view/components/field/index.js.map +0 -1
- package/dist/form/view/components/field/selection.d.ts +0 -2
- package/dist/form/view/components/field/selection.d.ts.map +0 -1
- package/dist/form/view/components/field/selection.js +0 -35
- package/dist/form/view/components/field/selection.js.map +0 -1
- package/dist/form/view/components/field/use-field.d.ts +0 -4
- package/dist/form/view/components/field/use-field.d.ts.map +0 -1
- package/dist/form/view/components/field/use-field.js +0 -41
- package/dist/form/view/components/field/use-field.js.map +0 -1
- package/dist/form/view/components/rows/row-container.d.ts +0 -18
- package/dist/form/view/components/rows/row-container.d.ts.map +0 -1
- package/dist/form/view/components/rows/row-container.js +0 -89
- package/dist/form/view/components/rows/row-container.js.map +0 -1
- package/dist/form/view/components/rows/wrapper.d.ts +0 -12
- package/dist/form/view/components/rows/wrapper.d.ts.map +0 -1
- package/dist/form/view/components/rows/wrapper.js +0 -27
- package/dist/form/view/components/rows/wrapper.js.map +0 -1
- package/dist/form/view/components/wrapped-form.d.ts +0 -6
- package/dist/form/view/components/wrapped-form.d.ts.map +0 -1
- package/dist/form/view/components/wrapped-form.js +0 -26
- package/dist/form/view/components/wrapped-form.js.map +0 -1
- package/dist/form/view/context.d.ts +0 -23
- package/dist/form/view/context.d.ts.map +0 -1
- package/dist/form/view/context.js +0 -7
- package/dist/form/view/context.js.map +0 -1
- package/dist/form/view/hooks/use-model.d.ts +0 -10
- package/dist/form/view/hooks/use-model.d.ts.map +0 -1
- package/dist/form/view/hooks/use-model.js +0 -31
- package/dist/form/view/hooks/use-model.js.map +0 -1
- package/dist/form/view/hooks/use-template.d.ts +0 -14
- package/dist/form/view/hooks/use-template.d.ts.map +0 -1
- package/dist/form/view/hooks/use-template.js +0 -57
- package/dist/form/view/hooks/use-template.js.map +0 -1
- package/dist/form/view/hooks/use-types.d.ts +0 -2
- package/dist/form/view/hooks/use-types.d.ts.map +0 -1
- package/dist/form/view/hooks/use-types.js +0 -19
- package/dist/form/view/hooks/use-types.js.map +0 -1
- package/dist/form/view/index.d.ts +0 -3
- package/dist/form/view/index.d.ts.map +0 -1
- package/dist/form/view/index.js +0 -38
- package/dist/form/view/index.js.map +0 -1
- package/dist/formulas/helpers/condition-types.d.ts +0 -5
- package/dist/formulas/helpers/condition-types.d.ts.map +0 -1
- package/dist/formulas/helpers/condition-types.js +0 -5
- package/dist/formulas/helpers/condition-types.js.map +0 -1
- package/dist/formulas/helpers/evaluations.d.ts +0 -15
- package/dist/formulas/helpers/evaluations.d.ts.map +0 -1
- package/dist/formulas/helpers/evaluations.js +0 -44
- package/dist/formulas/helpers/evaluations.js.map +0 -1
- package/dist/formulas/helpers/formula.d.ts +0 -6
- package/dist/formulas/helpers/formula.d.ts.map +0 -1
- package/dist/formulas/helpers/formula.js +0 -26
- package/dist/formulas/helpers/formula.js.map +0 -1
- package/dist/formulas/helpers/lexer.d.ts +0 -10
- package/dist/formulas/helpers/lexer.d.ts.map +0 -1
- package/dist/formulas/helpers/lexer.js +0 -73
- package/dist/formulas/helpers/lexer.js.map +0 -1
- package/dist/formulas/helpers/parser.d.ts +0 -24
- package/dist/formulas/helpers/parser.d.ts.map +0 -1
- package/dist/formulas/helpers/parser.js +0 -48
- package/dist/formulas/helpers/parser.js.map +0 -1
- package/dist/formulas/helpers/token.d.ts +0 -14
- package/dist/formulas/helpers/token.d.ts.map +0 -1
- package/dist/formulas/helpers/token.js +0 -14
- package/dist/formulas/helpers/token.js.map +0 -1
- package/dist/formulas/index.d.ts +0 -59
- package/dist/formulas/index.d.ts.map +0 -1
- package/dist/formulas/index.js +0 -186
- package/dist/formulas/index.js.map +0 -1
- package/dist/formulas/types/formulas.d.ts +0 -68
- package/dist/formulas/types/formulas.d.ts.map +0 -1
- package/dist/formulas/types/formulas.js +0 -2
- package/dist/formulas/types/formulas.js.map +0 -1
- package/dist/formulas/types/index.d.ts +0 -5
- package/dist/formulas/types/index.d.ts.map +0 -1
- package/dist/formulas/types/index.js +0 -2
- package/dist/formulas/types/index.js.map +0 -1
- package/dist/formulas/variants/array-formula.d.ts +0 -24
- package/dist/formulas/variants/array-formula.d.ts.map +0 -1
- package/dist/formulas/variants/array-formula.js +0 -142
- package/dist/formulas/variants/array-formula.js.map +0 -1
- package/dist/formulas/variants/base.d.ts +0 -6
- package/dist/formulas/variants/base.d.ts.map +0 -1
- package/dist/formulas/variants/base.js +0 -3
- package/dist/formulas/variants/base.js.map +0 -1
- package/dist/formulas/variants/basic.d.ts +0 -18
- package/dist/formulas/variants/basic.d.ts.map +0 -1
- package/dist/formulas/variants/basic.js +0 -128
- package/dist/formulas/variants/basic.js.map +0 -1
- package/dist/formulas/variants/comparison.d.ts +0 -25
- package/dist/formulas/variants/comparison.d.ts.map +0 -1
- package/dist/formulas/variants/comparison.js +0 -153
- package/dist/formulas/variants/comparison.js.map +0 -1
- package/dist/formulas/variants/conditional.d.ts +0 -18
- package/dist/formulas/variants/conditional.d.ts.map +0 -1
- package/dist/formulas/variants/conditional.js +0 -183
- package/dist/formulas/variants/conditional.js.map +0 -1
- package/dist/formulas/variants/iterative-array.d.ts +0 -20
- package/dist/formulas/variants/iterative-array.d.ts.map +0 -1
- package/dist/formulas/variants/iterative-array.js +0 -155
- package/dist/formulas/variants/iterative-array.js.map +0 -1
- package/dist/formulas/variants/per-value.d.ts +0 -20
- package/dist/formulas/variants/per-value.d.ts.map +0 -1
- package/dist/formulas/variants/per-value.js +0 -154
- package/dist/formulas/variants/per-value.js.map +0 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -6
- package/dist/index.js.map +0 -1
- package/dist/models/base.d.ts +0 -55
- package/dist/models/base.d.ts.map +0 -1
- package/dist/models/base.js +0 -146
- package/dist/models/base.js.map +0 -1
- package/dist/models/callback-manager.d.ts +0 -7
- package/dist/models/callback-manager.d.ts.map +0 -1
- package/dist/models/callback-manager.js +0 -89
- package/dist/models/callback-manager.js.map +0 -1
- package/dist/models/field.d.ts +0 -121
- package/dist/models/field.d.ts.map +0 -1
- package/dist/models/field.js +0 -443
- package/dist/models/field.js.map +0 -1
- package/dist/models/index.d.ts +0 -13
- package/dist/models/index.d.ts.map +0 -1
- package/dist/models/index.js +0 -7
- package/dist/models/index.js.map +0 -1
- package/dist/models/model.d.ts +0 -37
- package/dist/models/model.d.ts.map +0 -1
- package/dist/models/model.js +0 -245
- package/dist/models/model.js.map +0 -1
- package/dist/models/plugins/base.d.ts +0 -9
- package/dist/models/plugins/base.d.ts.map +0 -1
- package/dist/models/plugins/base.js +0 -3
- package/dist/models/plugins/base.js.map +0 -1
- package/dist/models/plugins/formula.d.ts +0 -18
- package/dist/models/plugins/formula.d.ts.map +0 -1
- package/dist/models/plugins/formula.js +0 -82
- package/dist/models/plugins/formula.js.map +0 -1
- package/dist/models/plugins/index.d.ts +0 -11
- package/dist/models/plugins/index.d.ts.map +0 -1
- package/dist/models/plugins/index.js +0 -52
- package/dist/models/plugins/index.js.map +0 -1
- package/dist/models/plugins/plugins.d.ts +0 -7
- package/dist/models/plugins/plugins.d.ts.map +0 -1
- package/dist/models/plugins/plugins.js +0 -7
- package/dist/models/plugins/plugins.js.map +0 -1
- package/dist/models/types/base-wise-model.d.ts +0 -7
- package/dist/models/types/base-wise-model.d.ts.map +0 -1
- package/dist/models/types/base-wise-model.js +0 -2
- package/dist/models/types/base-wise-model.js.map +0 -1
- package/dist/models/types/callbacks.d.ts +0 -19
- package/dist/models/types/callbacks.d.ts.map +0 -1
- package/dist/models/types/callbacks.js +0 -2
- package/dist/models/types/callbacks.js.map +0 -1
- package/dist/models/types/disabled.d.ts +0 -8
- package/dist/models/types/disabled.d.ts.map +0 -1
- package/dist/models/types/disabled.js +0 -2
- package/dist/models/types/disabled.js.map +0 -1
- package/dist/models/types/form-field.d.ts +0 -25
- package/dist/models/types/form-field.d.ts.map +0 -1
- package/dist/models/types/form-field.js +0 -2
- package/dist/models/types/form-field.js.map +0 -1
- package/dist/models/types/model.d.ts +0 -13
- package/dist/models/types/model.d.ts.map +0 -1
- package/dist/models/types/model.js +0 -2
- package/dist/models/types/model.js.map +0 -1
- package/dist/models/types/plugins.d.ts +0 -13
- package/dist/models/types/plugins.d.ts.map +0 -1
- package/dist/models/types/plugins.js +0 -2
- package/dist/models/types/plugins.js.map +0 -1
- package/dist/models/types/wrapped-form-model-props.d.ts +0 -11
- package/dist/models/types/wrapped-form-model-props.d.ts.map +0 -1
- package/dist/models/types/wrapped-form-model-props.js +0 -2
- package/dist/models/types/wrapped-form-model-props.js.map +0 -1
- package/dist/models/wrapper.d.ts +0 -30
- package/dist/models/wrapper.d.ts.map +0 -1
- package/dist/models/wrapper.js +0 -213
- package/dist/models/wrapper.js.map +0 -1
- package/dist/settings/index.d.ts +0 -7
- package/dist/settings/index.d.ts.map +0 -1
- package/dist/settings/index.js +0 -26
- package/dist/settings/index.js.map +0 -1
- package/dist/utils/pending-promise.d.ts +0 -6
- package/dist/utils/pending-promise.d.ts.map +0 -1
- package/dist/utils/pending-promise.js +0 -24
- package/dist/utils/pending-promise.js.map +0 -1
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bgroup/wise-form",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Wise Form - A reactive form library",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -13,8 +13,20 @@
|
|
|
13
13
|
"./styles": "./dist/form/styles.css"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
16
|
+
"dev": "pnpm run dev:all",
|
|
17
|
+
"dev:ts": "vite build --watch --mode development",
|
|
18
|
+
"dev:css": "pnpm exec postcss src/form/styles.css -o dist/form/styles.css --watch",
|
|
19
|
+
"dev:all": "pnpm run dev:ts & pnpm run dev:css",
|
|
20
|
+
"build": "pnpm run clean && pnpm run build:types && pnpm run build:vite && pnpm run build:css",
|
|
21
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
22
|
+
"build:vite": "vite build",
|
|
23
|
+
"build:css": "pnpm exec postcss src/form/styles.css -o dist/form/styles.css",
|
|
24
|
+
"watch": "pnpm run dev:all",
|
|
25
|
+
"watch:ts": "tsc --watch --emitDeclarationOnly",
|
|
26
|
+
"watch:css": "pnpm exec postcss src/form/styles.css -o dist/form/styles.css --watch",
|
|
27
|
+
"clean": "rimraf dist",
|
|
28
|
+
"prepublishOnly": "pnpm run build",
|
|
29
|
+
"publish:public": "npm publish --access public"
|
|
18
30
|
},
|
|
19
31
|
"keywords": [
|
|
20
32
|
"form",
|
|
@@ -33,6 +45,13 @@
|
|
|
33
45
|
},
|
|
34
46
|
"devDependencies": {
|
|
35
47
|
"@types/react": "^18.0.26",
|
|
36
|
-
"
|
|
48
|
+
"@vitejs/plugin-react": "^4.2.1",
|
|
49
|
+
"autoprefixer": "^10.4.22",
|
|
50
|
+
"postcss": "^8.5.6",
|
|
51
|
+
"postcss-cli": "^11.0.1",
|
|
52
|
+
"rimraf": "^5.0.5",
|
|
53
|
+
"tailwindcss": "^3.4.18",
|
|
54
|
+
"typescript": "^5.0.0",
|
|
55
|
+
"vite": "^5.0.0"
|
|
37
56
|
}
|
|
38
57
|
}
|
package/src/form/styles.css
CHANGED
|
@@ -1,40 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.reactive-form-container .rf-fields-container.fr-1 {
|
|
12
|
-
grid-template-columns: repeat(1, 1fr);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.reactive-form-container .rf-fields-container.fr-2 {
|
|
16
|
-
grid-template-columns: repeat(2, 1fr);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.reactive-form-container .rf-fields-container.fr-3 {
|
|
20
|
-
grid-template-columns: repeat(3, 1fr);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.reactive-form-container .rf-fields-container.fr-4 {
|
|
24
|
-
grid-template-columns: repeat(4, 1fr);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.reactive-form-container .rf-fields-container.fr-5 {
|
|
28
|
-
grid-template-columns: repeat(5, 1fr);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.reactive-form-container .rf-fields-container.fr-6 {
|
|
32
|
-
grid-template-columns: repeat(6, 1fr);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.reactive-form-container :not(.not-responsive) > .rf-fields-container {
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
@layer components {
|
|
6
|
+
/* Responsive: en mobile los contenedores sin .not-responsive se convierten en 1 columna */
|
|
7
|
+
/* Esto requiere un selector CSS complejo que no se puede hacer solo con clases de Tailwind */
|
|
8
|
+
/* Usamos !important para sobrescribir estilos inline dinámicos */
|
|
36
9
|
@media (max-width: 768px) {
|
|
37
|
-
|
|
10
|
+
.reactive-form-container :not(.not-responsive) > .rf-fields-container {
|
|
11
|
+
grid-template-columns: 1fr !important;
|
|
12
|
+
}
|
|
38
13
|
}
|
|
39
14
|
}
|
|
40
|
-
|
|
@@ -10,9 +10,38 @@ export function Containers() {
|
|
|
10
10
|
} = useWiseFormContext();
|
|
11
11
|
|
|
12
12
|
const fields = [...model.fields.values()];
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
|
|
14
|
+
// Use slice instead of splice to avoid mutating the array
|
|
15
|
+
// Calculate indices safely using useMemo with stable dependencies
|
|
16
|
+
const rowsLength = rows?.length || 0;
|
|
17
|
+
const fieldsSize = model.fields?.size || 0;
|
|
18
|
+
const modelName = model.name;
|
|
19
|
+
|
|
20
|
+
const containers = React.useMemo(() => {
|
|
21
|
+
let currentIndex = 0;
|
|
22
|
+
const result = rows.map((num, index) => {
|
|
23
|
+
const items = fields.slice(currentIndex, currentIndex + num[0]) as any; // Type assertion needed due to TypeScript strictness
|
|
24
|
+
currentIndex += num[0];
|
|
25
|
+
return <RowFieldContainer model={model} template={num} items={items} key={`rf-row--${index}.${num}`} styles={styles} />;
|
|
26
|
+
});
|
|
27
|
+
return result;
|
|
28
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
29
|
+
}, [rowsLength, fieldsSize, modelName]);
|
|
30
|
+
|
|
31
|
+
React.useEffect(() => {
|
|
32
|
+
const formElement = document.querySelector('form.reactive-form-container') as HTMLElement;
|
|
33
|
+
const containerElements = formElement?.querySelectorAll('.rf-fields-container');
|
|
34
|
+
|
|
35
|
+
// Verificar si hay algún contenedor que retorna null
|
|
36
|
+
if (containers.length > 0 && (!containerElements || containerElements.length === 0)) {
|
|
37
|
+
// Silent check - no logging
|
|
38
|
+
}
|
|
39
|
+
}, [containers.length]);
|
|
40
|
+
|
|
41
|
+
if (containers.length === 0) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return <>{containers}</>;
|
|
17
46
|
}
|
|
18
47
|
|
|
@@ -22,13 +22,12 @@ type WiseFormFieldControlProps = {
|
|
|
22
22
|
export const Control = ({ field, index, model, hidden }: WiseFormFieldControlProps) => {
|
|
23
23
|
const { formTypes } = useWiseFormContext();
|
|
24
24
|
const fieldItem = field as any; // Using any to access dynamic properties
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
// Early return if field doesn't have a name (except for wrapper types and special types)
|
|
27
27
|
const specialTypes = ['wrapper', 'hr', 'button'];
|
|
28
|
-
|
|
28
|
+
let fieldType = fieldItem?.type; // Use let instead of const to allow modification
|
|
29
29
|
const fieldName = fieldItem?.name;
|
|
30
30
|
if (!fieldName && !specialTypes.includes(fieldType)) {
|
|
31
|
-
console.warn('You need to provide a name to get a field in form', (model as any).name || 'unknown');
|
|
32
31
|
return null;
|
|
33
32
|
}
|
|
34
33
|
|
|
@@ -77,18 +76,54 @@ export const Control = ({ field, index, model, hidden }: WiseFormFieldControlPro
|
|
|
77
76
|
...formTypes,
|
|
78
77
|
};
|
|
79
78
|
|
|
79
|
+
// Handle undefined type fields - use default type instead of returning null
|
|
80
|
+
if (!fieldType && fieldName) {
|
|
81
|
+
// Check if field has className 'hide' - these are intentionally hidden fields
|
|
82
|
+
const className = (fieldItem as any).className || '';
|
|
83
|
+
if (className.includes('hide') || className === 'hide') {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Check if it's a hidden field in the model
|
|
88
|
+
const fieldModel = model.getField(fieldName);
|
|
89
|
+
if (fieldModel) {
|
|
90
|
+
const properties = (fieldModel as FormField).getProperties();
|
|
91
|
+
if ((properties as any).hidden) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// If no type is defined, use default - don't skip the field
|
|
97
|
+
(fieldItem as any).type = 'default';
|
|
98
|
+
fieldType = 'default'; // Update fieldType variable to use default
|
|
99
|
+
}
|
|
100
|
+
|
|
80
101
|
const ControlComponent = types[fieldType] ?? types.default;
|
|
81
|
-
|
|
102
|
+
|
|
103
|
+
if (!ControlComponent) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Validar que ControlComponent sea realmente un componente válido (función o clase)
|
|
108
|
+
if (typeof ControlComponent !== 'function' && typeof ControlComponent !== 'object') {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Si es un objeto, puede ser un componente de React (tiene render o $$typeof)
|
|
113
|
+
if (typeof ControlComponent === 'object' && !ControlComponent.$$typeof && typeof ControlComponent !== 'function') {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
82
117
|
// Merge field properties with attrs to ensure custom components receive all necessary props
|
|
83
118
|
const fieldModel = fieldName ? model.getField(fieldName) : null;
|
|
84
119
|
const fieldProperties = fieldModel ? fieldModel.getProperties() : {};
|
|
85
|
-
|
|
120
|
+
|
|
86
121
|
// Also include original field item properties (like options, label, etc.)
|
|
87
122
|
const fieldItemProps = { ...fieldItem };
|
|
88
123
|
// Remove internal properties that shouldn't be passed to components
|
|
89
124
|
delete (fieldItemProps as any).name;
|
|
90
125
|
delete (fieldItemProps as any).type;
|
|
91
|
-
|
|
126
|
+
|
|
92
127
|
// Filter out non-HTML attributes from fieldProperties to prevent React warnings
|
|
93
128
|
const invalidAttributes = ['processing', 'processed', 'properties', 'specs', 'hidden', 'identifier'];
|
|
94
129
|
const filteredFieldProperties = Object.keys(fieldProperties).reduce((acc, key) => {
|
|
@@ -97,7 +132,7 @@ export const Control = ({ field, index, model, hidden }: WiseFormFieldControlPro
|
|
|
97
132
|
}
|
|
98
133
|
return acc;
|
|
99
134
|
}, {} as any);
|
|
100
|
-
|
|
135
|
+
|
|
101
136
|
return (
|
|
102
137
|
<ControlFieldContainer>
|
|
103
138
|
<ControlComponent {...attrs} {...fieldItemProps} {...filteredFieldProperties} />
|
|
@@ -39,6 +39,15 @@ export function RowFieldContainer({ template: [totalFields, gridStyle], items, s
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
// Suscribirse a los cambios de cada campo
|
|
42
|
+
// Use stable references for field names to avoid unnecessary re-renders
|
|
43
|
+
const fieldNamesRef = React.useRef<string[]>([]);
|
|
44
|
+
const currentFieldNames = items.map((field: any) => field?.name).filter(Boolean);
|
|
45
|
+
const fieldNamesChanged = JSON.stringify(fieldNamesRef.current) !== JSON.stringify(currentFieldNames);
|
|
46
|
+
|
|
47
|
+
if (fieldNamesChanged) {
|
|
48
|
+
fieldNamesRef.current = currentFieldNames;
|
|
49
|
+
}
|
|
50
|
+
|
|
42
51
|
React.useEffect(() => {
|
|
43
52
|
const listeners: Array<() => void> = [];
|
|
44
53
|
|
|
@@ -53,10 +62,14 @@ export function RowFieldContainer({ template: [totalFields, gridStyle], items, s
|
|
|
53
62
|
|
|
54
63
|
const onChange = () => {
|
|
55
64
|
const properties = (fieldModel as FormField).getProperties();
|
|
56
|
-
setFieldHiddenStates((prev) =>
|
|
57
|
-
|
|
58
|
-
[fieldName]
|
|
59
|
-
|
|
65
|
+
setFieldHiddenStates((prev) => {
|
|
66
|
+
const newHidden = (properties as any).hidden ?? false;
|
|
67
|
+
if (prev[fieldName] === newHidden) return prev; // Avoid unnecessary state update
|
|
68
|
+
return {
|
|
69
|
+
...prev,
|
|
70
|
+
[fieldName]: newHidden,
|
|
71
|
+
};
|
|
72
|
+
});
|
|
60
73
|
};
|
|
61
74
|
|
|
62
75
|
fieldModel.on('change', onChange);
|
|
@@ -66,12 +79,15 @@ export function RowFieldContainer({ template: [totalFields, gridStyle], items, s
|
|
|
66
79
|
return () => {
|
|
67
80
|
listeners.forEach((cleanup) => cleanup());
|
|
68
81
|
};
|
|
69
|
-
|
|
82
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
83
|
+
}, [currentFieldNames.join(','), model.name]);
|
|
70
84
|
|
|
71
85
|
let hidden = false;
|
|
72
86
|
const output = items.reduce((acc: React.ReactElement[], field, index) => {
|
|
73
87
|
const fieldItem = field as any; // Using any to access dynamic properties
|
|
74
88
|
const fieldType = fieldItem?.type;
|
|
89
|
+
const fieldName = fieldItem?.name;
|
|
90
|
+
|
|
75
91
|
if (fieldType === "wrapper") {
|
|
76
92
|
const fieldModel = model.getField(fieldItem?.name);
|
|
77
93
|
const wrapperHidden = fieldModel ? ((fieldModel as WrappedFormModel).getProperties() as any).hidden ?? false : false;
|
|
@@ -80,7 +96,6 @@ export function RowFieldContainer({ template: [totalFields, gridStyle], items, s
|
|
|
80
96
|
return acc;
|
|
81
97
|
}
|
|
82
98
|
|
|
83
|
-
const fieldName = fieldItem?.name;
|
|
84
99
|
const isHidden = fieldName ? (fieldHiddenStates[fieldName] ?? (fieldItem as any).hidden ?? false) : false;
|
|
85
100
|
if (!isHidden) {
|
|
86
101
|
acc.push(<Control index={index} model={model} field={fieldItem} key={`rf-row__item--${index}`} hidden={isHidden} />);
|
|
@@ -88,9 +103,22 @@ export function RowFieldContainer({ template: [totalFields, gridStyle], items, s
|
|
|
88
103
|
return acc;
|
|
89
104
|
}, []);
|
|
90
105
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
106
|
+
// Construir clases de Tailwind para el contenedor
|
|
107
|
+
// grid gap-2 para el layout base
|
|
108
|
+
// En mobile (< 768px), los contenedores sin .not-responsive se convierten en 1 columna
|
|
109
|
+
// Esto se maneja con CSS personalizado porque requiere el selector :not(.not-responsive) >
|
|
110
|
+
const attrs = {
|
|
111
|
+
className: `rf-fields-container grid gap-2 w-full`,
|
|
112
|
+
style: { gridTemplateColumns: `${gridStyle}`, ...styles }
|
|
113
|
+
};
|
|
114
|
+
if (hidden) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (output.length === 0) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
94
122
|
return <div {...attrs}>{output}</div>;
|
|
95
123
|
}
|
|
96
124
|
|
|
@@ -1,27 +1,38 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {useWiseFormContext} from "../../context";
|
|
2
|
+
import { useWiseFormContext } from "../../context";
|
|
3
3
|
/**
|
|
4
4
|
*
|
|
5
5
|
* @param data {WrappedFormModel}
|
|
6
6
|
* @param model {FormModel} parent.
|
|
7
7
|
* @returns
|
|
8
8
|
*/
|
|
9
|
-
export function FormSectionWrapper({data, model}) {
|
|
10
|
-
const {formTypes} = useWiseFormContext();
|
|
9
|
+
export function FormSectionWrapper({ data, model }) {
|
|
10
|
+
const { formTypes } = useWiseFormContext();
|
|
11
11
|
|
|
12
12
|
const types = {
|
|
13
13
|
...formTypes,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
if (!data.control)
|
|
16
|
+
if (!data.control) {
|
|
17
|
+
throw new Error("Wrapper must have a control");
|
|
18
|
+
}
|
|
17
19
|
if (!data.name) {
|
|
18
|
-
console.error("Wrapper must have a name", data);
|
|
19
20
|
return null;
|
|
20
21
|
}
|
|
21
|
-
if (data?.hidden)
|
|
22
|
+
if (data?.hidden) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
22
25
|
|
|
23
26
|
const wrapperModel = model?.getField(data.name);
|
|
27
|
+
if (!wrapperModel) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
24
31
|
const Control = types[data.control];
|
|
32
|
+
if (!Control) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
25
36
|
// data = wrapperModel ? { ...data, ...wrapperModel.getProperties() } : data;
|
|
26
37
|
return <Control model={wrapperModel} />;
|
|
27
38
|
}
|
|
@@ -6,13 +6,46 @@ import { useTemplate } from '../hooks/use-template';
|
|
|
6
6
|
export function WrappedForm({ children, name, types }): JSX.Element {
|
|
7
7
|
const { model: parent } = useWiseFormContext();
|
|
8
8
|
const wrapper = parent.wrappers.get(name);
|
|
9
|
+
|
|
10
|
+
if (!wrapper) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
const model = wrapper;
|
|
10
15
|
const template = useTemplate(model.settings);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
// Memoizar fields usando una clave estable basada en el contenido
|
|
18
|
+
// Comparar por longitud y nombres de campos para evitar recrear el array innecesariamente
|
|
19
|
+
const fieldsKey = React.useMemo(() => {
|
|
20
|
+
const fieldsArray = model.settings.fields || [];
|
|
21
|
+
return `${fieldsArray.length}-${fieldsArray.slice(0, 5).map(f => f.name || f.type || '').join(',')}`;
|
|
22
|
+
}, [model.settings.fields]);
|
|
23
|
+
|
|
24
|
+
const fields = React.useMemo(() => {
|
|
25
|
+
return [...model.settings.fields];
|
|
26
|
+
}, [fieldsKey]);
|
|
27
|
+
|
|
28
|
+
// Use stable references for useMemo dependencies
|
|
29
|
+
// Usar una referencia estable del modelo y sus propiedades clave
|
|
30
|
+
const modelName = model.name;
|
|
31
|
+
const templateItemsLength = template.items?.length || 0;
|
|
32
|
+
const fieldsLength = fields.length;
|
|
33
|
+
|
|
34
|
+
// Crear una clave estable basada en las propiedades del modelo que realmente importan
|
|
35
|
+
const modelKey = React.useMemo(() => {
|
|
36
|
+
return `${modelName}-${templateItemsLength}-${fieldsLength}`;
|
|
37
|
+
}, [modelName, templateItemsLength, fieldsLength]);
|
|
38
|
+
|
|
39
|
+
const Containers = React.useMemo(() => {
|
|
40
|
+
let currentIndex = 0;
|
|
41
|
+
const result = template.items.map((num, index) => {
|
|
42
|
+
const items = fields.slice(currentIndex, currentIndex + num[0]);
|
|
43
|
+
currentIndex += num[0];
|
|
44
|
+
return <RowFieldContainer template={num} model={model} items={items} key={`rf-row--${index}.${num}`} />;
|
|
45
|
+
});
|
|
46
|
+
return result;
|
|
47
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
48
|
+
}, [modelKey]);
|
|
16
49
|
|
|
17
50
|
const value = {
|
|
18
51
|
model,
|
|
@@ -2,36 +2,102 @@ import React from 'react';
|
|
|
2
2
|
import { FormModel } from '@bgroup/wise-form/models';
|
|
3
3
|
import { useTemplate } from './use-template';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Hook para gestionar el modelo del formulario
|
|
7
|
+
*
|
|
8
|
+
* Principios SOLID aplicados:
|
|
9
|
+
* - Single Responsibility: Solo gestiona el estado del modelo del formulario
|
|
10
|
+
* - Open/Closed: Extensible mediante eventos del modelo sin modificar el hook
|
|
11
|
+
* - Dependency Inversion: Depende de la abstracción FormModel, no de implementaciones concretas
|
|
12
|
+
*/
|
|
5
13
|
export function useModel(settings, form?: FormModel) {
|
|
6
|
-
|
|
7
|
-
const [
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
// Estado del modelo - usa el form pasado o null inicialmente
|
|
15
|
+
const [model, setModel] = React.useState<FormModel | null>(form || null);
|
|
16
|
+
|
|
17
|
+
// Determinar si el modelo está listo basándose en su estado real
|
|
18
|
+
const getModelReadyState = React.useCallback((currentModel: FormModel | null): boolean => {
|
|
19
|
+
if (!currentModel) return false;
|
|
20
|
+
|
|
21
|
+
// Si el modelo tiene la propiedad ready, usarla
|
|
22
|
+
if (currentModel.ready !== undefined) {
|
|
23
|
+
return currentModel.ready === true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Si no tiene ready pero tiene campos y wrappers, asumir que está listo
|
|
27
|
+
const hasFields = currentModel.fields?.size > 0;
|
|
28
|
+
const hasWrappers = currentModel.wrappers?.size > 0;
|
|
29
|
+
const hasName = !!currentModel.name;
|
|
30
|
+
|
|
31
|
+
// Está listo si tiene al menos campos o wrappers y un nombre
|
|
32
|
+
return hasName && (hasFields || hasWrappers);
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
35
|
+
// Estado de ready basado en el modelo actual
|
|
36
|
+
const [ready, setReady] = React.useState(() => getModelReadyState(form || null));
|
|
37
|
+
const [values, setValues] = React.useState(() => form?.values || {});
|
|
38
|
+
|
|
39
|
+
// Template specs: usar settings si están disponibles, sino usar el form
|
|
40
|
+
const templateSpecs = settings || form;
|
|
41
|
+
const { type, styles, items } = useTemplate(templateSpecs, templateSpecs?.gap);
|
|
42
|
+
|
|
43
|
+
// Efecto para inicializar y suscribirse a cambios del modelo
|
|
44
|
+
React.useEffect(() => {
|
|
45
|
+
let currentModel: FormModel | null = null;
|
|
46
|
+
let cleanup: (() => void) | null = null;
|
|
47
|
+
|
|
48
|
+
// Si ya tenemos un modelo, usarlo directamente
|
|
49
|
+
if (form) {
|
|
50
|
+
currentModel = form;
|
|
51
|
+
setModel(form);
|
|
52
|
+
const initialReady = getModelReadyState(form);
|
|
53
|
+
setReady(initialReady);
|
|
15
54
|
setValues({ ...form.values });
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
55
|
+
}
|
|
56
|
+
// Si no hay modelo pero hay settings, crear uno nuevo
|
|
57
|
+
else if (settings) {
|
|
58
|
+
try {
|
|
59
|
+
const properties = settings.fields?.map((item: any) => item.name) || [];
|
|
60
|
+
const values = settings.values || {};
|
|
61
|
+
currentModel = new FormModel(settings, { properties, ...values });
|
|
62
|
+
setModel(currentModel);
|
|
63
|
+
|
|
64
|
+
// Verificar estado inicial del modelo creado
|
|
65
|
+
const modelReady = getModelReadyState(currentModel);
|
|
66
|
+
setReady(modelReady);
|
|
67
|
+
setValues({ ...currentModel.values });
|
|
68
|
+
} catch (error) {
|
|
69
|
+
setReady(false);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// No hay modelo ni settings
|
|
74
|
+
else {
|
|
75
|
+
setReady(false);
|
|
76
|
+
return;
|
|
22
77
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
78
|
+
|
|
79
|
+
// Suscribirse a cambios del modelo para actualizar el estado
|
|
80
|
+
if (currentModel) {
|
|
81
|
+
const onChange = () => {
|
|
82
|
+
const isReady = getModelReadyState(currentModel);
|
|
83
|
+
setReady(isReady);
|
|
84
|
+
if (currentModel) {
|
|
85
|
+
setValues({ ...currentModel.values });
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
currentModel.on('change', onChange);
|
|
90
|
+
cleanup = () => {
|
|
91
|
+
currentModel?.off('change', onChange);
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
29
95
|
return () => {
|
|
30
|
-
|
|
96
|
+
if (cleanup) {
|
|
97
|
+
cleanup();
|
|
98
|
+
}
|
|
31
99
|
};
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
React.useEffect(startup, [form?.name]);
|
|
100
|
+
}, [form?.name, settings?.name, getModelReadyState]);
|
|
35
101
|
|
|
36
102
|
return { ready, model, values, type, styles, items };
|
|
37
103
|
}
|
package/src/form/view/index.tsx
CHANGED
|
@@ -10,10 +10,22 @@ export function WiseForm({ children, settings, types, model }: IWiseFormSpecs):
|
|
|
10
10
|
const { ready, model: instance, type, styles, items } = useModel(settings, model);
|
|
11
11
|
const formTypes = useTypes(types);
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
// IMPORTANTE: useEffect debe estar ANTES de cualquier early return
|
|
14
|
+
// para cumplir con las reglas de hooks de React
|
|
15
|
+
React.useEffect(() => {
|
|
16
|
+
if (!ready || !instance) return;
|
|
17
|
+
}, [ready, instance?.name]);
|
|
18
|
+
|
|
19
|
+
if (!ready) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
14
22
|
|
|
15
23
|
if (!settings && !model) {
|
|
16
|
-
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!instance) {
|
|
28
|
+
return null;
|
|
17
29
|
}
|
|
18
30
|
|
|
19
31
|
const onSubmit = (event: React.FormEvent) => {
|
|
@@ -38,7 +50,7 @@ export function WiseForm({ children, settings, types, model }: IWiseFormSpecs):
|
|
|
38
50
|
<WiseFormContext.Provider value={value}>
|
|
39
51
|
<form onKeyDown={(e) => {
|
|
40
52
|
if (e.key === 'Enter') e.preventDefault();
|
|
41
|
-
}} className="reactive-form-container" onSubmit={onSubmit}>
|
|
53
|
+
}} className="reactive-form-container grid gap-4" onSubmit={onSubmit}>
|
|
42
54
|
<Containers />
|
|
43
55
|
{children}
|
|
44
56
|
</form>
|