@epilot/spark-ui 0.26.0 → 0.27.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.
Files changed (223) hide show
  1. package/dist/components/accordion.cjs.map +1 -1
  2. package/dist/components/accordion.d.cts +1 -1
  3. package/dist/components/accordion.d.ts +1 -1
  4. package/dist/components/accordion.js.map +1 -1
  5. package/dist/components/alert-dialog.cjs +2 -2
  6. package/dist/components/alert-dialog.cjs.map +1 -1
  7. package/dist/components/alert-dialog.js +2 -2
  8. package/dist/components/alert-dialog.js.map +1 -1
  9. package/dist/components/attachment.d.cts +1 -1
  10. package/dist/components/attachment.d.ts +1 -1
  11. package/dist/components/avatar.d.cts +1 -1
  12. package/dist/components/avatar.d.ts +1 -1
  13. package/dist/components/badge.cjs +10 -2
  14. package/dist/components/badge.cjs.map +1 -1
  15. package/dist/components/badge.d.cts +2 -1
  16. package/dist/components/badge.d.ts +2 -1
  17. package/dist/components/badge.js +10 -2
  18. package/dist/components/badge.js.map +1 -1
  19. package/dist/components/banner.d.cts +1 -1
  20. package/dist/components/banner.d.ts +1 -1
  21. package/dist/components/box.d.cts +1 -1
  22. package/dist/components/box.d.ts +1 -1
  23. package/dist/components/bubble.cjs +1 -1
  24. package/dist/components/bubble.cjs.map +1 -1
  25. package/dist/components/bubble.d.cts +1 -1
  26. package/dist/components/bubble.d.ts +1 -1
  27. package/dist/components/bubble.js +1 -1
  28. package/dist/components/bubble.js.map +1 -1
  29. package/dist/components/button-group.d.cts +1 -1
  30. package/dist/components/button-group.d.ts +1 -1
  31. package/dist/components/button.cjs +27 -6
  32. package/dist/components/button.cjs.map +1 -1
  33. package/dist/components/button.d.cts +9 -8
  34. package/dist/components/button.d.ts +9 -8
  35. package/dist/components/button.js +27 -6
  36. package/dist/components/button.js.map +1 -1
  37. package/dist/components/callout.cjs +1 -1
  38. package/dist/components/callout.cjs.map +1 -1
  39. package/dist/components/callout.d.cts +1 -1
  40. package/dist/components/callout.d.ts +1 -1
  41. package/dist/components/callout.js +1 -1
  42. package/dist/components/callout.js.map +1 -1
  43. package/dist/components/card.cjs +8 -4
  44. package/dist/components/card.cjs.map +1 -1
  45. package/dist/components/card.d.cts +6 -2
  46. package/dist/components/card.d.ts +6 -2
  47. package/dist/components/card.js +8 -4
  48. package/dist/components/card.js.map +1 -1
  49. package/dist/components/checkbox-group.cjs +31 -0
  50. package/dist/components/checkbox-group.cjs.map +1 -0
  51. package/dist/components/checkbox-group.d.cts +27 -0
  52. package/dist/components/checkbox-group.d.ts +27 -0
  53. package/dist/components/checkbox-group.js +28 -0
  54. package/dist/components/checkbox-group.js.map +1 -0
  55. package/dist/components/checkbox.d.cts +1 -1
  56. package/dist/components/checkbox.d.ts +1 -1
  57. package/dist/components/dialog.cjs +2 -2
  58. package/dist/components/dialog.cjs.map +1 -1
  59. package/dist/components/dialog.js +2 -2
  60. package/dist/components/dialog.js.map +1 -1
  61. package/dist/components/drawer.cjs +1 -1
  62. package/dist/components/drawer.cjs.map +1 -1
  63. package/dist/components/drawer.js +1 -1
  64. package/dist/components/drawer.js.map +1 -1
  65. package/dist/components/empty-state.cjs +3 -13
  66. package/dist/components/empty-state.cjs.map +1 -1
  67. package/dist/components/empty-state.js +3 -13
  68. package/dist/components/empty-state.js.map +1 -1
  69. package/dist/components/energy-breakdown.cjs +1 -1
  70. package/dist/components/energy-breakdown.cjs.map +1 -1
  71. package/dist/components/energy-breakdown.js +1 -1
  72. package/dist/components/energy-breakdown.js.map +1 -1
  73. package/dist/components/entity-card.cjs +1 -1
  74. package/dist/components/entity-card.cjs.map +1 -1
  75. package/dist/components/entity-card.js +1 -1
  76. package/dist/components/entity-card.js.map +1 -1
  77. package/dist/components/field.cjs +113 -18
  78. package/dist/components/field.cjs.map +1 -1
  79. package/dist/components/field.d.cts +16 -3
  80. package/dist/components/field.d.ts +16 -3
  81. package/dist/components/field.js +114 -20
  82. package/dist/components/field.js.map +1 -1
  83. package/dist/components/input-group.cjs +9 -9
  84. package/dist/components/input-group.cjs.map +1 -1
  85. package/dist/components/input-group.d.cts +1 -1
  86. package/dist/components/input-group.d.ts +1 -1
  87. package/dist/components/input-group.js +9 -9
  88. package/dist/components/input-group.js.map +1 -1
  89. package/dist/components/input.d.cts +1 -1
  90. package/dist/components/input.d.ts +1 -1
  91. package/dist/components/list.cjs +21 -5
  92. package/dist/components/list.cjs.map +1 -1
  93. package/dist/components/list.d.cts +13 -5
  94. package/dist/components/list.d.ts +13 -5
  95. package/dist/components/list.js +21 -5
  96. package/dist/components/list.js.map +1 -1
  97. package/dist/components/marker.cjs +1 -1
  98. package/dist/components/marker.cjs.map +1 -1
  99. package/dist/components/marker.js +1 -1
  100. package/dist/components/marker.js.map +1 -1
  101. package/dist/components/message-scroller.cjs +1 -1
  102. package/dist/components/message-scroller.cjs.map +1 -1
  103. package/dist/components/message-scroller.js +1 -1
  104. package/dist/components/message-scroller.js.map +1 -1
  105. package/dist/components/page-header.d.cts +1 -1
  106. package/dist/components/page-header.d.ts +1 -1
  107. package/dist/components/pill.d.cts +1 -1
  108. package/dist/components/pill.d.ts +1 -1
  109. package/dist/components/radio.cjs +6 -2
  110. package/dist/components/radio.cjs.map +1 -1
  111. package/dist/components/radio.d.cts +4 -2
  112. package/dist/components/radio.d.ts +4 -2
  113. package/dist/components/radio.js +6 -2
  114. package/dist/components/radio.js.map +1 -1
  115. package/dist/components/rating.cjs +167 -0
  116. package/dist/components/rating.cjs.map +1 -0
  117. package/dist/components/rating.d.cts +50 -0
  118. package/dist/components/rating.d.ts +50 -0
  119. package/dist/components/rating.js +162 -0
  120. package/dist/components/rating.js.map +1 -0
  121. package/dist/components/schedule-list.cjs +1 -1
  122. package/dist/components/schedule-list.cjs.map +1 -1
  123. package/dist/components/schedule-list.js +1 -1
  124. package/dist/components/schedule-list.js.map +1 -1
  125. package/dist/components/scroll-area.cjs +9 -2
  126. package/dist/components/scroll-area.cjs.map +1 -1
  127. package/dist/components/scroll-area.d.cts +1 -1
  128. package/dist/components/scroll-area.d.ts +1 -1
  129. package/dist/components/scroll-area.js +10 -3
  130. package/dist/components/scroll-area.js.map +1 -1
  131. package/dist/components/segmented-control.d.cts +1 -1
  132. package/dist/components/segmented-control.d.ts +1 -1
  133. package/dist/components/select.d.cts +1 -1
  134. package/dist/components/select.d.ts +1 -1
  135. package/dist/components/selection-item.cjs +42 -0
  136. package/dist/components/selection-item.cjs.map +1 -0
  137. package/dist/components/selection-item.d.cts +25 -0
  138. package/dist/components/selection-item.d.ts +25 -0
  139. package/dist/components/selection-item.js +39 -0
  140. package/dist/components/selection-item.js.map +1 -0
  141. package/dist/components/sheet.cjs +1 -1
  142. package/dist/components/sheet.js +1 -1
  143. package/dist/components/skeleton.cjs +1 -1
  144. package/dist/components/skeleton.cjs.map +1 -1
  145. package/dist/components/skeleton.js +1 -1
  146. package/dist/components/skeleton.js.map +1 -1
  147. package/dist/components/slider.cjs +1 -1
  148. package/dist/components/slider.cjs.map +1 -1
  149. package/dist/components/slider.js +1 -1
  150. package/dist/components/slider.js.map +1 -1
  151. package/dist/components/spinner.cjs +81 -8
  152. package/dist/components/spinner.cjs.map +1 -1
  153. package/dist/components/spinner.js +81 -8
  154. package/dist/components/spinner.js.map +1 -1
  155. package/dist/components/stat-card.cjs +1 -1
  156. package/dist/components/stat-card.cjs.map +1 -1
  157. package/dist/components/stat-card.js +1 -1
  158. package/dist/components/stat-card.js.map +1 -1
  159. package/dist/components/stepper.cjs +3 -2
  160. package/dist/components/stepper.cjs.map +1 -1
  161. package/dist/components/stepper.js +3 -2
  162. package/dist/components/stepper.js.map +1 -1
  163. package/dist/components/switch-group.cjs +32 -0
  164. package/dist/components/switch-group.cjs.map +1 -0
  165. package/dist/components/switch-group.d.cts +26 -0
  166. package/dist/components/switch-group.d.ts +26 -0
  167. package/dist/components/switch-group.js +29 -0
  168. package/dist/components/switch-group.js.map +1 -0
  169. package/dist/components/switch.d.cts +1 -1
  170. package/dist/components/switch.d.ts +1 -1
  171. package/dist/components/tabs.cjs +32 -23
  172. package/dist/components/tabs.cjs.map +1 -1
  173. package/dist/components/tabs.d.cts +5 -5
  174. package/dist/components/tabs.d.ts +5 -5
  175. package/dist/components/tabs.js +32 -23
  176. package/dist/components/tabs.js.map +1 -1
  177. package/dist/components/textarea.d.cts +1 -1
  178. package/dist/components/textarea.d.ts +1 -1
  179. package/dist/components/theme.cjs +44 -2
  180. package/dist/components/theme.cjs.map +1 -1
  181. package/dist/components/theme.d.cts +4 -2
  182. package/dist/components/theme.d.ts +4 -2
  183. package/dist/components/theme.js +44 -2
  184. package/dist/components/theme.js.map +1 -1
  185. package/dist/components/toast.cjs +2 -2
  186. package/dist/components/toast.cjs.map +1 -1
  187. package/dist/components/toast.js +2 -2
  188. package/dist/components/toast.js.map +1 -1
  189. package/dist/components/toggle-group.d.cts +1 -1
  190. package/dist/components/toggle-group.d.ts +1 -1
  191. package/dist/components/toggle.d.cts +2 -2
  192. package/dist/components/toggle.d.ts +2 -2
  193. package/dist/lib/accent-theme.d.cts +1 -1
  194. package/dist/lib/accent-theme.d.ts +1 -1
  195. package/dist/lib/container-chrome.cjs +4 -4
  196. package/dist/lib/container-chrome.cjs.map +1 -1
  197. package/dist/lib/container-chrome.d.cts +1 -1
  198. package/dist/lib/container-chrome.d.ts +1 -1
  199. package/dist/lib/container-chrome.js +4 -4
  200. package/dist/lib/container-chrome.js.map +1 -1
  201. package/dist/lib/input-box-variants.cjs +8 -8
  202. package/dist/lib/input-box-variants.cjs.map +1 -1
  203. package/dist/lib/input-box-variants.d.cts +1 -1
  204. package/dist/lib/input-box-variants.d.ts +1 -1
  205. package/dist/lib/input-box-variants.js +8 -8
  206. package/dist/lib/input-box-variants.js.map +1 -1
  207. package/dist/lib/selection-list.cjs +17 -0
  208. package/dist/lib/selection-list.cjs.map +1 -0
  209. package/dist/lib/selection-list.d.cts +11 -0
  210. package/dist/lib/selection-list.d.ts +11 -0
  211. package/dist/lib/selection-list.js +15 -0
  212. package/dist/lib/selection-list.js.map +1 -0
  213. package/dist/lib/theme-types.cjs.map +1 -1
  214. package/dist/lib/theme-types.d.cts +2 -2
  215. package/dist/lib/theme-types.d.ts +2 -2
  216. package/dist/lib/theme-types.js.map +1 -1
  217. package/dist/lib/toggle-group-context.d.cts +2 -1
  218. package/dist/lib/toggle-group-context.d.ts +2 -1
  219. package/dist/styles/spark-default.css +12 -1
  220. package/dist/styles/theme.css +98 -0
  221. package/dist/{theme-types-Bn5E15-P.d.ts → theme-types-CKZzOmSa.d.cts} +11 -2
  222. package/dist/{theme-types-Bn5E15-P.d.cts → theme-types-CKZzOmSa.d.ts} +11 -2
  223. package/package.json +1 -1
