@invana/forms 0.0.31 → 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.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var ui = require('@invana/ui');
4
3
  var React2 = require('react');
4
+ var ui = require('@invana/ui');
5
5
  var reactSlot = require('@radix-ui/react-slot');
6
6
  var reactHookForm = require('react-hook-form');
7
7
  var LabelPrimitive = require('@radix-ui/react-label');
@@ -94,7 +94,7 @@ var FormLabel = React2__namespace.forwardRef(({ className, ...props }, ref) => {
94
94
  Label,
95
95
  {
96
96
  ref,
97
- className: ui.cn(error && "text-destructive", className),
97
+ className: ui.cn(className, error && "text-destructive"),
98
98
  htmlFor: formItemId,
99
99
  ...props
100
100
  }
@@ -153,8 +153,9 @@ var Input = React2__namespace.forwardRef(
153
153
  {
154
154
  type,
155
155
  className: ui.cn(
156
- inputSize === "sm" ? "h-[26px] px-2 py-0" : "h-10 px-3 py-2",
157
- "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",
156
+ "py-0",
157
+ inputSize === "sm" ? "h-control-sm px-2" : inputSize === "lg" ? "h-control-lg px-3" : "h-control-md px-2.5",
158
+ "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",
158
159
  className
159
160
  ),
160
161
  ref,
@@ -164,6 +165,176 @@ var Input = React2__namespace.forwardRef(
164
165
  }
165
166
  );
166
167
  Input.displayName = "Input";
168
+ var Textarea = React2__namespace.forwardRef(({ className, inputSize = "default", ...props }, ref) => {
169
+ return /* @__PURE__ */ jsxRuntime.jsx(
170
+ "textarea",
171
+ {
172
+ className: ui.cn(
173
+ inputSize === "sm" ? "min-h-[52px] px-2 py-1" : "min-h-[80px] px-3 py-2",
174
+ "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",
175
+ className
176
+ ),
177
+ ref,
178
+ ...props
179
+ }
180
+ );
181
+ });
182
+ Textarea.displayName = "Textarea";
183
+ var InputGroupControl = React2__namespace.createContext({});
184
+ function InputGroup({
185
+ className,
186
+ id,
187
+ "aria-describedby": describedBy,
188
+ "aria-invalid": invalid,
189
+ ...props
190
+ }) {
191
+ const wiring = React2__namespace.useMemo(
192
+ () => ({ id, "aria-describedby": describedBy, "aria-invalid": invalid }),
193
+ [id, describedBy, invalid]
194
+ );
195
+ return /* @__PURE__ */ jsxRuntime.jsx(InputGroupControl.Provider, { value: wiring, children: /* @__PURE__ */ jsxRuntime.jsx(
196
+ "div",
197
+ {
198
+ "data-slot": "input-group",
199
+ role: "group",
200
+ className: ui.cn(
201
+ "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]",
202
+ "h-control-md has-[>textarea]:h-auto",
203
+ // Variants based on alignment.
204
+ "has-[>[data-align=inline-start]]:[&>input]:pl-2",
205
+ "has-[>[data-align=inline-end]]:[&>input]:pr-2",
206
+ "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
207
+ "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
208
+ // Focus state.
209
+ "has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1",
210
+ // Error state.
211
+ "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",
212
+ className
213
+ ),
214
+ ...props
215
+ }
216
+ ) });
217
+ }
218
+ var inputGroupAddonVariants = classVarianceAuthority.cva(
219
+ "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",
220
+ {
221
+ variants: {
222
+ align: {
223
+ "inline-start": "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
224
+ "inline-end": "order-last pr-3 has-[>button]:mr-[-0.4rem] has-[>kbd]:mr-[-0.35rem]",
225
+ "block-start": "[.border-b]:pb-3 order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5",
226
+ "block-end": "[.border-t]:pt-3 order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5"
227
+ }
228
+ },
229
+ defaultVariants: {
230
+ align: "inline-start"
231
+ }
232
+ }
233
+ );
234
+ function InputGroupAddon({
235
+ className,
236
+ align = "inline-start",
237
+ ...props
238
+ }) {
239
+ return /* @__PURE__ */ jsxRuntime.jsx(
240
+ "div",
241
+ {
242
+ role: "group",
243
+ "data-slot": "input-group-addon",
244
+ "data-align": align,
245
+ className: ui.cn(inputGroupAddonVariants({ align }), className),
246
+ onClick: (e) => {
247
+ if (e.target.closest("button")) {
248
+ return;
249
+ }
250
+ e.currentTarget.parentElement?.querySelector("input")?.focus();
251
+ },
252
+ ...props
253
+ }
254
+ );
255
+ }
256
+ var inputGroupButtonVariants = classVarianceAuthority.cva(
257
+ "flex items-center gap-2 shadow-none",
258
+ {
259
+ variants: {
260
+ size: {
261
+ xs: "h-control-xs gap-1 rounded-control px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
262
+ sm: "h-control-sm gap-1.5 rounded-control px-2.5 has-[>svg]:px-2.5",
263
+ "icon-xs": "size-control-xs rounded-control p-0 has-[>svg]:p-0",
264
+ "icon-sm": "size-control-sm p-0 has-[>svg]:p-0"
265
+ }
266
+ },
267
+ defaultVariants: {
268
+ size: "xs"
269
+ }
270
+ }
271
+ );
272
+ function InputGroupButton({
273
+ className,
274
+ type = "button",
275
+ variant = "ghost",
276
+ size = "xs",
277
+ ...props
278
+ }) {
279
+ return /* @__PURE__ */ jsxRuntime.jsx(
280
+ ui.Button,
281
+ {
282
+ type,
283
+ "data-size": size,
284
+ variant,
285
+ className: ui.cn(inputGroupButtonVariants({ size }), className),
286
+ ...props
287
+ }
288
+ );
289
+ }
290
+ function InputGroupText({ className, ...props }) {
291
+ return /* @__PURE__ */ jsxRuntime.jsx(
292
+ "span",
293
+ {
294
+ className: ui.cn(
295
+ "text-muted-foreground flex items-center gap-2 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
296
+ className
297
+ ),
298
+ ...props
299
+ }
300
+ );
301
+ }
302
+ function InputGroupInput({
303
+ className,
304
+ ...props
305
+ }) {
306
+ const wiring = React2__namespace.useContext(InputGroupControl);
307
+ return /* @__PURE__ */ jsxRuntime.jsx(
308
+ Input,
309
+ {
310
+ ...wiring,
311
+ "data-slot": "input-group-control",
312
+ className: ui.cn(
313
+ "flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent",
314
+ className
315
+ ),
316
+ ...props
317
+ }
318
+ );
319
+ }
320
+ function InputGroupTextarea({
321
+ className,
322
+ ...props
323
+ }) {
324
+ const wiring = React2__namespace.useContext(InputGroupControl);
325
+ return /* @__PURE__ */ jsxRuntime.jsx(
326
+ Textarea,
327
+ {
328
+ ...wiring,
329
+ "data-slot": "input-group-control",
330
+ className: ui.cn(
331
+ "flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent",
332
+ className
333
+ ),
334
+ ...props
335
+ }
336
+ );
337
+ }
167
338
  var PasswordInput = React2__namespace.forwardRef(
168
339
  ({ className, visible, onVisibleChange, disabled, ...props }, ref) => {
169
340
  const [internalVisible, setInternalVisible] = React2__namespace.useState(false);
@@ -202,21 +373,6 @@ var PasswordInput = React2__namespace.forwardRef(
202
373
  }
203
374
  );
204
375
  PasswordInput.displayName = "PasswordInput";
205
- var Textarea = React2__namespace.forwardRef(({ className, inputSize = "default", ...props }, ref) => {
206
- return /* @__PURE__ */ jsxRuntime.jsx(
207
- "textarea",
208
- {
209
- className: ui.cn(
210
- inputSize === "sm" ? "min-h-[52px] px-2 py-1" : "min-h-[80px] px-3 py-2",
211
- "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",
212
- className
213
- ),
214
- ref,
215
- ...props
216
- }
217
- );
218
- });
219
- Textarea.displayName = "Textarea";
220
376
  var Switch = React2__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
221
377
  SwitchPrimitives__namespace.Root,
222
378
  {
@@ -290,8 +446,9 @@ var SelectTrigger = React2__namespace.forwardRef(({ className, children, trigger
290
446
  {
291
447
  ref,
292
448
  className: ui.cn(
293
- triggerSize === "sm" ? "h-[26px] px-2 py-0" : "h-9 px-3 py-2",
294
- "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",
449
+ "py-0",
450
+ triggerSize === "sm" ? "h-control-sm px-2" : triggerSize === "lg" ? "h-control-lg px-3" : "h-control-md px-2.5",
451
+ "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",
295
452
  className
296
453
  ),
297
454
  ...props,
@@ -333,7 +490,7 @@ var SelectContent = React2__namespace.forwardRef(({ className, children, positio
333
490
  {
334
491
  ref,
335
492
  className: ui.cn(
336
- "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",
493
+ "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",
337
494
  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",
338
495
  className
339
496
  ),
@@ -403,12 +560,15 @@ var ColorSwatches = ({
403
560
  }) => {
404
561
  const [customColor, setCustomColor] = React2__namespace.useState(value || defaultValue);
405
562
  const [isCustom, setIsCustom] = React2__namespace.useState(false);
406
- React2__namespace.useEffect(() => {
407
- if (!value) return;
563
+ const [seen, setSeen] = React2__namespace.useState({
564
+ presetColors
565
+ });
566
+ if (value && (value !== seen.value || presetColors !== seen.presetColors)) {
567
+ setSeen({ value, presetColors });
408
568
  const isPreset = presetColors.some((c) => c.value === value);
409
569
  setIsCustom(!isPreset);
410
570
  if (!isPreset) setCustomColor(value);
411
- }, [value, presetColors]);
571
+ }
412
572
  const select = (newColor, custom = false) => {
413
573
  setIsCustom(custom);
414
574
  if (custom) setCustomColor(newColor);
@@ -488,9 +648,11 @@ var SliderNumber = ({
488
648
  className
489
649
  }) => {
490
650
  const [local, setLocal] = React2__namespace.useState(value);
491
- React2__namespace.useEffect(() => {
651
+ const [seen, setSeen] = React2__namespace.useState(value);
652
+ if (value !== seen) {
653
+ setSeen(value);
492
654
  setLocal(value);
493
- }, [value]);
655
+ }
494
656
  const set = (n) => {
495
657
  setLocal(n);
496
658
  onChange?.(n);
@@ -523,7 +685,7 @@ var SliderNumber = ({
523
685
  };
524
686
  var IconInput = ({ value, onChange }) => {
525
687
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
526
- /* @__PURE__ */ jsxRuntime.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" }),
688
+ /* @__PURE__ */ jsxRuntime.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" }),
527
689
  /* @__PURE__ */ jsxRuntime.jsx(
528
690
  Input,
529
691
  {
@@ -531,17 +693,21 @@ var IconInput = ({ value, onChange }) => {
531
693
  value: value ?? "",
532
694
  onChange: (e) => onChange?.(e.target.value),
533
695
  placeholder: "icon name",
534
- className: "h-8"
696
+ className: "h-control-md"
535
697
  }
536
698
  )
537
699
  ] });
538
700
  };
539
701
  var SIZE = {
702
+ // The dense tier — an ask in a conversation, an inspector. Controls are the
703
+ // scale's `sm` (26px), the text stays at the 13px floor; the field label is
704
+ // muted and regular so the values, not the labels, carry the weight.
540
705
  xs: {
541
- input: "h-9",
542
- select: "h-9",
706
+ input: "h-control-sm py-0",
707
+ select: "h-control-sm py-0",
543
708
  textarea: "",
544
709
  label: "text-base",
710
+ fieldLabel: "font-normal text-muted-foreground",
545
711
  desc: "text-base",
546
712
  gap: "gap-x-3 gap-y-2.5",
547
713
  section: "space-y-3",
@@ -554,10 +720,11 @@ var SIZE = {
554
720
  radio: "h-4 w-4"
555
721
  },
556
722
  sm: {
557
- input: "h-9",
558
- select: "h-9",
723
+ input: "h-control-md",
724
+ select: "h-control-md",
559
725
  textarea: "",
560
726
  label: "text-base",
727
+ fieldLabel: "",
561
728
  desc: "text-base",
562
729
  gap: "gap-x-3 gap-y-2",
563
730
  section: "space-y-3",
@@ -570,10 +737,11 @@ var SIZE = {
570
737
  radio: "h-4 w-4"
571
738
  },
572
739
  md: {
573
- input: "",
574
- select: "",
740
+ input: "h-control-lg px-3",
741
+ select: "h-control-lg px-3",
575
742
  textarea: "",
576
743
  label: "text-base",
744
+ fieldLabel: "",
577
745
  desc: "text-base",
578
746
  gap: "gap-4",
579
747
  section: "space-y-4",
@@ -588,7 +756,9 @@ var SIZE = {
588
756
  };
589
757
  function itemClasses(labelPosition, size, className) {
590
758
  return ui.cn(
591
- labelPosition === "side" && ui.cn("grid grid-cols-3 items-center", SIZE[size].sideGap),
759
+ // `space-y-0` undoes FormItem's own stacking, whose margin would push the
760
+ // control below its label in a row.
761
+ labelPosition === "side" && ui.cn("grid grid-cols-3 items-center space-y-0", SIZE[size].sideGap),
592
762
  labelPosition === "top" && SIZE[size].stack,
593
763
  className
594
764
  );
@@ -613,17 +783,30 @@ function FieldLabel({
613
783
  className
614
784
  }) {
615
785
  if (!label && !badge) return null;
616
- return /* @__PURE__ */ jsxRuntime.jsxs(FormLabel, { className: ui.cn(SIZE[size].label, className), children: [
786
+ return /* @__PURE__ */ jsxRuntime.jsxs(FormLabel, { className: ui.cn(SIZE[size].label, SIZE[size].fieldLabel, className), children: [
617
787
  label,
618
788
  badge && /* @__PURE__ */ jsxRuntime.jsx(StatusPill, { badge })
619
789
  ] });
620
790
  }
791
+ var AffixedInput = React2__namespace.forwardRef(({ unit, aside, className, ...props }, ref) => {
792
+ if (!unit && !aside) return /* @__PURE__ */ jsxRuntime.jsx(Input, { ref, className, ...props });
793
+ return /* @__PURE__ */ jsxRuntime.jsxs(InputGroup, { className: ui.cn("bg-background dark:bg-background", className), children: [
794
+ /* @__PURE__ */ jsxRuntime.jsx(InputGroupInput, { ref, className: "h-full", ...props }),
795
+ /* @__PURE__ */ jsxRuntime.jsxs(InputGroupAddon, { align: "inline-end", className: "font-mono font-normal", children: [
796
+ unit && /* @__PURE__ */ jsxRuntime.jsx("span", { children: unit }),
797
+ aside && /* @__PURE__ */ jsxRuntime.jsx("span", { children: aside })
798
+ ] })
799
+ ] });
800
+ });
801
+ AffixedInput.displayName = "AffixedInput";
621
802
  var InputField = ({
622
803
  label,
623
804
  description,
624
805
  placeholder,
625
806
  value,
626
807
  onChange,
808
+ unit,
809
+ aside,
627
810
  labelPosition = "side",
628
811
  size = "sm",
629
812
  labelClassName,
@@ -633,9 +816,11 @@ var InputField = ({
633
816
  /* @__PURE__ */ jsxRuntime.jsx(FieldLabel, { label, badge, size, className: labelClassName }),
634
817
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: inputWrapper(labelPosition, size), children: [
635
818
  /* @__PURE__ */ jsxRuntime.jsx(FormControl, { children: /* @__PURE__ */ jsxRuntime.jsx(
636
- Input,
819
+ AffixedInput,
637
820
  {
638
821
  className: SIZE[size].input,
822
+ unit,
823
+ aside,
639
824
  placeholder,
640
825
  value: value ?? "",
641
826
  onChange: (e) => onChange?.(e.target.value)
@@ -920,6 +1105,8 @@ var NumberField = ({
920
1105
  min,
921
1106
  max,
922
1107
  step,
1108
+ unit,
1109
+ aside,
923
1110
  labelPosition = "side",
924
1111
  size = "sm",
925
1112
  labelClassName,
@@ -928,7 +1115,7 @@ var NumberField = ({
928
1115
  }) => /* @__PURE__ */ jsxRuntime.jsxs(FormItem, { className: itemClasses(labelPosition, size, className), children: [
929
1116
  /* @__PURE__ */ jsxRuntime.jsx(FieldLabel, { label, badge, size, className: labelClassName }),
930
1117
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: inputWrapper(labelPosition, size), children: [
931
- /* @__PURE__ */ jsxRuntime.jsx(FormControl, { children: /* @__PURE__ */ jsxRuntime.jsx(
1118
+ /* @__PURE__ */ jsxRuntime.jsx(FormControl, { children: min != null && max != null ? /* @__PURE__ */ jsxRuntime.jsx(
932
1119
  SliderNumber,
933
1120
  {
934
1121
  value: typeof value === "number" ? value : 0,
@@ -937,6 +1124,19 @@ var NumberField = ({
937
1124
  max,
938
1125
  step
939
1126
  }
1127
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1128
+ AffixedInput,
1129
+ {
1130
+ type: "number",
1131
+ className: SIZE[size].input,
1132
+ unit,
1133
+ aside,
1134
+ min,
1135
+ max,
1136
+ step,
1137
+ value: typeof value === "number" ? value : "",
1138
+ onChange: (e) => onChange?.(e.target.value === "" ? void 0 : Number(e.target.value))
1139
+ }
940
1140
  ) }),
941
1141
  description && /* @__PURE__ */ jsxRuntime.jsx(FormDescription, { className: SIZE[size].desc, children: description }),
942
1142
  /* @__PURE__ */ jsxRuntime.jsx(FormMessage, { className: SIZE[size].desc })
@@ -960,18 +1160,6 @@ var IconField = ({
960
1160
  /* @__PURE__ */ jsxRuntime.jsx(FormMessage, { className: SIZE[size].desc })
961
1161
  ] })
962
1162
  ] });
963
- var Field = {
964
- Input: InputField,
965
- Password: PasswordField,
966
- Textarea: TextareaField,
967
- Boolean: BooleanField,
968
- Radio: RadioField,
969
- CheckboxGroup: CheckboxGroupField,
970
- Color: ColorField,
971
- Number: NumberField,
972
- Select: SelectField,
973
- Icon: IconField
974
- };
975
1163
  function humanize(name) {
976
1164
  return name.replace(/([A-Z])/g, " $1").replace(/^./, (c) => c.toUpperCase()).trim();
977
1165
  }
@@ -982,6 +1170,7 @@ function renderField(field, parentName, control, labelPosition, size) {
982
1170
  control,
983
1171
  name: `${parentName}.${field.name}`,
984
1172
  defaultValue: field.defaultValue,
1173
+ rules: field.rules,
985
1174
  render: ({ field: rhf }) => {
986
1175
  const common = {
987
1176
  label: field.label ?? humanize(field.name),
@@ -998,6 +1187,8 @@ function renderField(field, parentName, control, labelPosition, size) {
998
1187
  boxed: field.boxed,
999
1188
  labelClassName: field.labelClassName,
1000
1189
  badge: field.badge,
1190
+ unit: field.unit,
1191
+ aside: field.aside,
1001
1192
  labelPosition,
1002
1193
  size,
1003
1194
  value: rhf.value,
@@ -1049,8 +1240,21 @@ function renderField(field, parentName, control, labelPosition, size) {
1049
1240
  field.name
1050
1241
  );
1051
1242
  }
1052
- function renderGrid(fields, parentName, control, labelPosition, size, columns, key) {
1243
+ function renderGrid(fields, parentName, control, labelPosition, size, columns, key, fit = "viewport") {
1053
1244
  const customCols = columns !== 2;
1245
+ if (fit === "container") {
1246
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "@container", children: /* @__PURE__ */ jsxRuntime.jsx(
1247
+ "div",
1248
+ {
1249
+ className: ui.cn(
1250
+ "grid grid-cols-1",
1251
+ SIZE[size].gap,
1252
+ columns > 1 && "@min-[280px]:grid-cols-2 @min-[280px]:[&>*:last-child:nth-child(odd)]:col-span-2"
1253
+ ),
1254
+ children: fields.map((f) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: f.className, children: renderField(f, parentName, control, labelPosition, size) }, f.name))
1255
+ }
1256
+ ) }, key);
1257
+ }
1054
1258
  return /* @__PURE__ */ jsxRuntime.jsx(
1055
1259
  "div",
1056
1260
  {
@@ -1079,9 +1283,9 @@ function renderGrid(fields, parentName, control, labelPosition, size, columns, k
1079
1283
  key
1080
1284
  );
1081
1285
  }
1082
- function renderRows(fields, rowConfig, parentName, control, labelPosition, size, columns) {
1286
+ function renderRows(fields, rowConfig, parentName, control, labelPosition, size, columns, fit = "viewport") {
1083
1287
  if (!rowConfig || rowConfig.length === 0) {
1084
- return renderGrid(fields, parentName, control, labelPosition, size, columns);
1288
+ return renderGrid(fields, parentName, control, labelPosition, size, columns, void 0, fit);
1085
1289
  }
1086
1290
  const used = new Set(rowConfig.flatMap((r) => r.fields));
1087
1291
  const unassigned = fields.filter((f) => !used.has(f.name));
@@ -1097,7 +1301,8 @@ function renderRows(fields, rowConfig, parentName, control, labelPosition, size,
1097
1301
  labelPosition,
1098
1302
  size,
1099
1303
  columns,
1100
- row.id
1304
+ row.id,
1305
+ fit
1101
1306
  );
1102
1307
  }),
1103
1308
  unassigned.length > 0 && renderGrid(
@@ -1107,7 +1312,8 @@ function renderRows(fields, rowConfig, parentName, control, labelPosition, size,
1107
1312
  labelPosition,
1108
1313
  size,
1109
1314
  columns,
1110
- "_unassigned"
1315
+ "_unassigned",
1316
+ fit
1111
1317
  )
1112
1318
  ] });
1113
1319
  }
@@ -1119,7 +1325,9 @@ var ObjectField = ({
1119
1325
  groupConfig,
1120
1326
  labelPosition = "side",
1121
1327
  size = "sm",
1122
- columns = 2
1328
+ columns = 2,
1329
+ fit = "viewport",
1330
+ groupAs = "accordion"
1123
1331
  }) => {
1124
1332
  const grouped = fields.reduce((acc, f) => {
1125
1333
  const key = f.group ?? "_ungrouped";
@@ -1140,9 +1348,14 @@ var ObjectField = ({
1140
1348
  control,
1141
1349
  labelPosition,
1142
1350
  size,
1143
- columns
1351
+ columns,
1352
+ fit
1144
1353
  ) }),
1145
- groupedEntries.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1354
+ groupedEntries.length > 0 && groupAs === "section" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: SIZE[size].section, children: groupedEntries.map(([group, gFields]) => /* @__PURE__ */ jsxRuntime.jsxs("section", { className: SIZE[size].stack, children: [
1355
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Eyebrow, { children: groupConfigById.get(group)?.label ?? humanize(group) }),
1356
+ renderRows(gFields, rowConfig, name, control, labelPosition, size, columns, fit)
1357
+ ] }, group)) }),
1358
+ groupedEntries.length > 0 && groupAs === "accordion" && /* @__PURE__ */ jsxRuntime.jsx(
1146
1359
  ui.Accordion,
1147
1360
  {
1148
1361
  type: "multiple",
@@ -1179,7 +1392,8 @@ var ObjectField = ({
1179
1392
  control,
1180
1393
  labelPosition,
1181
1394
  size,
1182
- columns
1395
+ columns,
1396
+ fit
1183
1397
  ) }) })
1184
1398
  ] }, group);
1185
1399
  })
@@ -1268,7 +1482,7 @@ function FieldGroup({ className, ...props }) {
1268
1482
  }
1269
1483
  );
1270
1484
  }
1271
- classVarianceAuthority.cva(
1485
+ var fieldVariants = classVarianceAuthority.cva(
1272
1486
  "group/field data-[invalid=true]:text-destructive flex w-full gap-3",
1273
1487
  {
1274
1488
  variants: {
@@ -1291,6 +1505,22 @@ classVarianceAuthority.cva(
1291
1505
  }
1292
1506
  }
1293
1507
  );
1508
+ function Field({
1509
+ className,
1510
+ orientation = "vertical",
1511
+ ...props
1512
+ }) {
1513
+ return /* @__PURE__ */ jsxRuntime.jsx(
1514
+ "div",
1515
+ {
1516
+ role: "group",
1517
+ "data-slot": "field",
1518
+ "data-orientation": orientation,
1519
+ className: ui.cn(fieldVariants({ orientation }), className),
1520
+ ...props
1521
+ }
1522
+ );
1523
+ }
1294
1524
  function FieldContent({ className, ...props }) {
1295
1525
  return /* @__PURE__ */ jsxRuntime.jsx(
1296
1526
  "div",
@@ -1493,146 +1723,6 @@ var ParamRow = React2__namespace.forwardRef(
1493
1723
  )
1494
1724
  );
1495
1725
  ParamRow.displayName = "ParamRow";
1496
- function InputGroup({ className, ...props }) {
1497
- return /* @__PURE__ */ jsxRuntime.jsx(
1498
- "div",
1499
- {
1500
- "data-slot": "input-group",
1501
- role: "group",
1502
- className: ui.cn(
1503
- "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]",
1504
- "h-9 has-[>textarea]:h-auto",
1505
- // Variants based on alignment.
1506
- "has-[>[data-align=inline-start]]:[&>input]:pl-2",
1507
- "has-[>[data-align=inline-end]]:[&>input]:pr-2",
1508
- "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
1509
- "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
1510
- // Focus state.
1511
- "has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1",
1512
- // Error state.
1513
- "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",
1514
- className
1515
- ),
1516
- ...props
1517
- }
1518
- );
1519
- }
1520
- var inputGroupAddonVariants = classVarianceAuthority.cva(
1521
- "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",
1522
- {
1523
- variants: {
1524
- align: {
1525
- "inline-start": "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
1526
- "inline-end": "order-last pr-3 has-[>button]:mr-[-0.4rem] has-[>kbd]:mr-[-0.35rem]",
1527
- "block-start": "[.border-b]:pb-3 order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5",
1528
- "block-end": "[.border-t]:pt-3 order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5"
1529
- }
1530
- },
1531
- defaultVariants: {
1532
- align: "inline-start"
1533
- }
1534
- }
1535
- );
1536
- function InputGroupAddon({
1537
- className,
1538
- align = "inline-start",
1539
- ...props
1540
- }) {
1541
- return /* @__PURE__ */ jsxRuntime.jsx(
1542
- "div",
1543
- {
1544
- role: "group",
1545
- "data-slot": "input-group-addon",
1546
- "data-align": align,
1547
- className: ui.cn(inputGroupAddonVariants({ align }), className),
1548
- onClick: (e) => {
1549
- if (e.target.closest("button")) {
1550
- return;
1551
- }
1552
- e.currentTarget.parentElement?.querySelector("input")?.focus();
1553
- },
1554
- ...props
1555
- }
1556
- );
1557
- }
1558
- var inputGroupButtonVariants = classVarianceAuthority.cva(
1559
- "flex items-center gap-2 shadow-none",
1560
- {
1561
- variants: {
1562
- size: {
1563
- xs: "h-6 gap-1 rounded-control px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
1564
- sm: "h-8 gap-1.5 rounded-control px-2.5 has-[>svg]:px-2.5",
1565
- "icon-xs": "size-6 rounded-control p-0 has-[>svg]:p-0",
1566
- "icon-sm": "size-8 p-0 has-[>svg]:p-0"
1567
- }
1568
- },
1569
- defaultVariants: {
1570
- size: "xs"
1571
- }
1572
- }
1573
- );
1574
- function InputGroupButton({
1575
- className,
1576
- type = "button",
1577
- variant = "ghost",
1578
- size = "xs",
1579
- ...props
1580
- }) {
1581
- return /* @__PURE__ */ jsxRuntime.jsx(
1582
- ui.Button,
1583
- {
1584
- type,
1585
- "data-size": size,
1586
- variant,
1587
- className: ui.cn(inputGroupButtonVariants({ size }), className),
1588
- ...props
1589
- }
1590
- );
1591
- }
1592
- function InputGroupText({ className, ...props }) {
1593
- return /* @__PURE__ */ jsxRuntime.jsx(
1594
- "span",
1595
- {
1596
- className: ui.cn(
1597
- "text-muted-foreground flex items-center gap-2 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
1598
- className
1599
- ),
1600
- ...props
1601
- }
1602
- );
1603
- }
1604
- function InputGroupInput({
1605
- className,
1606
- ...props
1607
- }) {
1608
- return /* @__PURE__ */ jsxRuntime.jsx(
1609
- Input,
1610
- {
1611
- "data-slot": "input-group-control",
1612
- className: ui.cn(
1613
- "flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent",
1614
- className
1615
- ),
1616
- ...props
1617
- }
1618
- );
1619
- }
1620
- function InputGroupTextarea({
1621
- className,
1622
- ...props
1623
- }) {
1624
- return /* @__PURE__ */ jsxRuntime.jsx(
1625
- Textarea,
1626
- {
1627
- "data-slot": "input-group-control",
1628
- className: ui.cn(
1629
- "flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent",
1630
- className
1631
- ),
1632
- ...props
1633
- }
1634
- );
1635
- }
1636
1726
 
1637
1727
  exports.BooleanField = BooleanField;
1638
1728
  exports.Checkbox = Checkbox;