shadcn-zod-formkit 1.9.2 → 1.11.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/dist/index.d.mts CHANGED
@@ -71,7 +71,8 @@ declare enum InputTypes {
71
71
  CURRENCY = "currency",
72
72
  KEY_VALUE = "key_value",
73
73
  REPEATER = "repeater",
74
- MULTI_SELECT = "multi_select"
74
+ MULTI_SELECT = "multi_select",
75
+ COMBOBOX = "COMBO_BOX"
75
76
  }
76
77
  declare const inputFieldComp: InputTypes[];
77
78
 
package/dist/index.d.ts CHANGED
@@ -71,7 +71,8 @@ declare enum InputTypes {
71
71
  CURRENCY = "currency",
72
72
  KEY_VALUE = "key_value",
73
73
  REPEATER = "repeater",
74
- MULTI_SELECT = "multi_select"
74
+ MULTI_SELECT = "multi_select",
75
+ COMBOBOX = "COMBO_BOX"
75
76
  }
76
77
  declare const inputFieldComp: InputTypes[];
77
78
 
package/dist/index.mjs CHANGED
@@ -231,9 +231,11 @@ var InputTypes = /* @__PURE__ */ ((InputTypes2) => {
231
231
  InputTypes2["KEY_VALUE"] = "key_value";
232
232
  InputTypes2["REPEATER"] = "repeater";
233
233
  InputTypes2["MULTI_SELECT"] = "multi_select";
234
+ InputTypes2["COMBOBOX"] = "COMBO_BOX";
234
235
  return InputTypes2;
235
236
  })(InputTypes || {});
236
237
  var inputFieldComp = [
238
+ "COMBO_BOX" /* COMBOBOX */,
237
239
  "multi_select" /* MULTI_SELECT */,
238
240
  "repeater" /* REPEATER */,
239
241
  "key_value" /* KEY_VALUE */,
@@ -1949,6 +1951,210 @@ var ColorComp = React3__default.forwardRef(
1949
1951
  ] });
1950
1952
  }
1951
1953
  );
