@invana/forms 0.0.30 → 0.0.32

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.js CHANGED
@@ -1,6 +1,6 @@
1
- import { cn, Accordion, AccordionItem, AccordionTrigger, Badge, AccordionContent, Card, CardContent, Separator, Button } from '@invana/ui';
2
1
  import * as React2 from 'react';
3
2
  import { useMemo } from 'react';
3
+ import { cn, Eyebrow, Accordion, AccordionItem, AccordionTrigger, Badge, AccordionContent, Button, Card, CardContent, Separator } from '@invana/ui';
4
4
  import { Slot } from '@radix-ui/react-slot';
5
5
  import { useFormContext, Controller, FormProvider } from 'react-hook-form';
6
6
  import * as LabelPrimitive from '@radix-ui/react-label';
@@ -67,7 +67,7 @@ var FormLabel = React2.forwardRef(({ className, ...props }, ref) => {
67
67
  Label,
68
68
  {
69
69
  ref,
70
- className: cn(error && "text-destructive", className),
70
+ className: cn(className, error && "text-destructive"),
71
71
  htmlFor: formItemId,
72
72
  ...props
73
73
  }
@@ -126,8 +126,9 @@ var Input = React2.forwardRef(
126
126
  {
127
127
  type,
128
128
  className: cn(
129
- inputSize === "sm" ? "h-[26px] px-2 py-0" : "h-10 px-3 py-2",
130
- "flex w-full rounded-control border border-input bg-background text-base ring-offset-background file:border-0 file:bg-transparent file:font-medium file:text-foreground 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",
129
+ "py-0",
130
+ inputSize === "sm" ? "h-control-sm px-2" : inputSize === "lg" ? "h-control-lg px-3" : "h-control-md px-2.5",
131
+ "flex w-full rounded-control border border-input bg-background text-base ring-offset-background file:border-0 file:bg-transparent file:font-medium file:text-foreground 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 aria-invalid:border-destructive",
131
132
  className
132
133
  ),
133
134
  ref,
@@ -137,6 +138,176 @@ var Input = React2.forwardRef(
137
138
  }
138
139
  );
139
140
  Input.displayName = "Input";
141
+ var Textarea = React2.forwardRef(({ className, inputSize = "default", ...props }, ref) => {
142
+ return /* @__PURE__ */ jsx(
143
+ "textarea",
144
+ {
145
+ className: cn(
146
+ inputSize === "sm" ? "min-h-[52px] px-2 py-1" : "min-h-[80px] px-3 py-2",
147
+ "flex w-full rounded-control border border-input bg-background text-base ring-offset-background 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",
148
+ className
149
+ ),
150
+ ref,
151
+ ...props
152
+ }
153
+ );
154
+ });
155
+ Textarea.displayName = "Textarea";
156
+ var InputGroupControl = React2.createContext({});
157
+ function InputGroup({
158
+ className,
159
+ id,
160
+ "aria-describedby": describedBy,
161
+ "aria-invalid": invalid,
162
+ ...props
163
+ }) {
164
+ const wiring = React2.useMemo(
165
+ () => ({ id, "aria-describedby": describedBy, "aria-invalid": invalid }),
166
+ [id, describedBy, invalid]
167
+ );
168
+ return /* @__PURE__ */ jsx(InputGroupControl.Provider, { value: wiring, children: /* @__PURE__ */ jsx(
169
+ "div",
170
+ {
171
+ "data-slot": "input-group",
172
+ role: "group",
173
+ className: cn(
174
+ "group/input-group border-input dark:bg-input/30 shadow-xs relative flex w-full items-center rounded-control border outline-none transition-[color,box-shadow]",
175
+ "h-control-md has-[>textarea]:h-auto",
176
+ // Variants based on alignment.
177
+ "has-[>[data-align=inline-start]]:[&>input]:pl-2",
178
+ "has-[>[data-align=inline-end]]:[&>input]:pr-2",
179
+ "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
180
+ "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
181
+ // Focus state.
182
+ "has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1",
183
+ // Error state.
184
+ "has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40",
185
+ className
186
+ ),
187
+ ...props
188
+ }
189
+ ) });
190
+ }
191
+ var inputGroupAddonVariants = cva(
192
+ "text-muted-foreground flex h-auto cursor-text select-none items-center justify-center gap-2 py-1.5 font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-control [&>svg:not([class*='size-'])]:size-4",
193
+ {
194
+ variants: {
195
+ align: {
196
+ "inline-start": "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
197
+ "inline-end": "order-last pr-3 has-[>button]:mr-[-0.4rem] has-[>kbd]:mr-[-0.35rem]",
198
+ "block-start": "[.border-b]:pb-3 order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5",
199
+ "block-end": "[.border-t]:pt-3 order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5"
200
+ }
201
+ },
202
+ defaultVariants: {
203
+ align: "inline-start"
204
+ }
205
+ }
206
+ );
207
+ function InputGroupAddon({
208
+ className,
209
+ align = "inline-start",
210
+ ...props
211
+ }) {
212
+ return /* @__PURE__ */ jsx(
213
+ "div",
214
+ {
215
+ role: "group",
216
+ "data-slot": "input-group-addon",
217
+ "data-align": align,
218
+ className: cn(inputGroupAddonVariants({ align }), className),
219
+ onClick: (e) => {
220
+ if (e.target.closest("button")) {
221
+ return;
222
+ }
223
+ e.currentTarget.parentElement?.querySelector("input")?.focus();
224
+ },
225
+ ...props
226
+ }
227
+ );
228
+ }
229
+ var inputGroupButtonVariants = cva(
230
+ "flex items-center gap-2 shadow-none",
231
+ {
232
+ variants: {
233
+ size: {
234
+ xs: "h-control-xs gap-1 rounded-control px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
235
+ sm: "h-control-sm gap-1.5 rounded-control px-2.5 has-[>svg]:px-2.5",
236
+ "icon-xs": "size-control-xs rounded-control p-0 has-[>svg]:p-0",
237
+ "icon-sm": "size-control-sm p-0 has-[>svg]:p-0"
238
+ }
239
+ },
240
+ defaultVariants: {
241
+ size: "xs"
242
+ }
243
+ }
244
+ );
245
+ function InputGroupButton({
246
+ className,
247
+ type = "button",
248
+ variant = "ghost",
249
+ size = "xs",
250
+ ...props
251
+ }) {
252
+ return /* @__PURE__ */ jsx(
253
+ Button,
254
+ {
255
+ type,
256
+ "data-size": size,
257
+ variant,
258
+ className: cn(inputGroupButtonVariants({ size }), className),
259
+ ...props
260
+ }
261
+ );
262
+ }
263
+ function InputGroupText({ className, ...props }) {
264
+ return /* @__PURE__ */ jsx(
265
+ "span",
266
+ {
267
+ className: cn(
268
+ "text-muted-foreground flex items-center gap-2 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
269
+ className
270
+ ),
271
+ ...props
272
+ }
273
+ );
274
+ }
275
+ function InputGroupInput({
276
+ className,
277
+ ...props
278
+ }) {
279
+ const wiring = React2.useContext(InputGroupControl);
280
+ return /* @__PURE__ */ jsx(
281
+ Input,
282
+ {
283
+ ...wiring,
284
+ "data-slot": "input-group-control",
285
+ className: cn(
286
+ "flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent",
287
+ className
288
+ ),
289
+ ...props
290
+ }
291
+ );
292
+ }
293
+ function InputGroupTextarea({
294
+ className,
295
+ ...props
296
+ }) {
297
+ const wiring = React2.useContext(InputGroupControl);
298
+ return /* @__PURE__ */ jsx(
299
+ Textarea,
300
+ {
301
+ ...wiring,
302
+ "data-slot": "input-group-control",
303
+ className: cn(
304
+ "flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent",
305
+ className
306
+ ),
307
+ ...props
308
+ }
309
+ );
310
+ }
140
311
  var PasswordInput = React2.forwardRef(
141
312
  ({ className, visible, onVisibleChange, disabled, ...props }, ref) => {
142
313
  const [internalVisible, setInternalVisible] = React2.useState(false);
@@ -175,21 +346,6 @@ var PasswordInput = React2.forwardRef(
175
346
  }
176
347
  );
177
348
  PasswordInput.displayName = "PasswordInput";
178
- var Textarea = React2.forwardRef(({ className, inputSize = "default", ...props }, ref) => {
179
- return /* @__PURE__ */ jsx(
180
- "textarea",
181
- {
182
- className: cn(
183
- inputSize === "sm" ? "min-h-[52px] px-2 py-1" : "min-h-[80px] px-3 py-2",
184
- "flex w-full rounded-control border border-input bg-background text-base ring-offset-background 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",
185
- className
186
- ),
187
- ref,
188
- ...props
189
- }
190
- );
191
- });
192
- Textarea.displayName = "Textarea";
193
349
  var Switch = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
194
350
  SwitchPrimitives.Root,
195
351
  {
@@ -263,8 +419,9 @@ var SelectTrigger = React2.forwardRef(({ className, children, triggerSize = "def
263
419
  {
264
420
  ref,
265
421
  className: cn(
266
- triggerSize === "sm" ? "h-[26px] px-2 py-0" : "h-9 px-3 py-2",
267
- "flex w-full items-center justify-between whitespace-nowrap rounded-control border border-input bg-transparent shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
422
+ "py-0",
423
+ triggerSize === "sm" ? "h-control-sm px-2" : triggerSize === "lg" ? "h-control-lg px-3" : "h-control-md px-2.5",
424
+ "flex w-full items-center justify-between whitespace-nowrap rounded-control border border-input bg-transparent shadow-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
268
425
  className
269
426
  ),
270
427
  ...props,
@@ -306,7 +463,7 @@ var SelectContent = React2.forwardRef(({ className, children, position = "popper
306
463
  {
307
464
  ref,
308
465
  className: cn(
309
- "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
466
+ "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-surface border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
310
467
  position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
311
468
  className
312
469
  ),
@@ -376,12 +533,15 @@ var ColorSwatches = ({
376
533
  }) => {
377
534
  const [customColor, setCustomColor] = React2.useState(value || defaultValue);
378
535
  const [isCustom, setIsCustom] = React2.useState(false);
379
- React2.useEffect(() => {
380
- if (!value) return;
536
+ const [seen, setSeen] = React2.useState({
537
+ presetColors
538
+ });
539
+ if (value && (value !== seen.value || presetColors !== seen.presetColors)) {
540
+ setSeen({ value, presetColors });
381
541
  const isPreset = presetColors.some((c) => c.value === value);
382
542
  setIsCustom(!isPreset);
383
543
  if (!isPreset) setCustomColor(value);
384
- }, [value, presetColors]);
544
+ }
385
545
  const select = (newColor, custom = false) => {
386
546
  setIsCustom(custom);
387
547
  if (custom) setCustomColor(newColor);
@@ -461,9 +621,11 @@ var SliderNumber = ({
461
621
  className
462
622
  }) => {
463
623
  const [local, setLocal] = React2.useState(value);
464
- React2.useEffect(() => {
624
+ const [seen, setSeen] = React2.useState(value);
625
+ if (value !== seen) {
626
+ setSeen(value);
465
627
  setLocal(value);
466
- }, [value]);
628
+ }
467
629
  const set = (n) => {
468
630
  setLocal(n);
469
631
  onChange?.(n);
@@ -496,7 +658,7 @@ var SliderNumber = ({
496
658
  };
497
659
  var IconInput = ({ value, onChange }) => {
498
660
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
499
- /* @__PURE__ */ jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-control border bg-muted", children: value ? value.slice(0, 2) : "\u2013" }),
661
+ /* @__PURE__ */ jsx("div", { className: "flex size-control-md shrink-0 items-center justify-center rounded-control border bg-muted", children: value ? value.slice(0, 2) : "\u2013" }),
500
662
  /* @__PURE__ */ jsx(
501
663
  Input,
502
664
  {
@@ -504,17 +666,21 @@ var IconInput = ({ value, onChange }) => {
504
666
  value: value ?? "",
505
667
  onChange: (e) => onChange?.(e.target.value),
506
668
  placeholder: "icon name",
507
- className: "h-8"
669
+ className: "h-control-md"
508
670
  }
509
671
  )
510
672
  ] });
511
673
  };
512
674
  var SIZE = {
675
+ // The dense tier — an ask in a conversation, an inspector. Controls are the
676
+ // scale's `sm` (26px), the text stays at the 13px floor; the field label is
677
+ // muted and regular so the values, not the labels, carry the weight.
513
678
  xs: {
514
- input: "h-9",
515
- select: "h-9",
679
+ input: "h-control-sm py-0",
680
+ select: "h-control-sm py-0",
516
681
  textarea: "",
517
682
  label: "text-base",
683
+ fieldLabel: "font-normal text-muted-foreground",
518
684
  desc: "text-base",
519
685
  gap: "gap-x-3 gap-y-2.5",
520
686
  section: "space-y-3",
@@ -527,10 +693,11 @@ var SIZE = {
527
693
  radio: "h-4 w-4"
528
694
  },
529
695
  sm: {
530
- input: "h-9",
531
- select: "h-9",
696
+ input: "h-control-md",
697
+ select: "h-control-md",
532
698
  textarea: "",
533
699
  label: "text-base",
700
+ fieldLabel: "",
534
701
  desc: "text-base",
535
702
  gap: "gap-x-3 gap-y-2",
536
703
  section: "space-y-3",
@@ -543,10 +710,11 @@ var SIZE = {
543
710
  radio: "h-4 w-4"
544
711
  },
545
712
  md: {
546
- input: "",
547
- select: "",
713
+ input: "h-control-lg px-3",
714
+ select: "h-control-lg px-3",
548
715
  textarea: "",
549
716
  label: "text-base",
717
+ fieldLabel: "",
550
718
  desc: "text-base",
551
719
  gap: "gap-4",
552
720
  section: "space-y-4",
@@ -561,7 +729,9 @@ var SIZE = {
561
729
  };
562
730
  function itemClasses(labelPosition, size, className) {
563
731
  return cn(
564
- labelPosition === "side" && cn("grid grid-cols-3 items-center", SIZE[size].sideGap),
732
+ // `space-y-0` undoes FormItem's own stacking, whose margin would push the
733
+ // control below its label in a row.
734
+ labelPosition === "side" && cn("grid grid-cols-3 items-center space-y-0", SIZE[size].sideGap),
565
735
  labelPosition === "top" && SIZE[size].stack,
566
736
  className
567
737
  );
@@ -586,17 +756,30 @@ function FieldLabel({
586
756
  className
587
757
  }) {
588
758
  if (!label && !badge) return null;
589
- return /* @__PURE__ */ jsxs(FormLabel, { className: cn(SIZE[size].label, className), children: [
759
+ return /* @__PURE__ */ jsxs(FormLabel, { className: cn(SIZE[size].label, SIZE[size].fieldLabel, className), children: [
590
760
  label,
591
761
  badge && /* @__PURE__ */ jsx(StatusPill, { badge })
592
762
  ] });
593
763
  }
764
+ var AffixedInput = React2.forwardRef(({ unit, aside, className, ...props }, ref) => {
765
+ if (!unit && !aside) return /* @__PURE__ */ jsx(Input, { ref, className, ...props });
766
+ return /* @__PURE__ */ jsxs(InputGroup, { className: cn("bg-background dark:bg-background", className), children: [
767
+ /* @__PURE__ */ jsx(InputGroupInput, { ref, className: "h-full", ...props }),
768
+ /* @__PURE__ */ jsxs(InputGroupAddon, { align: "inline-end", className: "font-mono font-normal", children: [
769
+ unit && /* @__PURE__ */ jsx("span", { children: unit }),
770
+ aside && /* @__PURE__ */ jsx("span", { children: aside })
771
+ ] })
772
+ ] });
773
+ });
774
+ AffixedInput.displayName = "AffixedInput";
594
775
  var InputField = ({
595
776
  label,
596
777
  description,
597
778
  placeholder,
598
779
  value,
599
780
  onChange,
781
+ unit,
782
+ aside,
600
783
  labelPosition = "side",
601
784
  size = "sm",
602
785
  labelClassName,
@@ -606,9 +789,11 @@ var InputField = ({
606
789
  /* @__PURE__ */ jsx(FieldLabel, { label, badge, size, className: labelClassName }),
607
790
  /* @__PURE__ */ jsxs("div", { className: inputWrapper(labelPosition, size), children: [
608
791
  /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
609
- Input,
792
+ AffixedInput,
610
793
  {
611
794
  className: SIZE[size].input,
795
+ unit,
796
+ aside,
612
797
  placeholder,
613
798
  value: value ?? "",
614
799
  onChange: (e) => onChange?.(e.target.value)
@@ -893,6 +1078,8 @@ var NumberField = ({
893
1078
  min,
894
1079
  max,
895
1080
  step,
1081
+ unit,
1082
+ aside,
896
1083
  labelPosition = "side",
897
1084
  size = "sm",
898
1085
  labelClassName,
@@ -901,7 +1088,7 @@ var NumberField = ({
901
1088
  }) => /* @__PURE__ */ jsxs(FormItem, { className: itemClasses(labelPosition, size, className), children: [
902
1089
  /* @__PURE__ */ jsx(FieldLabel, { label, badge, size, className: labelClassName }),
903
1090
  /* @__PURE__ */ jsxs("div", { className: inputWrapper(labelPosition, size), children: [
904
- /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
1091
+ /* @__PURE__ */ jsx(FormControl, { children: min != null && max != null ? /* @__PURE__ */ jsx(
905
1092
  SliderNumber,
906
1093
  {
907
1094
  value: typeof value === "number" ? value : 0,
@@ -910,6 +1097,19 @@ var NumberField = ({
910
1097
  max,
911
1098
  step
912
1099
  }
1100
+ ) : /* @__PURE__ */ jsx(
1101
+ AffixedInput,
1102
+ {
1103
+ type: "number",
1104
+ className: SIZE[size].input,
1105
+ unit,
1106
+ aside,
1107
+ min,
1108
+ max,
1109
+ step,
1110
+ value: typeof value === "number" ? value : "",
1111
+ onChange: (e) => onChange?.(e.target.value === "" ? void 0 : Number(e.target.value))
1112
+ }
913
1113
  ) }),
914
1114
  description && /* @__PURE__ */ jsx(FormDescription, { className: SIZE[size].desc, children: description }),
915
1115
  /* @__PURE__ */ jsx(FormMessage, { className: SIZE[size].desc })
@@ -933,18 +1133,6 @@ var IconField = ({
933
1133
  /* @__PURE__ */ jsx(FormMessage, { className: SIZE[size].desc })
934
1134
  ] })
935
1135
  ] });
936
- var Field = {
937
- Input: InputField,
938
- Password: PasswordField,
939
- Textarea: TextareaField,
940
- Boolean: BooleanField,
941
- Radio: RadioField,
942
- CheckboxGroup: CheckboxGroupField,
943
- Color: ColorField,
944
- Number: NumberField,
945
- Select: SelectField,
946
- Icon: IconField
947
- };
948
1136
  function humanize(name) {
949
1137
  return name.replace(/([A-Z])/g, " $1").replace(/^./, (c) => c.toUpperCase()).trim();
950
1138
  }
@@ -955,6 +1143,7 @@ function renderField(field, parentName, control, labelPosition, size) {
955
1143
  control,
956
1144
  name: `${parentName}.${field.name}`,
957
1145
  defaultValue: field.defaultValue,
1146
+ rules: field.rules,
958
1147
  render: ({ field: rhf }) => {
959
1148
  const common = {
960
1149
  label: field.label ?? humanize(field.name),
@@ -971,6 +1160,8 @@ function renderField(field, parentName, control, labelPosition, size) {
971
1160
  boxed: field.boxed,
972
1161
  labelClassName: field.labelClassName,
973
1162
  badge: field.badge,
1163
+ unit: field.unit,
1164
+ aside: field.aside,
974
1165
  labelPosition,
975
1166
  size,
976
1167
  value: rhf.value,
@@ -1022,8 +1213,21 @@ function renderField(field, parentName, control, labelPosition, size) {
1022
1213
  field.name
1023
1214
  );
1024
1215
  }
1025
- function renderGrid(fields, parentName, control, labelPosition, size, columns, key) {
1216
+ function renderGrid(fields, parentName, control, labelPosition, size, columns, key, fit = "viewport") {
1026
1217
  const customCols = columns !== 2;
1218
+ if (fit === "container") {
1219
+ return /* @__PURE__ */ jsx("div", { className: "@container", children: /* @__PURE__ */ jsx(
1220
+ "div",
1221
+ {
1222
+ className: cn(
1223
+ "grid grid-cols-1",
1224
+ SIZE[size].gap,
1225
+ columns > 1 && "@min-[280px]:grid-cols-2 @min-[280px]:[&>*:last-child:nth-child(odd)]:col-span-2"
1226
+ ),
1227
+ children: fields.map((f) => /* @__PURE__ */ jsx("div", { className: f.className, children: renderField(f, parentName, control, labelPosition, size) }, f.name))
1228
+ }
1229
+ ) }, key);
1230
+ }
1027
1231
  return /* @__PURE__ */ jsx(
1028
1232
  "div",
1029
1233
  {
@@ -1052,9 +1256,9 @@ function renderGrid(fields, parentName, control, labelPosition, size, columns, k
1052
1256
  key
1053
1257
  );
1054
1258
  }
1055
- function renderRows(fields, rowConfig, parentName, control, labelPosition, size, columns) {
1259
+ function renderRows(fields, rowConfig, parentName, control, labelPosition, size, columns, fit = "viewport") {
1056
1260
  if (!rowConfig || rowConfig.length === 0) {
1057
- return renderGrid(fields, parentName, control, labelPosition, size, columns);
1261
+ return renderGrid(fields, parentName, control, labelPosition, size, columns, void 0, fit);
1058
1262
  }
1059
1263
  const used = new Set(rowConfig.flatMap((r) => r.fields));
1060
1264
  const unassigned = fields.filter((f) => !used.has(f.name));
@@ -1070,7 +1274,8 @@ function renderRows(fields, rowConfig, parentName, control, labelPosition, size,
1070
1274
  labelPosition,
1071
1275
  size,
1072
1276
  columns,
1073
- row.id
1277
+ row.id,
1278
+ fit
1074
1279
  );
1075
1280
  }),
1076
1281
  unassigned.length > 0 && renderGrid(
@@ -1080,7 +1285,8 @@ function renderRows(fields, rowConfig, parentName, control, labelPosition, size,
1080
1285
  labelPosition,
1081
1286
  size,
1082
1287
  columns,
1083
- "_unassigned"
1288
+ "_unassigned",
1289
+ fit
1084
1290
  )
1085
1291
  ] });
1086
1292
  }
@@ -1092,7 +1298,9 @@ var ObjectField = ({
1092
1298
  groupConfig,
1093
1299
  labelPosition = "side",
1094
1300
  size = "sm",
1095
- columns = 2
1301
+ columns = 2,
1302
+ fit = "viewport",
1303
+ groupAs = "accordion"
1096
1304
  }) => {
1097
1305
  const grouped = fields.reduce((acc, f) => {
1098
1306
  const key = f.group ?? "_ungrouped";
@@ -1113,9 +1321,14 @@ var ObjectField = ({
1113
1321
  control,
1114
1322
  labelPosition,
1115
1323
  size,
1116
- columns
1324
+ columns,
1325
+ fit
1117
1326
  ) }),
1118
- groupedEntries.length > 0 && /* @__PURE__ */ jsx(
1327
+ groupedEntries.length > 0 && groupAs === "section" && /* @__PURE__ */ jsx("div", { className: SIZE[size].section, children: groupedEntries.map(([group, gFields]) => /* @__PURE__ */ jsxs("section", { className: SIZE[size].stack, children: [
1328
+ /* @__PURE__ */ jsx(Eyebrow, { children: groupConfigById.get(group)?.label ?? humanize(group) }),
1329
+ renderRows(gFields, rowConfig, name, control, labelPosition, size, columns, fit)
1330
+ ] }, group)) }),
1331
+ groupedEntries.length > 0 && groupAs === "accordion" && /* @__PURE__ */ jsx(
1119
1332
  Accordion,
1120
1333
  {
1121
1334
  type: "multiple",
@@ -1152,7 +1365,8 @@ var ObjectField = ({
1152
1365
  control,
1153
1366
  labelPosition,
1154
1367
  size,
1155
- columns
1368
+ columns,
1369
+ fit
1156
1370
  ) }) })
1157
1371
  ] }, group);
1158
1372
  })
@@ -1241,7 +1455,7 @@ function FieldGroup({ className, ...props }) {
1241
1455
  }
1242
1456
  );
1243
1457
  }
1244
- cva(
1458
+ var fieldVariants = cva(
1245
1459
  "group/field data-[invalid=true]:text-destructive flex w-full gap-3",
1246
1460
  {
1247
1461
  variants: {
@@ -1264,6 +1478,22 @@ cva(
1264
1478
  }
1265
1479
  }
1266
1480
  );
1481
+ function Field({
1482
+ className,
1483
+ orientation = "vertical",
1484
+ ...props
1485
+ }) {
1486
+ return /* @__PURE__ */ jsx(
1487
+ "div",
1488
+ {
1489
+ role: "group",
1490
+ "data-slot": "field",
1491
+ "data-orientation": orientation,
1492
+ className: cn(fieldVariants({ orientation }), className),
1493
+ ...props
1494
+ }
1495
+ );
1496
+ }
1267
1497
  function FieldContent({ className, ...props }) {
1268
1498
  return /* @__PURE__ */ jsx(
1269
1499
  "div",
@@ -1466,146 +1696,6 @@ var ParamRow = React2.forwardRef(
1466
1696
  )
1467
1697
  );
1468
1698
  ParamRow.displayName = "ParamRow";
1469
- function InputGroup({ className, ...props }) {
1470
- return /* @__PURE__ */ jsx(
1471
- "div",
1472
- {
1473
- "data-slot": "input-group",
1474
- role: "group",
1475
- className: cn(
1476
- "group/input-group border-input dark:bg-input/30 shadow-xs relative flex w-full items-center rounded-control border outline-none transition-[color,box-shadow]",
1477
- "h-9 has-[>textarea]:h-auto",
1478
- // Variants based on alignment.
1479
- "has-[>[data-align=inline-start]]:[&>input]:pl-2",
1480
- "has-[>[data-align=inline-end]]:[&>input]:pr-2",
1481
- "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
1482
- "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
1483
- // Focus state.
1484
- "has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1",
1485
- // Error state.
1486
- "has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40",
1487
- className
1488
- ),
1489
- ...props
1490
- }
1491
- );
1492
- }
1493
- var inputGroupAddonVariants = cva(
1494
- "text-muted-foreground flex h-auto cursor-text select-none items-center justify-center gap-2 py-1.5 font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-control [&>svg:not([class*='size-'])]:size-4",
1495
- {
1496
- variants: {
1497
- align: {
1498
- "inline-start": "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
1499
- "inline-end": "order-last pr-3 has-[>button]:mr-[-0.4rem] has-[>kbd]:mr-[-0.35rem]",
1500
- "block-start": "[.border-b]:pb-3 order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5",
1501
- "block-end": "[.border-t]:pt-3 order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5"
1502
- }
1503
- },
1504
- defaultVariants: {
1505
- align: "inline-start"
1506
- }
1507
- }
1508
- );
1509
- function InputGroupAddon({
1510
- className,
1511
- align = "inline-start",
1512
- ...props
1513
- }) {
1514
- return /* @__PURE__ */ jsx(
1515
- "div",
1516
- {
1517
- role: "group",
1518
- "data-slot": "input-group-addon",
1519
- "data-align": align,
1520
- className: cn(inputGroupAddonVariants({ align }), className),
1521
- onClick: (e) => {
1522
- if (e.target.closest("button")) {
1523
- return;
1524
- }
1525
- e.currentTarget.parentElement?.querySelector("input")?.focus();
1526
- },
1527
- ...props
1528
- }
1529
- );
1530
- }
1531
- var inputGroupButtonVariants = cva(
1532
- "flex items-center gap-2 shadow-none",
1533
- {
1534
- variants: {
1535
- size: {
1536
- xs: "h-6 gap-1 rounded-control px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
1537
- sm: "h-8 gap-1.5 rounded-control px-2.5 has-[>svg]:px-2.5",
1538
- "icon-xs": "size-6 rounded-control p-0 has-[>svg]:p-0",
1539
- "icon-sm": "size-8 p-0 has-[>svg]:p-0"
1540
- }
1541
- },
1542
- defaultVariants: {
1543
- size: "xs"
1544
- }
1545
- }
1546
- );
1547
- function InputGroupButton({
1548
- className,
1549
- type = "button",
1550
- variant = "ghost",
1551
- size = "xs",
1552
- ...props
1553
- }) {
1554
- return /* @__PURE__ */ jsx(
1555
- Button,
1556
- {
1557
- type,
1558
- "data-size": size,
1559
- variant,
1560
- className: cn(inputGroupButtonVariants({ size }), className),
1561
- ...props
1562
- }
1563
- );
1564
- }
1565
- function InputGroupText({ className, ...props }) {
1566
- return /* @__PURE__ */ jsx(
1567
- "span",
1568
- {
1569
- className: cn(
1570
- "text-muted-foreground flex items-center gap-2 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
1571
- className
1572
- ),
1573
- ...props
1574
- }
1575
- );
1576
- }
1577
- function InputGroupInput({
1578
- className,
1579
- ...props
1580
- }) {
1581
- return /* @__PURE__ */ jsx(
1582
- Input,
1583
- {
1584
- "data-slot": "input-group-control",
1585
- className: cn(
1586
- "flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent",
1587
- className
1588
- ),
1589
- ...props
1590
- }
1591
- );
1592
- }
1593
- function InputGroupTextarea({
1594
- className,
1595
- ...props
1596
- }) {
1597
- return /* @__PURE__ */ jsx(
1598
- Textarea,
1599
- {
1600
- "data-slot": "input-group-control",
1601
- className: cn(
1602
- "flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent",
1603
- className
1604
- ),
1605
- ...props
1606
- }
1607
- );
1608
- }
1609
1699
 
1610
1700
  export { BooleanField, Checkbox, CheckboxGroupField, ColorField, ColorSwatches, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel2 as FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Form, FormControl, FormDescription, FormField2 as FormField, FormItem, FormLabel, FormMessage, IconField, IconInput, Input, InputField, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Label, NumberField, ObjectField, PARAM_SOURCES, ParamRow, PasswordField, PasswordInput, RadioField, RadioGroup, RadioGroupItem, Select, SelectContent, SelectField, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SettingsPanel, Slider, SliderNumber, Switch, Textarea, TextareaField, useFormField };
1611
1701
  //# sourceMappingURL=index.js.map