@btst/plugin-form-builder 1.0.0 → 1.2.0-beta.1

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 (84) hide show
  1. package/dist/api/index.cjs +1 -0
  2. package/dist/api/index.d.cts +1 -1
  3. package/dist/api/index.d.mts +1 -1
  4. package/dist/api/index.d.ts +1 -1
  5. package/dist/api/index.mjs +1 -1
  6. package/dist/api/operations.cjs +64 -4
  7. package/dist/api/operations.mjs +64 -5
  8. package/dist/api/plugin.cjs +8 -0
  9. package/dist/api/plugin.mjs +8 -0
  10. package/dist/api/submissions-csv.cjs +69 -0
  11. package/dist/api/submissions-csv.mjs +64 -0
  12. package/dist/client/components/forms/form-renderer.cjs +31 -2
  13. package/dist/client/components/forms/form-renderer.mjs +31 -2
  14. package/dist/client/components/forms/media-file-field.cjs +48 -0
  15. package/dist/client/components/forms/media-file-field.mjs +46 -0
  16. package/dist/client/components/index.d.cts +4 -2
  17. package/dist/client/components/index.d.mts +4 -2
  18. package/dist/client/components/index.d.ts +4 -2
  19. package/dist/client/components/pages/ai-schema.cjs +120 -0
  20. package/dist/client/components/pages/ai-schema.mjs +118 -0
  21. package/dist/client/components/pages/form-builder-page.internal.cjs +40 -1
  22. package/dist/client/components/pages/form-builder-page.internal.mjs +41 -2
  23. package/dist/client/components/pages/form-list-page.internal.cjs +1 -0
  24. package/dist/client/components/pages/form-list-page.internal.mjs +1 -0
  25. package/dist/client/components/pages/submissions-page.internal.cjs +40 -0
  26. package/dist/client/components/pages/submissions-page.internal.mjs +41 -1
  27. package/dist/client/components/shared/pagination.cjs +19 -0
  28. package/dist/client/components/shared/pagination.mjs +20 -1
  29. package/dist/client/hooks/form-builder-hooks.cjs +4 -0
  30. package/dist/client/hooks/form-builder-hooks.mjs +4 -1
  31. package/dist/client/hooks/index.cjs +1 -0
  32. package/dist/client/hooks/index.d.cts +7 -2
  33. package/dist/client/hooks/index.d.mts +7 -2
  34. package/dist/client/hooks/index.d.ts +7 -2
  35. package/dist/client/hooks/index.mjs +1 -1
  36. package/dist/client/index.d.cts +42 -3
  37. package/dist/client/index.d.mts +42 -3
  38. package/dist/client/index.d.ts +42 -3
  39. package/dist/permissions.cjs +8 -0
  40. package/dist/permissions.d.cts +6 -0
  41. package/dist/permissions.d.mts +6 -0
  42. package/dist/permissions.d.ts +6 -0
  43. package/dist/permissions.mjs +8 -0
  44. package/dist/query-keys.cjs +7 -0
  45. package/dist/query-keys.d.cts +29 -1
  46. package/dist/query-keys.d.mts +29 -1
  47. package/dist/query-keys.d.ts +29 -1
  48. package/dist/query-keys.mjs +7 -0
  49. package/dist/shared/{plugin-form-builder.CSP5HR2O.d.ts → plugin-form-builder.65tLgfcd.d.ts} +46 -29
  50. package/dist/shared/{plugin-form-builder.Bbl9NufB.d.cts → plugin-form-builder.DXdOj9vM.d.cts} +46 -29
  51. package/dist/shared/{plugin-form-builder.lp98rFNl.d.mts → plugin-form-builder.PWs25HN1.d.mts} +46 -29
  52. package/dist/shared/{plugin-form-builder.DWrQ3lRX.d.ts → plugin-form-builder.sdjcoJcH.d.cts} +15 -1
  53. package/dist/shared/{plugin-form-builder.DWrQ3lRX.d.cts → plugin-form-builder.sdjcoJcH.d.mts} +15 -1
  54. package/dist/shared/{plugin-form-builder.DWrQ3lRX.d.mts → plugin-form-builder.sdjcoJcH.d.ts} +15 -1
  55. package/dist/ui/src/components/auto-form/config.cjs +2 -0
  56. package/dist/ui/src/components/auto-form/config.mjs +2 -0
  57. package/dist/ui/src/components/auto-form/fields/file.cjs +68 -0
  58. package/dist/ui/src/components/auto-form/fields/file.mjs +63 -0
  59. package/dist/ui/src/components/auto-form/fields/object.cjs +9 -2
  60. package/dist/ui/src/components/auto-form/fields/object.mjs +9 -2
  61. package/dist/ui/src/components/auto-form/helpers.cjs +9 -0
  62. package/dist/ui/src/components/auto-form/helpers.mjs +9 -0
  63. package/dist/ui/src/components/auto-form/index.cjs +29 -4
  64. package/dist/ui/src/components/auto-form/index.mjs +31 -6
  65. package/dist/ui/src/components/auto-form/stepped-auto-form.cjs +34 -29
  66. package/dist/ui/src/components/auto-form/stepped-auto-form.mjs +35 -30
  67. package/dist/ui/src/components/form-builder/canvas.cjs +9 -0
  68. package/dist/ui/src/components/form-builder/canvas.mjs +9 -0
  69. package/dist/ui/src/components/form-builder/components/index.cjs +12 -0
  70. package/dist/ui/src/components/form-builder/components/index.mjs +12 -1
  71. package/dist/ui/src/components/form-builder/condition-editor.cjs +73 -0
  72. package/dist/ui/src/components/form-builder/condition-editor.mjs +71 -0
  73. package/dist/ui/src/components/form-builder/edit-field-dialog.cjs +6 -2
  74. package/dist/ui/src/components/form-builder/edit-field-dialog.mjs +6 -2
  75. package/dist/ui/src/components/form-builder/index.cjs +6 -1
  76. package/dist/ui/src/components/form-builder/index.mjs +6 -1
  77. package/dist/ui/src/components/form-builder/schema-utils.cjs +2 -0
  78. package/dist/ui/src/components/form-builder/schema-utils.mjs +2 -0
  79. package/dist/ui/src/components/form.mjs +1 -1
  80. package/dist/ui/src/lib/form-visibility.cjs +20 -0
  81. package/dist/ui/src/lib/form-visibility.mjs +18 -0
  82. package/dist/ui/src/lib/schema-converter.cjs +101 -0
  83. package/dist/ui/src/lib/schema-converter.mjs +100 -1
  84. package/package.json +4 -4
