pdyform 1.0.0

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 (76) hide show
  1. package/README.md +34 -0
  2. package/eslint.config.mjs +53 -0
  3. package/package.json +45 -0
  4. package/packages/core/dist/chunk-KQR3LFND.js +60 -0
  5. package/packages/core/dist/index.cjs +87 -0
  6. package/packages/core/dist/index.d.cts +2 -0
  7. package/packages/core/dist/index.d.ts +2 -0
  8. package/packages/core/dist/index.js +8 -0
  9. package/packages/core/dist/parser.cjs +1 -0
  10. package/packages/core/dist/parser.d.cts +2 -0
  11. package/packages/core/dist/parser.d.ts +2 -0
  12. package/packages/core/dist/parser.js +0 -0
  13. package/packages/core/dist/types.cjs +18 -0
  14. package/packages/core/dist/types.d.cts +39 -0
  15. package/packages/core/dist/types.d.ts +39 -0
  16. package/packages/core/dist/types.js +0 -0
  17. package/packages/core/dist/utils.cjs +85 -0
  18. package/packages/core/dist/utils.d.cts +6 -0
  19. package/packages/core/dist/utils.d.ts +6 -0
  20. package/packages/core/dist/utils.js +8 -0
  21. package/packages/core/node_modules/.bin/esbuild +14 -0
  22. package/packages/core/node_modules/.bin/tsc +17 -0
  23. package/packages/core/node_modules/.bin/tsserver +17 -0
  24. package/packages/core/node_modules/.bin/tsup +17 -0
  25. package/packages/core/node_modules/.bin/tsup-node +17 -0
  26. package/packages/core/node_modules/.bin/vitest +17 -0
  27. package/packages/core/node_modules/.vite/vitest/results.json +1 -0
  28. package/packages/core/package.json +30 -0
  29. package/packages/core/src/index.test.ts +37 -0
  30. package/packages/core/src/index.ts +2 -0
  31. package/packages/core/src/parser.ts +0 -0
  32. package/packages/core/src/types.ts +42 -0
  33. package/packages/core/src/utils.ts +59 -0
  34. package/packages/core/tsconfig.json +15 -0
  35. package/packages/core/tsup.config.ts +9 -0
  36. package/packages/react/dist/index.cjs +217 -0
  37. package/packages/react/dist/index.d.cts +20 -0
  38. package/packages/react/dist/index.d.ts +20 -0
  39. package/packages/react/dist/index.js +189 -0
  40. package/packages/react/node_modules/.bin/browserslist +17 -0
  41. package/packages/react/node_modules/.bin/esbuild +14 -0
  42. package/packages/react/node_modules/.bin/tsc +17 -0
  43. package/packages/react/node_modules/.bin/tsserver +17 -0
  44. package/packages/react/node_modules/.bin/tsup +17 -0
  45. package/packages/react/node_modules/.bin/tsup-node +17 -0
  46. package/packages/react/node_modules/.bin/vite +17 -0
  47. package/packages/react/node_modules/.bin/vitest +17 -0
  48. package/packages/react/node_modules/.vite/vitest/results.json +1 -0
  49. package/packages/react/package.json +45 -0
  50. package/packages/react/src/DynamicForm.test.tsx +25 -0
  51. package/packages/react/src/DynamicForm.tsx +93 -0
  52. package/packages/react/src/FormFieldRenderer.tsx +130 -0
  53. package/packages/react/src/index.tsx +2 -0
  54. package/packages/react/tsconfig.json +15 -0
  55. package/packages/react/vitest.config.ts +16 -0
  56. package/packages/vue/dist/index.js +1 -0
  57. package/packages/vue/dist/index.mjs +183 -0
  58. package/packages/vue/node_modules/.bin/tsc +17 -0
  59. package/packages/vue/node_modules/.bin/tsserver +17 -0
  60. package/packages/vue/node_modules/.bin/vite +17 -0
  61. package/packages/vue/node_modules/.bin/vitest +17 -0
  62. package/packages/vue/node_modules/.bin/vue-tsc +17 -0
  63. package/packages/vue/node_modules/.vite/vitest/results.json +1 -0
  64. package/packages/vue/node_modules/.vue-global-types/vue_3.5_0_0_0.d.ts +118 -0
  65. package/packages/vue/package.json +43 -0
  66. package/packages/vue/src/DynamicForm.test.ts +19 -0
  67. package/packages/vue/src/DynamicForm.vue +81 -0
  68. package/packages/vue/src/FormFieldRenderer.vue +114 -0
  69. package/packages/vue/src/env.d.ts +7 -0
  70. package/packages/vue/src/index.ts +2 -0
  71. package/packages/vue/tsconfig.json +15 -0
  72. package/packages/vue/vite.config.ts +28 -0
  73. package/packages/vue/vitest.config.ts +16 -0
  74. package/pnpm-workspace.yaml +4 -0
  75. package/tsconfig.json +21 -0
  76. package/turbo.json +17 -0