@@ -2,11 +2,12 @@
2
2
  "use client";
3
3
  import { cn } from "../utils/cn.js";
4
4
  import { useTheme } from "./theme.js";
5
+ import { Callout } from "./callout.js";
5
6
  import { Separator } from "./separator.js";
6
7
  import { Skeleton } from "./skeleton.js";
7
8
  import * as React$1 from "react";
8
9
  import { useId } from "react";
9
- import { jsx, jsxs } from "react/jsx-runtime";
10
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
11
  import { cva } from "class-variance-authority";
11
12
  //#region src/components/field.tsx
12
13
  const FieldContext = React$1.createContext(null);
@@ -33,19 +34,96 @@ function useFieldControl(options) {
33
34
  inputColor
34
35
  };
35
36
  }
36
- function FieldSet({ className, ...props }) {
37
- return /* @__PURE__ */ jsx("fieldset", {
38
- "data-slot": "field-set",
39
- className: cn("flex flex-col gap-[calc(var(--spark-layout-gap)*4)]", className),
40
- ...props
37
+ const FieldSetContext = React$1.createContext(null);
38
+ /** True when the nearest enclosing FieldSet has an error; ignores outer sets. */
39
+ function useFieldSetInvalid() {
40
+ return React$1.useContext(FieldSetContext)?.invalid || void 0;
41
+ }
42
+ function useSlotCount() {
43
+ const [count, setCount] = React$1.useState(0);
44
+ const setHas = React$1.useCallback((has) => setCount((n) => n + (has ? 1 : -1)), []);
45
+ return [count > 0, setHas];
46
+ }
47
+ function FieldSet({ className, indicator, indicatorLabel, "aria-describedby": ariaDescribedByProp, ...props }) {
48
+ const id = useId();
49
+ const [hasDescription, setHasDescription] = useSlotCount();
50
+ const [hasError, setHasError] = useSlotCount();
51
+ const [hasUnlinkedError, setHasUnlinkedError] = useSlotCount();
52
+ const invalid = hasError || hasUnlinkedError;
53
+ const fieldSetId = `field-set-${id}`;
54
+ const descriptionId = `${fieldSetId}-description`;
55
+ const errorId = `${fieldSetId}-error`;
56
+ const value = React$1.useMemo(() => ({
57
+ descriptionId,
58
+ hasDescription,
59
+ setHasDescription,
60
+ errorId,
61
+ hasError,
62
+ setHasError,
63
+ setHasUnlinkedError,
64
+ invalid,
65
+ indicator,
66
+ indicatorLabel
67
+ }), [
68
+ descriptionId,
69
+ hasDescription,
70
+ setHasDescription,
71
+ errorId,
72
+ hasError,
73
+ setHasError,
74
+ setHasUnlinkedError,
75
+ invalid,
76
+ indicator,
77
+ indicatorLabel
78
+ ]);
79
+ const ariaDescribedBy = [
80
+ hasError && errorId,
81
+ hasDescription && descriptionId,
82
+ ariaDescribedByProp
83
+ ].filter(Boolean).join(" ") || void 0;
84
+ return /* @__PURE__ */ jsx(FieldSetContext.Provider, {
85
+ value,
86
+ children: /* @__PURE__ */ jsx("fieldset", {
87
+ "data-slot": "field-set",
88
+ "data-invalid": invalid || void 0,
89
+ "aria-describedby": ariaDescribedBy,
90
+ className: cn("group/field-set flex flex-col gap-[calc(var(--spark-layout-gap)*4)]", className),
91
+ ...props
92
+ })
41
93
  });
42
94
  }
43
- function FieldLegend({ className, variant = "legend", ...props }) {
44
- return /* @__PURE__ */ jsx("legend", {
95
+ function FieldLegend({ className, variant = "legend", children, ...props }) {
96
+ const fieldSet = React$1.useContext(FieldSetContext);
97
+ const indicator = fieldSet?.indicator;
98
+ const indicatorLabel = fieldSet?.indicatorLabel ?? indicator;
99
+ return /* @__PURE__ */ jsxs("legend", {
100
+ "data-invalid": fieldSet?.invalid || void 0,
45
101
  "data-slot": "field-legend",
46
102
  "data-variant": variant,
47
- className: cn("mb-1.5 font-medium text-gray data-[variant=label]:text-sm data-[variant=legend]:text-base", className),
48
- ...props
103
+ className: cn("mb-1.5 font-medium text-gray data-[invalid=true]:text-error-active! data-[variant=label]:text-sm data-[variant=legend]:text-base", className),
104
+ ...props,
105
+ children: [
106
+ children,
107
+ indicator === "required" && /* @__PURE__ */ jsxs(Fragment, { children: [
108
+ " ",
109
+ /* @__PURE__ */ jsx("span", {
110
+ "aria-hidden": "true",
111
+ children: "*"
112
+ }),
113
+ /* @__PURE__ */ jsx("span", {
114
+ className: "sr-only",
115
+ children: indicatorLabel
116
+ })
117
+ ] }),
118
+ indicator === "optional" && /* @__PURE__ */ jsxs(Fragment, { children: [" ", /* @__PURE__ */ jsxs("span", {
119
+ className: "font-normal text-gray-light",
120
+ children: [
121
+ "(",
122
+ indicatorLabel,
123
+ ")"
124
+ ]
125
+ })] })
126
+ ]
49
127
  });
50
128
  }
51
129
  function FieldGroup({ className, ...props }) {
@@ -188,7 +266,7 @@ function Field({ className, children, labelPosition: labelPositionProp, inputSty
188
266
  function FieldContent({ className, ...props }) {
189
267
  return /* @__PURE__ */ jsx("div", {
190
268
  "data-slot": "field-content",
191
- className: cn("flex min-w-0 flex-1 flex-col gap-0.5 leading-snug", className),
269
+ className: cn("flex min-w-0 flex-1 flex-col gap-1 leading-snug", className),
192
270
  ...props
193
271
  });
194
272
  }
@@ -244,7 +322,9 @@ function FieldTitle({ className, ...props }) {
244
322
  }
245
323
  function FieldDescription({ className, id, ...props }) {
246
324
  const field = useFieldContext();
247
- const setHasDescription = field?.setHasDescription;
325
+ const fieldSet = React$1.useContext(FieldSetContext);
326
+ const owner = field ?? fieldSet;
327
+ const setHasDescription = owner?.setHasDescription;
248
328
  React$1.useEffect(() => {
249
329
  if (!setHasDescription) return;
250
330
  setHasDescription(true);
@@ -252,8 +332,8 @@ function FieldDescription({ className, id, ...props }) {
252
332
  }, [setHasDescription]);
253
333
  return /* @__PURE__ */ jsx("div", {
254
334
  "data-slot": "field-description",
255
- id: id ?? field?.descriptionId,
256
- className: cn("mt-0.5 text-sm leading-normal text-gray-light", className),
335
+ id: id ?? owner?.descriptionId,
336
+ className: cn("text-sm leading-normal text-gray-light", className),
257
337
  ...props
258
338
  });
259
339
  }
@@ -272,7 +352,8 @@ function FieldSeparator({ children, className, ...props }) {
272
352
  }
273
353
  function FieldError({ className, children, errors, id, ...props }) {
274
354
  const field = useFieldContext();
275
- const setHasError = field?.setHasError;
355
+ const fieldSet = React$1.useContext(FieldSetContext);
356
+ const setHasError = (field ?? fieldSet)?.setHasError;
276
357
  const content = React$1.useMemo(() => {
277
358
  if (children) return children;
278
359
  if (!errors?.length) return null;
@@ -285,26 +366,39 @@ function FieldError({ className, children, errors, id, ...props }) {
285
366
  }, [children, errors]);
286
367
  const hasContent = Boolean(content);
287
368
  const hasCustomId = id != null;
369
+ const setSetUnlinked = !field ? fieldSet?.setHasUnlinkedError : void 0;
288
370
  React$1.useEffect(() => {
289
- if (!setHasError || !hasContent || hasCustomId) return;
290
- setHasError(true);
291
- return () => setHasError(false);
371
+ if (!hasContent) return;
372
+ const set = hasCustomId ? setSetUnlinked : setHasError;
373
+ if (!set) return;
374
+ set(true);
375
+ return () => set(false);
292
376
  }, [
293
377
  setHasError,
378
+ setSetUnlinked,
294
379
  hasContent,
295
380
  hasCustomId
296
381
  ]);
297
382
  if (!content) return null;
383
+ if (!field && fieldSet) return /* @__PURE__ */ jsx(Callout, {
384
+ variant: "error",
385
+ role: "alert",
386
+ "data-slot": "field-error",
387
+ id: id ?? fieldSet.errorId,
388
+ className,
389
+ ...props,
390
+ children: content
391
+ });
298
392
  return /* @__PURE__ */ jsx("div", {
299
393
  role: "alert",
300
394
  "data-slot": "field-error",
301
395
  id: id ?? field?.errorId,
302
- className: cn("mt-0.5 text-sm font-normal text-error", className),
396
+ className: cn("text-sm font-normal text-error", className),
303
397
  ...props,
304
398
  children: content
305
399
  });
306
400
  }
307
401
  //#endregion
308
- export { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldSkeleton, FieldTitle, FieldValue, useFieldContext, useFieldControl };
402
+ export { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldSkeleton, FieldTitle, FieldValue, useFieldContext, useFieldControl, useFieldSetInvalid };
309
403
 
310
404
  //# sourceMappingURL=field.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"field.js","names":["React"],"sources":["../../src/components/field.tsx"],"sourcesContent":["'use client'\n\nimport { cva } from 'class-variance-authority'\nimport * as React from 'react'\nimport { useId } from 'react'\nimport type {\n SparkInputColor,\n SparkInputStyle,\n SparkLabelPosition,\n} from '../lib/theme-types'\nimport { cn } from '../utils/cn'\nimport { Separator } from './separator'\nimport { Skeleton } from './skeleton'\nimport { useTheme } from './theme'\n\ntype FieldContextValue = {\n id: string\n labelId: string\n descriptionId: string\n hasDescription: boolean\n setHasDescription: (has: boolean) => void\n errorId: string\n hasError: boolean\n setHasError: (has: boolean) => void\n readOnly: boolean\n labelPosition: SparkLabelPosition\n inputStyle: SparkInputStyle\n inputColor: SparkInputColor\n}\n\nconst FieldContext = React.createContext<FieldContextValue | null>(null)\n\nexport function useFieldContext() {\n return React.useContext(FieldContext)\n}\n\n// Field→Theme→default resolution + id/aria-describedby wiring, shared by every\n// control that can sit inside a Field (Input, SelectTrigger, …) so they can't\n// drift on how a style/color/id resolves. `variant` is the control's own\n// per-instance override (already normalized — e.g. Input maps its 'none' to\n// undefined before calling this).\nexport function useFieldControl(options?: {\n id?: string\n ariaDescribedBy?: string\n variant?: SparkInputStyle\n}) {\n const field = useFieldContext()\n const theme = useTheme()\n const id = options?.id ?? field?.id\n const errorId = field?.hasError ? field.errorId : undefined\n const descriptionId = field?.hasDescription ? field.descriptionId : undefined\n // error before hint: the actionable message should be announced first\n const ariaDescribedBy =\n [errorId, descriptionId, options?.ariaDescribedBy]\n .filter(Boolean)\n .join(' ') || undefined\n const inputStyle =\n options?.variant ?? field?.inputStyle ?? theme.inputStyle ?? 'soft'\n const inputColor = field?.inputColor ?? theme.inputColor ?? 'brand'\n const ariaInvalid = field?.hasError || undefined\n return { field, id, ariaDescribedBy, ariaInvalid, inputStyle, inputColor }\n}\n\nfunction FieldSet({ className, ...props }: React.ComponentProps<'fieldset'>) {\n return (\n <fieldset\n data-slot=\"field-set\"\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldLegend({\n className,\n variant = 'legend',\n ...props\n}: React.ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) {\n return (\n <legend\n data-slot=\"field-legend\"\n data-variant={variant}\n className={cn(\n 'mb-1.5 font-medium text-gray data-[variant=label]:text-sm data-[variant=legend]:text-base',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldGroup({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-group\"\n className={cn(\n 'group/field-group flex w-full flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst fieldVariants = cva(\n 'group/field relative flex w-full flex-col data-[invalid=true]:text-error-active',\n {\n variants: {\n labelPosition: {\n // inset puts label + input inside one shell, so the shell IS the input's box —\n // rounded-md tracks Input/Select/etc.'s own control radius, not the container one.\n // focus inside inset is the classic underline cue, not a shell ring\n inset: 'gap-y-1 rounded-md px-4 py-3',\n outset: 'gap-y-2',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n },\n compoundVariants: [\n {\n labelPosition: 'inset',\n inputStyle: 'soft',\n inputColor: 'brand',\n class:\n 'bg-input-base has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-input-base-hover',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'soft',\n inputColor: 'gray',\n class:\n 'bg-base-gray-soft has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-gray-a4',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'surface',\n inputColor: 'brand',\n class: 'border border-input bg-base-accent-surface',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'surface',\n inputColor: 'gray',\n class: 'border border-input-gray bg-base-gray-surface',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class: 'border border-input',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class: 'border border-input-gray',\n },\n // ghost inset = bare label + underlined input; the input carries the line\n {\n labelPosition: 'inset',\n inputStyle: 'ghost',\n class: 'rounded-none px-0',\n },\n // shared inset states: filled shells swap bg, bordered shells swap border\n // invalid hover deepens the error tint instead of falling back to accent\n {\n labelPosition: 'inset',\n inputStyle: ['soft', 'surface'],\n class:\n 'data-[disabled=true]:bg-base-gray-soft data-[invalid=true]:bg-base-error-soft data-[invalid=true]:has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-red-a4',\n },\n {\n labelPosition: 'inset',\n inputStyle: ['surface', 'outlined'],\n class:\n 'data-[disabled=true]:border-input-disabled data-[invalid=true]:border-input-invalid',\n },\n ],\n },\n)\n\ninterface FieldProps extends React.ComponentProps<'div'> {\n labelPosition?: SparkLabelPosition\n inputStyle?: SparkInputStyle\n inputColor?: SparkInputColor\n readOnly?: boolean\n 'data-invalid'?: boolean | 'true' | 'false'\n}\n\nfunction Field({\n className,\n children,\n labelPosition: labelPositionProp,\n inputStyle: inputStyleProp,\n inputColor: inputColorProp,\n readOnly = false,\n 'data-invalid': dataInvalid,\n ...props\n}: FieldProps) {\n const id = useId()\n const [descriptionCount, setDescriptionCount] = React.useState(0)\n const [errorCount, setErrorCount] = React.useState(0)\n // counts, not flags: one slot unmounting must not clear what siblings still need\n const setHasDescription = React.useCallback(\n (has: boolean) => setDescriptionCount((n) => n + (has ? 1 : -1)),\n [],\n )\n const setHasError = React.useCallback(\n (has: boolean) => setErrorCount((n) => n + (has ? 1 : -1)),\n [],\n )\n const hasDescription = descriptionCount > 0\n const hasError = errorCount > 0\n // knobs are structural (they move the label / pick the box carrier), so they\n // resolve here via the <Theme> context; props override per instance\n const theme = useTheme()\n const labelPosition = labelPositionProp ?? theme.labelPosition ?? 'inset'\n const inputStyle = inputStyleProp ?? theme.inputStyle ?? 'soft'\n const inputColor = inputColorProp ?? theme.inputColor ?? 'brand'\n const fieldId = `field-${id}`\n const labelId = `${fieldId}-label`\n const value = React.useMemo<FieldContextValue>(\n () => ({\n id: fieldId,\n labelId,\n descriptionId: `${fieldId}-description`,\n hasDescription,\n setHasDescription,\n errorId: `${fieldId}-error`,\n hasError,\n setHasError,\n readOnly,\n labelPosition,\n inputStyle,\n inputColor,\n }),\n [\n fieldId,\n labelId,\n hasDescription,\n setHasDescription,\n hasError,\n setHasError,\n readOnly,\n labelPosition,\n inputStyle,\n inputColor,\n ],\n )\n\n return (\n <FieldContext.Provider value={value}>\n <div\n role=\"group\"\n data-slot=\"field\"\n data-label-position={labelPosition}\n data-input-style={inputStyle}\n data-input-color={inputColor}\n data-invalid={dataInvalid ?? (hasError || undefined)}\n aria-labelledby={readOnly ? labelId : undefined}\n className={cn(\n fieldVariants({ labelPosition, inputStyle, inputColor }),\n className,\n )}\n {...props}\n >\n {children}\n </div>\n </FieldContext.Provider>\n )\n}\n\nfunction FieldContent({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-content\"\n className={cn(\n 'flex min-w-0 flex-1 flex-col gap-0.5 leading-snug',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst fieldLabelClassName =\n 'text-sm leading-5 font-normal text-gray transition-all group-data-[invalid=true]/field:text-error-active! motion-reduce:transition-none'\n\nfunction FieldLabel({\n className,\n htmlFor,\n srOnly,\n children,\n ...props\n}: React.ComponentProps<'label'> & { srOnly?: boolean }) {\n const field = useFieldContext()\n const classNames = cn(\n // labels stay full-contrast even when disabled — the control itself\n // (dimmed text, gray shell) signals the state\n fieldLabelClassName,\n // visually hidden but kept in the a11y tree (still names + focuses the control)\n srOnly && 'sr-only',\n className,\n )\n\n if (field?.readOnly) {\n return (\n <div data-slot=\"field-label\" id={field.labelId} className={classNames}>\n {children}\n </div>\n )\n }\n\n return (\n <label\n data-slot=\"field-label\"\n className={classNames}\n htmlFor={htmlFor ?? field?.id}\n {...props}\n >\n {children}\n </label>\n )\n}\n\nfunction FieldValue({\n className,\n id,\n title,\n truncate,\n children,\n ...props\n}: React.ComponentProps<'div'> & { truncate?: boolean }) {\n return (\n <div\n data-slot=\"field-value\"\n id={id}\n // truncated string values keep the full text reachable on hover\n title={\n title ??\n (truncate && typeof children === 'string' ? children : undefined)\n }\n className={cn(\n // values are content, not controls — disabled dims but stays ≥4.5:1\n 'min-h-8 w-full text-base text-gray tabular-nums group-data-[disabled=true]/field:opacity-70',\n truncate\n ? 'block truncate leading-8'\n : 'inline-flex items-center wrap-anywhere whitespace-pre-wrap',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction FieldSkeleton({\n className,\n labelClassName,\n valueClassName,\n truncate,\n ...props\n}: React.ComponentProps<'div'> & {\n truncate?: boolean\n labelClassName?: string\n valueClassName?: string\n}) {\n return (\n <div\n data-slot=\"field-skeleton\"\n aria-hidden=\"true\"\n className={cn('flex w-full flex-col gap-y-1', className)}\n {...props}\n >\n <Skeleton\n data-slot=\"field-skeleton-label\"\n className={cn('h-5 w-24', labelClassName)}\n />\n <Skeleton\n data-slot=\"field-skeleton-value\"\n className={cn(\n 'h-8 min-h-8 w-full',\n truncate && 'max-w-full truncate',\n valueClassName,\n )}\n />\n </div>\n )\n}\n\nfunction FieldTitle({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-title\"\n className={cn(\n 'flex w-fit items-center gap-2 text-sm font-medium text-gray',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldDescription({\n className,\n id,\n ...props\n}: React.ComponentProps<'div'>) {\n const field = useFieldContext()\n const setHasDescription = field?.setHasDescription\n\n React.useEffect(() => {\n if (!setHasDescription) return\n setHasDescription(true)\n return () => setHasDescription(false)\n }, [setHasDescription])\n\n return (\n <div\n data-slot=\"field-description\"\n id={id ?? field?.descriptionId}\n className={cn('mt-0.5 text-sm leading-normal text-gray-light', className)}\n {...props}\n />\n )\n}\n\nfunction FieldSeparator({\n children,\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-separator\"\n data-content={!!children}\n className={cn('relative -my-2 h-5 text-sm', className)}\n {...props}\n >\n <Separator className=\"absolute inset-0 top-1/2\" />\n {children && (\n <span\n className=\"relative mx-auto block w-fit bg-(--spark-background) px-2 text-gray-light\"\n data-slot=\"field-separator-content\"\n >\n {children}\n </span>\n )}\n </div>\n )\n}\n\nfunction FieldError({\n className,\n children,\n errors,\n id,\n ...props\n}: React.ComponentProps<'div'> & {\n errors?: Array<{ message?: string } | undefined>\n}) {\n const field = useFieldContext()\n const setHasError = field?.setHasError\n const content = React.useMemo(() => {\n if (children) return children\n if (!errors?.length) return null\n const unique = [\n ...new Map(errors.map((error) => [error?.message, error])).values(),\n ]\n if (unique.length === 1) return unique[0]?.message\n return (\n <ul className=\"ml-4 flex list-disc flex-col gap-1\">\n {unique.map(\n (error) =>\n error?.message && <li key={error.message}>{error.message}</li>,\n )}\n </ul>\n )\n }, [children, errors])\n\n const hasContent = Boolean(content)\n // a custom id means no element carries field.errorId, so don't advertise it\n const hasCustomId = id != null\n\n // must run before the empty-content early return to keep hook order stable\n React.useEffect(() => {\n if (!setHasError || !hasContent || hasCustomId) return\n setHasError(true)\n return () => setHasError(false)\n }, [setHasError, hasContent, hasCustomId])\n\n if (!content) return null\n\n return (\n <div\n role=\"alert\"\n data-slot=\"field-error\"\n id={id ?? field?.errorId}\n className={cn('mt-0.5 text-sm font-normal text-error', className)}\n {...props}\n >\n {content}\n </div>\n )\n}\n\nexport {\n Field,\n FieldContent,\n FieldDescription,\n FieldError,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSeparator,\n FieldSet,\n FieldSkeleton,\n FieldTitle,\n FieldValue,\n}\nexport type { FieldProps }\n"],"mappings":"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"}
1
+ {"version":3,"file":"field.js","names":["React"],"sources":["../../src/components/field.tsx"],"sourcesContent":["'use client'\n\nimport { cva } from 'class-variance-authority'\nimport * as React from 'react'\nimport { useId } from 'react'\nimport type {\n SparkInputColor,\n SparkInputStyle,\n SparkLabelPosition,\n} from '../lib/theme-types'\nimport { cn } from '../utils/cn'\nimport { Callout } from './callout'\nimport { Separator } from './separator'\nimport { Skeleton } from './skeleton'\nimport { useTheme } from './theme'\n\ntype FieldContextValue = {\n id: string\n labelId: string\n descriptionId: string\n hasDescription: boolean\n setHasDescription: (has: boolean) => void\n errorId: string\n hasError: boolean\n setHasError: (has: boolean) => void\n readOnly: boolean\n labelPosition: SparkLabelPosition\n inputStyle: SparkInputStyle\n inputColor: SparkInputColor\n}\n\nconst FieldContext = React.createContext<FieldContextValue | null>(null)\n\nexport function useFieldContext() {\n return React.useContext(FieldContext)\n}\n\n// Field→Theme→default resolution + id/aria-describedby wiring, shared by every\n// control that can sit inside a Field (Input, SelectTrigger, …) so they can't\n// drift on how a style/color/id resolves. `variant` is the control's own\n// per-instance override (already normalized — e.g. Input maps its 'none' to\n// undefined before calling this).\nexport function useFieldControl(options?: {\n id?: string\n ariaDescribedBy?: string\n variant?: SparkInputStyle\n}) {\n const field = useFieldContext()\n const theme = useTheme()\n const id = options?.id ?? field?.id\n const errorId = field?.hasError ? field.errorId : undefined\n const descriptionId = field?.hasDescription ? field.descriptionId : undefined\n // error before hint: the actionable message should be announced first\n const ariaDescribedBy =\n [errorId, descriptionId, options?.ariaDescribedBy]\n .filter(Boolean)\n .join(' ') || undefined\n const inputStyle =\n options?.variant ?? field?.inputStyle ?? theme.inputStyle ?? 'soft'\n const inputColor = field?.inputColor ?? theme.inputColor ?? 'brand'\n const ariaInvalid = field?.hasError || undefined\n return { field, id, ariaDescribedBy, ariaInvalid, inputStyle, inputColor }\n}\n\ntype FieldSetIndicator = 'required' | 'optional'\n\ntype FieldSetContextValue = {\n descriptionId: string\n hasDescription: boolean\n setHasDescription: (has: boolean) => void\n errorId: string\n hasError: boolean\n setHasError: (has: boolean) => void\n /** Marks the set invalid without linking `errorId` (error has a custom id). */\n setHasUnlinkedError: (has: boolean) => void\n invalid: boolean\n indicator?: FieldSetIndicator\n indicatorLabel?: string\n}\n\nconst FieldSetContext = React.createContext<FieldSetContextValue | null>(null)\n\n/** True when the nearest enclosing FieldSet has an error; ignores outer sets. */\nfunction useFieldSetInvalid() {\n return React.useContext(FieldSetContext)?.invalid || undefined\n}\n\nfunction useSlotCount() {\n const [count, setCount] = React.useState(0)\n const setHas = React.useCallback(\n (has: boolean) => setCount((n) => n + (has ? 1 : -1)),\n [],\n )\n return [count > 0, setHas] as const\n}\n\ninterface FieldSetProps extends React.ComponentProps<'fieldset'> {\n /** Marks the legend: `*` plus hidden text, or a visible \"(optional)\". */\n indicator?: FieldSetIndicator\n /** Text for the mark; defaults to `'required'` or `'optional'`. */\n indicatorLabel?: string\n}\n\nfunction FieldSet({\n className,\n indicator,\n indicatorLabel,\n 'aria-describedby': ariaDescribedByProp,\n ...props\n}: FieldSetProps) {\n const id = useId()\n const [hasDescription, setHasDescription] = useSlotCount()\n const [hasError, setHasError] = useSlotCount()\n const [hasUnlinkedError, setHasUnlinkedError] = useSlotCount()\n const invalid = hasError || hasUnlinkedError\n const fieldSetId = `field-set-${id}`\n const descriptionId = `${fieldSetId}-description`\n const errorId = `${fieldSetId}-error`\n const value = React.useMemo<FieldSetContextValue>(\n () => ({\n descriptionId,\n hasDescription,\n setHasDescription,\n errorId,\n hasError,\n setHasError,\n setHasUnlinkedError,\n invalid,\n indicator,\n indicatorLabel,\n }),\n [\n descriptionId,\n hasDescription,\n setHasDescription,\n errorId,\n hasError,\n setHasError,\n setHasUnlinkedError,\n invalid,\n indicator,\n indicatorLabel,\n ],\n )\n const ariaDescribedBy =\n [hasError && errorId, hasDescription && descriptionId, ariaDescribedByProp]\n .filter(Boolean)\n .join(' ') || undefined\n\n return (\n <FieldSetContext.Provider value={value}>\n <fieldset\n data-slot=\"field-set\"\n data-invalid={invalid || undefined}\n aria-describedby={ariaDescribedBy}\n className={cn(\n 'group/field-set flex flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n </FieldSetContext.Provider>\n )\n}\n\nfunction FieldLegend({\n className,\n variant = 'legend',\n children,\n ...props\n}: React.ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) {\n const fieldSet = React.useContext(FieldSetContext)\n const indicator = fieldSet?.indicator\n const indicatorLabel = fieldSet?.indicatorLabel ?? indicator\n return (\n <legend\n data-invalid={fieldSet?.invalid || undefined}\n data-slot=\"field-legend\"\n data-variant={variant}\n className={cn(\n 'mb-1.5 font-medium text-gray data-[invalid=true]:text-error-active! data-[variant=label]:text-sm data-[variant=legend]:text-base',\n className,\n )}\n {...props}\n >\n {children}\n {indicator === 'required' && (\n <>\n {' '}\n <span aria-hidden=\"true\">*</span>\n <span className=\"sr-only\">{indicatorLabel}</span>\n </>\n )}\n {indicator === 'optional' && (\n <>\n {' '}\n <span className=\"font-normal text-gray-light\">\n ({indicatorLabel})\n </span>\n </>\n )}\n </legend>\n )\n}\n\nfunction FieldGroup({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-group\"\n className={cn(\n 'group/field-group flex w-full flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst fieldVariants = cva(\n 'group/field relative flex w-full flex-col data-[invalid=true]:text-error-active',\n {\n variants: {\n labelPosition: {\n // inset puts label + input inside one shell, so the shell IS the input's box —\n // rounded-md tracks Input/Select/etc.'s own control radius, not the container one.\n // focus inside inset is the classic underline cue, not a shell ring\n inset: 'gap-y-1 rounded-md px-4 py-3',\n outset: 'gap-y-2',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n },\n compoundVariants: [\n {\n labelPosition: 'inset',\n inputStyle: 'soft',\n inputColor: 'brand',\n class:\n 'bg-input-base has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-input-base-hover',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'soft',\n inputColor: 'gray',\n class:\n 'bg-base-gray-soft has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-gray-a4',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'surface',\n inputColor: 'brand',\n class: 'border border-input bg-base-accent-surface',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'surface',\n inputColor: 'gray',\n class: 'border border-input-gray bg-base-gray-surface',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class: 'border border-input',\n },\n {\n labelPosition: 'inset',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class: 'border border-input-gray',\n },\n // ghost inset = bare label + underlined input; the input carries the line\n {\n labelPosition: 'inset',\n inputStyle: 'ghost',\n class: 'rounded-none px-0',\n },\n // shared inset states: filled shells swap bg, bordered shells swap border\n // invalid hover deepens the error tint instead of falling back to accent\n {\n labelPosition: 'inset',\n inputStyle: ['soft', 'surface'],\n class:\n 'data-[disabled=true]:bg-base-gray-soft data-[invalid=true]:bg-base-error-soft data-[invalid=true]:has-[:is(input,textarea,[data-slot=select-trigger]):not(:disabled)]:hover:bg-red-a4',\n },\n {\n labelPosition: 'inset',\n inputStyle: ['surface', 'outlined'],\n class:\n 'data-[disabled=true]:border-input-disabled data-[invalid=true]:border-input-invalid',\n },\n ],\n },\n)\n\ninterface FieldProps extends React.ComponentProps<'div'> {\n labelPosition?: SparkLabelPosition\n inputStyle?: SparkInputStyle\n inputColor?: SparkInputColor\n readOnly?: boolean\n 'data-invalid'?: boolean | 'true' | 'false'\n}\n\nfunction Field({\n className,\n children,\n labelPosition: labelPositionProp,\n inputStyle: inputStyleProp,\n inputColor: inputColorProp,\n readOnly = false,\n 'data-invalid': dataInvalid,\n ...props\n}: FieldProps) {\n const id = useId()\n const [descriptionCount, setDescriptionCount] = React.useState(0)\n const [errorCount, setErrorCount] = React.useState(0)\n // counts, not flags: one slot unmounting must not clear what siblings still need\n const setHasDescription = React.useCallback(\n (has: boolean) => setDescriptionCount((n) => n + (has ? 1 : -1)),\n [],\n )\n const setHasError = React.useCallback(\n (has: boolean) => setErrorCount((n) => n + (has ? 1 : -1)),\n [],\n )\n const hasDescription = descriptionCount > 0\n const hasError = errorCount > 0\n // knobs are structural (they move the label / pick the box carrier), so they\n // resolve here via the <Theme> context; props override per instance\n const theme = useTheme()\n const labelPosition = labelPositionProp ?? theme.labelPosition ?? 'inset'\n const inputStyle = inputStyleProp ?? theme.inputStyle ?? 'soft'\n const inputColor = inputColorProp ?? theme.inputColor ?? 'brand'\n const fieldId = `field-${id}`\n const labelId = `${fieldId}-label`\n const value = React.useMemo<FieldContextValue>(\n () => ({\n id: fieldId,\n labelId,\n descriptionId: `${fieldId}-description`,\n hasDescription,\n setHasDescription,\n errorId: `${fieldId}-error`,\n hasError,\n setHasError,\n readOnly,\n labelPosition,\n inputStyle,\n inputColor,\n }),\n [\n fieldId,\n labelId,\n hasDescription,\n setHasDescription,\n hasError,\n setHasError,\n readOnly,\n labelPosition,\n inputStyle,\n inputColor,\n ],\n )\n\n return (\n <FieldContext.Provider value={value}>\n <div\n role=\"group\"\n data-slot=\"field\"\n data-label-position={labelPosition}\n data-input-style={inputStyle}\n data-input-color={inputColor}\n data-invalid={dataInvalid ?? (hasError || undefined)}\n aria-labelledby={readOnly ? labelId : undefined}\n className={cn(\n fieldVariants({ labelPosition, inputStyle, inputColor }),\n className,\n )}\n {...props}\n >\n {children}\n </div>\n </FieldContext.Provider>\n )\n}\n\nfunction FieldContent({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-content\"\n className={cn(\n 'flex min-w-0 flex-1 flex-col gap-1 leading-snug',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst fieldLabelClassName =\n 'text-sm leading-5 font-normal text-gray transition-all group-data-[invalid=true]/field:text-error-active! motion-reduce:transition-none'\n\nfunction FieldLabel({\n className,\n htmlFor,\n srOnly,\n children,\n ...props\n}: React.ComponentProps<'label'> & { srOnly?: boolean }) {\n const field = useFieldContext()\n const classNames = cn(\n // labels stay full-contrast even when disabled — the control itself\n // (dimmed text, gray shell) signals the state\n fieldLabelClassName,\n // visually hidden but kept in the a11y tree (still names + focuses the control)\n srOnly && 'sr-only',\n className,\n )\n\n if (field?.readOnly) {\n return (\n <div data-slot=\"field-label\" id={field.labelId} className={classNames}>\n {children}\n </div>\n )\n }\n\n return (\n <label\n data-slot=\"field-label\"\n className={classNames}\n htmlFor={htmlFor ?? field?.id}\n {...props}\n >\n {children}\n </label>\n )\n}\n\nfunction FieldValue({\n className,\n id,\n title,\n truncate,\n children,\n ...props\n}: React.ComponentProps<'div'> & { truncate?: boolean }) {\n return (\n <div\n data-slot=\"field-value\"\n id={id}\n // truncated string values keep the full text reachable on hover\n title={\n title ??\n (truncate && typeof children === 'string' ? children : undefined)\n }\n className={cn(\n // values are content, not controls — disabled dims but stays ≥4.5:1\n 'min-h-8 w-full text-base text-gray tabular-nums group-data-[disabled=true]/field:opacity-70',\n truncate\n ? 'block truncate leading-8'\n : 'inline-flex items-center wrap-anywhere whitespace-pre-wrap',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction FieldSkeleton({\n className,\n labelClassName,\n valueClassName,\n truncate,\n ...props\n}: React.ComponentProps<'div'> & {\n truncate?: boolean\n labelClassName?: string\n valueClassName?: string\n}) {\n return (\n <div\n data-slot=\"field-skeleton\"\n aria-hidden=\"true\"\n className={cn('flex w-full flex-col gap-y-1', className)}\n {...props}\n >\n <Skeleton\n data-slot=\"field-skeleton-label\"\n className={cn('h-5 w-24', labelClassName)}\n />\n <Skeleton\n data-slot=\"field-skeleton-value\"\n className={cn(\n 'h-8 min-h-8 w-full',\n truncate && 'max-w-full truncate',\n valueClassName,\n )}\n />\n </div>\n )\n}\n\nfunction FieldTitle({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-title\"\n className={cn(\n 'flex w-fit items-center gap-2 text-sm font-medium text-gray',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction FieldDescription({\n className,\n id,\n ...props\n}: React.ComponentProps<'div'>) {\n const field = useFieldContext()\n const fieldSet = React.useContext(FieldSetContext)\n const owner = field ?? fieldSet\n const setHasDescription = owner?.setHasDescription\n\n React.useEffect(() => {\n if (!setHasDescription) return\n setHasDescription(true)\n return () => setHasDescription(false)\n }, [setHasDescription])\n\n return (\n <div\n data-slot=\"field-description\"\n id={id ?? owner?.descriptionId}\n className={cn('text-sm leading-normal text-gray-light', className)}\n {...props}\n />\n )\n}\n\nfunction FieldSeparator({\n children,\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"field-separator\"\n data-content={!!children}\n className={cn('relative -my-2 h-5 text-sm', className)}\n {...props}\n >\n <Separator className=\"absolute inset-0 top-1/2\" />\n {children && (\n <span\n className=\"relative mx-auto block w-fit bg-(--spark-background) px-2 text-gray-light\"\n data-slot=\"field-separator-content\"\n >\n {children}\n </span>\n )}\n </div>\n )\n}\n\nfunction FieldError({\n className,\n children,\n errors,\n id,\n ...props\n}: React.ComponentProps<'div'> & {\n errors?: Array<{ message?: string } | undefined>\n}) {\n const field = useFieldContext()\n const fieldSet = React.useContext(FieldSetContext)\n const owner = field ?? fieldSet\n const setHasError = owner?.setHasError\n const content = React.useMemo(() => {\n if (children) return children\n if (!errors?.length) return null\n const unique = [\n ...new Map(errors.map((error) => [error?.message, error])).values(),\n ]\n if (unique.length === 1) return unique[0]?.message\n return (\n <ul className=\"ml-4 flex list-disc flex-col gap-1\">\n {unique.map(\n (error) =>\n error?.message && <li key={error.message}>{error.message}</li>,\n )}\n </ul>\n )\n }, [children, errors])\n\n const hasContent = Boolean(content)\n // a custom id means no element carries owner.errorId, so don't advertise it\n const hasCustomId = id != null\n const setSetUnlinked = !field ? fieldSet?.setHasUnlinkedError : undefined\n\n // must run before the empty-content early return to keep hook order stable\n React.useEffect(() => {\n if (!hasContent) return\n const set = hasCustomId ? setSetUnlinked : setHasError\n if (!set) return\n set(true)\n return () => set(false)\n }, [setHasError, setSetUnlinked, hasContent, hasCustomId])\n\n if (!content) return null\n\n if (!field && fieldSet) {\n // straight into Callout: CalloutDescription's <p> cannot hold the <ul> above\n return (\n <Callout\n variant=\"error\"\n role=\"alert\"\n data-slot=\"field-error\"\n id={id ?? fieldSet.errorId}\n className={className}\n {...props}\n >\n {content}\n </Callout>\n )\n }\n\n return (\n <div\n role=\"alert\"\n data-slot=\"field-error\"\n id={id ?? field?.errorId}\n className={cn('text-sm font-normal text-error', className)}\n {...props}\n >\n {content}\n </div>\n )\n}\n\nexport {\n useFieldSetInvalid,\n Field,\n FieldContent,\n FieldDescription,\n FieldError,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSeparator,\n FieldSet,\n FieldSkeleton,\n FieldTitle,\n FieldValue,\n}\nexport type { FieldProps, FieldSetProps }\n"],"mappings":"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"}
@@ -11,7 +11,7 @@ let react_jsx_runtime = require("react/jsx-runtime");
11
11
  let class_variance_authority = require("class-variance-authority");
12
12
  let cn = require("cn");
13
13
  //#region src/components/input-group.tsx
14
- const GHOST = "rounded-none border-0 border-b-2 px-0 focus-within:border-b-input-active has-[[data-slot=input][aria-invalid=true]]:border-b-input-invalid has-[[data-slot=input][aria-invalid=true]]:focus-within:border-b-red-a8! group-data-[invalid=true]/field:border-b-input-invalid! group-data-[invalid=true]/field:focus-within:border-b-red-a8!";
14
+ const GHOST = "rounded-none border-0 border-b-2 px-0 has-[:focus-visible]:border-b-input-active has-[[data-slot=input][aria-invalid=true]]:border-b-input-invalid has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:border-b-red-a8! group-data-[invalid=true]/field:border-b-input-invalid! group-data-[invalid=true]/field:has-[:focus-visible]:border-b-red-a8!";
15
15
  const inputGroupVariants = (0, class_variance_authority.cva)("group/input-group relative flex h-10 w-full min-w-0 items-center gap-2 bg-transparent transition-[color,border-color] outline-none motion-reduce:transition-none", {
16
16
  variants: {
17
17
  chrome: {
@@ -33,48 +33,48 @@ const inputGroupVariants = (0, class_variance_authority.cva)("group/input-group
33
33
  {
34
34
  chrome: "box",
35
35
  inputStyle: "soft",
36
- class: "group-data-[invalid=true]/field:bg-base-error-soft focus-within:ring-2 focus-within:ring-offset-2 group-data-[invalid=true]/field:focus-within:ring-red-a8 has-[[data-slot=input][aria-invalid=true]]:bg-base-error-soft has-[[data-slot=input][aria-invalid=true]]:focus-within:ring-red-a8 has-[[data-slot=input][aria-invalid=true]:not(:disabled)]:hover:bg-red-a4 group-data-[invalid=true]/field:has-[input:not(:disabled)]:hover:bg-red-a4"
36
+ class: "group-data-[invalid=true]/field:bg-base-error-soft has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-offset-2 group-data-[invalid=true]/field:has-[:focus-visible]:ring-(--color-error-active) has-[[data-slot=input][aria-invalid=true]]:bg-base-error-soft has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:ring-(--color-error-active) has-[[data-slot=input][aria-invalid=true]:not(:disabled)]:hover:bg-red-a4 group-data-[invalid=true]/field:has-[input:not(:disabled)]:hover:bg-red-a4"
37
37
  },
38
38
  {
39
39
  chrome: "box",
40
40
  inputStyle: "soft",
41
41
  inputColor: "brand",
42
- class: "bg-input-base focus-within:ring-input-active has-[input:not(:disabled)]:hover:bg-input-base-hover"
42
+ class: "bg-input-base has-[:focus-visible]:ring-(--color-focus-root) has-[input:not(:disabled)]:hover:bg-input-base-hover"
43
43
  },
44
44
  {
45
45
  chrome: "box",
46
46
  inputStyle: "soft",
47
47
  inputColor: "gray",
48
- class: "bg-base-gray-soft focus-within:ring-gray-a8 has-[input:not(:disabled)]:hover:bg-gray-a4"
48
+ class: "bg-base-gray-soft has-[:focus-visible]:ring-(--color-focus-root) has-[input:not(:disabled)]:hover:bg-gray-a4"
49
49
  },
50
50
  {
51
51
  chrome: "box",
52
52
  inputStyle: ["surface", "outlined"],
53
- class: "border group-data-[invalid=true]/field:border-input-invalid focus-within:ring-1 group-data-[invalid=true]/field:focus-within:border-input-invalid! group-data-[invalid=true]/field:focus-within:ring-red-a4! has-[[data-slot=input][aria-invalid=true]]:border-input-invalid has-[[data-slot=input][aria-invalid=true]]:focus-within:border-input-invalid! has-[[data-slot=input][aria-invalid=true]]:focus-within:ring-red-a4!"
53
+ class: "border group-data-[invalid=true]/field:border-input-invalid has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-offset-2 group-data-[invalid=true]/field:has-[:focus-visible]:border-input-invalid! group-data-[invalid=true]/field:has-[:focus-visible]:ring-(--color-error-active)! has-[[data-slot=input][aria-invalid=true]]:border-input-invalid has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:border-input-invalid! has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:ring-(--color-error-active)!"
54
54
  },
55
55
  {
56
56
  chrome: "box",
57
57
  inputStyle: "surface",
58
58
  inputColor: "brand",
59
- class: "border-input bg-base-accent-surface focus-within:border-input-active focus-within:ring-spark-a4"
59
+ class: "border-input bg-base-accent-surface has-[:focus-visible]:border-input-active has-[:focus-visible]:ring-(--color-focus-root)"
60
60
  },
61
61
  {
62
62
  chrome: "box",
63
63
  inputStyle: "surface",
64
64
  inputColor: "gray",
65
- class: "border-input-gray bg-base-gray-surface focus-within:border-gray-a8 focus-within:ring-gray-a4"
65
+ class: "border-input-gray bg-base-gray-surface has-[:focus-visible]:border-gray-a8 has-[:focus-visible]:ring-(--color-focus-root)"
66
66
  },
67
67
  {
68
68
  chrome: "box",
69
69
  inputStyle: "outlined",
70
70
  inputColor: "brand",
71
- class: "border-input focus-within:border-input-active focus-within:ring-spark-a4"
71
+ class: "border-input has-[:focus-visible]:border-input-active has-[:focus-visible]:ring-(--color-focus-root)"
72
72
  },
73
73
  {
74
74
  chrome: "box",
75
75
  inputStyle: "outlined",
76
76
  inputColor: "gray",
77
- class: "border-input-gray focus-within:border-gray-a8 focus-within:ring-gray-a4"
77
+ class: "border-input-gray has-[:focus-visible]:border-gray-a8 has-[:focus-visible]:ring-(--color-focus-root)"
78
78
  },
79
79
  {
80
80
  chrome: "box",
@@ -1 +1 @@
1
- {"version":3,"file":"input-group.cjs","names":["useFieldContext","useTheme","React","Input"],"sources":["../../src/components/input-group.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\nimport { useFieldContext } from './field'\nimport { Input, type InputProps } from './input'\nimport { useTheme } from './theme'\n\nconst GHOST =\n 'rounded-none border-0 border-b-2 px-0 focus-within:border-b-input-active has-[[data-slot=input][aria-invalid=true]]:border-b-input-invalid has-[[data-slot=input][aria-invalid=true]]:focus-within:border-b-red-a8! group-data-[invalid=true]/field:border-b-input-invalid! group-data-[invalid=true]/field:focus-within:border-b-red-a8!'\n\nconst inputGroupVariants = cva(\n 'group/input-group relative flex h-10 w-full min-w-0 items-center gap-2 bg-transparent transition-[color,border-color] outline-none motion-reduce:transition-none',\n {\n variants: {\n chrome: {\n // inside an inset field the shell is the box; the group keeps the\n // classic underline (inputs inside stay chrome-less)\n inset: GHOST,\n // h-11 matches the standalone Input box\n box: 'h-11 rounded-md px-3 transition-all motion-reduce:transition-none',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n },\n compoundVariants: [\n {\n chrome: 'box',\n inputStyle: 'soft',\n // invalid hover deepens the error tint instead of the accent hover\n class:\n 'group-data-[invalid=true]/field:bg-base-error-soft focus-within:ring-2 focus-within:ring-offset-2 group-data-[invalid=true]/field:focus-within:ring-red-a8 has-[[data-slot=input][aria-invalid=true]]:bg-base-error-soft has-[[data-slot=input][aria-invalid=true]]:focus-within:ring-red-a8 has-[[data-slot=input][aria-invalid=true]:not(:disabled)]:hover:bg-red-a4 group-data-[invalid=true]/field:has-[input:not(:disabled)]:hover:bg-red-a4',\n },\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'brand',\n class:\n 'bg-input-base focus-within:ring-input-active has-[input:not(:disabled)]:hover:bg-input-base-hover',\n },\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'gray',\n class:\n 'bg-base-gray-soft focus-within:ring-gray-a8 has-[input:not(:disabled)]:hover:bg-gray-a4',\n },\n {\n chrome: 'box',\n inputStyle: ['surface', 'outlined'],\n class:\n 'border group-data-[invalid=true]/field:border-input-invalid focus-within:ring-1 group-data-[invalid=true]/field:focus-within:border-input-invalid! group-data-[invalid=true]/field:focus-within:ring-red-a4! has-[[data-slot=input][aria-invalid=true]]:border-input-invalid has-[[data-slot=input][aria-invalid=true]]:focus-within:border-input-invalid! has-[[data-slot=input][aria-invalid=true]]:focus-within:ring-red-a4!',\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'brand',\n class:\n 'border-input bg-base-accent-surface focus-within:border-input-active focus-within:ring-spark-a4',\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'gray',\n class:\n 'border-input-gray bg-base-gray-surface focus-within:border-gray-a8 focus-within:ring-gray-a4',\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class:\n 'border-input focus-within:border-input-active focus-within:ring-spark-a4',\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class:\n 'border-input-gray focus-within:border-gray-a8 focus-within:ring-gray-a4',\n },\n { chrome: 'box', inputStyle: 'ghost', class: GHOST },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'brand',\n class: 'border-b-input',\n },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'gray',\n class: 'border-b-input-gray',\n },\n { chrome: 'inset', inputColor: 'brand', class: 'border-b-input' },\n { chrome: 'inset', inputColor: 'gray', class: 'border-b-input-gray' },\n ],\n },\n)\n\n// The group carries the box + focus/invalid states; inputs inside are\n// chrome-less (variant=\"none\"). Style follows the enclosing Field's knobs,\n// else the <Theme> input-style/input-color knobs.\nfunction InputGroup({ className, ...props }: React.ComponentProps<'div'>) {\n const field = useFieldContext()\n const theme = useTheme()\n const inputStyle = field?.inputStyle ?? theme.inputStyle ?? 'soft'\n const inputColor = field?.inputColor ?? theme.inputColor ?? 'brand'\n const chrome = field?.labelPosition === 'inset' ? 'inset' : 'box'\n return (\n <div\n data-slot=\"input-group\"\n role=\"group\"\n className={cn(\n inputGroupVariants({ chrome, inputStyle, inputColor }),\n className,\n )}\n {...props}\n />\n )\n}\n\nconst inputGroupAddonVariants = cva(\n 'flex h-auto cursor-text items-center justify-center gap-2 py-2 text-sm font-medium text-gray-light select-none [&_svg:not([class*=size-])]:size-4',\n {\n variants: {\n align: {\n // button addons bring their own inner padding — pull them halfway\n // into the group's px so the visual gap matches the text side\n 'inline-start': 'order-first has-[>button]:-ml-2',\n 'inline-end': 'order-last has-[>button]:-mr-2',\n },\n },\n defaultVariants: {\n align: 'inline-start',\n },\n },\n)\n\nfunction InputGroupAddon({\n className,\n align = 'inline-start',\n ...props\n}: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) {\n return (\n <div\n // chrome, not a control: the click only forwards focus to the input the\n // way a label would, and Tab already reaches that input directly\n role=\"presentation\"\n data-slot=\"input-group-addon\"\n data-align={align}\n className={cn(inputGroupAddonVariants({ align }), className)}\n onClick={(event) => {\n if ((event.target as HTMLElement).closest('button')) return\n event.currentTarget.parentElement?.querySelector('input')?.focus()\n }}\n {...props}\n />\n )\n}\n\nfunction InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n className={cn(\n 'flex items-center gap-2 text-xs text-gray-light [&_svg]:pointer-events-none [&_svg:not([class*=size-])]:size-4',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst InputGroupInput = React.forwardRef<HTMLInputElement, InputProps>(\n function InputGroupInput({ className, ...props }, ref) {\n return (\n <Input\n data-slot=\"input\"\n variant=\"none\"\n className={cn('flex-1', className)}\n ref={ref}\n {...props}\n />\n )\n },\n)\n\nexport { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText }\n"],"mappings":";;;;;;;;;;;;;AASA,MAAM,QACJ;AAEF,MAAM,sBAAA,GAAA,yBAAA,KACJ,oKACA;CACE,UAAU;EACR,QAAQ;GAGN,OAAO;GAEP,KAAK;EACP;EACA,YAAY;GAAE,MAAM;GAAI,SAAS;GAAI,UAAU;GAAI,OAAO;EAAG;EAC7D,YAAY;GAAE,OAAO;GAAI,MAAM;EAAG;CACpC;CACA,kBAAkB;EAChB;GACE,QAAQ;GACR,YAAY;GAEZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY,CAAC,WAAW,UAAU;GAClC,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GAAE,QAAQ;GAAO,YAAY;GAAS,OAAO;EAAM;EACnD;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO;EACT;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO;EACT;EACA;GAAE,QAAQ;GAAS,YAAY;GAAS,OAAO;EAAiB;EAChE;GAAE,QAAQ;GAAS,YAAY;GAAQ,OAAO;EAAsB;CACtE;AACF,CACF;AAKA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,MAAM,QAAQA,yBAAAA,gBAAgB;CAC9B,MAAM,QAAQC,yBAAAA,SAAS;CACvB,MAAM,aAAa,OAAO,cAAc,MAAM,cAAc;CAC5D,MAAM,aAAa,OAAO,cAAc,MAAM,cAAc;CAE5D,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,aAAU;EACV,MAAK;EACL,YAAA,GAAA,GAAA,IACE,mBAAmB;GAAE,QANZ,OAAO,kBAAkB,UAAU,UAAU;GAMzB;GAAY;EAAW,CAAC,GACrD,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,2BAAA,GAAA,yBAAA,KACJ,qJACA;CACE,UAAU,EACR,OAAO;EAGL,gBAAgB;EAChB,cAAc;CAChB,EACF;CACA,iBAAiB,EACf,OAAO,eACT;AACF,CACF;AAEA,SAAS,gBAAgB,EACvB,WACA,QAAQ,gBACR,GAAG,SAC0E;CAC7E,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EAGE,MAAK;EACL,aAAU;EACV,cAAY;EACZ,YAAA,GAAA,GAAA,IAAc,wBAAwB,EAAE,MAAM,CAAC,GAAG,SAAS;EAC3D,UAAU,UAAU;GAClB,IAAK,MAAM,OAAuB,QAAQ,QAAQ,GAAG;GACrD,MAAM,cAAc,eAAe,cAAc,OAAO,GAAG,MAAM;EACnE;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,SAAuC;CAC7E,OACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;EACE,YAAA,GAAA,GAAA,IACE,kHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,kBAAkBC,MAAM,WAC5B,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAAS,KAAK;CACrD,OACE,iBAAA,GAAA,kBAAA,KAACC,yBAAAA,OAAD;EACE,aAAU;EACV,SAAQ;EACR,YAAA,GAAA,GAAA,IAAc,UAAU,SAAS;EAC5B;EACL,GAAI;CACL,CAAA;AAEL,CACF"}
1
+ {"version":3,"file":"input-group.cjs","names":["useFieldContext","useTheme","React","Input"],"sources":["../../src/components/input-group.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\nimport { useFieldContext } from './field'\nimport { Input, type InputProps } from './input'\nimport { useTheme } from './theme'\n\nconst GHOST =\n 'rounded-none border-0 border-b-2 px-0 has-[:focus-visible]:border-b-input-active has-[[data-slot=input][aria-invalid=true]]:border-b-input-invalid has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:border-b-red-a8! group-data-[invalid=true]/field:border-b-input-invalid! group-data-[invalid=true]/field:has-[:focus-visible]:border-b-red-a8!'\n\nconst inputGroupVariants = cva(\n 'group/input-group relative flex h-10 w-full min-w-0 items-center gap-2 bg-transparent transition-[color,border-color] outline-none motion-reduce:transition-none',\n {\n variants: {\n chrome: {\n // inside an inset field the shell is the box; the group keeps the\n // classic underline (inputs inside stay chrome-less)\n inset: GHOST,\n // h-11 matches the standalone Input box\n box: 'h-11 rounded-md px-3 transition-all motion-reduce:transition-none',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n },\n compoundVariants: [\n {\n chrome: 'box',\n inputStyle: 'soft',\n // invalid hover deepens the error tint instead of the accent hover\n class:\n 'group-data-[invalid=true]/field:bg-base-error-soft has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-offset-2 group-data-[invalid=true]/field:has-[:focus-visible]:ring-(--color-error-active) has-[[data-slot=input][aria-invalid=true]]:bg-base-error-soft has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:ring-(--color-error-active) has-[[data-slot=input][aria-invalid=true]:not(:disabled)]:hover:bg-red-a4 group-data-[invalid=true]/field:has-[input:not(:disabled)]:hover:bg-red-a4',\n },\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'brand',\n class:\n 'bg-input-base has-[:focus-visible]:ring-(--color-focus-root) has-[input:not(:disabled)]:hover:bg-input-base-hover',\n },\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'gray',\n class:\n 'bg-base-gray-soft has-[:focus-visible]:ring-(--color-focus-root) has-[input:not(:disabled)]:hover:bg-gray-a4',\n },\n {\n chrome: 'box',\n inputStyle: ['surface', 'outlined'],\n class:\n 'border group-data-[invalid=true]/field:border-input-invalid has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-offset-2 group-data-[invalid=true]/field:has-[:focus-visible]:border-input-invalid! group-data-[invalid=true]/field:has-[:focus-visible]:ring-(--color-error-active)! has-[[data-slot=input][aria-invalid=true]]:border-input-invalid has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:border-input-invalid! has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:ring-(--color-error-active)!',\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'brand',\n class:\n 'border-input bg-base-accent-surface has-[:focus-visible]:border-input-active has-[:focus-visible]:ring-(--color-focus-root)',\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'gray',\n class:\n 'border-input-gray bg-base-gray-surface has-[:focus-visible]:border-gray-a8 has-[:focus-visible]:ring-(--color-focus-root)',\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class:\n 'border-input has-[:focus-visible]:border-input-active has-[:focus-visible]:ring-(--color-focus-root)',\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class:\n 'border-input-gray has-[:focus-visible]:border-gray-a8 has-[:focus-visible]:ring-(--color-focus-root)',\n },\n { chrome: 'box', inputStyle: 'ghost', class: GHOST },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'brand',\n class: 'border-b-input',\n },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'gray',\n class: 'border-b-input-gray',\n },\n { chrome: 'inset', inputColor: 'brand', class: 'border-b-input' },\n { chrome: 'inset', inputColor: 'gray', class: 'border-b-input-gray' },\n ],\n },\n)\n\n// The group carries the box + focus/invalid states; inputs inside are\n// chrome-less (variant=\"none\"). Style follows the enclosing Field's knobs,\n// else the <Theme> input-style/input-color knobs.\nfunction InputGroup({ className, ...props }: React.ComponentProps<'div'>) {\n const field = useFieldContext()\n const theme = useTheme()\n const inputStyle = field?.inputStyle ?? theme.inputStyle ?? 'soft'\n const inputColor = field?.inputColor ?? theme.inputColor ?? 'brand'\n const chrome = field?.labelPosition === 'inset' ? 'inset' : 'box'\n return (\n <div\n data-slot=\"input-group\"\n role=\"group\"\n className={cn(\n inputGroupVariants({ chrome, inputStyle, inputColor }),\n className,\n )}\n {...props}\n />\n )\n}\n\nconst inputGroupAddonVariants = cva(\n 'flex h-auto cursor-text items-center justify-center gap-2 py-2 text-sm font-medium text-gray-light select-none [&_svg:not([class*=size-])]:size-4',\n {\n variants: {\n align: {\n // button addons bring their own inner padding — pull them halfway\n // into the group's px so the visual gap matches the text side\n 'inline-start': 'order-first has-[>button]:-ml-2',\n 'inline-end': 'order-last has-[>button]:-mr-2',\n },\n },\n defaultVariants: {\n align: 'inline-start',\n },\n },\n)\n\nfunction InputGroupAddon({\n className,\n align = 'inline-start',\n ...props\n}: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) {\n return (\n <div\n // chrome, not a control: the click only forwards focus to the input the\n // way a label would, and Tab already reaches that input directly\n role=\"presentation\"\n data-slot=\"input-group-addon\"\n data-align={align}\n className={cn(inputGroupAddonVariants({ align }), className)}\n onClick={(event) => {\n if ((event.target as HTMLElement).closest('button')) return\n event.currentTarget.parentElement?.querySelector('input')?.focus()\n }}\n {...props}\n />\n )\n}\n\nfunction InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n className={cn(\n 'flex items-center gap-2 text-xs text-gray-light [&_svg]:pointer-events-none [&_svg:not([class*=size-])]:size-4',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst InputGroupInput = React.forwardRef<HTMLInputElement, InputProps>(\n function InputGroupInput({ className, ...props }, ref) {\n return (\n <Input\n data-slot=\"input\"\n variant=\"none\"\n className={cn('flex-1', className)}\n ref={ref}\n {...props}\n />\n )\n },\n)\n\nexport { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText }\n"],"mappings":";;;;;;;;;;;;;AASA,MAAM,QACJ;AAEF,MAAM,sBAAA,GAAA,yBAAA,KACJ,oKACA;CACE,UAAU;EACR,QAAQ;GAGN,OAAO;GAEP,KAAK;EACP;EACA,YAAY;GAAE,MAAM;GAAI,SAAS;GAAI,UAAU;GAAI,OAAO;EAAG;EAC7D,YAAY;GAAE,OAAO;GAAI,MAAM;EAAG;CACpC;CACA,kBAAkB;EAChB;GACE,QAAQ;GACR,YAAY;GAEZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY,CAAC,WAAW,UAAU;GAClC,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GAAE,QAAQ;GAAO,YAAY;GAAS,OAAO;EAAM;EACnD;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO;EACT;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO;EACT;EACA;GAAE,QAAQ;GAAS,YAAY;GAAS,OAAO;EAAiB;EAChE;GAAE,QAAQ;GAAS,YAAY;GAAQ,OAAO;EAAsB;CACtE;AACF,CACF;AAKA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,MAAM,QAAQA,yBAAAA,gBAAgB;CAC9B,MAAM,QAAQC,yBAAAA,SAAS;CACvB,MAAM,aAAa,OAAO,cAAc,MAAM,cAAc;CAC5D,MAAM,aAAa,OAAO,cAAc,MAAM,cAAc;CAE5D,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,aAAU;EACV,MAAK;EACL,YAAA,GAAA,GAAA,IACE,mBAAmB;GAAE,QANZ,OAAO,kBAAkB,UAAU,UAAU;GAMzB;GAAY;EAAW,CAAC,GACrD,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,2BAAA,GAAA,yBAAA,KACJ,qJACA;CACE,UAAU,EACR,OAAO;EAGL,gBAAgB;EAChB,cAAc;CAChB,EACF;CACA,iBAAiB,EACf,OAAO,eACT;AACF,CACF;AAEA,SAAS,gBAAgB,EACvB,WACA,QAAQ,gBACR,GAAG,SAC0E;CAC7E,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EAGE,MAAK;EACL,aAAU;EACV,cAAY;EACZ,YAAA,GAAA,GAAA,IAAc,wBAAwB,EAAE,MAAM,CAAC,GAAG,SAAS;EAC3D,UAAU,UAAU;GAClB,IAAK,MAAM,OAAuB,QAAQ,QAAQ,GAAG;GACrD,MAAM,cAAc,eAAe,cAAc,OAAO,GAAG,MAAM;EACnE;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,SAAuC;CAC7E,OACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;EACE,YAAA,GAAA,GAAA,IACE,kHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,kBAAkBC,MAAM,WAC5B,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAAS,KAAK;CACrD,OACE,iBAAA,GAAA,kBAAA,KAACC,yBAAAA,OAAD;EACE,aAAU;EACV,SAAQ;EACR,YAAA,GAAA,GAAA,IAAc,UAAU,SAAS;EAC5B;EACL,GAAI;CACL,CAAA;AAEL,CACF"}
@@ -10,7 +10,7 @@ declare function InputGroup({
10
10
  ...props
11
11
  }: React$1.ComponentProps<'div'>): import("react/jsx-runtime").JSX.Element;
12
12
  declare const inputGroupAddonVariants: (props?: ({
13
- align?: "inline-start" | "inline-end" | null | undefined;
13
+ align?: "inline-end" | "inline-start" | null | undefined;
14
14
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
15
15
  declare function InputGroupAddon({
16
16
  className,
@@ -10,7 +10,7 @@ declare function InputGroup({
10
10
  ...props
11
11
  }: React$1.ComponentProps<'div'>): import("react/jsx-runtime").JSX.Element;
12
12
  declare const inputGroupAddonVariants: (props?: ({
13
- align?: "inline-start" | "inline-end" | null | undefined;
13
+ align?: "inline-end" | "inline-start" | null | undefined;
14
14
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
15
15
  declare function InputGroupAddon({
16
16
  className,
@@ -8,7 +8,7 @@ import * as React$1 from "react";
8
8
  import { jsx } from "react/jsx-runtime";
9
9
  import { cva } from "class-variance-authority";
10
10
  //#region src/components/input-group.tsx
11
- const GHOST = "rounded-none border-0 border-b-2 px-0 focus-within:border-b-input-active has-[[data-slot=input][aria-invalid=true]]:border-b-input-invalid has-[[data-slot=input][aria-invalid=true]]:focus-within:border-b-red-a8! group-data-[invalid=true]/field:border-b-input-invalid! group-data-[invalid=true]/field:focus-within:border-b-red-a8!";
11
+ const GHOST = "rounded-none border-0 border-b-2 px-0 has-[:focus-visible]:border-b-input-active has-[[data-slot=input][aria-invalid=true]]:border-b-input-invalid has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:border-b-red-a8! group-data-[invalid=true]/field:border-b-input-invalid! group-data-[invalid=true]/field:has-[:focus-visible]:border-b-red-a8!";
12
12
  const inputGroupVariants = cva("group/input-group relative flex h-10 w-full min-w-0 items-center gap-2 bg-transparent transition-[color,border-color] outline-none motion-reduce:transition-none", {
13
13
  variants: {
14
14
  chrome: {
@@ -30,48 +30,48 @@ const inputGroupVariants = cva("group/input-group relative flex h-10 w-full min-
30
30
  {
31
31
  chrome: "box",
32
32
  inputStyle: "soft",
33
- class: "group-data-[invalid=true]/field:bg-base-error-soft focus-within:ring-2 focus-within:ring-offset-2 group-data-[invalid=true]/field:focus-within:ring-red-a8 has-[[data-slot=input][aria-invalid=true]]:bg-base-error-soft has-[[data-slot=input][aria-invalid=true]]:focus-within:ring-red-a8 has-[[data-slot=input][aria-invalid=true]:not(:disabled)]:hover:bg-red-a4 group-data-[invalid=true]/field:has-[input:not(:disabled)]:hover:bg-red-a4"
33
+ class: "group-data-[invalid=true]/field:bg-base-error-soft has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-offset-2 group-data-[invalid=true]/field:has-[:focus-visible]:ring-(--color-error-active) has-[[data-slot=input][aria-invalid=true]]:bg-base-error-soft has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:ring-(--color-error-active) has-[[data-slot=input][aria-invalid=true]:not(:disabled)]:hover:bg-red-a4 group-data-[invalid=true]/field:has-[input:not(:disabled)]:hover:bg-red-a4"
34
34
  },
35
35
  {
36
36
  chrome: "box",
37
37
  inputStyle: "soft",
38
38
  inputColor: "brand",
39
- class: "bg-input-base focus-within:ring-input-active has-[input:not(:disabled)]:hover:bg-input-base-hover"
39
+ class: "bg-input-base has-[:focus-visible]:ring-(--color-focus-root) has-[input:not(:disabled)]:hover:bg-input-base-hover"
40
40
  },
41
41
  {
42
42
  chrome: "box",
43
43
  inputStyle: "soft",
44
44
  inputColor: "gray",
45
- class: "bg-base-gray-soft focus-within:ring-gray-a8 has-[input:not(:disabled)]:hover:bg-gray-a4"
45
+ class: "bg-base-gray-soft has-[:focus-visible]:ring-(--color-focus-root) has-[input:not(:disabled)]:hover:bg-gray-a4"
46
46
  },
47
47
  {
48
48
  chrome: "box",
49
49
  inputStyle: ["surface", "outlined"],
50
- class: "border group-data-[invalid=true]/field:border-input-invalid focus-within:ring-1 group-data-[invalid=true]/field:focus-within:border-input-invalid! group-data-[invalid=true]/field:focus-within:ring-red-a4! has-[[data-slot=input][aria-invalid=true]]:border-input-invalid has-[[data-slot=input][aria-invalid=true]]:focus-within:border-input-invalid! has-[[data-slot=input][aria-invalid=true]]:focus-within:ring-red-a4!"
50
+ class: "border group-data-[invalid=true]/field:border-input-invalid has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-offset-2 group-data-[invalid=true]/field:has-[:focus-visible]:border-input-invalid! group-data-[invalid=true]/field:has-[:focus-visible]:ring-(--color-error-active)! has-[[data-slot=input][aria-invalid=true]]:border-input-invalid has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:border-input-invalid! has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:ring-(--color-error-active)!"
51
51
  },
52
52
  {
53
53
  chrome: "box",
54
54
  inputStyle: "surface",
55
55
  inputColor: "brand",
56
- class: "border-input bg-base-accent-surface focus-within:border-input-active focus-within:ring-spark-a4"
56
+ class: "border-input bg-base-accent-surface has-[:focus-visible]:border-input-active has-[:focus-visible]:ring-(--color-focus-root)"
57
57
  },
58
58
  {
59
59
  chrome: "box",
60
60
  inputStyle: "surface",
61
61
  inputColor: "gray",
62
- class: "border-input-gray bg-base-gray-surface focus-within:border-gray-a8 focus-within:ring-gray-a4"
62
+ class: "border-input-gray bg-base-gray-surface has-[:focus-visible]:border-gray-a8 has-[:focus-visible]:ring-(--color-focus-root)"
63
63
  },
64
64
  {
65
65
  chrome: "box",
66
66
  inputStyle: "outlined",
67
67
  inputColor: "brand",
68
- class: "border-input focus-within:border-input-active focus-within:ring-spark-a4"
68
+ class: "border-input has-[:focus-visible]:border-input-active has-[:focus-visible]:ring-(--color-focus-root)"
69
69
  },
70
70
  {
71
71
  chrome: "box",
72
72
  inputStyle: "outlined",
73
73
  inputColor: "gray",
74
- class: "border-input-gray focus-within:border-gray-a8 focus-within:ring-gray-a4"
74
+ class: "border-input-gray has-[:focus-visible]:border-gray-a8 has-[:focus-visible]:ring-(--color-focus-root)"
75
75
  },
76
76
  {
77
77
  chrome: "box",
@@ -1 +1 @@
1
- {"version":3,"file":"input-group.js","names":["React"],"sources":["../../src/components/input-group.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\nimport { useFieldContext } from './field'\nimport { Input, type InputProps } from './input'\nimport { useTheme } from './theme'\n\nconst GHOST =\n 'rounded-none border-0 border-b-2 px-0 focus-within:border-b-input-active has-[[data-slot=input][aria-invalid=true]]:border-b-input-invalid has-[[data-slot=input][aria-invalid=true]]:focus-within:border-b-red-a8! group-data-[invalid=true]/field:border-b-input-invalid! group-data-[invalid=true]/field:focus-within:border-b-red-a8!'\n\nconst inputGroupVariants = cva(\n 'group/input-group relative flex h-10 w-full min-w-0 items-center gap-2 bg-transparent transition-[color,border-color] outline-none motion-reduce:transition-none',\n {\n variants: {\n chrome: {\n // inside an inset field the shell is the box; the group keeps the\n // classic underline (inputs inside stay chrome-less)\n inset: GHOST,\n // h-11 matches the standalone Input box\n box: 'h-11 rounded-md px-3 transition-all motion-reduce:transition-none',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n },\n compoundVariants: [\n {\n chrome: 'box',\n inputStyle: 'soft',\n // invalid hover deepens the error tint instead of the accent hover\n class:\n 'group-data-[invalid=true]/field:bg-base-error-soft focus-within:ring-2 focus-within:ring-offset-2 group-data-[invalid=true]/field:focus-within:ring-red-a8 has-[[data-slot=input][aria-invalid=true]]:bg-base-error-soft has-[[data-slot=input][aria-invalid=true]]:focus-within:ring-red-a8 has-[[data-slot=input][aria-invalid=true]:not(:disabled)]:hover:bg-red-a4 group-data-[invalid=true]/field:has-[input:not(:disabled)]:hover:bg-red-a4',\n },\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'brand',\n class:\n 'bg-input-base focus-within:ring-input-active has-[input:not(:disabled)]:hover:bg-input-base-hover',\n },\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'gray',\n class:\n 'bg-base-gray-soft focus-within:ring-gray-a8 has-[input:not(:disabled)]:hover:bg-gray-a4',\n },\n {\n chrome: 'box',\n inputStyle: ['surface', 'outlined'],\n class:\n 'border group-data-[invalid=true]/field:border-input-invalid focus-within:ring-1 group-data-[invalid=true]/field:focus-within:border-input-invalid! group-data-[invalid=true]/field:focus-within:ring-red-a4! has-[[data-slot=input][aria-invalid=true]]:border-input-invalid has-[[data-slot=input][aria-invalid=true]]:focus-within:border-input-invalid! has-[[data-slot=input][aria-invalid=true]]:focus-within:ring-red-a4!',\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'brand',\n class:\n 'border-input bg-base-accent-surface focus-within:border-input-active focus-within:ring-spark-a4',\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'gray',\n class:\n 'border-input-gray bg-base-gray-surface focus-within:border-gray-a8 focus-within:ring-gray-a4',\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class:\n 'border-input focus-within:border-input-active focus-within:ring-spark-a4',\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class:\n 'border-input-gray focus-within:border-gray-a8 focus-within:ring-gray-a4',\n },\n { chrome: 'box', inputStyle: 'ghost', class: GHOST },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'brand',\n class: 'border-b-input',\n },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'gray',\n class: 'border-b-input-gray',\n },\n { chrome: 'inset', inputColor: 'brand', class: 'border-b-input' },\n { chrome: 'inset', inputColor: 'gray', class: 'border-b-input-gray' },\n ],\n },\n)\n\n// The group carries the box + focus/invalid states; inputs inside are\n// chrome-less (variant=\"none\"). Style follows the enclosing Field's knobs,\n// else the <Theme> input-style/input-color knobs.\nfunction InputGroup({ className, ...props }: React.ComponentProps<'div'>) {\n const field = useFieldContext()\n const theme = useTheme()\n const inputStyle = field?.inputStyle ?? theme.inputStyle ?? 'soft'\n const inputColor = field?.inputColor ?? theme.inputColor ?? 'brand'\n const chrome = field?.labelPosition === 'inset' ? 'inset' : 'box'\n return (\n <div\n data-slot=\"input-group\"\n role=\"group\"\n className={cn(\n inputGroupVariants({ chrome, inputStyle, inputColor }),\n className,\n )}\n {...props}\n />\n )\n}\n\nconst inputGroupAddonVariants = cva(\n 'flex h-auto cursor-text items-center justify-center gap-2 py-2 text-sm font-medium text-gray-light select-none [&_svg:not([class*=size-])]:size-4',\n {\n variants: {\n align: {\n // button addons bring their own inner padding — pull them halfway\n // into the group's px so the visual gap matches the text side\n 'inline-start': 'order-first has-[>button]:-ml-2',\n 'inline-end': 'order-last has-[>button]:-mr-2',\n },\n },\n defaultVariants: {\n align: 'inline-start',\n },\n },\n)\n\nfunction InputGroupAddon({\n className,\n align = 'inline-start',\n ...props\n}: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) {\n return (\n <div\n // chrome, not a control: the click only forwards focus to the input the\n // way a label would, and Tab already reaches that input directly\n role=\"presentation\"\n data-slot=\"input-group-addon\"\n data-align={align}\n className={cn(inputGroupAddonVariants({ align }), className)}\n onClick={(event) => {\n if ((event.target as HTMLElement).closest('button')) return\n event.currentTarget.parentElement?.querySelector('input')?.focus()\n }}\n {...props}\n />\n )\n}\n\nfunction InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n className={cn(\n 'flex items-center gap-2 text-xs text-gray-light [&_svg]:pointer-events-none [&_svg:not([class*=size-])]:size-4',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst InputGroupInput = React.forwardRef<HTMLInputElement, InputProps>(\n function InputGroupInput({ className, ...props }, ref) {\n return (\n <Input\n data-slot=\"input\"\n variant=\"none\"\n className={cn('flex-1', className)}\n ref={ref}\n {...props}\n />\n )\n },\n)\n\nexport { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText }\n"],"mappings":";;;;;;;;;;AASA,MAAM,QACJ;AAEF,MAAM,qBAAqB,IACzB,oKACA;CACE,UAAU;EACR,QAAQ;GAGN,OAAO;GAEP,KAAK;EACP;EACA,YAAY;GAAE,MAAM;GAAI,SAAS;GAAI,UAAU;GAAI,OAAO;EAAG;EAC7D,YAAY;GAAE,OAAO;GAAI,MAAM;EAAG;CACpC;CACA,kBAAkB;EAChB;GACE,QAAQ;GACR,YAAY;GAEZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY,CAAC,WAAW,UAAU;GAClC,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GAAE,QAAQ;GAAO,YAAY;GAAS,OAAO;EAAM;EACnD;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO;EACT;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO;EACT;EACA;GAAE,QAAQ;GAAS,YAAY;GAAS,OAAO;EAAiB;EAChE;GAAE,QAAQ;GAAS,YAAY;GAAQ,OAAO;EAAsB;CACtE;AACF,CACF;AAKA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,QAAQ,SAAS;CACvB,MAAM,aAAa,OAAO,cAAc,MAAM,cAAc;CAC5D,MAAM,aAAa,OAAO,cAAc,MAAM,cAAc;CAE5D,OACE,oBAAC,OAAD;EACE,aAAU;EACV,MAAK;EACL,WAAW,GACT,mBAAmB;GAAE,QANZ,OAAO,kBAAkB,UAAU,UAAU;GAMzB;GAAY;EAAW,CAAC,GACrD,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,IAC9B,qJACA;CACE,UAAU,EACR,OAAO;EAGL,gBAAgB;EAChB,cAAc;CAChB,EACF;CACA,iBAAiB,EACf,OAAO,eACT;AACF,CACF;AAEA,SAAS,gBAAgB,EACvB,WACA,QAAQ,gBACR,GAAG,SAC0E;CAC7E,OACE,oBAAC,OAAD;EAGE,MAAK;EACL,aAAU;EACV,cAAY;EACZ,WAAW,GAAG,wBAAwB,EAAE,MAAM,CAAC,GAAG,SAAS;EAC3D,UAAU,UAAU;GAClB,IAAK,MAAM,OAAuB,QAAQ,QAAQ,GAAG;GACrD,MAAM,cAAc,eAAe,cAAc,OAAO,GAAG,MAAM;EACnE;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,SAAuC;CAC7E,OACE,oBAAC,QAAD;EACE,WAAW,GACT,kHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,kBAAkBA,QAAM,WAC5B,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAAS,KAAK;CACrD,OACE,oBAAC,OAAD;EACE,aAAU;EACV,SAAQ;EACR,WAAW,GAAG,UAAU,SAAS;EAC5B;EACL,GAAI;CACL,CAAA;AAEL,CACF"}
1
+ {"version":3,"file":"input-group.js","names":["React"],"sources":["../../src/components/input-group.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\nimport { useFieldContext } from './field'\nimport { Input, type InputProps } from './input'\nimport { useTheme } from './theme'\n\nconst GHOST =\n 'rounded-none border-0 border-b-2 px-0 has-[:focus-visible]:border-b-input-active has-[[data-slot=input][aria-invalid=true]]:border-b-input-invalid has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:border-b-red-a8! group-data-[invalid=true]/field:border-b-input-invalid! group-data-[invalid=true]/field:has-[:focus-visible]:border-b-red-a8!'\n\nconst inputGroupVariants = cva(\n 'group/input-group relative flex h-10 w-full min-w-0 items-center gap-2 bg-transparent transition-[color,border-color] outline-none motion-reduce:transition-none',\n {\n variants: {\n chrome: {\n // inside an inset field the shell is the box; the group keeps the\n // classic underline (inputs inside stay chrome-less)\n inset: GHOST,\n // h-11 matches the standalone Input box\n box: 'h-11 rounded-md px-3 transition-all motion-reduce:transition-none',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n },\n compoundVariants: [\n {\n chrome: 'box',\n inputStyle: 'soft',\n // invalid hover deepens the error tint instead of the accent hover\n class:\n 'group-data-[invalid=true]/field:bg-base-error-soft has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-offset-2 group-data-[invalid=true]/field:has-[:focus-visible]:ring-(--color-error-active) has-[[data-slot=input][aria-invalid=true]]:bg-base-error-soft has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:ring-(--color-error-active) has-[[data-slot=input][aria-invalid=true]:not(:disabled)]:hover:bg-red-a4 group-data-[invalid=true]/field:has-[input:not(:disabled)]:hover:bg-red-a4',\n },\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'brand',\n class:\n 'bg-input-base has-[:focus-visible]:ring-(--color-focus-root) has-[input:not(:disabled)]:hover:bg-input-base-hover',\n },\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'gray',\n class:\n 'bg-base-gray-soft has-[:focus-visible]:ring-(--color-focus-root) has-[input:not(:disabled)]:hover:bg-gray-a4',\n },\n {\n chrome: 'box',\n inputStyle: ['surface', 'outlined'],\n class:\n 'border group-data-[invalid=true]/field:border-input-invalid has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-offset-2 group-data-[invalid=true]/field:has-[:focus-visible]:border-input-invalid! group-data-[invalid=true]/field:has-[:focus-visible]:ring-(--color-error-active)! has-[[data-slot=input][aria-invalid=true]]:border-input-invalid has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:border-input-invalid! has-[[data-slot=input][aria-invalid=true]]:has-[:focus-visible]:ring-(--color-error-active)!',\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'brand',\n class:\n 'border-input bg-base-accent-surface has-[:focus-visible]:border-input-active has-[:focus-visible]:ring-(--color-focus-root)',\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'gray',\n class:\n 'border-input-gray bg-base-gray-surface has-[:focus-visible]:border-gray-a8 has-[:focus-visible]:ring-(--color-focus-root)',\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class:\n 'border-input has-[:focus-visible]:border-input-active has-[:focus-visible]:ring-(--color-focus-root)',\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class:\n 'border-input-gray has-[:focus-visible]:border-gray-a8 has-[:focus-visible]:ring-(--color-focus-root)',\n },\n { chrome: 'box', inputStyle: 'ghost', class: GHOST },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'brand',\n class: 'border-b-input',\n },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'gray',\n class: 'border-b-input-gray',\n },\n { chrome: 'inset', inputColor: 'brand', class: 'border-b-input' },\n { chrome: 'inset', inputColor: 'gray', class: 'border-b-input-gray' },\n ],\n },\n)\n\n// The group carries the box + focus/invalid states; inputs inside are\n// chrome-less (variant=\"none\"). Style follows the enclosing Field's knobs,\n// else the <Theme> input-style/input-color knobs.\nfunction InputGroup({ className, ...props }: React.ComponentProps<'div'>) {\n const field = useFieldContext()\n const theme = useTheme()\n const inputStyle = field?.inputStyle ?? theme.inputStyle ?? 'soft'\n const inputColor = field?.inputColor ?? theme.inputColor ?? 'brand'\n const chrome = field?.labelPosition === 'inset' ? 'inset' : 'box'\n return (\n <div\n data-slot=\"input-group\"\n role=\"group\"\n className={cn(\n inputGroupVariants({ chrome, inputStyle, inputColor }),\n className,\n )}\n {...props}\n />\n )\n}\n\nconst inputGroupAddonVariants = cva(\n 'flex h-auto cursor-text items-center justify-center gap-2 py-2 text-sm font-medium text-gray-light select-none [&_svg:not([class*=size-])]:size-4',\n {\n variants: {\n align: {\n // button addons bring their own inner padding — pull them halfway\n // into the group's px so the visual gap matches the text side\n 'inline-start': 'order-first has-[>button]:-ml-2',\n 'inline-end': 'order-last has-[>button]:-mr-2',\n },\n },\n defaultVariants: {\n align: 'inline-start',\n },\n },\n)\n\nfunction InputGroupAddon({\n className,\n align = 'inline-start',\n ...props\n}: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) {\n return (\n <div\n // chrome, not a control: the click only forwards focus to the input the\n // way a label would, and Tab already reaches that input directly\n role=\"presentation\"\n data-slot=\"input-group-addon\"\n data-align={align}\n className={cn(inputGroupAddonVariants({ align }), className)}\n onClick={(event) => {\n if ((event.target as HTMLElement).closest('button')) return\n event.currentTarget.parentElement?.querySelector('input')?.focus()\n }}\n {...props}\n />\n )\n}\n\nfunction InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n className={cn(\n 'flex items-center gap-2 text-xs text-gray-light [&_svg]:pointer-events-none [&_svg:not([class*=size-])]:size-4',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst InputGroupInput = React.forwardRef<HTMLInputElement, InputProps>(\n function InputGroupInput({ className, ...props }, ref) {\n return (\n <Input\n data-slot=\"input\"\n variant=\"none\"\n className={cn('flex-1', className)}\n ref={ref}\n {...props}\n />\n )\n },\n)\n\nexport { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText }\n"],"mappings":";;;;;;;;;;AASA,MAAM,QACJ;AAEF,MAAM,qBAAqB,IACzB,oKACA;CACE,UAAU;EACR,QAAQ;GAGN,OAAO;GAEP,KAAK;EACP;EACA,YAAY;GAAE,MAAM;GAAI,SAAS;GAAI,UAAU;GAAI,OAAO;EAAG;EAC7D,YAAY;GAAE,OAAO;GAAI,MAAM;EAAG;CACpC;CACA,kBAAkB;EAChB;GACE,QAAQ;GACR,YAAY;GAEZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY,CAAC,WAAW,UAAU;GAClC,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OACE;EACJ;EACA;GAAE,QAAQ;GAAO,YAAY;GAAS,OAAO;EAAM;EACnD;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO;EACT;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO;EACT;EACA;GAAE,QAAQ;GAAS,YAAY;GAAS,OAAO;EAAiB;EAChE;GAAE,QAAQ;GAAS,YAAY;GAAQ,OAAO;EAAsB;CACtE;AACF,CACF;AAKA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,QAAQ,SAAS;CACvB,MAAM,aAAa,OAAO,cAAc,MAAM,cAAc;CAC5D,MAAM,aAAa,OAAO,cAAc,MAAM,cAAc;CAE5D,OACE,oBAAC,OAAD;EACE,aAAU;EACV,MAAK;EACL,WAAW,GACT,mBAAmB;GAAE,QANZ,OAAO,kBAAkB,UAAU,UAAU;GAMzB;GAAY;EAAW,CAAC,GACrD,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,IAC9B,qJACA;CACE,UAAU,EACR,OAAO;EAGL,gBAAgB;EAChB,cAAc;CAChB,EACF;CACA,iBAAiB,EACf,OAAO,eACT;AACF,CACF;AAEA,SAAS,gBAAgB,EACvB,WACA,QAAQ,gBACR,GAAG,SAC0E;CAC7E,OACE,oBAAC,OAAD;EAGE,MAAK;EACL,aAAU;EACV,cAAY;EACZ,WAAW,GAAG,wBAAwB,EAAE,MAAM,CAAC,GAAG,SAAS;EAC3D,UAAU,UAAU;GAClB,IAAK,MAAM,OAAuB,QAAQ,QAAQ,GAAG;GACrD,MAAM,cAAc,eAAe,cAAc,OAAO,GAAG,MAAM;EACnE;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,SAAuC;CAC7E,OACE,oBAAC,QAAD;EACE,WAAW,GACT,kHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,kBAAkBA,QAAM,WAC5B,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAAS,KAAK;CACrD,OACE,oBAAC,OAAD;EACE,aAAU;EACV,SAAQ;EACR,WAAW,GAAG,UAAU,SAAS;EAC5B;EACL,GAAI;CACL,CAAA;AAEL,CACF"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { a as SparkInputStyle } from "../theme-types-Bn5E15-P.cjs";
3
+ import { l as SparkInputStyle } from "../theme-types-CKZzOmSa.cjs";
4
4
  import * as React$1 from "react";
5
5
 
6
6
  //#region src/components/input.d.ts
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { a as SparkInputStyle } from "../theme-types-Bn5E15-P.js";
3
+ import { l as SparkInputStyle } from "../theme-types-CKZzOmSa.js";
4
4
  import * as React$1 from "react";
5
5
 
6
6
  //#region src/components/input.d.ts