1954
+ function Command({
1955
+ className,
1956
+ ...props
1957
+ }) {
1958
+ return /* @__PURE__ */ jsx(
1959
+ Command$1,
1960
+ {
1961
+ "data-slot": "command",
1962
+ className: cn(
1963
+ "bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
1964
+ className
1965
+ ),
1966
+ ...props
1967
+ }
1968
+ );
1969
+ }
1970
+ function CommandInput({
1971
+ className,
1972
+ ...props
1973
+ }) {
1974
+ return /* @__PURE__ */ jsxs(
1975
+ "div",
1976
+ {
1977
+ "data-slot": "command-input-wrapper",
1978
+ className: "flex h-9 items-center gap-2 border-b px-3",
1979
+ children: [
1980
+ /* @__PURE__ */ jsx(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
1981
+ /* @__PURE__ */ jsx(
1982
+ Command$1.Input,
1983
+ {
1984
+ "data-slot": "command-input",
1985
+ className: cn(
1986
+ "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",
1987
+ className
1988
+ ),
1989
+ ...props
1990
+ }
1991
+ )
1992
+ ]
1993
+ }
1994
+ );
1995
+ }
1996
+ function CommandList({
1997
+ className,
1998
+ ...props
1999
+ }) {
2000
+ return /* @__PURE__ */ jsx(
2001
+ Command$1.List,
2002
+ {
2003
+ "data-slot": "command-list",
2004
+ className: cn(
2005
+ "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
2006
+ className
2007
+ ),
2008
+ ...props
2009
+ }
2010
+ );
2011
+ }
2012
+ function CommandEmpty({
2013
+ ...props
2014
+ }) {
2015
+ return /* @__PURE__ */ jsx(
2016
+ Command$1.Empty,
2017
+ {
2018
+ "data-slot": "command-empty",
2019
+ className: "py-6 text-center text-sm",
2020
+ ...props
2021
+ }
2022
+ );
2023
+ }
2024
+ function CommandGroup({
2025
+ className,
2026
+ ...props
2027
+ }) {
2028
+ return /* @__PURE__ */ jsx(
2029
+ Command$1.Group,
2030
+ {
2031
+ "data-slot": "command-group",
2032
+ className: cn(
2033
+ "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",
2034
+ className
2035
+ ),
2036
+ ...props
2037
+ }
2038
+ );
2039
+ }
2040
+ function CommandItem({
2041
+ className,
2042
+ ...props
2043
+ }) {
2044
+ return /* @__PURE__ */ jsx(
2045
+ Command$1.Item,
2046
+ {
2047
+ "data-slot": "command-item",
2048
+ className: cn(
2049
+ "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",
2050
+ className
2051
+ ),
2052
+ ...props
2053
+ }
2054
+ );
2055
+ }
2056
+ var ComboboxInput = class extends BaseInput {
2057
+ render() {
2058
+ const { input, form, isSubmitting } = this;
2059
+ return /* @__PURE__ */ jsx(FieldCombobox, { input, form, isSubmitting });
2060
+ }
2061
+ };
2062
+ var FieldCombobox = ({ form, input, isSubmitting }) => {
2063
+ const [open, setOpen] = React3.useState(false);
2064
+ const [options, setOptions] = React3.useState(
2065
+ () => input.listConfig?.list?.length ? input.listConfig.list : []
2066
+ );
2067
+ const optionValue = input?.listConfig?.optionValue ?? input.optionValue ?? "id";
2068
+ const [value, setValue] = React3.useState(input.value?.toString() ?? "");
2069
+ React3.useEffect(() => {
2070
+ const dependsOn = input.dependsOn;
2071
+ if (!dependsOn || !input.loadOptions) return;
2072
+ const subscription = form.watch(async (values) => {
2073
+ const parentValue = values[dependsOn];
2074
+ if (parentValue) {
2075
+ const loader = input.loadOptions;
2076
+ const newOptions = await loader(parentValue);
2077
+ setOptions(newOptions);
2078
+ form.setValue(input.name, "");
2079
+ setValue("");
2080
+ } else {
2081
+ setOptions([]);
2082
+ }
2083
+ });
2084
+ return () => subscription.unsubscribe?.();
2085
+ }, [form, input.loadOptions, input.dependsOn]);
2086
+ React3.useEffect(() => {
2087
+ const currentValue = form.getValues(input.name);
2088
+ if (!currentValue && input.value) {
2089
+ form.setValue(input.name, input.value);
2090
+ setValue(input.value.toString());
2091
+ }
2092
+ }, [form, input.name, input.value]);
2093
+ const getValue = (item) => (optionValue === "name" ? item.name : item.value?.toString() ?? item.id?.toString()) ?? "";
2094
+ const selectedOption = options.find((o) => getValue(o) === value);
2095
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
2096
+ input.label && /* @__PURE__ */ jsx("label", { className: "font-medium text-sm", children: input.label }),
2097
+ /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
2098
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
2099
+ Button,
2100
+ {
2101
+ disabled: input.disabled || isSubmitting,
2102
+ variant: "outline",
2103
+ role: "combobox",
2104
+ "aria-expanded": open,
2105
+ className: "w-[60%] justify-between bg-black/10 dark:bg-white/25",
2106
+ children: [
2107
+ selectedOption ? selectedOption.name : input.placeHolder ?? "Seleccionar...",
2108
+ /* @__PURE__ */ jsx(ChevronsUpDown, { className: "opacity-50" })
2109
+ ]
2110
+ }
2111
+ ) }),
2112
+ /* @__PURE__ */ jsx(PopoverContent, { className: "w-[60%] p-0", children: /* @__PURE__ */ jsxs(
2113
+ Command,
2114
+ {
2115
+ filter: (value2, search) => {
2116
+ const option = options.find((o) => getValue(o) === value2);
2117
+ return option?.name?.toLowerCase().includes(search.toLowerCase()) ? 1 : 0;
2118
+ },
2119
+ children: [
2120
+ /* @__PURE__ */ jsx(CommandInput, { placeholder: `Buscar ${input.label?.toLowerCase()}...`, className: "h-9" }),
2121
+ /* @__PURE__ */ jsxs(CommandList, { children: [
2122
+ /* @__PURE__ */ jsx(CommandEmpty, { children: "No se encontraron resultados." }),
2123
+ /* @__PURE__ */ jsx(CommandGroup, { children: options.map((item) => /* @__PURE__ */ jsxs(
2124
+ CommandItem,
2125
+ {
2126
+ value: getValue(item),
2127
+ onSelect: (currentValue) => {
2128
+ const newValue = currentValue === value ? "" : currentValue;
2129
+ setValue(newValue);
2130
+ form.setValue(input.name, newValue);
2131
+ input.listConfig?.onOptionChange?.(
2132
+ options.find((o) => getValue(o) === newValue)
2133
+ );
2134
+ setOpen(false);
2135
+ },
2136
+ children: [
2137
+ item.name,
2138
+ /* @__PURE__ */ jsx(
2139
+ Check,
2140
+ {
2141
+ className: cn(
2142
+ "ml-auto",
2143
+ value === getValue(item) ? "opacity-100" : "opacity-0"
2144
+ )
2145
+ }
2146
+ )
2147
+ ]
2148
+ },
2149
+ item.id
2150
+ )) })
2151
+ ] })
2152
+ ]
2153
+ }
2154
+ ) })
2155
+ ] })
2156
+ ] });
2157
+ };
1952
2158
  var CurrencyInput = class extends BaseInput {
1953
2159
  render() {
1954
2160
  const { input, form, isSubmitting } = this;
@@ -4010,108 +4216,6 @@ var FieldKeyValueList = ({ form, input, isSubmitting }) => {
4010
4216
  }
4011
4217
  );
4012
4218
  };