@@ -0,0 +1,183 @@
1
+ import { defineComponent as p, computed as F, openBlock as t, createElementBlock as a, normalizeClass as v, toDisplayString as o, createCommentVNode as b, createElementVNode as f, Fragment as y, renderList as g, ref as V, onMounted as $, withModifiers as S, createBlock as E } from "vue";
2
+ import { getDefaultValues as N, validateField as C } from "pdyform/core";
3
+ const A = ["for"], B = ["id", "placeholder", "disabled", "name", "value"], D = ["id", "disabled", "name", "value"], I = {
4
+ value: "",
5
+ disabled: ""
6
+ }, U = ["value"], M = {
7
+ key: 3,
8
+ class: "flex flex-wrap gap-4"
9
+ }, R = ["disabled", "checked", "onChange"], j = {
10
+ key: 4,
11
+ class: "flex flex-wrap gap-4"
12
+ }, z = ["disabled", "name", "checked", "onChange"], L = ["id", "type", "placeholder", "disabled", "name", "value"], O = {
13
+ key: 6,
14
+ class: "text-sm text-muted-foreground"
15
+ }, T = {
16
+ key: 7,
17
+ class: "text-sm font-medium text-destructive"
18
+ }, w = "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", q = /* @__PURE__ */ p({
19
+ __name: "FormFieldRenderer",
20
+ props: {
21
+ field: {},
22
+ modelValue: {},
23
+ error: {}
24
+ },
25
+ emits: ["update:modelValue"],
26
+ setup(e, { emit: x }) {
27
+ const c = e, k = x, n = F(() => `field-${c.field.name}`), r = (m) => {
28
+ k("update:modelValue", m);
29
+ }, h = (m, s) => {
30
+ const l = Array.isArray(c.modelValue) ? [...c.modelValue] : [];
31
+ if (s)
32
+ l.push(m);
33
+ else {
34
+ const d = l.indexOf(m);
35
+ d > -1 && l.splice(d, 1);
36
+ }
37
+ r(l);
38
+ };
39
+ return (m, s) => (t(), a("div", {
40
+ class: v(["space-y-2", e.field.className])
41
+ }, [
42
+ e.field.label ? (t(), a("label", {
43
+ key: 0,
44
+ for: n.value,
45
+ class: "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
46
+ }, o(e.field.label), 9, A)) : b("", !0),
47
+ e.field.type === "textarea" ? (t(), a("textarea", {
48
+ key: 1,
49
+ id: n.value,
50
+ class: v([w, "min-h-[80px]"]),
51
+ placeholder: e.field.placeholder,
52
+ disabled: e.field.disabled,
53
+ name: e.field.name,
54
+ value: e.modelValue,
55
+ onInput: s[0] || (s[0] = (l) => r(l.target.value))
56
+ }, null, 42, B)) : e.field.type === "select" ? (t(), a("select", {
57
+ key: 2,
58
+ id: n.value,
59
+ class: v(w),
60
+ disabled: e.field.disabled,
61
+ name: e.field.name,
62
+ value: e.modelValue,
63
+ onChange: s[1] || (s[1] = (l) => r(l.target.value))
64
+ }, [
65
+ f("option", I, o(e.field.placeholder || "Select an option"), 1),
66
+ (t(!0), a(y, null, g(e.field.options, (l) => (t(), a("option", {
67
+ key: l.value,
68
+ value: l.value
69
+ }, o(l.label), 9, U))), 128))
70
+ ], 40, D)) : e.field.type === "checkbox" ? (t(), a("div", M, [
71
+ (t(!0), a(y, null, g(e.field.options, (l) => (t(), a("label", {
72
+ key: l.value,
73
+ class: "flex items-center space-x-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
74
+ }, [
75
+ f("input", {
76
+ type: "checkbox",
77
+ class: "h-4 w-4 rounded border-primary text-primary focus:ring-primary",
78
+ disabled: e.field.disabled,
79
+ checked: Array.isArray(e.modelValue) && e.modelValue.includes(l.value),
80
+ onChange: (d) => h(l.value, d.target.checked)
81
+ }, null, 40, R),
82
+ f("span", null, o(l.label), 1)
83
+ ]))), 128))
84
+ ])) : e.field.type === "radio" ? (t(), a("div", j, [
85
+ (t(!0), a(y, null, g(e.field.options, (l) => (t(), a("label", {
86
+ key: l.value,
87
+ class: "flex items-center space-x-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
88
+ }, [
89
+ f("input", {
90
+ type: "radio",
91
+ class: "h-4 w-4 border-primary text-primary focus:ring-primary",
92
+ disabled: e.field.disabled,
93
+ name: e.field.name,
94
+ checked: e.modelValue === l.value,
95
+ onChange: (d) => r(l.value)
96
+ }, null, 40, z),
97
+ f("span", null, o(l.label), 1)
98
+ ]))), 128))
99
+ ])) : (t(), a("input", {
100
+ key: 5,
101
+ id: n.value,
102
+ type: e.field.type,
103
+ class: v(w),
104
+ placeholder: e.field.placeholder,
105
+ disabled: e.field.disabled,
106
+ name: e.field.name,
107
+ value: e.modelValue,
108
+ onInput: s[2] || (s[2] = (l) => r(l.target.value))
109
+ }, null, 40, L)),
110
+ e.field.description ? (t(), a("p", O, o(e.field.description), 1)) : b("", !0),
111
+ e.error ? (t(), a("p", T, o(e.error), 1)) : b("", !0)
112
+ ], 2));
113
+ }
114
+ }), G = {
115
+ key: 0,
116
+ class: "space-y-1"
117
+ }, H = {
118
+ key: 0,
119
+ class: "text-2xl font-bold tracking-tight"
120
+ }, J = {
121
+ key: 1,
122
+ class: "text-muted-foreground"
123
+ }, K = { class: "space-y-4" }, P = ["disabled"], X = /* @__PURE__ */ p({
124
+ __name: "DynamicForm",
125
+ props: {
126
+ schema: {},
127
+ className: {}
128
+ },
129
+ emits: ["submit"],
130
+ setup(e, { emit: x }) {
131
+ const c = e, k = x, n = V({}), r = V({}), h = V(!1);
132
+ $(() => {
133
+ n.value = N(c.schema.fields);
134
+ });
135
+ const m = (l, d) => {
136
+ n.value[l] = d;
137
+ const i = c.schema.fields.find((u) => u.name === l);
138
+ if (i) {
139
+ const u = C(d, i);
140
+ r.value[l] = u || "";
141
+ }
142
+ }, s = () => {
143
+ h.value = !0;
144
+ const l = {};
145
+ let d = !1;
146
+ c.schema.fields.forEach((i) => {
147
+ const u = C(n.value[i.name], i);
148
+ u && (l[i.name] = u, d = !0);
149
+ }), r.value = l, d || k("submit", { ...n.value }), h.value = !1;
150
+ };
151
+ return (l, d) => (t(), a("form", {
152
+ class: v(["space-y-6", e.className]),
153
+ onSubmit: S(s, ["prevent"])
154
+ }, [
155
+ e.schema.title || e.schema.description ? (t(), a("div", G, [
156
+ e.schema.title ? (t(), a("h2", H, o(e.schema.title), 1)) : b("", !0),
157
+ e.schema.description ? (t(), a("p", J, o(e.schema.description), 1)) : b("", !0)
158
+ ])) : b("", !0),
159
+ f("div", K, [
160
+ (t(!0), a(y, null, g(e.schema.fields, (i) => (t(), a(y, {
161
+ key: i.id
162
+ }, [
163
+ i.hidden ? b("", !0) : (t(), E(q, {
164
+ key: 0,
165
+ field: i,
166
+ "model-value": n.value[i.name],
167
+ error: r.value[i.name],
168
+ "onUpdate:modelValue": (u) => m(i.name, u)
169
+ }, null, 8, ["field", "model-value", "error", "onUpdate:modelValue"]))
170
+ ], 64))), 128))
171
+ ]),
172
+ f("button", {
173
+ type: "submit",
174
+ disabled: h.value,
175
+ class: "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 w-full"
176
+ }, o(h.value ? "Submitting..." : e.schema.submitButtonText || "Submit"), 9, P)
177
+ ], 34));
178
+ }
179
+ });
180
+ export {
181
+ X as DynamicForm,
182
+ q as FormFieldRenderer
183
+ };
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
15
+ else
16
+ exec node "$basedir/../typescript/bin/tsc" "$@"
17
+ fi
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
15
+ else
16
+ exec node "$basedir/../typescript/bin/tsserver" "$@"
17
+ fi
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vite@5.4.21_@types+node@20.19.35/node_modules/vite/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vite@5.4.21_@types+node@20.19.35/node_modules/vite/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vite@5.4.21_@types+node@20.19.35/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vite@5.4.21_@types+node@20.19.35/node_modules/vite/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vite@5.4.21_@types+node@20.19.35/node_modules/vite/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vite@5.4.21_@types+node@20.19.35/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../vite/bin/vite.js" "$@"
15
+ else
16
+ exec node "$basedir/../vite/bin/vite.js" "$@"
17
+ fi
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.35_jsdom@22.1.0/node_modules/vitest/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.35_jsdom@22.1.0/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.35_jsdom@22.1.0/node_modules/vitest/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.35_jsdom@22.1.0/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
15
+ else
16
+ exec node "$basedir/../vitest/vitest.mjs" "$@"
17
+ fi
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vue-tsc@2.2.12_typescript@5.9.3/node_modules/vue-tsc/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vue-tsc@2.2.12_typescript@5.9.3/node_modules/vue-tsc/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vue-tsc@2.2.12_typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vue-tsc@2.2.12_typescript@5.9.3/node_modules/vue-tsc/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vue-tsc@2.2.12_typescript@5.9.3/node_modules/vue-tsc/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vue-tsc@2.2.12_typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../vue-tsc/bin/vue-tsc.js" "$@"
15
+ else
16
+ exec node "$basedir/../vue-tsc/bin/vue-tsc.js" "$@"
17
+ fi
@@ -0,0 +1 @@
1
+ {"version":"1.6.1","results":[[":src/DynamicForm.test.ts",{"duration":17,"failed":false}]]}
@@ -0,0 +1,118 @@
1
+ // @ts-nocheck
2
+ export {};
3
+
4
+ ; declare global {
5
+ const __VLS_intrinsicElements: __VLS_IntrinsicElements;
6
+ const __VLS_directiveBindingRestFields: { instance: null, oldValue: null, modifiers: any, dir: any };
7
+ const __VLS_unref: typeof import('vue').unref;
8
+ const __VLS_placeholder: any;
9
+
10
+ type __VLS_NativeElements = __VLS_SpreadMerge<SVGElementTagNameMap, HTMLElementTagNameMap>;
11
+ type __VLS_IntrinsicElements = import('vue/jsx-runtime').JSX.IntrinsicElements;
12
+ type __VLS_Element = import('vue/jsx-runtime').JSX.Element;
13
+ type __VLS_GlobalComponents = import('vue').GlobalComponents;
14
+ type __VLS_GlobalDirectives = import('vue').GlobalDirectives;
15
+ type __VLS_IsAny<T> = 0 extends 1 & T ? true : false;
16
+ type __VLS_PickNotAny<A, B> = __VLS_IsAny<A> extends true ? B : A;
17
+ type __VLS_SpreadMerge<A, B> = Omit<A, keyof B> & B;
18
+ type __VLS_WithComponent<N0 extends string, LocalComponents, Self, N1 extends string, N2 extends string, N3 extends string> =
19
+ N1 extends keyof LocalComponents ? N1 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N1] } :
20
+ N2 extends keyof LocalComponents ? N2 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N2] } :
21
+ N3 extends keyof LocalComponents ? N3 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N3] } :
22
+ Self extends object ? { [K in N0]: Self } :
23
+ N1 extends keyof __VLS_GlobalComponents ? N1 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N1] } :
24
+ N2 extends keyof __VLS_GlobalComponents ? N2 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N2] } :
25
+ N3 extends keyof __VLS_GlobalComponents ? N3 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N3] } :
26
+ { [K in N0]: unknown };
27
+ type __VLS_FunctionalComponentProps<T, K> =
28
+ '__ctx' extends keyof __VLS_PickNotAny<K, {}> ? K extends { __ctx?: { props?: infer P } } ? NonNullable<P> : never
29
+ : T extends (props: infer P, ...args: any) => any ? P :
30
+ {};
31
+ type __VLS_IsFunction<T, K> = K extends keyof T
32
+ ? __VLS_IsAny<T[K]> extends false
33
+ ? unknown extends T[K]
34
+ ? false
35
+ : true
36
+ : false
37
+ : false;
38
+ type __VLS_NormalizeComponentEvent<Props, Events, onEvent extends keyof Props, Event extends keyof Events, CamelizedEvent extends keyof Events> = (
39
+ __VLS_IsFunction<Props, onEvent> extends true
40
+ ? Props
41
+ : __VLS_IsFunction<Events, Event> extends true
42
+ ? { [K in onEvent]?: Events[Event] }
43
+ : __VLS_IsFunction<Events, CamelizedEvent> extends true
44
+ ? { [K in onEvent]?: Events[CamelizedEvent] }
45
+ : Props
46
+ ) & Record<string, unknown>;
47
+ // fix https://github.com/vuejs/language-tools/issues/926
48
+ type __VLS_UnionToIntersection<U> = (U extends unknown ? (arg: U) => unknown : never) extends ((arg: infer P) => unknown) ? P : never;
49
+ type __VLS_OverloadUnionInner<T, U = unknown> = U & T extends (...args: infer A) => infer R
50
+ ? U extends T
51
+ ? never
52
+ : __VLS_OverloadUnionInner<T, Pick<T, keyof T> & U & ((...args: A) => R)> | ((...args: A) => R)
53
+ : never;
54
+ type __VLS_OverloadUnion<T> = Exclude<
55
+ __VLS_OverloadUnionInner<(() => never) & T>,
56
+ T extends () => never ? never : () => never
57
+ >;
58
+ type __VLS_ConstructorOverloads<T> = __VLS_OverloadUnion<T> extends infer F
59
+ ? F extends (event: infer E, ...args: infer A) => any
60
+ ? { [K in E & string]: (...args: A) => void; }
61
+ : never
62
+ : never;
63
+ type __VLS_NormalizeEmits<T> = __VLS_PrettifyGlobal<
64
+ __VLS_UnionToIntersection<
65
+ __VLS_ConstructorOverloads<T> & {
66
+ [K in keyof T]: T[K] extends any[] ? { (...args: T[K]): void } : never
67
+ }
68
+ >
69
+ >;
70
+ type __VLS_PrettifyGlobal<T> = { [K in keyof T]: T[K]; } & {};
71
+ type __VLS_PickFunctionalComponentCtx<T, K> = NonNullable<__VLS_PickNotAny<
72
+ '__ctx' extends keyof __VLS_PickNotAny<K, {}> ? K extends { __ctx?: infer Ctx } ? Ctx : never : any
73
+ , T extends (props: any, ctx: infer Ctx) => any ? Ctx : any
74
+ >>;
75
+ type __VLS_UseTemplateRef<T> = Readonly<import('vue').ShallowRef<T | null>>;
76
+
77
+ function __VLS_getVForSourceType<T extends number | string | any[] | Iterable<any>>(source: T): [
78
+ item: T extends number ? number
79
+ : T extends string ? string
80
+ : T extends any[] ? T[number]
81
+ : T extends Iterable<infer T1> ? T1
82
+ : any,
83
+ index: number,
84
+ ][];
85
+ function __VLS_getVForSourceType<T>(source: T): [
86
+ item: T[keyof T],
87
+ key: keyof T,
88
+ index: number,
89
+ ][];
90
+ // @ts-ignore
91
+ function __VLS_getSlotParams<T>(slot: T): Parameters<__VLS_PickNotAny<NonNullable<T>, (...args: any[]) => any>>;
92
+ // @ts-ignore
93
+ function __VLS_getSlotParam<T>(slot: T): Parameters<__VLS_PickNotAny<NonNullable<T>, (...args: any[]) => any>>[0];
94
+ function __VLS_asFunctionalDirective<T>(dir: T): T extends import('vue').ObjectDirective
95
+ ? NonNullable<T['created' | 'beforeMount' | 'mounted' | 'beforeUpdate' | 'updated' | 'beforeUnmount' | 'unmounted']>
96
+ : T extends (...args: any) => any
97
+ ? T
98
+ : (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void;
99
+ function __VLS_makeOptional<T>(t: T): { [K in keyof T]?: T[K] };
100
+ function __VLS_asFunctionalComponent<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K):
101
+ T extends new (...args: any) => any
102
+ ? (props: (K extends { $props: infer Props } ? Props : any) & Record<string, unknown>, ctx?: any) => __VLS_Element & {
103
+ __ctx?: {
104
+ attrs?: any;
105
+ slots?: K extends { $slots: infer Slots } ? Slots : any;
106
+ emit?: K extends { $emit: infer Emit } ? Emit : any;
107
+ expose?(exposed: K): void;
108
+ props?: (K extends { $props: infer Props } ? Props : any) & Record<string, unknown>;
109
+ }
110
+ }
111
+ : T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>
112
+ : T extends (...args: any) => any ? T
113
+ : (_: {} & Record<string, unknown>, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {} & Record<string, unknown> } };
114
+ function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): 2 extends Parameters<T>['length'] ? [any] : [];
115
+ function __VLS_asFunctionalElement<T>(tag: T, endTag?: T): (attrs: T & Record<string, unknown>) => void;
116
+ function __VLS_asFunctionalSlot<S>(slot: S): S extends () => infer R ? (props: {}) => R : NonNullable<S>;
117
+ function __VLS_tryAsConstant<const T>(t: T): T;
118
+ }
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "pdyform-vue",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "homepage": "https://github.com/LaoChen1994/pdyform",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/LaoChen1994/pdyform"
15
+ },
16
+ "scripts": {
17
+ "build": "vite build && vue-tsc -p tsconfig.json --declaration --emitDeclarationOnly --outDir dist",
18
+ "dev": "vite",
19
+ "test": "vitest run",
20
+ "lint": "eslint src/**/*.{ts,vue} --no-error-on-unmatched-pattern"
21
+ },
22
+ "dependencies": {
23
+ "clsx": "^2.0.0",
24
+ "lucide-vue-next": "^0.300.0",
25
+ "pdyform": "workspace:*",
26
+ "tailwind-merge": "^2.0.0"
27
+ },
28
+ "peerDependencies": {
29
+ "vue": "^3.5.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^20.0.0",
33
+ "@vitejs/plugin-vue": "^5.0.0",
34
+ "@vue/test-utils": "^2.4.6",
35
+ "@vue/tsconfig": "^0.5.0",
36
+ "jsdom": "^22.1.0",
37
+ "typescript": "^5.0.0",
38
+ "vite": "^5.0.0",
39
+ "vitest": "^1.0.0",
40
+ "vue": "^3.5.0",
41
+ "vue-tsc": "^2.0.0"
42
+ }
43
+ }
@@ -0,0 +1,19 @@
1
+ // @vitest-environment jsdom
2
+ import { describe, it, expect } from 'vitest';
3
+ import { mount } from '@vue/test-utils';
4
+ import DynamicForm from '../src/DynamicForm.vue';
5
+
6
+ describe('Vue DynamicForm', () => {
7
+ const schema: any = {
8
+ fields: [
9
+ { name: 'username', label: 'Username', type: 'text' }
10
+ ]
11
+ };
12
+
13
+ it('renders correctly', () => {
14
+ const wrapper = mount(DynamicForm, {
15
+ props: { schema }
16
+ });
17
+ expect(wrapper.find('label').text()).toBe('Username');
18
+ });
19
+ });
@@ -0,0 +1,81 @@
1
+ <script setup lang="ts">
2
+ import { ref, onMounted } from 'vue';
3
+ import type { FormSchema } from 'pdyform/core';
4
+ import { validateField, getDefaultValues } from 'pdyform/core';
5
+ import FormFieldRenderer from './FormFieldRenderer.vue';
6
+
7
+ const props = defineProps<{
8
+ schema: FormSchema;
9
+ className?: string;
10
+ }>();
11
+
12
+ const emit = defineEmits(['submit']);
13
+
14
+ const values = ref<Record<string, any>>({});
15
+ const errors = ref<Record<string, string>>({});
16
+ const isSubmitting = ref(false);
17
+
18
+ onMounted(() => {
19
+ values.value = getDefaultValues(props.schema.fields);
20
+ });
21
+
22
+ const handleFieldChange = (name: string, value: any) => {
23
+ values.value[name] = value;
24
+
25
+ const field = props.schema.fields.find(f => f.name === name);
26
+ if (field) {
27
+ const error = validateField(value, field);
28
+ errors.value[name] = error || '';
29
+ }
30
+ };
31
+
32
+ const handleSubmit = () => {
33
+ isSubmitting.value = true;
34
+ const newErrors: Record<string, string> = {};
35
+ let hasError = false;
36
+
37
+ props.schema.fields.forEach((field) => {
38
+ const error = validateField(values.value[field.name], field);
39
+ if (error) {
40
+ newErrors[field.name] = error;
41
+ hasError = true;
42
+ }
43
+ });
44
+
45
+ errors.value = newErrors;
46
+
47
+ if (!hasError) {
48
+ emit('submit', { ...values.value });
49
+ }
50
+ isSubmitting.value = false;
51
+ };
52
+ </script>
53
+
54
+ <template>
55
+ <form :class="['space-y-6', className]" @submit.prevent="handleSubmit">
56
+ <div v-if="schema.title || schema.description" class="space-y-1">
57
+ <h2 v-if="schema.title" class="text-2xl font-bold tracking-tight">{{ schema.title }}</h2>
58
+ <p v-if="schema.description" class="text-muted-foreground">{{ schema.description }}</p>
59
+ </div>
60
+
61
+ <div class="space-y-4">
62
+ <template v-for="field in schema.fields" :key="field.id">
63
+ <FormFieldRenderer
64
+ v-if="!field.hidden"
65
+ :field="field"
66
+ :model-value="values[field.name]"
67
+ :error="errors[field.name]"
68
+ @update:model-value="(val: any) => handleFieldChange(field.name, val)"
69
+ />
70
+ </template>
71
+ </div>
72
+
73
+ <button
74
+ type="submit"
75
+ :disabled="isSubmitting"
76
+ class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 w-full"
77
+ >
78
+ {{ isSubmitting ? 'Submitting...' : (schema.submitButtonText || 'Submit') }}
79
+ </button>
80
+ </form>
81
+ </template>
@@ -0,0 +1,114 @@
1
+ <script setup lang="ts">
2
+ import type { FormField } from 'pdyform/core';
3
+ import { computed } from 'vue';
4
+
5
+ const props = defineProps<{
6
+ field: FormField;
7
+ modelValue: any;
8
+ error?: string;
9
+ }>();
10
+
11
+ const emit = defineEmits(['update:modelValue']);
12
+
13
+ const fieldId = computed(() => `field-${props.field.name}`);
14
+
15
+ const baseInputClasses = "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50";
16
+
17
+ const handleUpdate = (val: any) => {
18
+ emit('update:modelValue', val);
19
+ };
20
+
21
+ const handleCheckboxChange = (val: any, checked: boolean) => {
22
+ const current = Array.isArray(props.modelValue) ? [...props.modelValue] : [];
23
+ if (checked) {
24
+ current.push(val);
25
+ } else {
26
+ const idx = current.indexOf(val);
27
+ if (idx > -1) current.splice(idx, 1);
28
+ }
29
+ handleUpdate(current);
30
+ };
31
+ </script>
32
+
33
+ <template>
34
+ <div :class="['space-y-2', field.className]">
35
+ <label v-if="field.label" :for="fieldId" class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
36
+ {{ field.label }}
37
+ </label>
38
+
39
+ <template v-if="field.type === 'textarea'">
40
+ <textarea
41
+ :id="fieldId"
42
+ :class="[baseInputClasses, 'min-h-[80px]']"
43
+ :placeholder="field.placeholder"
44
+ :disabled="field.disabled"
45
+ :name="field.name"
46
+ :value="modelValue"
47
+ @input="(e: any) => handleUpdate(e.target.value)"
48
+ />
49
+ </template>
50
+
51
+ <template v-else-if="field.type === 'select'">
52
+ <select
53
+ :id="fieldId"
54
+ :class="baseInputClasses"
55
+ :disabled="field.disabled"
56
+ :name="field.name"
57
+ :value="modelValue"
58
+ @change="(e: any) => handleUpdate(e.target.value)"
59
+ >
60
+ <option value="" disabled>{{ field.placeholder || 'Select an option' }}</option>
61
+ <option v-for="opt in field.options" :key="opt.value" :value="opt.value">
62
+ {{ opt.label }}
63
+ </option>
64
+ </select>
65
+ </template>
66
+
67
+ <template v-else-if="field.type === 'checkbox'">
68
+ <div class="flex flex-wrap gap-4">
69
+ <label v-for="opt in field.options" :key="opt.value" class="flex items-center space-x-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
70
+ <input
71
+ type="checkbox"
72
+ class="h-4 w-4 rounded border-primary text-primary focus:ring-primary"
73
+ :disabled="field.disabled"
74
+ :checked="Array.isArray(modelValue) && modelValue.includes(opt.value)"
75
+ @change="(e: any) => handleCheckboxChange(opt.value, e.target.checked)"
76
+ />
77
+ <span>{{ opt.label }}</span>
78
+ </label>
79
+ </div>
80
+ </template>
81
+
82
+ <template v-else-if="field.type === 'radio'">
83
+ <div class="flex flex-wrap gap-4">
84
+ <label v-for="opt in field.options" :key="opt.value" class="flex items-center space-x-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
85
+ <input
86
+ type="radio"
87
+ class="h-4 w-4 border-primary text-primary focus:ring-primary"
88
+ :disabled="field.disabled"
89
+ :name="field.name"
90
+ :checked="modelValue === opt.value"
91
+ @change="handleUpdate(opt.value)"
92
+ />
93
+ <span>{{ opt.label }}</span>
94
+ </label>
95
+ </div>
96
+ </template>
97
+
98
+ <template v-else>
99
+ <input
100
+ :id="fieldId"
101
+ :type="field.type"
102
+ :class="baseInputClasses"
103
+ :placeholder="field.placeholder"
104
+ :disabled="field.disabled"
105
+ :name="field.name"
106
+ :value="modelValue"
107
+ @input="(e: any) => handleUpdate(e.target.value)"
108
+ />
109
+ </template>
110
+
111
+ <p v-if="field.description" class="text-sm text-muted-foreground">{{ field.description }}</p>
112
+ <p v-if="error" class="text-sm font-medium text-destructive">{{ error }}</p>
113
+ </div>
114
+ </template>