shadcn-zod-formkit 1.6.0 → 1.8.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.
package/README.md CHANGED
@@ -26,7 +26,7 @@ yarn add shadcn-zod-formkit
26
26
  You need installa shadcn basic components
27
27
  ```typescript
28
28
  # Add Shadcn Basics
29
- npx shadcn@latest add accordion alert badge button calendar card checkbox dialog popover form input label select sonner tooltip switch textarea input-otp collapsible input-group radio-group slider button-group
29
+ npx shadcn@latest add accordion alert badge button calendar card checkbox dialog popover form input label select sonner tooltip switch textarea input-otp collapsible input-group radio-group slider button-group command
30
30
  ```
31
31
 
32
32
 
@@ -116,7 +116,9 @@ const mockFields: Array<FieldProps |FieldProps[]> = [
116
116
  | **Upload Multi File** | `InputTypes.FILE_MULTI_UPLOAD` |
117
117
  | **Button Group** | `InputTypes.BUTTON_GROUP` |
118
118
  | **Input Currency** | `InputTypes.CURRENCY` |
119
- | **Input Key Value** | `InputTypes.KEY_VALUE` |
119
+ | **Input Key Value** | `InputTypes.KEY_VALUE` |
120
+ | **Input Repeater** | `InputTypes.REPEATER` |
121
+ | **Input Multi Select** | `InputTypes.MULTI_SELECT` |
120
122
 
121
123
 
122
124
 
package/dist/index.cjs CHANGED
@@ -26,6 +26,7 @@ var nextThemes = require('next-themes');
26
26
  var sonner = require('sonner');
27
27
  var SwitchPrimitive = require('@radix-ui/react-switch');
28
28
  var TooltipPrimitive = require('@radix-ui/react-tooltip');
29
+ var cmdk = require('cmdk');
29
30
  var SliderPrimitive = require('@radix-ui/react-slider');
30
31
  var z2 = require('zod');
31
32
  var zod = require('@hookform/resolvers/zod');
@@ -266,9 +267,11 @@ var InputTypes = /* @__PURE__ */ ((InputTypes2) => {
266
267
  InputTypes2["CURRENCY"] = "currency";
267
268
  InputTypes2["KEY_VALUE"] = "key_value";
268
269
  InputTypes2["REPEATER"] = "repeater";
270
+ InputTypes2["MULTI_SELECT"] = "multi_select";
269
271
  return InputTypes2;
270
272
  })(InputTypes || {});
271
273
  var inputFieldComp = [
274
+ "multi_select" /* MULTI_SELECT */,
272
275
  "repeater" /* REPEATER */,
273
276
  "key_value" /* KEY_VALUE */,
274
277
  "currency" /* CURRENCY */,
@@ -4044,6 +4047,201 @@ var FieldKeyValueList = ({ form, input, isSubmitting }) => {
4044
4047
  }
4045
4048
  );
4046
4049
  };