@@ -1,3 +1,4 @@
1
+ import AutoFormFile from './fields/file.mjs';
1
2
  import AutoFormCheckbox from './fields/checkbox.mjs';
2
3
  import AutoFormDate from './fields/date.mjs';
3
4
  import AutoFormEnum from './fields/enum.mjs';
@@ -8,6 +9,7 @@ import AutoFormSwitch from './fields/switch.mjs';
8
9
  import AutoFormTextarea from './fields/textarea.mjs';
9
10
 
10
11
  const INPUT_COMPONENTS = {
12
+ file: AutoFormFile,
11
13
  checkbox: AutoFormCheckbox,
12
14
  date: AutoFormDate,
13
15
  select: AutoFormEnum,
@@ -0,0 +1,68 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ const jsxRuntime = require('react/jsx-runtime');
7
+ const React = require('react');
8
+ const reactHookForm = require('react-hook-form');
9
+ const form = require('../../form.cjs');
10
+ const input = require('../../input.cjs');
11
+ const label = require('../common/label.cjs');
12
+ const tooltip = require('../common/tooltip.cjs');
13
+
14
+ const FileUploadStatusContext = React.createContext(() => {
15
+ });
16
+ function AutoFormFile({ field, fieldProps, fieldConfigItem, label: label$1, isRequired }) {
17
+ const [uploading, setUploading] = React.useState(false);
18
+ const [error, setError] = React.useState(null);
19
+ const form$1 = reactHookForm.useFormContext();
20
+ const reportStatus = React.useContext(FileUploadStatusContext);
21
+ React.useEffect(() => () => reportStatus(field.name, null), [field.name, reportStatus]);
22
+ const onUpload = fieldConfigItem.onUpload;
23
+ return /* @__PURE__ */ jsxRuntime.jsxs(form.FormItem, { children: [
24
+ /* @__PURE__ */ jsxRuntime.jsx(label, { label: fieldConfigItem.label || label$1, isRequired }),
25
+ /* @__PURE__ */ jsxRuntime.jsx(form.FormControl, { children: /* @__PURE__ */ jsxRuntime.jsx(
26
+ input.Input,
27
+ {
28
+ type: "file",
29
+ name: field.name,
30
+ onBlur: field.onBlur,
31
+ accept: fieldProps.accept,
32
+ disabled: fieldProps.disabled || uploading || !onUpload,
33
+ required: isRequired && !field.value,
34
+ onChange: async (event) => {
35
+ const input = event.currentTarget;
36
+ const file = input.files?.[0];
37
+ if (!file || !onUpload) return;
38
+ setUploading(true);
39
+ reportStatus(field.name, "uploading");
40
+ setError(null);
41
+ form$1.setError(field.name, { type: "upload", message: "Upload in progress" });
42
+ try {
43
+ const url = await onUpload(file);
44
+ if (typeof url !== "string" || !url.trim()) throw new Error("Upload must return a URL string");
45
+ field.onChange(url);
46
+ form$1.clearErrors(field.name);
47
+ reportStatus(field.name, null);
48
+ } catch (error2) {
49
+ const message = error2 instanceof Error ? error2.message : "Upload failed";
50
+ setError(message);
51
+ reportStatus(field.name, "failed");
52
+ form$1.setError(field.name, { type: "upload", message });
53
+ } finally {
54
+ setUploading(false);
55
+ input.value = "";
56
+ }
57
+ }
58
+ }
59
+ ) }),
60
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", role: "status", children: uploading ? "Uploading\u2026" : !onUpload ? "File uploads are not configured." : field.value ? "File uploaded" : "" }),
61
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-sm text-destructive", children: error }),
62
+ /* @__PURE__ */ jsxRuntime.jsx(tooltip, { fieldConfigItem }),
63
+ /* @__PURE__ */ jsxRuntime.jsx(form.FormMessage, {})
64
+ ] });
65
+ }
66
+
67
+ exports.FileUploadStatusContext = FileUploadStatusContext;
68
+ exports.default = AutoFormFile;
@@ -0,0 +1,63 @@
1
+ 'use client';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { useState, useContext, useEffect, createContext } from 'react';
4
+ import { useFormContext } from 'react-hook-form';
5
+ import { FormItem, FormControl, FormMessage } from '../../form.mjs';
6
+ import { Input } from '../../input.mjs';
7
+ import AutoFormLabel from '../common/label.mjs';
8
+ import AutoFormTooltip from '../common/tooltip.mjs';
9
+
10
+ const FileUploadStatusContext = createContext(() => {
11
+ });
12
+ function AutoFormFile({ field, fieldProps, fieldConfigItem, label, isRequired }) {
13
+ const [uploading, setUploading] = useState(false);
14
+ const [error, setError] = useState(null);
15
+ const form = useFormContext();
16
+ const reportStatus = useContext(FileUploadStatusContext);
17
+ useEffect(() => () => reportStatus(field.name, null), [field.name, reportStatus]);
18
+ const onUpload = fieldConfigItem.onUpload;
19
+ return /* @__PURE__ */ jsxs(FormItem, { children: [
20
+ /* @__PURE__ */ jsx(AutoFormLabel, { label: fieldConfigItem.label || label, isRequired }),
21
+ /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
22
+ Input,
23
+ {
24
+ type: "file",
25
+ name: field.name,
26
+ onBlur: field.onBlur,
27
+ accept: fieldProps.accept,
28
+ disabled: fieldProps.disabled || uploading || !onUpload,
29
+ required: isRequired && !field.value,
30
+ onChange: async (event) => {
31
+ const input = event.currentTarget;
32
+ const file = input.files?.[0];
33
+ if (!file || !onUpload) return;
34
+ setUploading(true);
35
+ reportStatus(field.name, "uploading");
36
+ setError(null);
37
+ form.setError(field.name, { type: "upload", message: "Upload in progress" });
38
+ try {
39
+ const url = await onUpload(file);
40
+ if (typeof url !== "string" || !url.trim()) throw new Error("Upload must return a URL string");
41
+ field.onChange(url);
42
+ form.clearErrors(field.name);
43
+ reportStatus(field.name, null);
44
+ } catch (error2) {
45
+ const message = error2 instanceof Error ? error2.message : "Upload failed";
46
+ setError(message);
47
+ reportStatus(field.name, "failed");
48
+ form.setError(field.name, { type: "upload", message });
49
+ } finally {
50
+ setUploading(false);
51
+ input.value = "";
52
+ }
53
+ }
54
+ }
55
+ ) }),
56
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", role: "status", children: uploading ? "Uploading\u2026" : !onUpload ? "File uploads are not configured." : field.value ? "File uploaded" : "" }),
57
+ error && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm text-destructive", children: error }),
58
+ /* @__PURE__ */ jsx(AutoFormTooltip, { fieldConfigItem }),
59
+ /* @__PURE__ */ jsx(FormMessage, {})
60
+ ] });
61
+ }
62
+
63
+ export { FileUploadStatusContext, AutoFormFile as default };
@@ -1,6 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  const jsxRuntime = require('react/jsx-runtime');
4
+ const schemaConverter = require('../../../lib/schema-converter.cjs');
5
+ const formVisibility = require('../../../lib/form-visibility.cjs');
4
6
  const accordion = require('../../accordion.cjs');