4013
- function Command({
4014
- className,
4015
- ...props
4016
- }) {
4017
- return /* @__PURE__ */ jsx(
4018
- Command$1,
4019
- {
4020
- "data-slot": "command",
4021
- className: cn(
4022
- "bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
4023
- className
4024
- ),
4025
- ...props
4026
- }
4027
- );
4028
- }
4029
- function CommandInput({
4030
- className,
4031
- ...props
4032
- }) {
4033
- return /* @__PURE__ */ jsxs(
4034
- "div",
4035
- {
4036
- "data-slot": "command-input-wrapper",
4037
- className: "flex h-9 items-center gap-2 border-b px-3",
4038
- children: [
4039
- /* @__PURE__ */ jsx(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
4040
- /* @__PURE__ */ jsx(
4041
- Command$1.Input,
4042
- {
4043
- "data-slot": "command-input",
4044
- className: cn(
4045
- "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",
4046
- className
4047
- ),
4048
- ...props
4049
- }
4050
- )
4051
- ]
4052
- }
4053
- );
4054
- }
4055
- function CommandList({
4056
- className,
4057
- ...props
4058
- }) {
4059
- return /* @__PURE__ */ jsx(
4060
- Command$1.List,
4061
- {
4062
- "data-slot": "command-list",
4063
- className: cn(
4064
- "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
4065
- className
4066
- ),
4067
- ...props
4068
- }
4069
- );
4070
- }
4071
- function CommandEmpty({
4072
- ...props
4073
- }) {
4074
- return /* @__PURE__ */ jsx(
4075
- Command$1.Empty,
4076
- {
4077
- "data-slot": "command-empty",
4078
- className: "py-6 text-center text-sm",
4079
- ...props
4080
- }
4081
- );
4082
- }
4083
- function CommandGroup({
4084
- className,
4085
- ...props
4086
- }) {
4087
- return /* @__PURE__ */ jsx(
4088
- Command$1.Group,
4089
- {
4090
- "data-slot": "command-group",
4091
- className: cn(
4092
- "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",
4093
- className
4094
- ),
4095
- ...props
4096
- }
4097
- );
4098
- }
4099
- function CommandItem({
4100
- className,
4101
- ...props
4102
- }) {
4103
- return /* @__PURE__ */ jsx(
4104
- Command$1.Item,
4105
- {
4106
- "data-slot": "command-item",
4107
- className: cn(
4108
- "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",
4109
- className
4110
- ),
4111
- ...props
4112
- }
4113
- );
4114
- }
4115
4219
  var MultiSelectInput = class extends BaseInput {
4116
4220
  render() {
4117
4221
  const { input, form, isSubmitting } = this;
@@ -4487,11 +4591,12 @@ var FieldSelect = ({ form, input, isSubmitting }) => {
4487
4591
  { value: 3, id: 3, name: "MOCK OPTION - PERMISO 3" },
4488
4592
  { value: 4, id: 4, name: "MOCK OPTION - PERMISO 4" }
4489
4593
  ];
4490
- const lista = input?.listConfig?.list?.every((item) => "name" in item) ? input.listConfig.list : mockInputOptions;
4491
- const optionValue = input?.listConfig?.optionValue ?? input.optionValue ?? "id";
4492
- const [value, setValue] = useState(
4493
- input.value?.toString() ?? ""
4594
+ const [lista, setLista] = useState(
4595
+ input?.listConfig?.list?.every((item) => "name" in item) ? input.listConfig.list : mockInputOptions
4494
4596
  );
4597
+ const [loading, setLoading] = useState(false);
4598
+ const [value, setValue] = useState(input.value?.toString() ?? "");
4599
+ const optionValue = input?.listConfig?.optionValue ?? input.optionValue ?? "id";
4495
4600
  useEffect(() => {
4496
4601
  const currentValue = form.getValues(input.name);
4497
4602
  if (!currentValue && input.value) {
@@ -4499,8 +4604,32 @@ var FieldSelect = ({ form, input, isSubmitting }) => {
4499
4604
  setValue(input.value.toString());
4500
4605
  }
4501
4606
  }, [form, input.name, input.value]);
4607
+ useEffect(() => {
4608
+ if (input.dependsOn && input.loadOptions) {
4609
+ const subscription = form.watch(async (values) => {
4610
+ const dependencyValue = values[input.dependsOn];
4611
+ if (dependencyValue) {
4612
+ try {
4613
+ setLoading(true);
4614
+ const newOptions = await input.loadOptions(dependencyValue);
4615
+ setLista(newOptions);
4616
+ } catch (err) {
4617
+ console.error(`Error loading options for ${input.name}:`, err);
4618
+ setLista([]);
4619
+ } finally {
4620
+ setLoading(false);
4621
+ }
4622
+ } else {
4623
+ setLista([]);
4624
+ form.setValue(input.name, "");
4625
+ }
4626
+ });
4627
+ return () => subscription.unsubscribe?.();
4628
+ }
4629
+ }, [form, input.dependsOn, input.loadOptions, input.name]);
4502
4630
  const getValue = (item) => {
4503
- return (optionValue === "name" ? item.name.toString() : item.value.toString() ?? item.id).toString();
4631
+ const val = optionValue === "name" ? item.name : item.value?.toString?.() ?? item.id?.toString();
4632
+ return val?.toString() ?? "";
4504
4633
  };
4505
4634
  return /* @__PURE__ */ jsx(
4506
4635
  FormField,
@@ -4518,15 +4647,29 @@ var FieldSelect = ({ form, input, isSubmitting }) => {
4518
4647
  /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsxs(
4519
4648
  Select,
4520
4649
  {
4521
- disabled: input.disabled || isSubmitting,
4650
+ disabled: input.disabled || isSubmitting || loading,
4522
4651
  onValueChange: (val) => {
4523
4652
  field.onChange(val);
4524
4653
  setValue(val);
4654
+ if (input.listConfig?.onOptionChange) {
4655
+ const selectedItem = lista.find(
4656
+ (item) => getValue(item) === val
4657
+ );
4658
+ input.listConfig.onOptionChange(selectedItem);
4659
+ }
4525
4660
  },
4526
4661
  value: currentValue || void 0,
4527
4662
  children: [
4528
- /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(SelectTrigger, { className: "w-[60%] bg-black/10 dark:bg-white/25", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: input.placeHolder }) }) }),
4529
- /* @__PURE__ */ jsx(SelectContent, { children: lista.map((item) => /* @__PURE__ */ jsx(SelectItem, { value: getValue(item), children: item.name }, item.id)) })
4663
+ /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(SelectTrigger, { className: "w-[60%] bg-black/10 dark:bg-white/25", children: /* @__PURE__ */ jsx(
4664
+ SelectValue,
4665
+ {
4666
+ placeholder: loading ? "Cargando..." : input.placeHolder ?? "Seleccionar"
4667
+ }
4668
+ ) }) }),
4669
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
4670
+ lista.map((item) => /* @__PURE__ */ jsx(SelectItem, { value: getValue(item), children: item.name }, item.id)),
4671
+ lista.length === 0 && !loading && /* @__PURE__ */ jsx("div", { className: "p-2 text-sm text-muted-foreground", children: "No hay opciones disponibles" })
4672
+ ] })
4530
4673
  ]
4531
4674
  }
4532
4675
  ) })
@@ -5015,6 +5158,7 @@ var inputMap = {
5015
5158
  ["key_value" /* KEY_VALUE */]: KeyValueListInput,
5016
5159
  ["repeater" /* REPEATER */]: RepeaterInput,
5017
5160
  ["multi_select" /* MULTI_SELECT */]: MultiSelectInput,
5161
+ ["COMBO_BOX" /* COMBOBOX */]: ComboboxInput,
5018
5162
  //ToDos: ============================================================
5019
5163
  ["slider" /* SLIDER */]: SliderInput,
5020
5164
  //ToDo: // PENDIENTE ... VISUALMENTE NO SE VE BIEN.!!!