4050
+ function Command({
4051
+ className,
4052
+ ...props
4053
+ }) {
4054
+ return /* @__PURE__ */ jsxRuntime.jsx(
4055
+ cmdk.Command,
4056
+ {
4057
+ "data-slot": "command",
4058
+ className: cn(
4059
+ "bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
4060
+ className
4061
+ ),
4062
+ ...props
4063
+ }
4064
+ );
4065
+ }
4066
+ function CommandInput({
4067
+ className,
4068
+ ...props
4069
+ }) {
4070
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4071
+ "div",
4072
+ {
4073
+ "data-slot": "command-input-wrapper",
4074
+ className: "flex h-9 items-center gap-2 border-b px-3",
4075
+ children: [
4076
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
4077
+ /* @__PURE__ */ jsxRuntime.jsx(
4078
+ cmdk.Command.Input,
4079
+ {
4080
+ "data-slot": "command-input",
4081
+ className: cn(
4082
+ "placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
4083
+ className
4084
+ ),
4085
+ ...props
4086
+ }
4087
+ )
4088
+ ]
4089
+ }
4090
+ );
4091
+ }
4092
+ function CommandList({
4093
+ className,
4094
+ ...props
4095
+ }) {
4096
+ return /* @__PURE__ */ jsxRuntime.jsx(
4097
+ cmdk.Command.List,
4098
+ {
4099
+ "data-slot": "command-list",
4100
+ className: cn(
4101
+ "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
4102
+ className
4103
+ ),
4104
+ ...props
4105
+ }
4106
+ );
4107
+ }
4108
+ function CommandEmpty({
4109
+ ...props
4110
+ }) {
4111
+ return /* @__PURE__ */ jsxRuntime.jsx(
4112
+ cmdk.Command.Empty,
4113
+ {
4114
+ "data-slot": "command-empty",
4115
+ className: "py-6 text-center text-sm",
4116
+ ...props
4117
+ }
4118
+ );
4119
+ }
4120
+ function CommandGroup({
4121
+ className,
4122
+ ...props
4123
+ }) {
4124
+ return /* @__PURE__ */ jsxRuntime.jsx(
4125
+ cmdk.Command.Group,
4126
+ {
4127
+ "data-slot": "command-group",
4128
+ className: cn(
4129
+ "text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium",
4130
+ className
4131
+ ),
4132
+ ...props
4133
+ }
4134
+ );
4135
+ }
4136
+ function CommandItem({
4137
+ className,
4138
+ ...props
4139
+ }) {
4140
+ return /* @__PURE__ */ jsxRuntime.jsx(
4141
+ cmdk.Command.Item,
4142
+ {
4143
+ "data-slot": "command-item",
4144
+ className: cn(
4145
+ "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
4146
+ className
4147
+ ),
4148
+ ...props
4149
+ }
4150
+ );
4151
+ }
4152
+ var MultiSelectInput = class extends BaseInput {
4153
+ render() {
4154
+ const { input, form, isSubmitting } = this;
4155
+ return /* @__PURE__ */ jsxRuntime.jsx(FieldMultiSelect, { input, form, isSubmitting });
4156
+ }
4157
+ };
4158
+ var FieldMultiSelect = ({ form, input, isSubmitting }) => {
4159
+ const mockInputOptions = [
4160
+ { id: 1, name: "PERMISO 1" },
4161
+ { id: 2, name: "PERMISO 2" },
4162
+ { id: 3, name: "PERMISO 3" },
4163
+ { id: 4, name: "PERMISO 4" }
4164
+ ];
4165
+ const lista = input?.listConfig?.list ?? mockInputOptions;
4166
+ const optionValue = input?.listConfig?.optionValue ?? input.optionValue ?? "id";
4167
+ const getValue = (item) => {
4168
+ if (optionValue === "name") return item[optionValue];
4169
+ return item.value ?? item.id;
4170
+ };
4171
+ const [open, setOpen] = React3.useState(false);
4172
+ return /* @__PURE__ */ jsxRuntime.jsx(
4173
+ FormField,
4174
+ {
4175
+ control: form.control,
4176
+ name: input.name,
4177
+ render: ({ field }) => {
4178
+ const selectedValues = Array.isArray(field.value) ? field.value : [];
4179
+ const toggleOption = (value) => {
4180
+ const newValues = selectedValues.includes(value) ? selectedValues.filter((v) => v !== value) : [...selectedValues, value];
4181
+ field.onChange(newValues);
4182
+ };
4183
+ return /* @__PURE__ */ jsxRuntime.jsxs(FormItem, { className: "flex flex-col rounded-lg border p-3 shadow bg-blue-100/20", children: [
4184
+ /* @__PURE__ */ jsxRuntime.jsx(FormLabel, { children: /* @__PURE__ */ jsxRuntime.jsx("b", { children: input.label }) }),
4185
+ input.description && /* @__PURE__ */ jsxRuntime.jsx(FormDescription, { children: input.description }),
4186
+ /* @__PURE__ */ jsxRuntime.jsx(FormControl, { children: /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
4187
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
4188
+ Button,
4189
+ {
4190
+ variant: "outline",
4191
+ role: "combobox",
4192
+ disabled: input.disabled || isSubmitting,
4193
+ className: cn(
4194
+ "justify-between w-full bg-black/10 dark:bg-white/10",
4195
+ !selectedValues.length && "text-muted-foreground"
4196
+ ),
4197
+ children: [
4198
+ selectedValues.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: selectedValues.map((val) => {
4199
+ const option = lista.find(
4200
+ (item) => getValue(item).toString() === val
4201
+ );
4202
+ return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "secondary", children: option?.name ?? val }, val);
4203
+ }) }) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: input.placeHolder ?? "Selecciona..." }),
4204
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: "ml-2 h-4 w-4 opacity-50" })
4205
+ ]
4206
+ }
4207
+ ) }),
4208
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "p-0 w-[var(--radix-popover-trigger-width)]", children: /* @__PURE__ */ jsxRuntime.jsxs(Command, { children: [
4209
+ /* @__PURE__ */ jsxRuntime.jsx(CommandInput, { placeholder: "Buscar..." }),
4210
+ /* @__PURE__ */ jsxRuntime.jsxs(CommandList, { children: [
4211
+ /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { children: "No hay resultados." }),
4212
+ /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { children: lista.map((item) => {
4213
+ const value = getValue(item).toString();
4214
+ const selected = selectedValues.includes(value);
4215
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4216
+ CommandItem,
4217
+ {
4218
+ onSelect: () => toggleOption(value),
4219
+ children: [
4220
+ /* @__PURE__ */ jsxRuntime.jsx(
4221
+ lucideReact.Check,
4222
+ {
4223
+ className: cn(
4224
+ "mr-2 h-4 w-4",
4225
+ selected ? "opacity-100" : "opacity-0"
4226
+ )
4227
+ }
4228
+ ),
4229
+ item.name
4230
+ ]
4231
+ },
4232
+ value
4233
+ );
4234
+ }) })
4235
+ ] })
4236
+ ] }) })
4237
+ ] }) }),
4238
+ /* @__PURE__ */ jsxRuntime.jsx(FormMessage, {})
4239
+ ] });
4240
+ }
4241
+ },
4242
+ input.name
4243
+ );
4244
+ };
4047
4245
  var TextInputGroup = class extends BaseInput {
4048
4246
  render() {
4049
4247
  const { input, form, isSubmitting } = this;
@@ -4841,6 +5039,7 @@ var inputMap = {
4841
5039
  ["currency" /* CURRENCY */]: CurrencyInput,
4842
5040
  ["key_value" /* KEY_VALUE */]: KeyValueListInput,
4843
5041
  ["repeater" /* REPEATER */]: RepeaterInput,
5042
+ ["multi_select" /* MULTI_SELECT */]: MultiSelectInput,
4844
5043
  //ToDos: ============================================================
4845
5044
  ["slider" /* SLIDER */]: SliderInput,
4846
5045
  //ToDo: // PENDIENTE ... VISUALMENTE NO SE VE BIEN.!!!
@@ -4932,15 +5131,19 @@ var getFieldLabel = (fieldErrorKey, fields) => {
4932
5131
  const findedField = fields.find((field) => field.name == fieldErrorKey);
4933
5132
  return findedField?.label ?? fieldErrorKey;
4934
5133
  };
4935
- var FormFieldsGrid = ({ fields, form, isPending, className = "", gap = "gap-2" }) => {
5134
+ var FormFieldsGrid = ({ fields, form, isPending, readOnly, className = "", gap = "gap-2" }) => {
4936
5135
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fields.map(
4937
- (input, idx) => Array.isArray(input) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-full flex flex-row justify-between py-3", children: input.map((field, subIdx) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full px-2", children: InputFactory.create(field, form, isPending) }, subIdx)) }, `field-group-${idx}`) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-col justify-between py-3 w-full px-2", children: InputFactory.create(input, form, isPending) }, `field-group-${idx}`)
5136
+ (input, idx) => Array.isArray(input) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-full flex flex-row justify-between py-3", children: input.map((field, subIdx) => {
5137
+ if (readOnly) field.disabled = readOnly;
5138
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full px-2", children: InputFactory.create(field, form, isPending) }, subIdx);
5139
+ }) }, `field-group-${idx}`) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-col justify-between py-3 w-full px-2", children: InputFactory.create(input, form, isPending) }, `field-group-${idx}`)
4938
5140
  ) });