5
7
  const form = require('../../form.cjs');
6
8
  const reactHookForm = require('react-hook-form');
@@ -32,7 +34,8 @@ function AutoFormObject({
32
34
  form: form$1,
33
35
  fieldConfig,
34
36
  path = [],
35
- dependencies: dependencies$1 = []
37
+ dependencies: dependencies$1 = [],
38
+ visibilityValues
36
39
  }) {
37
40
  const { watch } = reactHookForm.useFormContext();
38
41
  if (!schema) {
@@ -56,6 +59,9 @@ function AutoFormObject({
56
59
  return item;
57
60
  };
58
61
  const sortedFieldKeys = helpers.sortFieldsByOrder(fieldConfig, Object.keys(shape));
62
+ const siblingValues = visibilityValues ?? schemaConverter.resolveVisibleSchema({
63
+ properties: Object.fromEntries(Object.keys(shape).map((name) => [name, { showIf: fieldConfig?.[name]?.showIf }]))
64
+ }, path.length ? watch(path.join(".")) ?? {} : watch()).data;
59
65
  return /* @__PURE__ */ jsxRuntime.jsx(accordion.Accordion, { type: "multiple", className: "space-y-5 border-none", children: sortedFieldKeys.map((name) => {
60
66
  let item = shape[name];
61
67
  item = handleIfZodNumber(item);
@@ -68,7 +74,7 @@ function AutoFormObject({
68
74
  isRequired: isRequiredByDependency,
69
75
  overrideOptions
70
76
  } = dependencies(dependencies$1, name, watch);
71
- if (isHidden) {
77
+ if (isHidden || !formVisibility.matchesShowIf(fieldConfig?.[name]?.showIf, siblingValues)) {
72
78
  return null;
73
79
  }
74
80
  if (zodBaseType === "ZodObject") {
@@ -202,6 +208,7 @@ function AutoFormObject({
202
208
  const fieldProps = {
203
209
  ...helpers.zodToHtmlInputProps(item),
204
210
  ...field,
211
+ onChange: zodBaseType === "ZodNumber" && inputType === "number" ? (event) => field.onChange(event.target.value === "" ? void 0 : Number(event.target.value)) : field.onChange,
205
212
  ...safeInputProps,
206
213
  disabled: safeInputProps.disabled || isDisabled,
207
214
  ref: void 0,
@@ -1,4 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { resolveVisibleSchema } from '../../../lib/schema-converter.mjs';
3
+ import { matchesShowIf } from '../../../lib/form-visibility.mjs';
2
4
  import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '../../accordion.mjs';
3
5
  import { FormField } from '../../form.mjs';
4
6
  import { useFormContext } from 'react-hook-form';
@@ -16,7 +18,8 @@ function AutoFormObject({
16
18
  form,
17
19
  fieldConfig,
18
20
  path = [],
19
- dependencies = []
21
+ dependencies = [],
22
+ visibilityValues
20
23
  }) {
21
24
  const { watch } = useFormContext();
22
25
  if (!schema) {
@@ -40,6 +43,9 @@ function AutoFormObject({
40
43
  return item;
41
44
  };
42
45
  const sortedFieldKeys = sortFieldsByOrder(fieldConfig, Object.keys(shape));
46
+ const siblingValues = visibilityValues ?? resolveVisibleSchema({
47
+ properties: Object.fromEntries(Object.keys(shape).map((name) => [name, { showIf: fieldConfig?.[name]?.showIf }]))
48
+ }, path.length ? watch(path.join(".")) ?? {} : watch()).data;
43
49
  return /* @__PURE__ */ jsx(Accordion, { type: "multiple", className: "space-y-5 border-none", children: sortedFieldKeys.map((name) => {
44
50
  let item = shape[name];
45
51
  item = handleIfZodNumber(item);
@@ -52,7 +58,7 @@ function AutoFormObject({
52
58
  isRequired: isRequiredByDependency,
53
59
  overrideOptions
54
60
  } = resolveDependencies(dependencies, name, watch);
55
- if (isHidden) {
61
+ if (isHidden || !matchesShowIf(fieldConfig?.[name]?.showIf, siblingValues)) {
56
62
  return null;
57
63
  }
58
64
  if (zodBaseType === "ZodObject") {
@@ -186,6 +192,7 @@ function AutoFormObject({
186
192
  const fieldProps = {
187
193
  ...zodToHtmlInputProps(item),
188
194
  ...field,
195
+ onChange: zodBaseType === "ZodNumber" && inputType === "number" ? (event) => field.onChange(event.target.value === "" ? void 0 : Number(event.target.value)) : field.onChange,
189
196
  ...safeInputProps,
190
197
  disabled: safeInputProps.disabled || isDisabled,
191
198
  ref: void 0,
@@ -1,9 +1,11 @@
1
1
  'use strict';
2
2
 
3
3
  const jsxRuntime = require('react/jsx-runtime');
4
+ const schemaConverter = require('../../lib/schema-converter.cjs');
4
5
  require('zod');
5
6
 
6
7
  const BUILTIN_FIELD_TYPES = [
8
+ "file",
7
9
  "checkbox",
8
10
  "date",
9
11
  "select",
@@ -24,6 +26,8 @@ function beautifyObjectName(string) {
24
26
  }
25
27
  function getBaseSchema(schema) {
26
28
  if (!schema) return null;
29
+ const display = schemaConverter.getFormDisplaySchema(schema);
30
+ if (display) return display;
27
31
  const def = schema._zod?.def;
28
32
  if (!def) return schema;
29
33
  if (def.innerType) {
@@ -107,6 +111,8 @@ function getDefaultValues(schema, fieldConfig) {
107
111
  }
108
112
  function getObjectFormSchema(schema) {
109
113
  if (!schema) return schema;
114
+ const displaySchema = schemaConverter.getFormDisplaySchema(schema);
115
+ if (displaySchema) return displaySchema;
110
116
  const def = schema._zod?.def;
111
117
  if (!def) return schema;
112
118
  if (def.type === "pipe") {
@@ -176,6 +182,7 @@ function buildFieldConfigFromJsonSchema(jsonSchema, fieldComponents) {
176
182
  if (!properties) return fieldConfig;
177
183
  for (const [key, value] of Object.entries(properties)) {
178
184
  const config = {};
185
+ if (value.showIf) config.showIf = value.showIf;
179
186
  if (value.label) {
180
187
  config.label = value.label;
181
188
  } else if (value.title) {
@@ -218,6 +225,8 @@ function buildFieldConfigFromJsonSchema(jsonSchema, fieldComponents) {
218
225
  "inputProps",
219
226
  "fieldType",
220
227
  "renderParent",
228
+ "showIf",
229
+ "onUpload",
221
230
  "order"
222
231
  ]);
223
232
  if (value.properties) {
@@ -1,7 +1,9 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
+ import { getFormDisplaySchema } from '../../lib/schema-converter.mjs';
2
3
  import 'zod';
3
4
 
4
5
  const BUILTIN_FIELD_TYPES = [
6
+ "file",
5
7
  "checkbox",
6
8
  "date",
7
9
  "select",
@@ -22,6 +24,8 @@ function beautifyObjectName(string) {
22
24
  }
23
25
  function getBaseSchema(schema) {
24
26
  if (!schema) return null;
27
+ const display = getFormDisplaySchema(schema);
28
+ if (display) return display;
25
29
  const def = schema._zod?.def;
26
30
  if (!def) return schema;
27
31
  if (def.innerType) {
@@ -105,6 +109,8 @@ function getDefaultValues(schema, fieldConfig) {
105
109
  }
106
110
  function getObjectFormSchema(schema) {
107
111
  if (!schema) return schema;
112
+ const displaySchema = getFormDisplaySchema(schema);
113
+ if (displaySchema) return displaySchema;
108
114
  const def = schema._zod?.def;
109
115
  if (!def) return schema;
110
116
  if (def.type === "pipe") {
@@ -174,6 +180,7 @@ function buildFieldConfigFromJsonSchema(jsonSchema, fieldComponents) {
174
180
  if (!properties) return fieldConfig;
175
181
  for (const [key, value] of Object.entries(properties)) {
176
182
  const config = {};
183
+ if (value.showIf) config.showIf = value.showIf;
177
184
  if (value.label) {
178
185
  config.label = value.label;
179
186
  } else if (value.title) {
@@ -216,6 +223,8 @@ function buildFieldConfigFromJsonSchema(jsonSchema, fieldComponents) {
216
223
  "inputProps",
217
224
  "fieldType",
218
225
  "renderParent",
226
+ "showIf",
227
+ "onUpload",
219
228
  "order"
220
229
  ]);
221
230
  if (value.properties) {
@@ -5,9 +5,11 @@ const jsxRuntime = require('react/jsx-runtime');
5
5
  const form = require('../form.cjs');
6
6
  const React = require('react');
7
7
  const reactHookForm = require('react-hook-form');
8
+ const schemaConverter = require('../../lib/schema-converter.cjs');
8
9
  require('../button.cjs');
9
10
  const utils = require('../../lib/utils.cjs');
10
11
  const zod = require('@hookform/resolvers/zod');
12
+ const file = require('./fields/file.cjs');
11
13
  const object = require('./fields/object.cjs');
12
14
  const helpers = require('./helpers.cjs');
13
15
 
@@ -34,6 +36,23 @@ function AutoForm({
34
36
  defaultValues: defaultValues ?? void 0,
35
37
  values: valuesProp
36
38
  });
39
+ const [uploadStatuses, setUploadStatuses] = React.useState({});
40
+ const reportUploadStatus = React.useCallback((name, status) => {
41
+ setUploadStatuses((previous) => {
42
+ if (previous[name] === status || !status && !(name in previous)) return previous;
43
+ const next = { ...previous };
44
+ if (status) next[name] = status;
45
+ else Reflect.deleteProperty(next, name);
46
+ return next;
47
+ });
48
+ }, []);
49
+ const uploading = Object.values(uploadStatuses).includes("uploading");
50
+ const uploadBlocked = Object.keys(uploadStatuses).length > 0;
51
+ const watchedValues = reactHookForm.useWatch({ control: form$1.control });
52
+ const metadata = formSchema.meta();
53
+ const visibility = metadata?.properties ? schemaConverter.resolveVisibleSchema(metadata, watchedValues) : void 0;
54
+ const visibleKeys = visibility ? Object.keys(visibility.schema.properties ?? {}) : null;
55
+ const visibleObjectSchema = visibleKeys ? objectFormSchema.pick(Object.fromEntries(visibleKeys.map((key) => [key, true]))) : objectFormSchema;
37
56
  const [schemaSubmitError, setSchemaSubmitError] = React.useState(null);
38
57
  function onSubmit(values) {
39
58
  setSchemaSubmitError(null);
@@ -58,18 +77,24 @@ function AutoForm({
58
77
  return () => subscription.unsubscribe();
59
78
  }, [form$1, formSchema, onValuesChangeProp, onParsedValuesChange]);
60
79
  const renderChildren = typeof children === "function" ? children(form$1.formState) : children;
61
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx(form.Form, { ...form$1, children: /* @__PURE__ */ jsxRuntime.jsxs(
80
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx(form.Form, { ...form$1, children: /* @__PURE__ */ jsxRuntime.jsx(
62
81
  "form",
63
82
  {
64
83
  onSubmit: (e) => {
84
+ if (uploadBlocked) {
85
+ e.preventDefault();
86
+ setSchemaSubmitError(uploading ? "Wait for the upload to finish." : "Retry the failed file upload before submitting.");
87
+ return;
88
+ }
65
89
  form$1.handleSubmit(onSubmit, () => setSchemaSubmitError(null))(e);
66
90
  },
67
91
  className: utils.cn("space-y-5", className),
68
- children: [
92
+ children: /* @__PURE__ */ jsxRuntime.jsx(file.FileUploadStatusContext.Provider, { value: reportUploadStatus, children: /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { disabled: uploading, className: "contents", children: [
69
93
  /* @__PURE__ */ jsxRuntime.jsx(
70
94
  object,
71
95
  {
72
- schema: objectFormSchema,
96
+ schema: visibleObjectSchema,
97
+ visibilityValues: visibility?.data,
73
98
  form: form$1,
74
99
  dependencies,
75
100
  fieldConfig
@@ -84,7 +109,7 @@ function AutoForm({
84
109
  }
85
110
  ) : null,
86
111
  renderChildren
87
- ]
112
+ ] }) })
88
113
  }
89
114
  ) }) });
90
115
  }
@@ -1,11 +1,13 @@
1
1
  'use client';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
  import { Form } from '../form.mjs';
4
- import React__default, { useState } from 'react';
5
- import { useForm } from 'react-hook-form';
4
+ import React__default, { useState, useCallback } from 'react';
5
+ import { useForm, useWatch } from 'react-hook-form';
6
+ import { resolveVisibleSchema } from '../../lib/schema-converter.mjs';
6
7
  import '../button.mjs';
7
8
  import { cn } from '../../lib/utils.mjs';
8
9
  import { zodResolver } from '@hookform/resolvers/zod';
10
+ import { FileUploadStatusContext } from './fields/file.mjs';
9
11
  import AutoFormObject from './fields/object.mjs';
10
12
  import { getObjectFormSchema, getDefaultValues } from './helpers.mjs';
11
13
 
@@ -28,6 +30,23 @@ function AutoForm({
28
30
  defaultValues: defaultValues ?? void 0,
29
31
  values: valuesProp
30
32
  });
33
+ const [uploadStatuses, setUploadStatuses] = useState({});
34
+ const reportUploadStatus = useCallback((name, status) => {
35
+ setUploadStatuses((previous) => {
36
+ if (previous[name] === status || !status && !(name in previous)) return previous;
37
+ const next = { ...previous };
38
+ if (status) next[name] = status;
39
+ else Reflect.deleteProperty(next, name);
40
+ return next;
41
+ });
42
+ }, []);
43
+ const uploading = Object.values(uploadStatuses).includes("uploading");
44
+ const uploadBlocked = Object.keys(uploadStatuses).length > 0;
45
+ const watchedValues = useWatch({ control: form.control });
46
+ const metadata = formSchema.meta();
47
+ const visibility = metadata?.properties ? resolveVisibleSchema(metadata, watchedValues) : void 0;
48
+ const visibleKeys = visibility ? Object.keys(visibility.schema.properties ?? {}) : null;
49
+ const visibleObjectSchema = visibleKeys ? objectFormSchema.pick(Object.fromEntries(visibleKeys.map((key) => [key, true]))) : objectFormSchema;
31
50
  const [schemaSubmitError, setSchemaSubmitError] = useState(null);
32
51
  function onSubmit(values) {
33
52
  setSchemaSubmitError(null);
@@ -52,18 +71,24 @@ function AutoForm({
52
71
  return () => subscription.unsubscribe();
53
72
  }, [form, formSchema, onValuesChangeProp, onParsedValuesChange]);
54
73
  const renderChildren = typeof children === "function" ? children(form.formState) : children;
55
- return /* @__PURE__ */ jsx("div", { className: "w-full", children: /* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsxs(
74
+ return /* @__PURE__ */ jsx("div", { className: "w-full", children: /* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsx(
56
75
  "form",
57
76
  {
58
77
  onSubmit: (e) => {
78
+ if (uploadBlocked) {
79
+ e.preventDefault();
80
+ setSchemaSubmitError(uploading ? "Wait for the upload to finish." : "Retry the failed file upload before submitting.");
81
+ return;
82
+ }
59
83
  form.handleSubmit(onSubmit, () => setSchemaSubmitError(null))(e);
60
84
  },
61
85
  className: cn("space-y-5", className),
62
- children: [
86
+ children: /* @__PURE__ */ jsx(FileUploadStatusContext.Provider, { value: reportUploadStatus, children: /* @__PURE__ */ jsxs("fieldset", { disabled: uploading, className: "contents", children: [
63
87
  /* @__PURE__ */ jsx(
64
88
  AutoFormObject,
65
89
  {
66
- schema: objectFormSchema,
90
+ schema: visibleObjectSchema,
91
+ visibilityValues: visibility?.data,
67
92
  form,
68
93
  dependencies,
69
94
  fieldConfig
@@ -78,7 +103,7 @@ function AutoForm({
78
103
  }
79
104
  ) : null,
80
105
  renderChildren
81
- ]
106
+ ] }) })
82
107
  }
83
108
  ) }) });
84
109
  }
@@ -5,6 +5,9 @@ const jsxRuntime = require('react/jsx-runtime');
5
5
  const React = require('react');
6
6
  const z = require('zod');
7
7
  const index = require('./index.cjs');
8
+ const helpers = require('./helpers.cjs');
9
+ const schemaConverter = require('../../lib/schema-converter.cjs');
10
+ const formVisibility = require('../../lib/form-visibility.cjs');
8
11
  const button = require('../button.cjs');
9
12
  const separator = require('../separator.cjs');
10
13
  const utils = require('../../lib/utils.cjs');
@@ -15,7 +18,7 @@ const React__default = /*#__PURE__*/_interopDefaultCompat(React);
15
18
 
16
19
  function extractStepsFromSchema(schema) {
17
20
  try {
18
- const jsonSchema = schema.toJSONSchema();
21
+ const jsonSchema = schema.meta()?.steps ? schema.meta() : schema.toJSONSchema();
19
22
  if (jsonSchema.steps && Array.isArray(jsonSchema.steps)) {
20
23
  return jsonSchema.steps;
21
24
  }
@@ -26,7 +29,7 @@ function extractStepsFromSchema(schema) {
26
29
  function getFieldStepAssignments(schema) {
27
30
  const assignments = /* @__PURE__ */ new Map();
28
31
  try {
29
- const jsonSchema = schema.toJSONSchema();
32
+ const jsonSchema = schema.meta()?.steps ? schema.meta() : schema.toJSONSchema();
30
33
  const stepGroupMap = jsonSchema.stepGroupMap;
31
34
  if (stepGroupMap) {
32
35
  for (const [fieldName, stepGroup] of Object.entries(stepGroupMap)) {
@@ -60,21 +63,6 @@ function createStepSchema(fullSchema, stepIndex, fieldAssignments) {
60
63
  }
61
64
  return fullSchema.pick(pickObject);
62
65
  }
63
- function getObjectSchema(schema) {
64
- if (schema instanceof z.z.ZodObject) {
65
- return schema;
66
- }
67
- const schemaDef = schema._zod?.def ?? schema._def;
68
- if (schemaDef) {
69
- if (schemaDef.schema) {
70
- return getObjectSchema(schemaDef.schema);
71
- }
72
- if (schemaDef.innerType) {
73
- return getObjectSchema(schemaDef.innerType);
74
- }
75
- }
76
- return null;
77
- }
78
66
  function DefaultStepper({
79
67
  steps,
80
68
  currentStepIndex,
@@ -122,16 +110,25 @@ function SteppedAutoForm({
122
110
  StepperComponent = DefaultStepper,
123
111
  isSubmitting = false
124
112
  }) {
125
- const steps = React.useMemo(() => extractStepsFromSchema(formSchema), [formSchema]);
126
- const hasMultipleSteps = steps.length > 1;
127
- const fieldAssignments = React.useMemo(
113
+ const allSteps = React.useMemo(() => extractStepsFromSchema(formSchema), [formSchema]);
114
+ const hasMultipleSteps = allSteps.length > 1;
115
+ const originalFieldAssignments = React.useMemo(
128
116
  () => getFieldStepAssignments(formSchema),
129
117
  [formSchema]
130
118
  );
131
119
  const [currentStepIndex, setCurrentStepIndex] = React.useState(0);
132
120
  const [accumulatedValues, setAccumulatedValues] = React.useState(
133
- initialValues ?? {}
121
+ () => ({ ...helpers.getDefaultValues(helpers.getObjectFormSchema(formSchema), fieldConfig) ?? {}, ...initialValues ?? {} })
134
122
  );
123
+ const steps = React.useMemo(() => {
124
+ const metadata = formSchema.meta();
125
+ const visibleValues = metadata?.properties ? schemaConverter.resolveVisibleSchema(metadata, accumulatedValues).data : accumulatedValues;
126
+ return allSteps.map((step, originalIndex) => ({ ...step, originalIndex })).filter((step) => formVisibility.matchesShowIf(step.showIf, visibleValues));
127
+ }, [allSteps, accumulatedValues, formSchema]);
128
+ const fieldAssignments = React.useMemo(() => new Map(Array.from(originalFieldAssignments).map(([key, originalIndex]) => [key, steps.findIndex((step) => step.originalIndex === originalIndex)])), [originalFieldAssignments, steps]);
129
+ React.useEffect(() => {
130
+ setCurrentStepIndex((index) => Math.min(index, Math.max(0, steps.length - 1)));
131
+ }, [steps.length]);
135
132
  const [completedSteps, setCompletedSteps] = React.useState(/* @__PURE__ */ new Set());
136
133
  const [schemaErrors, setSchemaErrors] = React.useState(null);
137
134
  const accumulatedValuesRef = React.useRef(accumulatedValues);
@@ -152,13 +149,19 @@ function SteppedAutoForm({
152
149
  setAccumulatedValues(newValues);
153
150
  }
154
151
  }, [initialValues]);
155
- const objectSchema = React.useMemo(() => getObjectSchema(formSchema), [formSchema]);
152
+ const objectSchema = React.useMemo(() => helpers.getObjectFormSchema(formSchema), [formSchema]);
156
153
  const stepSchemas = React.useMemo(() => {
157
154
  if (!hasMultipleSteps || !objectSchema) return [];
158
- return steps.map(
159
- (_, index) => createStepSchema(objectSchema, index, fieldAssignments)
160
- );
161
- }, [hasMultipleSteps, objectSchema, steps, fieldAssignments]);
155
+ const metadata = formSchema.meta();
156
+ if (metadata?.properties) {
157
+ const visible = schemaConverter.resolveVisibleSchema(metadata, accumulatedValues).schema;
158
+ return steps.map((_, index) => {
159
+ const properties = Object.fromEntries(Object.entries(visible.properties ?? {}).filter(([key]) => fieldAssignments.get(key) === index));
160
+ return schemaConverter.formSchemaToZod({ ...visible, properties, required: visible.required?.filter((key) => key in properties), steps: void 0 });
161
+ });
162
+ }
163
+ return steps.map((_, index) => createStepSchema(objectSchema, index, fieldAssignments));
164
+ }, [hasMultipleSteps, objectSchema, steps, fieldAssignments, accumulatedValues, formSchema]);
162
165
  const currentStep = steps[currentStepIndex];
163
166
  const currentStepSchema = stepSchemas[currentStepIndex];
164
167
  const isFirst = currentStepIndex === 0;
@@ -166,14 +169,16 @@ function SteppedAutoForm({
166
169
  const currentStepFieldConfig = React.useMemo(() => {
167
170
  if (!fieldConfig) return void 0;
168
171
  const stepFields = Array.from(fieldAssignments.entries()).filter(([, step]) => step === currentStepIndex).map(([field]) => field);
172
+ const properties = formSchema.meta()?.properties;
169
173
  const filtered = {};
170
174
  for (const field of stepFields) {
171
175
  if (field in fieldConfig) {
172
- filtered[field] = fieldConfig[field];
176
+ const config = fieldConfig[field];
177
+ filtered[field] = properties?.[field]?.showIf ? { ...config, showIf: void 0 } : config;
173
178
  }
174
179
  }
175
180
  return filtered;
176
- }, [fieldConfig, fieldAssignments, currentStepIndex]);
181
+ }, [fieldConfig, fieldAssignments, currentStepIndex, formSchema]);
177
182
  const currentStepValues = React.useMemo(() => {
178
183
  const stepFields = Array.from(fieldAssignments.entries()).filter(([, step]) => step === currentStepIndex).map(([field]) => field);
179
184
  const values = {};
@@ -251,7 +256,7 @@ function SteppedAutoForm({
251
256
  setSchemaErrors(null);
252
257
  }
253
258
  }, [isFirst]);
254
- if (!hasMultipleSteps) {
259
+ if (!hasMultipleSteps || steps.length === 0) {
255
260
  return /* @__PURE__ */ jsxRuntime.jsxs(
256
261
  index,
257
262
  {