4939
5141
  };
4940
5142
  var DynamicForm = ({
4941
5143
  formTitle,
4942
5144
  formSubTitle,
4943
5145
  fields,
5146
+ readOnly = false,
4944
5147
  record = {},
4945
5148
  onSubmit,
4946
5149
  extraValidations,
@@ -4948,7 +5151,7 @@ var DynamicForm = ({
4948
5151
  errorAlertPosition = "up",
4949
5152
  withCard = false,
4950
5153
  submitBtnClass = "",
4951
- submitBtnLabel = "Submit"
5154
+ submitBtnLabel = "Guardar"
4952
5155
  }) => {
4953
5156
  const [isPending, startTransition] = React3.useTransition();
4954
5157
  const schema = React3.useMemo(() => getDynamicSchema(fields, extraValidations), [fields, extraValidations]);
@@ -4961,6 +5164,7 @@ var DynamicForm = ({
4961
5164
  form.reset(defaultValues);
4962
5165
  }, [defaultValues, form]);
4963
5166
  const handleSubmit = (data) => {
5167
+ if (readOnly) return;
4964
5168
  try {
4965
5169
  startTransition(async () => {
4966
5170
  const resp = { data, form };
@@ -4972,20 +5176,30 @@ var DynamicForm = ({
4972
5176
  };
4973
5177
  const formContent = /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4974
5178
  /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "flex items-center gap-2 p-2 border-b", children: [
4975
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { className: "h-5 w-5" }),
4976
- formTitle
5179
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-5 w-5" }),
5180
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
5181
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: formTitle }),
5182
+ formSubTitle && /* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: formSubTitle })
5183
+ ] })
4977
5184
  ] }),
4978
5185
  withErrorsAlert && errorAlertPosition === "up" && /* @__PURE__ */ jsxRuntime.jsx(FormErrorsAlert, { formState: form.formState, fields }),
4979
- /* @__PURE__ */ jsxRuntime.jsx(Form, { ...form, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: form.handleSubmit(handleSubmit), className: "flex flex-col gap-2", children: [
4980
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full grid grid-cols-1", children: /* @__PURE__ */ jsxRuntime.jsx(FormFieldsGrid, { fields, form }) }),
4981
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-row gap-2 justify-end items-end", children: /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", size: "lg", className: submitBtnClass, disabled: isPending, children: isPending ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4982
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 mr-2 animate-spin" }),
4983
- submitBtnLabel ?? "Saving..."
4984
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4985
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Save, { className: "h-4 w-4 mr-2" }),
4986
- submitBtnLabel ?? "Save"
4987
- ] }) }) })
4988
- ] }) }),
5186
+ /* @__PURE__ */ jsxRuntime.jsx(Form, { ...form, children: /* @__PURE__ */ jsxRuntime.jsxs(
5187
+ "form",
5188
+ {
5189
+ onSubmit: form.handleSubmit(handleSubmit),
5190
+ className: `flex flex-col gap-2 ${readOnly ? "opacity-70 pointer-events-none select-none" : ""}`,
5191
+ children: [
5192
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full grid grid-cols-1", children: /* @__PURE__ */ jsxRuntime.jsx(FormFieldsGrid, { fields, form, readOnly }) }),
5193
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-row gap-2 justify-end items-end", children: /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", size: "lg", className: submitBtnClass, disabled: isPending, children: isPending ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5194
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 mr-2 animate-spin" }),
5195
+ "Guardando..."
5196
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5197
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Save, { className: "h-4 w-4 mr-2" }),
5198
+ submitBtnLabel
5199
+ ] }) }) })
5200
+ ]
5201
+ }
5202
+ ) }),
4989
5203
  withErrorsAlert && errorAlertPosition === "down" && /* @__PURE__ */ jsxRuntime.jsx(FormErrorsAlert, { formState: form.formState, fields })
4990
5204
  ] });
4991
5205
  if (!withCard) return formContent;