@epilot/spark-ui 0.15.1 → 0.16.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 (150) hide show
  1. package/dist/components/accordion.cjs +4 -4
  2. package/dist/components/accordion.cjs.map +1 -1
  3. package/dist/components/accordion.d.ts +1 -1
  4. package/dist/components/accordion.js +4 -4
  5. package/dist/components/accordion.js.map +1 -1
  6. package/dist/components/attachment.cjs +3 -3
  7. package/dist/components/attachment.cjs.map +1 -1
  8. package/dist/components/attachment.js +3 -3
  9. package/dist/components/attachment.js.map +1 -1
  10. package/dist/components/badge.cjs +1 -1
  11. package/dist/components/badge.cjs.map +1 -1
  12. package/dist/components/badge.js +1 -1
  13. package/dist/components/badge.js.map +1 -1
  14. package/dist/components/bar-chart.js +1 -1
  15. package/dist/components/box.cjs +1 -1
  16. package/dist/components/box.cjs.map +1 -1
  17. package/dist/components/box.d.cts +1 -1
  18. package/dist/components/box.d.ts +1 -1
  19. package/dist/components/box.js +1 -1
  20. package/dist/components/box.js.map +1 -1
  21. package/dist/components/breadcrumbs.cjs +1 -1
  22. package/dist/components/breadcrumbs.cjs.map +1 -1
  23. package/dist/components/breadcrumbs.js +1 -1
  24. package/dist/components/breadcrumbs.js.map +1 -1
  25. package/dist/components/bubble.cjs +1 -1
  26. package/dist/components/bubble.cjs.map +1 -1
  27. package/dist/components/bubble.d.cts +1 -1
  28. package/dist/components/bubble.d.ts +1 -1
  29. package/dist/components/bubble.js +1 -1
  30. package/dist/components/bubble.js.map +1 -1
  31. package/dist/components/button.d.cts +2 -2
  32. package/dist/components/button.d.ts +2 -2
  33. package/dist/components/card.cjs +2 -2
  34. package/dist/components/card.cjs.map +1 -1
  35. package/dist/components/card.d.cts +1 -1
  36. package/dist/components/card.d.ts +1 -1
  37. package/dist/components/card.js +2 -2
  38. package/dist/components/card.js.map +1 -1
  39. package/dist/components/checkbox.cjs +1 -1
  40. package/dist/components/checkbox.cjs.map +1 -1
  41. package/dist/components/checkbox.js +1 -1
  42. package/dist/components/checkbox.js.map +1 -1
  43. package/dist/components/day-of-week-picker.cjs +2 -2
  44. package/dist/components/day-of-week-picker.cjs.map +1 -1
  45. package/dist/components/day-of-week-picker.js +2 -2
  46. package/dist/components/day-of-week-picker.js.map +1 -1
  47. package/dist/components/device-card.cjs +2 -2
  48. package/dist/components/device-card.cjs.map +1 -1
  49. package/dist/components/device-card.js +2 -2
  50. package/dist/components/device-card.js.map +1 -1
  51. package/dist/components/drawer.cjs +1 -1
  52. package/dist/components/drawer.cjs.map +1 -1
  53. package/dist/components/drawer.js +1 -1
  54. package/dist/components/drawer.js.map +1 -1
  55. package/dist/components/dropdown-menu.cjs +4 -4
  56. package/dist/components/dropdown-menu.cjs.map +1 -1
  57. package/dist/components/dropdown-menu.js +4 -4
  58. package/dist/components/dropdown-menu.js.map +1 -1
  59. package/dist/components/empty-state.cjs +1 -1
  60. package/dist/components/empty-state.cjs.map +1 -1
  61. package/dist/components/empty-state.js +1 -1
  62. package/dist/components/empty-state.js.map +1 -1
  63. package/dist/components/feed-in-hero.cjs +1 -1
  64. package/dist/components/feed-in-hero.cjs.map +1 -1
  65. package/dist/components/feed-in-hero.js +1 -1
  66. package/dist/components/feed-in-hero.js.map +1 -1
  67. package/dist/components/field.cjs +43 -8
  68. package/dist/components/field.cjs.map +1 -1
  69. package/dist/components/field.d.cts +7 -0
  70. package/dist/components/field.d.ts +7 -0
  71. package/dist/components/field.js +43 -8
  72. package/dist/components/field.js.map +1 -1
  73. package/dist/components/info-block.cjs +2 -2
  74. package/dist/components/info-block.cjs.map +1 -1
  75. package/dist/components/info-block.d.cts +1 -1
  76. package/dist/components/info-block.d.ts +1 -1
  77. package/dist/components/info-block.js +2 -2
  78. package/dist/components/info-block.js.map +1 -1
  79. package/dist/components/input-group.cjs +1 -1
  80. package/dist/components/input-group.cjs.map +1 -1
  81. package/dist/components/input-group.js +1 -1
  82. package/dist/components/input-group.js.map +1 -1
  83. package/dist/components/input-otp.cjs +3 -2
  84. package/dist/components/input-otp.cjs.map +1 -1
  85. package/dist/components/input-otp.js +3 -2
  86. package/dist/components/input-otp.js.map +1 -1
  87. package/dist/components/input.cjs +3 -2
  88. package/dist/components/input.cjs.map +1 -1
  89. package/dist/components/input.js +3 -2
  90. package/dist/components/input.js.map +1 -1
  91. package/dist/components/line-chart.cjs +1 -1
  92. package/dist/components/line-chart.js +2 -2
  93. package/dist/components/list.cjs +10 -10
  94. package/dist/components/list.cjs.map +1 -1
  95. package/dist/components/list.d.cts +1 -1
  96. package/dist/components/list.d.ts +1 -1
  97. package/dist/components/list.js +10 -10
  98. package/dist/components/list.js.map +1 -1
  99. package/dist/components/marker.d.cts +1 -1
  100. package/dist/components/marker.d.ts +1 -1
  101. package/dist/components/message-scroller.cjs +1 -1
  102. package/dist/components/message-scroller.js +1 -1
  103. package/dist/components/page-header.d.cts +1 -1
  104. package/dist/components/page-header.d.ts +1 -1
  105. package/dist/components/power-history-chart.cjs +1 -1
  106. package/dist/components/power-history-chart.js +2 -2
  107. package/dist/components/power-history.cjs +1 -1
  108. package/dist/components/power-history.js +1 -1
  109. package/dist/components/power-network.cjs +7 -7
  110. package/dist/components/power-network.cjs.map +1 -1
  111. package/dist/components/power-network.js +7 -7
  112. package/dist/components/power-network.js.map +1 -1
  113. package/dist/components/schedule-list.cjs +3 -3
  114. package/dist/components/schedule-list.cjs.map +1 -1
  115. package/dist/components/schedule-list.js +3 -3
  116. package/dist/components/schedule-list.js.map +1 -1
  117. package/dist/components/select.cjs +4 -3
  118. package/dist/components/select.cjs.map +1 -1
  119. package/dist/components/select.js +4 -3
  120. package/dist/components/select.js.map +1 -1
  121. package/dist/components/series-legend.cjs +1 -1
  122. package/dist/components/series-legend.cjs.map +1 -1
  123. package/dist/components/series-legend.js +1 -1
  124. package/dist/components/series-legend.js.map +1 -1
  125. package/dist/components/skeleton.cjs +1 -1
  126. package/dist/components/skeleton.cjs.map +1 -1
  127. package/dist/components/skeleton.js +1 -1
  128. package/dist/components/skeleton.js.map +1 -1
  129. package/dist/components/stat-card.cjs +1 -1
  130. package/dist/components/stat-card.cjs.map +1 -1
  131. package/dist/components/stat-card.js +1 -1
  132. package/dist/components/stat-card.js.map +1 -1
  133. package/dist/components/stepper.cjs +3 -3
  134. package/dist/components/stepper.cjs.map +1 -1
  135. package/dist/components/stepper.js +3 -3
  136. package/dist/components/stepper.js.map +1 -1
  137. package/dist/components/textarea.cjs +3 -2
  138. package/dist/components/textarea.cjs.map +1 -1
  139. package/dist/components/textarea.js +3 -2
  140. package/dist/components/textarea.js.map +1 -1
  141. package/dist/components/time-picker.cjs +1 -1
  142. package/dist/components/time-picker.cjs.map +1 -1
  143. package/dist/components/time-picker.js +1 -1
  144. package/dist/components/time-picker.js.map +1 -1
  145. package/dist/components/toast.cjs +1 -1
  146. package/dist/components/toast.cjs.map +1 -1
  147. package/dist/components/toast.js +1 -1
  148. package/dist/components/toast.js.map +1 -1
  149. package/dist/styles/theme.css +1 -2
  150. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"series-legend.js","names":[],"sources":["../../src/components/series-legend.tsx"],"sourcesContent":["import { cn } from '../utils/cn'\n\nexport interface SeriesLegendItem {\n id: string\n label: string\n /** CSS color value applied inline (e.g. `var(--orange-a9)` or `#f00`). */\n color: string\n /** Swatch shape: `dot` (default) for bar/area series, `dashed-line` for line overlays. */\n marker?: 'dot' | 'dashed-line'\n}\n\ninterface SeriesLegendProps {\n items: SeriesLegendItem[]\n hiddenIds: ReadonlySet<string>\n onToggle: (id: string) => void\n className?: string\n /** Accessible label announced for the legend group. */\n ariaLabel?: string\n}\n\nexport function SeriesLegend({\n ariaLabel = 'Filter data series',\n className,\n hiddenIds,\n items,\n onToggle,\n}: SeriesLegendProps) {\n return (\n <div\n role=\"group\"\n aria-label={ariaLabel}\n className={cn('flex flex-wrap gap-x-4 gap-y-1.5', className)}\n >\n {items.map((item) => {\n const hidden = hiddenIds.has(item.id)\n return (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => onToggle(item.id)}\n aria-pressed={!hidden}\n aria-label={`${item.label}, ${hidden ? 'hidden' : 'shown'}`}\n className={cn(\n 'flex cursor-pointer items-center gap-1.5 rounded-sm text-xs text-gray-light transition-opacity hover:text-gray focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden',\n hidden && 'opacity-40',\n )}\n >\n {item.marker === 'dashed-line' ? (\n <span\n aria-hidden=\"true\"\n className=\"w-3 shrink-0 border-t-2 border-dashed\"\n style={{ borderColor: item.color }}\n />\n ) : (\n <span\n aria-hidden=\"true\"\n className=\"size-2.5 shrink-0 rounded-circle\"\n style={{ backgroundColor: item.color }}\n />\n )}\n <span className={cn(hidden && 'line-through')}>{item.label}</span>\n </button>\n )\n })}\n </div>\n )\n}\n"],"mappings":";;;;AAoBA,SAAgB,aAAa,EAC3B,YAAY,sBACZ,WACA,WACA,OACA,YACoB;CACpB,OACE,oBAAC,OAAD;EACE,MAAK;EACL,cAAY;EACZ,WAAW,GAAG,oCAAoC,SAAS;YAE1D,MAAM,KAAK,SAAS;GACnB,MAAM,SAAS,UAAU,IAAI,KAAK,EAAE;GACpC,OACE,qBAAC,UAAD;IAEE,MAAK;IACL,eAAe,SAAS,KAAK,EAAE;IAC/B,gBAAc,CAAC;IACf,cAAY,GAAG,KAAK,MAAM,IAAI,SAAS,WAAW;IAClD,WAAW,GACT,gMACA,UAAU,YACZ;cATF,CAWG,KAAK,WAAW,gBACf,oBAAC,QAAD;KACE,eAAY;KACZ,WAAU;KACV,OAAO,EAAE,aAAa,KAAK,MAAM;IAClC,CAAA,IAED,oBAAC,QAAD;KACE,eAAY;KACZ,WAAU;KACV,OAAO,EAAE,iBAAiB,KAAK,MAAM;IACtC,CAAA,GAEH,oBAAC,QAAD;KAAM,WAAW,GAAG,UAAU,cAAc;eAAI,KAAK;IAAY,CAAA,CAC3D;MAxBD,KAAK,EAwBJ;EAEZ,CAAC;CACE,CAAA;AAET"}
1
+ {"version":3,"file":"series-legend.js","names":[],"sources":["../../src/components/series-legend.tsx"],"sourcesContent":["import { cn } from '../utils/cn'\n\nexport interface SeriesLegendItem {\n id: string\n label: string\n /** CSS color value applied inline (e.g. `var(--orange-a9)` or `#f00`). */\n color: string\n /** Swatch shape: `dot` (default) for bar/area series, `dashed-line` for line overlays. */\n marker?: 'dot' | 'dashed-line'\n}\n\ninterface SeriesLegendProps {\n items: SeriesLegendItem[]\n hiddenIds: ReadonlySet<string>\n onToggle: (id: string) => void\n className?: string\n /** Accessible label announced for the legend group. */\n ariaLabel?: string\n}\n\nexport function SeriesLegend({\n ariaLabel = 'Filter data series',\n className,\n hiddenIds,\n items,\n onToggle,\n}: SeriesLegendProps) {\n return (\n <div\n role=\"group\"\n aria-label={ariaLabel}\n className={cn('flex flex-wrap gap-x-4 gap-y-1.5', className)}\n >\n {items.map((item) => {\n const hidden = hiddenIds.has(item.id)\n return (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => onToggle(item.id)}\n aria-pressed={!hidden}\n aria-label={`${item.label}, ${hidden ? 'hidden' : 'shown'}`}\n className={cn(\n 'flex cursor-pointer items-center gap-1.5 rounded-sm text-xs text-gray-light transition-opacity hover:text-gray focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden',\n hidden && 'opacity-40',\n )}\n >\n {item.marker === 'dashed-line' ? (\n <span\n aria-hidden=\"true\"\n className=\"w-3 shrink-0 border-t-2 border-dashed\"\n style={{ borderColor: item.color }}\n />\n ) : (\n <span\n aria-hidden=\"true\"\n className=\"size-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: item.color }}\n />\n )}\n <span className={cn(hidden && 'line-through')}>{item.label}</span>\n </button>\n )\n })}\n </div>\n )\n}\n"],"mappings":";;;;AAoBA,SAAgB,aAAa,EAC3B,YAAY,sBACZ,WACA,WACA,OACA,YACoB;CACpB,OACE,oBAAC,OAAD;EACE,MAAK;EACL,cAAY;EACZ,WAAW,GAAG,oCAAoC,SAAS;YAE1D,MAAM,KAAK,SAAS;GACnB,MAAM,SAAS,UAAU,IAAI,KAAK,EAAE;GACpC,OACE,qBAAC,UAAD;IAEE,MAAK;IACL,eAAe,SAAS,KAAK,EAAE;IAC/B,gBAAc,CAAC;IACf,cAAY,GAAG,KAAK,MAAM,IAAI,SAAS,WAAW;IAClD,WAAW,GACT,gMACA,UAAU,YACZ;cATF,CAWG,KAAK,WAAW,gBACf,oBAAC,QAAD;KACE,eAAY;KACZ,WAAU;KACV,OAAO,EAAE,aAAa,KAAK,MAAM;IAClC,CAAA,IAED,oBAAC,QAAD;KACE,eAAY;KACZ,WAAU;KACV,OAAO,EAAE,iBAAiB,KAAK,MAAM;IACtC,CAAA,GAEH,oBAAC,QAAD;KAAM,WAAW,GAAG,UAAU,cAAc;eAAI,KAAK;IAAY,CAAA,CAC3D;MAxBD,KAAK,EAwBJ;EAEZ,CAAC;CACE,CAAA;AAET"}
@@ -11,7 +11,7 @@ function Skeleton({ className = "", ...props }) {
11
11
  }
12
12
  function CardSkeleton({ children, className = "", padding = "p-4", ...props }) {
13
13
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14
- className: (0, cnfast.cn)("flex flex-col rounded-2xl border border-gray", padding, className),
14
+ className: (0, cnfast.cn)("flex flex-col rounded-lg border border-gray", padding, className),
15
15
  ...props,
16
16
  children
17
17
  });
@@ -1 +1 @@
1
- {"version":3,"file":"skeleton.cjs","names":[],"sources":["../../src/components/skeleton.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../utils/cn'\n\ntype SkeletonProps = HTMLAttributes<HTMLDivElement>\n\nexport function Skeleton({ className = '', ...props }: SkeletonProps) {\n return (\n <div\n className={cn(\n 'animate-pulse rounded-md bg-base-gray-soft motion-reduce:animate-none',\n className,\n )}\n {...props}\n />\n )\n}\n\ninterface CardSkeletonProps extends HTMLAttributes<HTMLDivElement> {\n children?: ReactNode\n padding?: 'p-3' | 'p-4'\n}\n\nexport function CardSkeleton({\n children,\n className = '',\n padding = 'p-4',\n ...props\n}: CardSkeletonProps) {\n return (\n <div\n className={cn(\n 'flex flex-col rounded-2xl border border-gray',\n padding,\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\n"],"mappings":";;;;;AAKA,SAAgB,SAAS,EAAE,YAAY,IAAI,GAAG,SAAwB;CACpE,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,OAAA,IACE,yEACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAOA,SAAgB,aAAa,EAC3B,UACA,YAAY,IACZ,UAAU,OACV,GAAG,SACiB;CACpB,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,OAAA,IACE,gDACA,SACA,SACF;EACA,GAAI;EAEH;CACE,CAAA;AAET"}
1
+ {"version":3,"file":"skeleton.cjs","names":[],"sources":["../../src/components/skeleton.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../utils/cn'\n\ntype SkeletonProps = HTMLAttributes<HTMLDivElement>\n\nexport function Skeleton({ className = '', ...props }: SkeletonProps) {\n return (\n <div\n className={cn(\n 'animate-pulse rounded-md bg-base-gray-soft motion-reduce:animate-none',\n className,\n )}\n {...props}\n />\n )\n}\n\ninterface CardSkeletonProps extends HTMLAttributes<HTMLDivElement> {\n children?: ReactNode\n padding?: 'p-3' | 'p-4'\n}\n\nexport function CardSkeleton({\n children,\n className = '',\n padding = 'p-4',\n ...props\n}: CardSkeletonProps) {\n return (\n <div\n className={cn(\n 'flex flex-col rounded-lg border border-gray',\n padding,\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\n"],"mappings":";;;;;AAKA,SAAgB,SAAS,EAAE,YAAY,IAAI,GAAG,SAAwB;CACpE,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,OAAA,IACE,yEACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAOA,SAAgB,aAAa,EAC3B,UACA,YAAY,IACZ,UAAU,OACV,GAAG,SACiB;CACpB,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,OAAA,IACE,+CACA,SACA,SACF;EACA,GAAI;EAEH;CACE,CAAA;AAET"}
@@ -10,7 +10,7 @@ function Skeleton({ className = "", ...props }) {
10
10
  }
11
11
  function CardSkeleton({ children, className = "", padding = "p-4", ...props }) {
12
12
  return /* @__PURE__ */ jsx("div", {
13
- className: cn("flex flex-col rounded-2xl border border-gray", padding, className),
13
+ className: cn("flex flex-col rounded-lg border border-gray", padding, className),
14
14
  ...props,
15
15
  children
16
16
  });
@@ -1 +1 @@
1
- {"version":3,"file":"skeleton.js","names":[],"sources":["../../src/components/skeleton.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../utils/cn'\n\ntype SkeletonProps = HTMLAttributes<HTMLDivElement>\n\nexport function Skeleton({ className = '', ...props }: SkeletonProps) {\n return (\n <div\n className={cn(\n 'animate-pulse rounded-md bg-base-gray-soft motion-reduce:animate-none',\n className,\n )}\n {...props}\n />\n )\n}\n\ninterface CardSkeletonProps extends HTMLAttributes<HTMLDivElement> {\n children?: ReactNode\n padding?: 'p-3' | 'p-4'\n}\n\nexport function CardSkeleton({\n children,\n className = '',\n padding = 'p-4',\n ...props\n}: CardSkeletonProps) {\n return (\n <div\n className={cn(\n 'flex flex-col rounded-2xl border border-gray',\n padding,\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\n"],"mappings":";;;;AAKA,SAAgB,SAAS,EAAE,YAAY,IAAI,GAAG,SAAwB;CACpE,OACE,oBAAC,OAAD;EACE,WAAW,GACT,yEACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAOA,SAAgB,aAAa,EAC3B,UACA,YAAY,IACZ,UAAU,OACV,GAAG,SACiB;CACpB,OACE,oBAAC,OAAD;EACE,WAAW,GACT,gDACA,SACA,SACF;EACA,GAAI;EAEH;CACE,CAAA;AAET"}
1
+ {"version":3,"file":"skeleton.js","names":[],"sources":["../../src/components/skeleton.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../utils/cn'\n\ntype SkeletonProps = HTMLAttributes<HTMLDivElement>\n\nexport function Skeleton({ className = '', ...props }: SkeletonProps) {\n return (\n <div\n className={cn(\n 'animate-pulse rounded-md bg-base-gray-soft motion-reduce:animate-none',\n className,\n )}\n {...props}\n />\n )\n}\n\ninterface CardSkeletonProps extends HTMLAttributes<HTMLDivElement> {\n children?: ReactNode\n padding?: 'p-3' | 'p-4'\n}\n\nexport function CardSkeleton({\n children,\n className = '',\n padding = 'p-4',\n ...props\n}: CardSkeletonProps) {\n return (\n <div\n className={cn(\n 'flex flex-col rounded-lg border border-gray',\n padding,\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\n"],"mappings":";;;;AAKA,SAAgB,SAAS,EAAE,YAAY,IAAI,GAAG,SAAwB;CACpE,OACE,oBAAC,OAAD;EACE,WAAW,GACT,yEACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAOA,SAAgB,aAAa,EAC3B,UACA,YAAY,IACZ,UAAU,OACV,GAAG,SACiB;CACpB,OACE,oBAAC,OAAD;EACE,WAAW,GACT,+CACA,SACA,SACF;EACA,GAAI;EAEH;CACE,CAAA;AAET"}
@@ -41,7 +41,7 @@ const StatCardSecondaryValue = ({ className, ...rest }) => {
41
41
  };
42
42
  const StatCardIcon = ({ className, ...rest }) => {
43
43
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
44
- className: (0, cnfast.cn)(`flex size-10 shrink-0 items-center justify-center rounded-xl`, className),
44
+ className: (0, cnfast.cn)("flex size-10 shrink-0 items-center justify-center rounded-[max(var(--spark-rounded-md),var(--spark-rounded-full))]", className),
45
45
  ...rest
46
46
  });
47
47
  };
@@ -1 +1 @@
1
- {"version":3,"file":"stat-card.cjs","names":[],"sources":["../../src/components/stat-card.tsx"],"sourcesContent":["import { cn } from '../utils/cn'\n\nconst StatCardContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex w-full flex-col gap-3 p-4 text-left', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardLabel = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-xs font-medium text-gray-light', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardContent = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex items-end justify-between gap-px', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardValueContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return <div className={cn('flex flex-col gap-0.5', className)} {...rest} />\n}\n\nconst StatCardValue = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-lg font-bold text-gray tabular-nums', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardSecondaryValue = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return <span className={cn('text-xs text-gray-light', className)} {...rest} />\n}\n\nconst StatCardIcon = ({ className, ...rest }: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn(\n `flex size-10 shrink-0 items-center justify-center rounded-xl`,\n className,\n )}\n {...rest}\n />\n )\n}\n\nexport {\n StatCardContainer,\n StatCardLabel,\n StatCardContent,\n StatCardValueContainer,\n StatCardValue,\n StatCardSecondaryValue,\n StatCardIcon,\n}\n"],"mappings":";;;;;AAEA,MAAM,qBAAqB,EACzB,WACA,GAAG,WAC8B;CACjC,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,OAAA,IAAc,4CAA4C,SAAS;EACnE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,iBAAiB,EACrB,WACA,GAAG,WAC+B;CAClC,OACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;EACE,YAAA,GAAA,OAAA,IAAc,uCAAuC,SAAS;EAC9D,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,mBAAmB,EACvB,WACA,GAAG,WAC8B;CACjC,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,OAAA,IAAc,yCAAyC,SAAS;EAChE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,EAC9B,WACA,GAAG,WAC8B;CACjC,OAAO,iBAAA,GAAA,kBAAA,KAAC,OAAD;EAAK,YAAA,GAAA,OAAA,IAAc,yBAAyB,SAAS;EAAG,GAAI;CAAO,CAAA;AAC5E;AAEA,MAAM,iBAAiB,EACrB,WACA,GAAG,WAC+B;CAClC,OACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;EACE,YAAA,GAAA,OAAA,IAAc,4CAA4C,SAAS;EACnE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,EAC9B,WACA,GAAG,WAC+B;CAClC,OAAO,iBAAA,GAAA,kBAAA,KAAC,QAAD;EAAM,YAAA,GAAA,OAAA,IAAc,2BAA2B,SAAS;EAAG,GAAI;CAAO,CAAA;AAC/E;AAEA,MAAM,gBAAgB,EAAE,WAAW,GAAG,WAAwC;CAC5E,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,OAAA,IACE,gEACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
1
+ {"version":3,"file":"stat-card.cjs","names":[],"sources":["../../src/components/stat-card.tsx"],"sourcesContent":["import { cn } from '../utils/cn'\n\nconst StatCardContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex w-full flex-col gap-3 p-4 text-left', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardLabel = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-xs font-medium text-gray-light', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardContent = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex items-end justify-between gap-px', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardValueContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return <div className={cn('flex flex-col gap-0.5', className)} {...rest} />\n}\n\nconst StatCardValue = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-lg font-bold text-gray tabular-nums', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardSecondaryValue = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return <span className={cn('text-xs text-gray-light', className)} {...rest} />\n}\n\nconst StatCardIcon = ({ className, ...rest }: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn(\n // max() pill escape (matches Icon): a tile stays rounded-md at low Roundness but\n // becomes a circle at large/full, same as it did pre-harmonization via clamping.\n 'flex size-10 shrink-0 items-center justify-center rounded-[max(var(--spark-rounded-md),var(--spark-rounded-full))]',\n className,\n )}\n {...rest}\n />\n )\n}\n\nexport {\n StatCardContainer,\n StatCardLabel,\n StatCardContent,\n StatCardValueContainer,\n StatCardValue,\n StatCardSecondaryValue,\n StatCardIcon,\n}\n"],"mappings":";;;;;AAEA,MAAM,qBAAqB,EACzB,WACA,GAAG,WAC8B;CACjC,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,OAAA,IAAc,4CAA4C,SAAS;EACnE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,iBAAiB,EACrB,WACA,GAAG,WAC+B;CAClC,OACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;EACE,YAAA,GAAA,OAAA,IAAc,uCAAuC,SAAS;EAC9D,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,mBAAmB,EACvB,WACA,GAAG,WAC8B;CACjC,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,OAAA,IAAc,yCAAyC,SAAS;EAChE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,EAC9B,WACA,GAAG,WAC8B;CACjC,OAAO,iBAAA,GAAA,kBAAA,KAAC,OAAD;EAAK,YAAA,GAAA,OAAA,IAAc,yBAAyB,SAAS;EAAG,GAAI;CAAO,CAAA;AAC5E;AAEA,MAAM,iBAAiB,EACrB,WACA,GAAG,WAC+B;CAClC,OACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;EACE,YAAA,GAAA,OAAA,IAAc,4CAA4C,SAAS;EACnE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,EAC9B,WACA,GAAG,WAC+B;CAClC,OAAO,iBAAA,GAAA,kBAAA,KAAC,QAAD;EAAM,YAAA,GAAA,OAAA,IAAc,2BAA2B,SAAS;EAAG,GAAI;CAAO,CAAA;AAC/E;AAEA,MAAM,gBAAgB,EAAE,WAAW,GAAG,WAAwC;CAC5E,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,YAAA,GAAA,OAAA,IAGE,sHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
@@ -40,7 +40,7 @@ const StatCardSecondaryValue = ({ className, ...rest }) => {
40
40
  };
41
41
  const StatCardIcon = ({ className, ...rest }) => {
42
42
  return /* @__PURE__ */ jsx("div", {
43
- className: cn(`flex size-10 shrink-0 items-center justify-center rounded-xl`, className),
43
+ className: cn("flex size-10 shrink-0 items-center justify-center rounded-[max(var(--spark-rounded-md),var(--spark-rounded-full))]", className),
44
44
  ...rest
45
45
  });
46
46
  };
@@ -1 +1 @@
1
- {"version":3,"file":"stat-card.js","names":[],"sources":["../../src/components/stat-card.tsx"],"sourcesContent":["import { cn } from '../utils/cn'\n\nconst StatCardContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex w-full flex-col gap-3 p-4 text-left', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardLabel = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-xs font-medium text-gray-light', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardContent = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex items-end justify-between gap-px', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardValueContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return <div className={cn('flex flex-col gap-0.5', className)} {...rest} />\n}\n\nconst StatCardValue = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-lg font-bold text-gray tabular-nums', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardSecondaryValue = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return <span className={cn('text-xs text-gray-light', className)} {...rest} />\n}\n\nconst StatCardIcon = ({ className, ...rest }: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn(\n `flex size-10 shrink-0 items-center justify-center rounded-xl`,\n className,\n )}\n {...rest}\n />\n )\n}\n\nexport {\n StatCardContainer,\n StatCardLabel,\n StatCardContent,\n StatCardValueContainer,\n StatCardValue,\n StatCardSecondaryValue,\n StatCardIcon,\n}\n"],"mappings":";;;;AAEA,MAAM,qBAAqB,EACzB,WACA,GAAG,WAC8B;CACjC,OACE,oBAAC,OAAD;EACE,WAAW,GAAG,4CAA4C,SAAS;EACnE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,iBAAiB,EACrB,WACA,GAAG,WAC+B;CAClC,OACE,oBAAC,QAAD;EACE,WAAW,GAAG,uCAAuC,SAAS;EAC9D,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,mBAAmB,EACvB,WACA,GAAG,WAC8B;CACjC,OACE,oBAAC,OAAD;EACE,WAAW,GAAG,yCAAyC,SAAS;EAChE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,EAC9B,WACA,GAAG,WAC8B;CACjC,OAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,yBAAyB,SAAS;EAAG,GAAI;CAAO,CAAA;AAC5E;AAEA,MAAM,iBAAiB,EACrB,WACA,GAAG,WAC+B;CAClC,OACE,oBAAC,QAAD;EACE,WAAW,GAAG,4CAA4C,SAAS;EACnE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,EAC9B,WACA,GAAG,WAC+B;CAClC,OAAO,oBAAC,QAAD;EAAM,WAAW,GAAG,2BAA2B,SAAS;EAAG,GAAI;CAAO,CAAA;AAC/E;AAEA,MAAM,gBAAgB,EAAE,WAAW,GAAG,WAAwC;CAC5E,OACE,oBAAC,OAAD;EACE,WAAW,GACT,gEACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
1
+ {"version":3,"file":"stat-card.js","names":[],"sources":["../../src/components/stat-card.tsx"],"sourcesContent":["import { cn } from '../utils/cn'\n\nconst StatCardContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex w-full flex-col gap-3 p-4 text-left', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardLabel = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-xs font-medium text-gray-light', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardContent = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn('flex items-end justify-between gap-px', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardValueContainer = ({\n className,\n ...rest\n}: React.ComponentProps<'div'>) => {\n return <div className={cn('flex flex-col gap-0.5', className)} {...rest} />\n}\n\nconst StatCardValue = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return (\n <span\n className={cn('text-lg font-bold text-gray tabular-nums', className)}\n {...rest}\n />\n )\n}\n\nconst StatCardSecondaryValue = ({\n className,\n ...rest\n}: React.ComponentProps<'span'>) => {\n return <span className={cn('text-xs text-gray-light', className)} {...rest} />\n}\n\nconst StatCardIcon = ({ className, ...rest }: React.ComponentProps<'div'>) => {\n return (\n <div\n className={cn(\n // max() pill escape (matches Icon): a tile stays rounded-md at low Roundness but\n // becomes a circle at large/full, same as it did pre-harmonization via clamping.\n 'flex size-10 shrink-0 items-center justify-center rounded-[max(var(--spark-rounded-md),var(--spark-rounded-full))]',\n className,\n )}\n {...rest}\n />\n )\n}\n\nexport {\n StatCardContainer,\n StatCardLabel,\n StatCardContent,\n StatCardValueContainer,\n StatCardValue,\n StatCardSecondaryValue,\n StatCardIcon,\n}\n"],"mappings":";;;;AAEA,MAAM,qBAAqB,EACzB,WACA,GAAG,WAC8B;CACjC,OACE,oBAAC,OAAD;EACE,WAAW,GAAG,4CAA4C,SAAS;EACnE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,iBAAiB,EACrB,WACA,GAAG,WAC+B;CAClC,OACE,oBAAC,QAAD;EACE,WAAW,GAAG,uCAAuC,SAAS;EAC9D,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,mBAAmB,EACvB,WACA,GAAG,WAC8B;CACjC,OACE,oBAAC,OAAD;EACE,WAAW,GAAG,yCAAyC,SAAS;EAChE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,EAC9B,WACA,GAAG,WAC8B;CACjC,OAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,yBAAyB,SAAS;EAAG,GAAI;CAAO,CAAA;AAC5E;AAEA,MAAM,iBAAiB,EACrB,WACA,GAAG,WAC+B;CAClC,OACE,oBAAC,QAAD;EACE,WAAW,GAAG,4CAA4C,SAAS;EACnE,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,0BAA0B,EAC9B,WACA,GAAG,WAC+B;CAClC,OAAO,oBAAC,QAAD;EAAM,WAAW,GAAG,2BAA2B,SAAS;EAAG,GAAI;CAAO,CAAA;AAC/E;AAEA,MAAM,gBAAgB,EAAE,WAAW,GAAG,WAAwC;CAC5E,OACE,oBAAC,OAAD;EACE,WAAW,GAGT,sHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
@@ -40,14 +40,14 @@ const Stepper = react.forwardRef(({ value, onValueChange, onValueCommit, min = 0
40
40
  ref,
41
41
  role: "group",
42
42
  "aria-label": ariaLabel,
43
- className: (0, cnfast.cn)("inline-flex h-12 w-full items-center justify-between rounded-xl bg-base-gray-soft px-2", className),
43
+ className: (0, cnfast.cn)("inline-flex h-12 w-full items-center justify-between rounded-md bg-base-gray-soft px-2", className),
44
44
  children: [
45
45
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
46
46
  type: "button",
47
47
  "aria-label": decreaseLabel,
48
48
  onClick: decrement,
49
49
  disabled: disabled || atMin,
50
- className: "inline-flex size-8 items-center justify-center rounded-md text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent",
50
+ className: "inline-flex size-8 items-center justify-center rounded-sm text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent",
51
51
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_material_symbol.MaterialSymbol, {
52
52
  className: "text-[16px]",
53
53
  name: "chevron_left"
@@ -63,7 +63,7 @@ const Stepper = react.forwardRef(({ value, onValueChange, onValueCommit, min = 0
63
63
  "aria-label": increaseLabel,
64
64
  onClick: increment,
65
65
  disabled: disabled || atMax,
66
- className: "inline-flex size-8 items-center justify-center rounded-md text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent",
66
+ className: "inline-flex size-8 items-center justify-center rounded-sm text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent",
67
67
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_material_symbol.MaterialSymbol, {
68
68
  className: "text-[16px]",
69
69
  name: "chevron_right"
@@ -1 +1 @@
1
- {"version":3,"file":"stepper.cjs","names":["React","MaterialSymbol"],"sources":["../../src/components/stepper.tsx"],"sourcesContent":["import * as React from 'react'\nimport { MaterialSymbol } from '../icons/material-symbol'\nimport { cn } from '../utils/cn'\n\ninterface StepperProps {\n value: number\n onValueChange: (value: number) => void\n /**\n * Fires once after the user stops interacting (default: 400ms after the last\n * click). Use this for side effects like persisting the value, so rapid\n * clicks don't fan out into a request per click.\n */\n onValueCommit?: (value: number) => void\n min?: number\n max?: number\n step?: number\n formatValue?: (value: number) => string\n disabled?: boolean\n className?: string\n /** Delay (ms) after the last click before `onValueCommit` fires. */\n commitDelayMs?: number\n /** Accessible label, e.g. \"Sunshare percentage\". */\n 'aria-label'?: string\n /** Accessible label for the decrement button. Defaults to `\"Decrease\"`. */\n decreaseLabel?: string\n /** Accessible label for the increment button. Defaults to `\"Increase\"`. */\n increaseLabel?: string\n}\n\nconst Stepper = React.forwardRef<HTMLDivElement, StepperProps>(\n (\n {\n value,\n onValueChange,\n onValueCommit,\n min = 0,\n max = 100,\n step = 1,\n formatValue = (v) => String(v),\n disabled,\n className,\n commitDelayMs = 400,\n 'aria-label': ariaLabel,\n decreaseLabel = 'Decrease',\n increaseLabel = 'Increase',\n },\n ref,\n ) => {\n const commitTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null,\n )\n\n React.useEffect(\n () => () => {\n if (commitTimerRef.current) clearTimeout(commitTimerRef.current)\n },\n [],\n )\n\n const scheduleCommit = (next: number) => {\n if (!onValueCommit) return\n if (commitTimerRef.current) clearTimeout(commitTimerRef.current)\n commitTimerRef.current = setTimeout(() => {\n commitTimerRef.current = null\n onValueCommit(next)\n }, commitDelayMs)\n }\n\n const decrement = () => {\n const next = Math.max(min, value - step)\n if (next !== value) {\n onValueChange(next)\n scheduleCommit(next)\n }\n }\n const increment = () => {\n const next = Math.min(max, value + step)\n if (next !== value) {\n onValueChange(next)\n scheduleCommit(next)\n }\n }\n\n const atMin = value <= min\n const atMax = value >= max\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={ariaLabel}\n className={cn(\n 'inline-flex h-12 w-full items-center justify-between rounded-xl bg-base-gray-soft px-2',\n className,\n )}\n >\n <button\n type=\"button\"\n aria-label={decreaseLabel}\n onClick={decrement}\n disabled={disabled || atMin}\n className=\"inline-flex size-8 items-center justify-center rounded-md text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent\"\n >\n <MaterialSymbol className=\"text-[16px]\" name=\"chevron_left\" />\n </button>\n <span\n className=\"text-base font-semibold text-gray tabular-nums select-none\"\n aria-live=\"polite\"\n >\n {formatValue(value)}\n </span>\n <button\n type=\"button\"\n aria-label={increaseLabel}\n onClick={increment}\n disabled={disabled || atMax}\n className=\"inline-flex size-8 items-center justify-center rounded-md text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent\"\n >\n <MaterialSymbol className=\"text-[16px]\" name=\"chevron_right\" />\n </button>\n </div>\n )\n },\n)\n\nStepper.displayName = 'Stepper'\n\nexport { Stepper }\nexport type { StepperProps }\n"],"mappings":";;;;;;;;;AA6BA,MAAM,UAAUA,MAAM,YAElB,EACE,OACA,eACA,eACA,MAAM,GACN,MAAM,KACN,OAAO,GACP,eAAe,MAAM,OAAO,CAAC,GAC7B,UACA,WACA,gBAAgB,KAChB,cAAc,WACd,gBAAgB,YAChB,gBAAgB,cAElB,QACG;CACH,MAAM,iBAAiBA,MAAM,OAC3B,IACF;CAEA,MAAM,sBACQ;EACV,IAAI,eAAe,SAAS,aAAa,eAAe,OAAO;CACjE,GACA,CAAC,CACH;CAEA,MAAM,kBAAkB,SAAiB;EACvC,IAAI,CAAC,eAAe;EACpB,IAAI,eAAe,SAAS,aAAa,eAAe,OAAO;EAC/D,eAAe,UAAU,iBAAiB;GACxC,eAAe,UAAU;GACzB,cAAc,IAAI;EACpB,GAAG,aAAa;CAClB;CAEA,MAAM,kBAAkB;EACtB,MAAM,OAAO,KAAK,IAAI,KAAK,QAAQ,IAAI;EACvC,IAAI,SAAS,OAAO;GAClB,cAAc,IAAI;GAClB,eAAe,IAAI;EACrB;CACF;CACA,MAAM,kBAAkB;EACtB,MAAM,OAAO,KAAK,IAAI,KAAK,QAAQ,IAAI;EACvC,IAAI,SAAS,OAAO;GAClB,cAAc,IAAI;GAClB,eAAe,IAAI;EACrB;CACF;CAEA,MAAM,QAAQ,SAAS;CACvB,MAAM,QAAQ,SAAS;CAEvB,OACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;EACO;EACL,MAAK;EACL,cAAY;EACZ,YAAA,GAAA,OAAA,IACE,0FACA,SACF;YAPF;GASE,iBAAA,GAAA,kBAAA,KAAC,UAAD;IACE,MAAK;IACL,cAAY;IACZ,SAAS;IACT,UAAU,YAAY;IACtB,WAAU;cAEV,iBAAA,GAAA,kBAAA,KAACC,8BAAAA,gBAAD;KAAgB,WAAU;KAAc,MAAK;IAAgB,CAAA;GACvD,CAAA;GACR,iBAAA,GAAA,kBAAA,KAAC,QAAD;IACE,WAAU;IACV,aAAU;cAET,YAAY,KAAK;GACd,CAAA;GACN,iBAAA,GAAA,kBAAA,KAAC,UAAD;IACE,MAAK;IACL,cAAY;IACZ,SAAS;IACT,UAAU,YAAY;IACtB,WAAU;cAEV,iBAAA,GAAA,kBAAA,KAACA,8BAAAA,gBAAD;KAAgB,WAAU;KAAc,MAAK;IAAiB,CAAA;GACxD,CAAA;EACL;;AAET,CACF;AAEA,QAAQ,cAAc"}
1
+ {"version":3,"file":"stepper.cjs","names":["React","MaterialSymbol"],"sources":["../../src/components/stepper.tsx"],"sourcesContent":["import * as React from 'react'\nimport { MaterialSymbol } from '../icons/material-symbol'\nimport { cn } from '../utils/cn'\n\ninterface StepperProps {\n value: number\n onValueChange: (value: number) => void\n /**\n * Fires once after the user stops interacting (default: 400ms after the last\n * click). Use this for side effects like persisting the value, so rapid\n * clicks don't fan out into a request per click.\n */\n onValueCommit?: (value: number) => void\n min?: number\n max?: number\n step?: number\n formatValue?: (value: number) => string\n disabled?: boolean\n className?: string\n /** Delay (ms) after the last click before `onValueCommit` fires. */\n commitDelayMs?: number\n /** Accessible label, e.g. \"Sunshare percentage\". */\n 'aria-label'?: string\n /** Accessible label for the decrement button. Defaults to `\"Decrease\"`. */\n decreaseLabel?: string\n /** Accessible label for the increment button. Defaults to `\"Increase\"`. */\n increaseLabel?: string\n}\n\nconst Stepper = React.forwardRef<HTMLDivElement, StepperProps>(\n (\n {\n value,\n onValueChange,\n onValueCommit,\n min = 0,\n max = 100,\n step = 1,\n formatValue = (v) => String(v),\n disabled,\n className,\n commitDelayMs = 400,\n 'aria-label': ariaLabel,\n decreaseLabel = 'Decrease',\n increaseLabel = 'Increase',\n },\n ref,\n ) => {\n const commitTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null,\n )\n\n React.useEffect(\n () => () => {\n if (commitTimerRef.current) clearTimeout(commitTimerRef.current)\n },\n [],\n )\n\n const scheduleCommit = (next: number) => {\n if (!onValueCommit) return\n if (commitTimerRef.current) clearTimeout(commitTimerRef.current)\n commitTimerRef.current = setTimeout(() => {\n commitTimerRef.current = null\n onValueCommit(next)\n }, commitDelayMs)\n }\n\n const decrement = () => {\n const next = Math.max(min, value - step)\n if (next !== value) {\n onValueChange(next)\n scheduleCommit(next)\n }\n }\n const increment = () => {\n const next = Math.min(max, value + step)\n if (next !== value) {\n onValueChange(next)\n scheduleCommit(next)\n }\n }\n\n const atMin = value <= min\n const atMax = value >= max\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={ariaLabel}\n className={cn(\n 'inline-flex h-12 w-full items-center justify-between rounded-md bg-base-gray-soft px-2',\n className,\n )}\n >\n <button\n type=\"button\"\n aria-label={decreaseLabel}\n onClick={decrement}\n disabled={disabled || atMin}\n className=\"inline-flex size-8 items-center justify-center rounded-sm text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent\"\n >\n <MaterialSymbol className=\"text-[16px]\" name=\"chevron_left\" />\n </button>\n <span\n className=\"text-base font-semibold text-gray tabular-nums select-none\"\n aria-live=\"polite\"\n >\n {formatValue(value)}\n </span>\n <button\n type=\"button\"\n aria-label={increaseLabel}\n onClick={increment}\n disabled={disabled || atMax}\n className=\"inline-flex size-8 items-center justify-center rounded-sm text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent\"\n >\n <MaterialSymbol className=\"text-[16px]\" name=\"chevron_right\" />\n </button>\n </div>\n )\n },\n)\n\nStepper.displayName = 'Stepper'\n\nexport { Stepper }\nexport type { StepperProps }\n"],"mappings":";;;;;;;;;AA6BA,MAAM,UAAUA,MAAM,YAElB,EACE,OACA,eACA,eACA,MAAM,GACN,MAAM,KACN,OAAO,GACP,eAAe,MAAM,OAAO,CAAC,GAC7B,UACA,WACA,gBAAgB,KAChB,cAAc,WACd,gBAAgB,YAChB,gBAAgB,cAElB,QACG;CACH,MAAM,iBAAiBA,MAAM,OAC3B,IACF;CAEA,MAAM,sBACQ;EACV,IAAI,eAAe,SAAS,aAAa,eAAe,OAAO;CACjE,GACA,CAAC,CACH;CAEA,MAAM,kBAAkB,SAAiB;EACvC,IAAI,CAAC,eAAe;EACpB,IAAI,eAAe,SAAS,aAAa,eAAe,OAAO;EAC/D,eAAe,UAAU,iBAAiB;GACxC,eAAe,UAAU;GACzB,cAAc,IAAI;EACpB,GAAG,aAAa;CAClB;CAEA,MAAM,kBAAkB;EACtB,MAAM,OAAO,KAAK,IAAI,KAAK,QAAQ,IAAI;EACvC,IAAI,SAAS,OAAO;GAClB,cAAc,IAAI;GAClB,eAAe,IAAI;EACrB;CACF;CACA,MAAM,kBAAkB;EACtB,MAAM,OAAO,KAAK,IAAI,KAAK,QAAQ,IAAI;EACvC,IAAI,SAAS,OAAO;GAClB,cAAc,IAAI;GAClB,eAAe,IAAI;EACrB;CACF;CAEA,MAAM,QAAQ,SAAS;CACvB,MAAM,QAAQ,SAAS;CAEvB,OACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;EACO;EACL,MAAK;EACL,cAAY;EACZ,YAAA,GAAA,OAAA,IACE,0FACA,SACF;YAPF;GASE,iBAAA,GAAA,kBAAA,KAAC,UAAD;IACE,MAAK;IACL,cAAY;IACZ,SAAS;IACT,UAAU,YAAY;IACtB,WAAU;cAEV,iBAAA,GAAA,kBAAA,KAACC,8BAAAA,gBAAD;KAAgB,WAAU;KAAc,MAAK;IAAgB,CAAA;GACvD,CAAA;GACR,iBAAA,GAAA,kBAAA,KAAC,QAAD;IACE,WAAU;IACV,aAAU;cAET,YAAY,KAAK;GACd,CAAA;GACN,iBAAA,GAAA,kBAAA,KAAC,UAAD;IACE,MAAK;IACL,cAAY;IACZ,SAAS;IACT,UAAU,YAAY;IACtB,WAAU;cAEV,iBAAA,GAAA,kBAAA,KAACA,8BAAAA,gBAAD;KAAgB,WAAU;KAAc,MAAK;IAAiB,CAAA;GACxD,CAAA;EACL;;AAET,CACF;AAEA,QAAQ,cAAc"}
@@ -37,14 +37,14 @@ const Stepper = React$1.forwardRef(({ value, onValueChange, onValueCommit, min =
37
37
  ref,
38
38
  role: "group",
39
39
  "aria-label": ariaLabel,
40
- className: cn("inline-flex h-12 w-full items-center justify-between rounded-xl bg-base-gray-soft px-2", className),
40
+ className: cn("inline-flex h-12 w-full items-center justify-between rounded-md bg-base-gray-soft px-2", className),
41
41
  children: [
42
42
  /* @__PURE__ */ jsx("button", {
43
43
  type: "button",
44
44
  "aria-label": decreaseLabel,
45
45
  onClick: decrement,
46
46
  disabled: disabled || atMin,
47
- className: "inline-flex size-8 items-center justify-center rounded-md text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent",
47
+ className: "inline-flex size-8 items-center justify-center rounded-sm text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent",
48
48
  children: /* @__PURE__ */ jsx(MaterialSymbol, {
49
49
  className: "text-[16px]",
50
50
  name: "chevron_left"
@@ -60,7 +60,7 @@ const Stepper = React$1.forwardRef(({ value, onValueChange, onValueCommit, min =
60
60
  "aria-label": increaseLabel,
61
61
  onClick: increment,
62
62
  disabled: disabled || atMax,
63
- className: "inline-flex size-8 items-center justify-center rounded-md text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent",
63
+ className: "inline-flex size-8 items-center justify-center rounded-sm text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent",
64
64
  children: /* @__PURE__ */ jsx(MaterialSymbol, {
65
65
  className: "text-[16px]",
66
66
  name: "chevron_right"
@@ -1 +1 @@
1
- {"version":3,"file":"stepper.js","names":["React"],"sources":["../../src/components/stepper.tsx"],"sourcesContent":["import * as React from 'react'\nimport { MaterialSymbol } from '../icons/material-symbol'\nimport { cn } from '../utils/cn'\n\ninterface StepperProps {\n value: number\n onValueChange: (value: number) => void\n /**\n * Fires once after the user stops interacting (default: 400ms after the last\n * click). Use this for side effects like persisting the value, so rapid\n * clicks don't fan out into a request per click.\n */\n onValueCommit?: (value: number) => void\n min?: number\n max?: number\n step?: number\n formatValue?: (value: number) => string\n disabled?: boolean\n className?: string\n /** Delay (ms) after the last click before `onValueCommit` fires. */\n commitDelayMs?: number\n /** Accessible label, e.g. \"Sunshare percentage\". */\n 'aria-label'?: string\n /** Accessible label for the decrement button. Defaults to `\"Decrease\"`. */\n decreaseLabel?: string\n /** Accessible label for the increment button. Defaults to `\"Increase\"`. */\n increaseLabel?: string\n}\n\nconst Stepper = React.forwardRef<HTMLDivElement, StepperProps>(\n (\n {\n value,\n onValueChange,\n onValueCommit,\n min = 0,\n max = 100,\n step = 1,\n formatValue = (v) => String(v),\n disabled,\n className,\n commitDelayMs = 400,\n 'aria-label': ariaLabel,\n decreaseLabel = 'Decrease',\n increaseLabel = 'Increase',\n },\n ref,\n ) => {\n const commitTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null,\n )\n\n React.useEffect(\n () => () => {\n if (commitTimerRef.current) clearTimeout(commitTimerRef.current)\n },\n [],\n )\n\n const scheduleCommit = (next: number) => {\n if (!onValueCommit) return\n if (commitTimerRef.current) clearTimeout(commitTimerRef.current)\n commitTimerRef.current = setTimeout(() => {\n commitTimerRef.current = null\n onValueCommit(next)\n }, commitDelayMs)\n }\n\n const decrement = () => {\n const next = Math.max(min, value - step)\n if (next !== value) {\n onValueChange(next)\n scheduleCommit(next)\n }\n }\n const increment = () => {\n const next = Math.min(max, value + step)\n if (next !== value) {\n onValueChange(next)\n scheduleCommit(next)\n }\n }\n\n const atMin = value <= min\n const atMax = value >= max\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={ariaLabel}\n className={cn(\n 'inline-flex h-12 w-full items-center justify-between rounded-xl bg-base-gray-soft px-2',\n className,\n )}\n >\n <button\n type=\"button\"\n aria-label={decreaseLabel}\n onClick={decrement}\n disabled={disabled || atMin}\n className=\"inline-flex size-8 items-center justify-center rounded-md text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent\"\n >\n <MaterialSymbol className=\"text-[16px]\" name=\"chevron_left\" />\n </button>\n <span\n className=\"text-base font-semibold text-gray tabular-nums select-none\"\n aria-live=\"polite\"\n >\n {formatValue(value)}\n </span>\n <button\n type=\"button\"\n aria-label={increaseLabel}\n onClick={increment}\n disabled={disabled || atMax}\n className=\"inline-flex size-8 items-center justify-center rounded-md text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent\"\n >\n <MaterialSymbol className=\"text-[16px]\" name=\"chevron_right\" />\n </button>\n </div>\n )\n },\n)\n\nStepper.displayName = 'Stepper'\n\nexport { Stepper }\nexport type { StepperProps }\n"],"mappings":";;;;;;AA6BA,MAAM,UAAUA,QAAM,YAElB,EACE,OACA,eACA,eACA,MAAM,GACN,MAAM,KACN,OAAO,GACP,eAAe,MAAM,OAAO,CAAC,GAC7B,UACA,WACA,gBAAgB,KAChB,cAAc,WACd,gBAAgB,YAChB,gBAAgB,cAElB,QACG;CACH,MAAM,iBAAiBA,QAAM,OAC3B,IACF;CAEA,QAAM,sBACQ;EACV,IAAI,eAAe,SAAS,aAAa,eAAe,OAAO;CACjE,GACA,CAAC,CACH;CAEA,MAAM,kBAAkB,SAAiB;EACvC,IAAI,CAAC,eAAe;EACpB,IAAI,eAAe,SAAS,aAAa,eAAe,OAAO;EAC/D,eAAe,UAAU,iBAAiB;GACxC,eAAe,UAAU;GACzB,cAAc,IAAI;EACpB,GAAG,aAAa;CAClB;CAEA,MAAM,kBAAkB;EACtB,MAAM,OAAO,KAAK,IAAI,KAAK,QAAQ,IAAI;EACvC,IAAI,SAAS,OAAO;GAClB,cAAc,IAAI;GAClB,eAAe,IAAI;EACrB;CACF;CACA,MAAM,kBAAkB;EACtB,MAAM,OAAO,KAAK,IAAI,KAAK,QAAQ,IAAI;EACvC,IAAI,SAAS,OAAO;GAClB,cAAc,IAAI;GAClB,eAAe,IAAI;EACrB;CACF;CAEA,MAAM,QAAQ,SAAS;CACvB,MAAM,QAAQ,SAAS;CAEvB,OACE,qBAAC,OAAD;EACO;EACL,MAAK;EACL,cAAY;EACZ,WAAW,GACT,0FACA,SACF;YAPF;GASE,oBAAC,UAAD;IACE,MAAK;IACL,cAAY;IACZ,SAAS;IACT,UAAU,YAAY;IACtB,WAAU;cAEV,oBAAC,gBAAD;KAAgB,WAAU;KAAc,MAAK;IAAgB,CAAA;GACvD,CAAA;GACR,oBAAC,QAAD;IACE,WAAU;IACV,aAAU;cAET,YAAY,KAAK;GACd,CAAA;GACN,oBAAC,UAAD;IACE,MAAK;IACL,cAAY;IACZ,SAAS;IACT,UAAU,YAAY;IACtB,WAAU;cAEV,oBAAC,gBAAD;KAAgB,WAAU;KAAc,MAAK;IAAiB,CAAA;GACxD,CAAA;EACL;;AAET,CACF;AAEA,QAAQ,cAAc"}
1
+ {"version":3,"file":"stepper.js","names":["React"],"sources":["../../src/components/stepper.tsx"],"sourcesContent":["import * as React from 'react'\nimport { MaterialSymbol } from '../icons/material-symbol'\nimport { cn } from '../utils/cn'\n\ninterface StepperProps {\n value: number\n onValueChange: (value: number) => void\n /**\n * Fires once after the user stops interacting (default: 400ms after the last\n * click). Use this for side effects like persisting the value, so rapid\n * clicks don't fan out into a request per click.\n */\n onValueCommit?: (value: number) => void\n min?: number\n max?: number\n step?: number\n formatValue?: (value: number) => string\n disabled?: boolean\n className?: string\n /** Delay (ms) after the last click before `onValueCommit` fires. */\n commitDelayMs?: number\n /** Accessible label, e.g. \"Sunshare percentage\". */\n 'aria-label'?: string\n /** Accessible label for the decrement button. Defaults to `\"Decrease\"`. */\n decreaseLabel?: string\n /** Accessible label for the increment button. Defaults to `\"Increase\"`. */\n increaseLabel?: string\n}\n\nconst Stepper = React.forwardRef<HTMLDivElement, StepperProps>(\n (\n {\n value,\n onValueChange,\n onValueCommit,\n min = 0,\n max = 100,\n step = 1,\n formatValue = (v) => String(v),\n disabled,\n className,\n commitDelayMs = 400,\n 'aria-label': ariaLabel,\n decreaseLabel = 'Decrease',\n increaseLabel = 'Increase',\n },\n ref,\n ) => {\n const commitTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null,\n )\n\n React.useEffect(\n () => () => {\n if (commitTimerRef.current) clearTimeout(commitTimerRef.current)\n },\n [],\n )\n\n const scheduleCommit = (next: number) => {\n if (!onValueCommit) return\n if (commitTimerRef.current) clearTimeout(commitTimerRef.current)\n commitTimerRef.current = setTimeout(() => {\n commitTimerRef.current = null\n onValueCommit(next)\n }, commitDelayMs)\n }\n\n const decrement = () => {\n const next = Math.max(min, value - step)\n if (next !== value) {\n onValueChange(next)\n scheduleCommit(next)\n }\n }\n const increment = () => {\n const next = Math.min(max, value + step)\n if (next !== value) {\n onValueChange(next)\n scheduleCommit(next)\n }\n }\n\n const atMin = value <= min\n const atMax = value >= max\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={ariaLabel}\n className={cn(\n 'inline-flex h-12 w-full items-center justify-between rounded-md bg-base-gray-soft px-2',\n className,\n )}\n >\n <button\n type=\"button\"\n aria-label={decreaseLabel}\n onClick={decrement}\n disabled={disabled || atMin}\n className=\"inline-flex size-8 items-center justify-center rounded-sm text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent\"\n >\n <MaterialSymbol className=\"text-[16px]\" name=\"chevron_left\" />\n </button>\n <span\n className=\"text-base font-semibold text-gray tabular-nums select-none\"\n aria-live=\"polite\"\n >\n {formatValue(value)}\n </span>\n <button\n type=\"button\"\n aria-label={increaseLabel}\n onClick={increment}\n disabled={disabled || atMax}\n className=\"inline-flex size-8 items-center justify-center rounded-sm text-gray transition-colors hover:bg-gray-a3 disabled:opacity-40 disabled:hover:bg-transparent\"\n >\n <MaterialSymbol className=\"text-[16px]\" name=\"chevron_right\" />\n </button>\n </div>\n )\n },\n)\n\nStepper.displayName = 'Stepper'\n\nexport { Stepper }\nexport type { StepperProps }\n"],"mappings":";;;;;;AA6BA,MAAM,UAAUA,QAAM,YAElB,EACE,OACA,eACA,eACA,MAAM,GACN,MAAM,KACN,OAAO,GACP,eAAe,MAAM,OAAO,CAAC,GAC7B,UACA,WACA,gBAAgB,KAChB,cAAc,WACd,gBAAgB,YAChB,gBAAgB,cAElB,QACG;CACH,MAAM,iBAAiBA,QAAM,OAC3B,IACF;CAEA,QAAM,sBACQ;EACV,IAAI,eAAe,SAAS,aAAa,eAAe,OAAO;CACjE,GACA,CAAC,CACH;CAEA,MAAM,kBAAkB,SAAiB;EACvC,IAAI,CAAC,eAAe;EACpB,IAAI,eAAe,SAAS,aAAa,eAAe,OAAO;EAC/D,eAAe,UAAU,iBAAiB;GACxC,eAAe,UAAU;GACzB,cAAc,IAAI;EACpB,GAAG,aAAa;CAClB;CAEA,MAAM,kBAAkB;EACtB,MAAM,OAAO,KAAK,IAAI,KAAK,QAAQ,IAAI;EACvC,IAAI,SAAS,OAAO;GAClB,cAAc,IAAI;GAClB,eAAe,IAAI;EACrB;CACF;CACA,MAAM,kBAAkB;EACtB,MAAM,OAAO,KAAK,IAAI,KAAK,QAAQ,IAAI;EACvC,IAAI,SAAS,OAAO;GAClB,cAAc,IAAI;GAClB,eAAe,IAAI;EACrB;CACF;CAEA,MAAM,QAAQ,SAAS;CACvB,MAAM,QAAQ,SAAS;CAEvB,OACE,qBAAC,OAAD;EACO;EACL,MAAK;EACL,cAAY;EACZ,WAAW,GACT,0FACA,SACF;YAPF;GASE,oBAAC,UAAD;IACE,MAAK;IACL,cAAY;IACZ,SAAS;IACT,UAAU,YAAY;IACtB,WAAU;cAEV,oBAAC,gBAAD;KAAgB,WAAU;KAAc,MAAK;IAAgB,CAAA;GACvD,CAAA;GACR,oBAAC,QAAD;IACE,WAAU;IACV,aAAU;cAET,YAAY,KAAK;GACd,CAAA;GACN,oBAAC,UAAD;IACE,MAAK;IACL,cAAY;IACZ,SAAS;IACT,UAAU,YAAY;IACtB,WAAU;cAEV,oBAAC,gBAAD;KAAgB,WAAU;KAAc,MAAK;IAAiB,CAAA;GACxD,CAAA;EACL;;AAET,CACF;AAEA,QAAQ,cAAc"}
@@ -14,7 +14,7 @@ const textareaVariants = (0, class_variance_authority.cva)("flex w-full min-w-0
14
14
  chrome: {
15
15
  none: "border-0 px-0",
16
16
  inset: require_lib_input_box_variants.GHOST_UNDERLINE,
17
- box: "min-h-11 rounded-lg px-3 py-2 text-base transition-all motion-reduce:transition-none"
17
+ box: "min-h-11 rounded-md px-3 py-2 text-base transition-all motion-reduce:transition-none"
18
18
  },
19
19
  inputStyle: {
20
20
  soft: "",
@@ -102,7 +102,7 @@ const textareaVariants = (0, class_variance_authority.cva)("flex w-full min-w-0
102
102
  ]
103
103
  });
104
104
  const Textarea = react.forwardRef(function Textarea({ variant, autoResize = false, rows = 3, className, id: idProp, "aria-describedby": ariaDescribedByProp, ...props }, ref) {
105
- const { field, id, ariaDescribedBy, inputStyle, inputColor } = require_components_field.useFieldControl({
105
+ const { field, id, ariaDescribedBy, ariaInvalid, inputStyle, inputColor } = require_components_field.useFieldControl({
106
106
  id: idProp,
107
107
  ariaDescribedBy: ariaDescribedByProp,
108
108
  variant: variant !== "none" ? variant : void 0
@@ -118,6 +118,7 @@ const Textarea = react.forwardRef(function Textarea({ variant, autoResize = fals
118
118
  id,
119
119
  rows,
120
120
  ref,
121
+ "aria-invalid": ariaInvalid,
121
122
  ...props,
122
123
  "aria-describedby": ariaDescribedBy
123
124
  });
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.cjs","names":["GHOST_UNDERLINE","boxChrome","React","useFieldControl"],"sources":["../../src/components/textarea.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority'\nimport * as React from 'react'\nimport { boxChrome, GHOST_UNDERLINE } from '../lib/input-box-variants'\nimport type { SparkInputStyle } from '../lib/theme-types'\nimport { cn } from '../utils/cn'\nimport { useFieldControl } from './field'\n\ntype TextareaVariant = SparkInputStyle | 'none'\n\nconst textareaVariants = cva(\n 'flex w-full min-w-0 bg-transparent text-gray outline-hidden transition-all group-data-[invalid=true]/field:text-error placeholder:text-gray-disabled disabled:cursor-not-allowed disabled:text-gray-disabled aria-invalid:text-error motion-reduce:transition-none',\n {\n variants: {\n chrome: {\n none: 'border-0 px-0',\n inset: GHOST_UNDERLINE,\n box: 'min-h-11 rounded-lg px-3 py-2 text-base transition-all motion-reduce:transition-none',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n autoResize: {\n true: 'field-sizing-content resize-none',\n false: 'resize-y',\n },\n },\n compoundVariants: [\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'brand',\n class: boxChrome.soft.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'gray',\n class: boxChrome.soft.gray,\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'brand',\n class: boxChrome.surface.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'gray',\n class: boxChrome.surface.gray,\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class: boxChrome.outlined.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class: boxChrome.outlined.gray,\n },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'brand',\n class: boxChrome.ghost.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'gray',\n class: boxChrome.ghost.gray,\n },\n { chrome: 'inset', inputColor: 'brand', class: 'border-b-input' },\n { chrome: 'inset', inputColor: 'gray', class: 'border-b-input-gray' },\n // GHOST_UNDERLINE and boxChrome.ghost.* hardcode h-10; un-clamp for\n // textarea's min-height model — must come after those compounds above\n { chrome: 'inset', class: 'h-auto min-h-10' },\n { chrome: 'box', inputStyle: 'ghost', class: 'h-auto' },\n ],\n },\n)\n\ninterface TextareaProps extends React.ComponentProps<'textarea'> {\n variant?: TextareaVariant\n autoResize?: boolean\n}\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n function Textarea(\n {\n variant,\n autoResize = false,\n rows = 3,\n className,\n id: idProp,\n 'aria-describedby': ariaDescribedByProp,\n ...props\n },\n ref,\n ) {\n const { field, id, ariaDescribedBy, inputStyle, inputColor } =\n useFieldControl({\n id: idProp,\n ariaDescribedBy: ariaDescribedByProp,\n variant: variant !== 'none' ? variant : undefined,\n })\n // an explicit variant prop keeps the box even inside an inset field\n const chrome =\n variant === 'none'\n ? 'none'\n : !variant && field?.labelPosition === 'inset'\n ? 'inset'\n : 'box'\n\n return (\n <textarea\n data-slot=\"textarea\"\n className={cn(\n textareaVariants({ chrome, inputStyle, inputColor, autoResize }),\n className,\n )}\n id={id}\n rows={rows}\n ref={ref}\n {...props}\n aria-describedby={ariaDescribedBy}\n />\n )\n },\n)\n\nexport { Textarea }\nexport type { TextareaProps, TextareaVariant }\n"],"mappings":";;;;;;;;;;;AASA,MAAM,oBAAA,GAAA,yBAAA,KACJ,sQACA;CACE,UAAU;EACR,QAAQ;GACN,MAAM;GACN,OAAOA,+BAAAA;GACP,KAAK;EACP;EACA,YAAY;GAAE,MAAM;GAAI,SAAS;GAAI,UAAU;GAAI,OAAO;EAAG;EAC7D,YAAY;GAAE,OAAO;GAAI,MAAM;EAAG;EAClC,YAAY;GACV,MAAM;GACN,OAAO;EACT;CACF;CACA,kBAAkB;EAChB;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOC,+BAAAA,UAAU,KAAK;EACxB;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,KAAK;EACxB;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,QAAQ;EAC3B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,QAAQ;EAC3B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,SAAS;EAC5B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,SAAS;EAC5B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,MAAM;EACzB;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,MAAM;EACzB;EACA;GAAE,QAAQ;GAAS,YAAY;GAAS,OAAO;EAAiB;EAChE;GAAE,QAAQ;GAAS,YAAY;GAAQ,OAAO;EAAsB;EAGpE;GAAE,QAAQ;GAAS,OAAO;EAAkB;EAC5C;GAAE,QAAQ;GAAO,YAAY;GAAS,OAAO;EAAS;CACxD;AACF,CACF;AAOA,MAAM,WAAWC,MAAM,WACrB,SAAS,SACP,EACE,SACA,aAAa,OACb,OAAO,GACP,WACA,IAAI,QACJ,oBAAoB,qBACpB,GAAG,SAEL,KACA;CACA,MAAM,EAAE,OAAO,IAAI,iBAAiB,YAAY,eAC9CC,yBAAAA,gBAAgB;EACd,IAAI;EACJ,iBAAiB;EACjB,SAAS,YAAY,SAAS,UAAU,KAAA;CAC1C,CAAC;CASH,OACE,iBAAA,GAAA,kBAAA,KAAC,YAAD;EACE,aAAU;EACV,YAAA,GAAA,OAAA,IACE,iBAAiB;GAAE,QAVvB,YAAY,SACR,SACA,CAAC,WAAW,OAAO,kBAAkB,UACnC,UACA;GAMyB;GAAY;GAAY;EAAW,CAAC,GAC/D,SACF;EACI;EACE;EACD;EACL,GAAI;EACJ,oBAAkB;CACnB,CAAA;AAEL,CACF"}
1
+ {"version":3,"file":"textarea.cjs","names":["GHOST_UNDERLINE","boxChrome","React","useFieldControl"],"sources":["../../src/components/textarea.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority'\nimport * as React from 'react'\nimport { boxChrome, GHOST_UNDERLINE } from '../lib/input-box-variants'\nimport type { SparkInputStyle } from '../lib/theme-types'\nimport { cn } from '../utils/cn'\nimport { useFieldControl } from './field'\n\ntype TextareaVariant = SparkInputStyle | 'none'\n\nconst textareaVariants = cva(\n 'flex w-full min-w-0 bg-transparent text-gray outline-hidden transition-all group-data-[invalid=true]/field:text-error placeholder:text-gray-disabled disabled:cursor-not-allowed disabled:text-gray-disabled aria-invalid:text-error motion-reduce:transition-none',\n {\n variants: {\n chrome: {\n none: 'border-0 px-0',\n inset: GHOST_UNDERLINE,\n box: 'min-h-11 rounded-md px-3 py-2 text-base transition-all motion-reduce:transition-none',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n autoResize: {\n true: 'field-sizing-content resize-none',\n false: 'resize-y',\n },\n },\n compoundVariants: [\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'brand',\n class: boxChrome.soft.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'gray',\n class: boxChrome.soft.gray,\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'brand',\n class: boxChrome.surface.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'gray',\n class: boxChrome.surface.gray,\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class: boxChrome.outlined.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class: boxChrome.outlined.gray,\n },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'brand',\n class: boxChrome.ghost.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'gray',\n class: boxChrome.ghost.gray,\n },\n { chrome: 'inset', inputColor: 'brand', class: 'border-b-input' },\n { chrome: 'inset', inputColor: 'gray', class: 'border-b-input-gray' },\n // GHOST_UNDERLINE and boxChrome.ghost.* hardcode h-10; un-clamp for\n // textarea's min-height model — must come after those compounds above\n { chrome: 'inset', class: 'h-auto min-h-10' },\n { chrome: 'box', inputStyle: 'ghost', class: 'h-auto' },\n ],\n },\n)\n\ninterface TextareaProps extends React.ComponentProps<'textarea'> {\n variant?: TextareaVariant\n autoResize?: boolean\n}\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n function Textarea(\n {\n variant,\n autoResize = false,\n rows = 3,\n className,\n id: idProp,\n 'aria-describedby': ariaDescribedByProp,\n ...props\n },\n ref,\n ) {\n const { field, id, ariaDescribedBy, ariaInvalid, inputStyle, inputColor } =\n useFieldControl({\n id: idProp,\n ariaDescribedBy: ariaDescribedByProp,\n variant: variant !== 'none' ? variant : undefined,\n })\n // an explicit variant prop keeps the box even inside an inset field\n const chrome =\n variant === 'none'\n ? 'none'\n : !variant && field?.labelPosition === 'inset'\n ? 'inset'\n : 'box'\n\n return (\n <textarea\n data-slot=\"textarea\"\n className={cn(\n textareaVariants({ chrome, inputStyle, inputColor, autoResize }),\n className,\n )}\n id={id}\n rows={rows}\n ref={ref}\n aria-invalid={ariaInvalid}\n {...props}\n aria-describedby={ariaDescribedBy}\n />\n )\n },\n)\n\nexport { Textarea }\nexport type { TextareaProps, TextareaVariant }\n"],"mappings":";;;;;;;;;;;AASA,MAAM,oBAAA,GAAA,yBAAA,KACJ,sQACA;CACE,UAAU;EACR,QAAQ;GACN,MAAM;GACN,OAAOA,+BAAAA;GACP,KAAK;EACP;EACA,YAAY;GAAE,MAAM;GAAI,SAAS;GAAI,UAAU;GAAI,OAAO;EAAG;EAC7D,YAAY;GAAE,OAAO;GAAI,MAAM;EAAG;EAClC,YAAY;GACV,MAAM;GACN,OAAO;EACT;CACF;CACA,kBAAkB;EAChB;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOC,+BAAAA,UAAU,KAAK;EACxB;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,KAAK;EACxB;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,QAAQ;EAC3B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,QAAQ;EAC3B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,SAAS;EAC5B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,SAAS;EAC5B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,MAAM;EACzB;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAOA,+BAAAA,UAAU,MAAM;EACzB;EACA;GAAE,QAAQ;GAAS,YAAY;GAAS,OAAO;EAAiB;EAChE;GAAE,QAAQ;GAAS,YAAY;GAAQ,OAAO;EAAsB;EAGpE;GAAE,QAAQ;GAAS,OAAO;EAAkB;EAC5C;GAAE,QAAQ;GAAO,YAAY;GAAS,OAAO;EAAS;CACxD;AACF,CACF;AAOA,MAAM,WAAWC,MAAM,WACrB,SAAS,SACP,EACE,SACA,aAAa,OACb,OAAO,GACP,WACA,IAAI,QACJ,oBAAoB,qBACpB,GAAG,SAEL,KACA;CACA,MAAM,EAAE,OAAO,IAAI,iBAAiB,aAAa,YAAY,eAC3DC,yBAAAA,gBAAgB;EACd,IAAI;EACJ,iBAAiB;EACjB,SAAS,YAAY,SAAS,UAAU,KAAA;CAC1C,CAAC;CASH,OACE,iBAAA,GAAA,kBAAA,KAAC,YAAD;EACE,aAAU;EACV,YAAA,GAAA,OAAA,IACE,iBAAiB;GAAE,QAVvB,YAAY,SACR,SACA,CAAC,WAAW,OAAO,kBAAkB,UACnC,UACA;GAMyB;GAAY;GAAY;EAAW,CAAC,GAC/D,SACF;EACI;EACE;EACD;EACL,gBAAc;EACd,GAAI;EACJ,oBAAkB;CACnB,CAAA;AAEL,CACF"}
@@ -11,7 +11,7 @@ const textareaVariants = cva("flex w-full min-w-0 bg-transparent text-gray outli
11
11
  chrome: {
12
12
  none: "border-0 px-0",
13
13
  inset: GHOST_UNDERLINE,
14
- box: "min-h-11 rounded-lg px-3 py-2 text-base transition-all motion-reduce:transition-none"
14
+ box: "min-h-11 rounded-md px-3 py-2 text-base transition-all motion-reduce:transition-none"
15
15
  },
16
16
  inputStyle: {
17
17
  soft: "",
@@ -99,7 +99,7 @@ const textareaVariants = cva("flex w-full min-w-0 bg-transparent text-gray outli
99
99
  ]
100
100
  });
101
101
  const Textarea = React$1.forwardRef(function Textarea({ variant, autoResize = false, rows = 3, className, id: idProp, "aria-describedby": ariaDescribedByProp, ...props }, ref) {
102
- const { field, id, ariaDescribedBy, inputStyle, inputColor } = useFieldControl({
102
+ const { field, id, ariaDescribedBy, ariaInvalid, inputStyle, inputColor } = useFieldControl({
103
103
  id: idProp,
104
104
  ariaDescribedBy: ariaDescribedByProp,
105
105
  variant: variant !== "none" ? variant : void 0
@@ -115,6 +115,7 @@ const Textarea = React$1.forwardRef(function Textarea({ variant, autoResize = fa
115
115
  id,
116
116
  rows,
117
117
  ref,
118
+ "aria-invalid": ariaInvalid,
118
119
  ...props,
119
120
  "aria-describedby": ariaDescribedBy
120
121
  });
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.js","names":["React"],"sources":["../../src/components/textarea.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority'\nimport * as React from 'react'\nimport { boxChrome, GHOST_UNDERLINE } from '../lib/input-box-variants'\nimport type { SparkInputStyle } from '../lib/theme-types'\nimport { cn } from '../utils/cn'\nimport { useFieldControl } from './field'\n\ntype TextareaVariant = SparkInputStyle | 'none'\n\nconst textareaVariants = cva(\n 'flex w-full min-w-0 bg-transparent text-gray outline-hidden transition-all group-data-[invalid=true]/field:text-error placeholder:text-gray-disabled disabled:cursor-not-allowed disabled:text-gray-disabled aria-invalid:text-error motion-reduce:transition-none',\n {\n variants: {\n chrome: {\n none: 'border-0 px-0',\n inset: GHOST_UNDERLINE,\n box: 'min-h-11 rounded-lg px-3 py-2 text-base transition-all motion-reduce:transition-none',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n autoResize: {\n true: 'field-sizing-content resize-none',\n false: 'resize-y',\n },\n },\n compoundVariants: [\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'brand',\n class: boxChrome.soft.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'gray',\n class: boxChrome.soft.gray,\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'brand',\n class: boxChrome.surface.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'gray',\n class: boxChrome.surface.gray,\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class: boxChrome.outlined.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class: boxChrome.outlined.gray,\n },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'brand',\n class: boxChrome.ghost.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'gray',\n class: boxChrome.ghost.gray,\n },\n { chrome: 'inset', inputColor: 'brand', class: 'border-b-input' },\n { chrome: 'inset', inputColor: 'gray', class: 'border-b-input-gray' },\n // GHOST_UNDERLINE and boxChrome.ghost.* hardcode h-10; un-clamp for\n // textarea's min-height model — must come after those compounds above\n { chrome: 'inset', class: 'h-auto min-h-10' },\n { chrome: 'box', inputStyle: 'ghost', class: 'h-auto' },\n ],\n },\n)\n\ninterface TextareaProps extends React.ComponentProps<'textarea'> {\n variant?: TextareaVariant\n autoResize?: boolean\n}\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n function Textarea(\n {\n variant,\n autoResize = false,\n rows = 3,\n className,\n id: idProp,\n 'aria-describedby': ariaDescribedByProp,\n ...props\n },\n ref,\n ) {\n const { field, id, ariaDescribedBy, inputStyle, inputColor } =\n useFieldControl({\n id: idProp,\n ariaDescribedBy: ariaDescribedByProp,\n variant: variant !== 'none' ? variant : undefined,\n })\n // an explicit variant prop keeps the box even inside an inset field\n const chrome =\n variant === 'none'\n ? 'none'\n : !variant && field?.labelPosition === 'inset'\n ? 'inset'\n : 'box'\n\n return (\n <textarea\n data-slot=\"textarea\"\n className={cn(\n textareaVariants({ chrome, inputStyle, inputColor, autoResize }),\n className,\n )}\n id={id}\n rows={rows}\n ref={ref}\n {...props}\n aria-describedby={ariaDescribedBy}\n />\n )\n },\n)\n\nexport { Textarea }\nexport type { TextareaProps, TextareaVariant }\n"],"mappings":";;;;;;;;AASA,MAAM,mBAAmB,IACvB,sQACA;CACE,UAAU;EACR,QAAQ;GACN,MAAM;GACN,OAAO;GACP,KAAK;EACP;EACA,YAAY;GAAE,MAAM;GAAI,SAAS;GAAI,UAAU;GAAI,OAAO;EAAG;EAC7D,YAAY;GAAE,OAAO;GAAI,MAAM;EAAG;EAClC,YAAY;GACV,MAAM;GACN,OAAO;EACT;CACF;CACA,kBAAkB;EAChB;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,KAAK;EACxB;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,KAAK;EACxB;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,QAAQ;EAC3B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,QAAQ;EAC3B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,SAAS;EAC5B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,SAAS;EAC5B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,MAAM;EACzB;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,MAAM;EACzB;EACA;GAAE,QAAQ;GAAS,YAAY;GAAS,OAAO;EAAiB;EAChE;GAAE,QAAQ;GAAS,YAAY;GAAQ,OAAO;EAAsB;EAGpE;GAAE,QAAQ;GAAS,OAAO;EAAkB;EAC5C;GAAE,QAAQ;GAAO,YAAY;GAAS,OAAO;EAAS;CACxD;AACF,CACF;AAOA,MAAM,WAAWA,QAAM,WACrB,SAAS,SACP,EACE,SACA,aAAa,OACb,OAAO,GACP,WACA,IAAI,QACJ,oBAAoB,qBACpB,GAAG,SAEL,KACA;CACA,MAAM,EAAE,OAAO,IAAI,iBAAiB,YAAY,eAC9C,gBAAgB;EACd,IAAI;EACJ,iBAAiB;EACjB,SAAS,YAAY,SAAS,UAAU,KAAA;CAC1C,CAAC;CASH,OACE,oBAAC,YAAD;EACE,aAAU;EACV,WAAW,GACT,iBAAiB;GAAE,QAVvB,YAAY,SACR,SACA,CAAC,WAAW,OAAO,kBAAkB,UACnC,UACA;GAMyB;GAAY;GAAY;EAAW,CAAC,GAC/D,SACF;EACI;EACE;EACD;EACL,GAAI;EACJ,oBAAkB;CACnB,CAAA;AAEL,CACF"}
1
+ {"version":3,"file":"textarea.js","names":["React"],"sources":["../../src/components/textarea.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority'\nimport * as React from 'react'\nimport { boxChrome, GHOST_UNDERLINE } from '../lib/input-box-variants'\nimport type { SparkInputStyle } from '../lib/theme-types'\nimport { cn } from '../utils/cn'\nimport { useFieldControl } from './field'\n\ntype TextareaVariant = SparkInputStyle | 'none'\n\nconst textareaVariants = cva(\n 'flex w-full min-w-0 bg-transparent text-gray outline-hidden transition-all group-data-[invalid=true]/field:text-error placeholder:text-gray-disabled disabled:cursor-not-allowed disabled:text-gray-disabled aria-invalid:text-error motion-reduce:transition-none',\n {\n variants: {\n chrome: {\n none: 'border-0 px-0',\n inset: GHOST_UNDERLINE,\n box: 'min-h-11 rounded-md px-3 py-2 text-base transition-all motion-reduce:transition-none',\n },\n inputStyle: { soft: '', surface: '', outlined: '', ghost: '' },\n inputColor: { brand: '', gray: '' },\n autoResize: {\n true: 'field-sizing-content resize-none',\n false: 'resize-y',\n },\n },\n compoundVariants: [\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'brand',\n class: boxChrome.soft.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'soft',\n inputColor: 'gray',\n class: boxChrome.soft.gray,\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'brand',\n class: boxChrome.surface.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'surface',\n inputColor: 'gray',\n class: boxChrome.surface.gray,\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'brand',\n class: boxChrome.outlined.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'outlined',\n inputColor: 'gray',\n class: boxChrome.outlined.gray,\n },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'brand',\n class: boxChrome.ghost.brand,\n },\n {\n chrome: 'box',\n inputStyle: 'ghost',\n inputColor: 'gray',\n class: boxChrome.ghost.gray,\n },\n { chrome: 'inset', inputColor: 'brand', class: 'border-b-input' },\n { chrome: 'inset', inputColor: 'gray', class: 'border-b-input-gray' },\n // GHOST_UNDERLINE and boxChrome.ghost.* hardcode h-10; un-clamp for\n // textarea's min-height model — must come after those compounds above\n { chrome: 'inset', class: 'h-auto min-h-10' },\n { chrome: 'box', inputStyle: 'ghost', class: 'h-auto' },\n ],\n },\n)\n\ninterface TextareaProps extends React.ComponentProps<'textarea'> {\n variant?: TextareaVariant\n autoResize?: boolean\n}\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n function Textarea(\n {\n variant,\n autoResize = false,\n rows = 3,\n className,\n id: idProp,\n 'aria-describedby': ariaDescribedByProp,\n ...props\n },\n ref,\n ) {\n const { field, id, ariaDescribedBy, ariaInvalid, inputStyle, inputColor } =\n useFieldControl({\n id: idProp,\n ariaDescribedBy: ariaDescribedByProp,\n variant: variant !== 'none' ? variant : undefined,\n })\n // an explicit variant prop keeps the box even inside an inset field\n const chrome =\n variant === 'none'\n ? 'none'\n : !variant && field?.labelPosition === 'inset'\n ? 'inset'\n : 'box'\n\n return (\n <textarea\n data-slot=\"textarea\"\n className={cn(\n textareaVariants({ chrome, inputStyle, inputColor, autoResize }),\n className,\n )}\n id={id}\n rows={rows}\n ref={ref}\n aria-invalid={ariaInvalid}\n {...props}\n aria-describedby={ariaDescribedBy}\n />\n )\n },\n)\n\nexport { Textarea }\nexport type { TextareaProps, TextareaVariant }\n"],"mappings":";;;;;;;;AASA,MAAM,mBAAmB,IACvB,sQACA;CACE,UAAU;EACR,QAAQ;GACN,MAAM;GACN,OAAO;GACP,KAAK;EACP;EACA,YAAY;GAAE,MAAM;GAAI,SAAS;GAAI,UAAU;GAAI,OAAO;EAAG;EAC7D,YAAY;GAAE,OAAO;GAAI,MAAM;EAAG;EAClC,YAAY;GACV,MAAM;GACN,OAAO;EACT;CACF;CACA,kBAAkB;EAChB;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,KAAK;EACxB;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,KAAK;EACxB;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,QAAQ;EAC3B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,QAAQ;EAC3B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,SAAS;EAC5B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,SAAS;EAC5B;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,MAAM;EACzB;EACA;GACE,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,OAAO,UAAU,MAAM;EACzB;EACA;GAAE,QAAQ;GAAS,YAAY;GAAS,OAAO;EAAiB;EAChE;GAAE,QAAQ;GAAS,YAAY;GAAQ,OAAO;EAAsB;EAGpE;GAAE,QAAQ;GAAS,OAAO;EAAkB;EAC5C;GAAE,QAAQ;GAAO,YAAY;GAAS,OAAO;EAAS;CACxD;AACF,CACF;AAOA,MAAM,WAAWA,QAAM,WACrB,SAAS,SACP,EACE,SACA,aAAa,OACb,OAAO,GACP,WACA,IAAI,QACJ,oBAAoB,qBACpB,GAAG,SAEL,KACA;CACA,MAAM,EAAE,OAAO,IAAI,iBAAiB,aAAa,YAAY,eAC3D,gBAAgB;EACd,IAAI;EACJ,iBAAiB;EACjB,SAAS,YAAY,SAAS,UAAU,KAAA;CAC1C,CAAC;CASH,OACE,oBAAC,YAAD;EACE,aAAU;EACV,WAAW,GACT,iBAAiB;GAAE,QAVvB,YAAY,SACR,SACA,CAAC,WAAW,OAAO,kBAAkB,UACnC,UACA;GAMyB;GAAY;GAAY;EAAW,CAAC,GAC/D,SACF;EACI;EACE;EACD;EACL,gBAAc;EACd,GAAI;EACJ,oBAAkB;CACnB,CAAA;AAEL,CACF"}
@@ -64,7 +64,7 @@ const TimePicker = react.forwardRef(({ "aria-label": ariaLabel, className, disab
64
64
  if (snapped !== event.currentTarget.value) onValueChange(snapped);
65
65
  },
66
66
  "aria-label": ariaLabel,
67
- className: (0, cnfast.cn)("h-10 w-full rounded-xl bg-base-gray-soft px-3 text-base font-medium text-gray tabular-nums transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50", className)
67
+ className: (0, cnfast.cn)("h-10 w-full rounded-md bg-base-gray-soft px-3 text-base font-medium text-gray tabular-nums transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50", className)
68
68
  });
69
69
  });
70
70
  TimePicker.displayName = "TimePicker";
@@ -1 +1 @@
1
- {"version":3,"file":"time-picker.cjs","names":["React"],"sources":["../../src/components/time-picker.tsx"],"sourcesContent":["import * as React from 'react'\nimport { cn } from '../utils/cn'\n\ninterface TimePickerProps {\n /** `HH:MM` 24-hour string. */\n value: string\n onValueChange: (next: string) => void\n disabled?: boolean\n /** Step in seconds (defaults to 60 — minute-resolution). */\n step?: number\n className?: string\n id?: string\n 'aria-label'?: string\n}\n\nconst MINUTES_PER_DAY = 24 * 60\n\n/**\n * Move `HH:mm` one grid step in `direction`, aligning to the `step` grid first.\n * A native `<input type=\"time\">` steps each focused segment by one unit and\n * ignores `step`, so callers that want arrow keys to move by a coarse step\n * (e.g. 5 minutes) route the arrow keys through this instead. Clamped to\n * `00:00`–`23:55` (no wrap); an off-grid start lands on the next grid point in\n * the pressed direction.\n */\nfunction stepGridValue(value: string, step: number, direction: 1 | -1): string {\n const stepMinutes = Math.floor(step / 60)\n if (stepMinutes <= 1) return value\n const match = /^(\\d{1,2}):(\\d{2})/.exec(value)\n const base = match ? Number(match[1]) * 60 + Number(match[2]) : 0\n const next =\n direction === 1\n ? Math.floor(base / stepMinutes) * stepMinutes + stepMinutes\n : Math.ceil(base / stepMinutes) * stepMinutes - stepMinutes\n const lastOnGrid =\n Math.floor((MINUTES_PER_DAY - 1) / stepMinutes) * stepMinutes\n const clamped = Math.max(0, Math.min(next, lastOnGrid))\n const hh = String(Math.floor(clamped / 60)).padStart(2, '0')\n const mm = String(clamped % 60).padStart(2, '0')\n return `${hh}:${mm}`\n}\n\n/**\n * Round `HH:mm` to the nearest multiple of `step` (used to autofix a typed\n * off-grid value on blur). Already-on-grid values pass through unchanged (so a\n * seconds suffix is preserved); anything that isn't `HH:mm(:ss)` passes through.\n */\nfunction snapToNearestStep(value: string, step: number): string {\n const stepMinutes = Math.floor(step / 60)\n if (stepMinutes <= 1) return value\n const match = /^(\\d{1,2}):(\\d{2})/.exec(value)\n if (!match) return value\n const minutes = Number(match[2])\n if (minutes % stepMinutes === 0) return value\n const total = Number(match[1]) * 60 + minutes\n const lastOnGrid =\n Math.floor((MINUTES_PER_DAY - 1) / stepMinutes) * stepMinutes\n const snapped = Math.min(\n Math.round(total / stepMinutes) * stepMinutes,\n lastOnGrid,\n )\n const hh = String(Math.floor(snapped / 60)).padStart(2, '0')\n const mm = String(snapped % 60).padStart(2, '0')\n return `${hh}:${mm}`\n}\n\nconst TimePicker = React.forwardRef<HTMLInputElement, TimePickerProps>(\n (\n {\n 'aria-label': ariaLabel,\n className,\n disabled,\n id,\n onValueChange,\n step = 60,\n value,\n },\n ref,\n ) => {\n const stepMinutes = Math.floor(step / 60)\n return (\n <input\n ref={ref}\n id={id}\n type=\"time\"\n value={value}\n step={step}\n disabled={disabled}\n onChange={(event) => onValueChange(event.target.value)}\n onKeyDown={(event) => {\n // Native arrows step the focused segment by one unit and ignore step;\n // for a coarse grid, drive up/down through the grid instead.\n if (stepMinutes <= 1) return\n if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return\n event.preventDefault()\n onValueChange(\n stepGridValue(value, step, event.key === 'ArrowUp' ? 1 : -1),\n )\n }}\n onBlur={(event) => {\n // Autofix a typed off-grid value to the closest grid point on blur.\n if (stepMinutes <= 1) return\n const snapped = snapToNearestStep(event.currentTarget.value, step)\n if (snapped !== event.currentTarget.value) onValueChange(snapped)\n }}\n aria-label={ariaLabel}\n className={cn(\n 'h-10 w-full rounded-xl bg-base-gray-soft px-3 text-base font-medium text-gray tabular-nums transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n />\n )\n },\n)\n\nTimePicker.displayName = 'TimePicker'\n\ninterface TimeRangePickerProps {\n start: string\n end: string\n onStartChange: (next: string) => void\n onEndChange: (next: string) => void\n disabled?: boolean\n startLabel?: string\n endLabel?: string\n /** Step in seconds, forwarded to both inputs (defaults to 60). */\n step?: number\n className?: string\n}\n\nfunction TimeRangePicker({\n className,\n disabled,\n end,\n endLabel = 'End',\n onEndChange,\n onStartChange,\n start,\n startLabel = 'Start',\n step,\n}: TimeRangePickerProps) {\n return (\n <div className={cn('grid grid-cols-2 gap-2', className)}>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-gray-light\">\n {startLabel}\n </span>\n <TimePicker\n value={start}\n onValueChange={onStartChange}\n disabled={disabled}\n step={step}\n aria-label={startLabel}\n />\n </label>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-gray-light\">{endLabel}</span>\n <TimePicker\n value={end}\n onValueChange={onEndChange}\n disabled={disabled}\n step={step}\n aria-label={endLabel}\n />\n </label>\n </div>\n )\n}\n\nexport { TimePicker, TimeRangePicker }\n"],"mappings":"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"}
1
+ {"version":3,"file":"time-picker.cjs","names":["React"],"sources":["../../src/components/time-picker.tsx"],"sourcesContent":["import * as React from 'react'\nimport { cn } from '../utils/cn'\n\ninterface TimePickerProps {\n /** `HH:MM` 24-hour string. */\n value: string\n onValueChange: (next: string) => void\n disabled?: boolean\n /** Step in seconds (defaults to 60 — minute-resolution). */\n step?: number\n className?: string\n id?: string\n 'aria-label'?: string\n}\n\nconst MINUTES_PER_DAY = 24 * 60\n\n/**\n * Move `HH:mm` one grid step in `direction`, aligning to the `step` grid first.\n * A native `<input type=\"time\">` steps each focused segment by one unit and\n * ignores `step`, so callers that want arrow keys to move by a coarse step\n * (e.g. 5 minutes) route the arrow keys through this instead. Clamped to\n * `00:00`–`23:55` (no wrap); an off-grid start lands on the next grid point in\n * the pressed direction.\n */\nfunction stepGridValue(value: string, step: number, direction: 1 | -1): string {\n const stepMinutes = Math.floor(step / 60)\n if (stepMinutes <= 1) return value\n const match = /^(\\d{1,2}):(\\d{2})/.exec(value)\n const base = match ? Number(match[1]) * 60 + Number(match[2]) : 0\n const next =\n direction === 1\n ? Math.floor(base / stepMinutes) * stepMinutes + stepMinutes\n : Math.ceil(base / stepMinutes) * stepMinutes - stepMinutes\n const lastOnGrid =\n Math.floor((MINUTES_PER_DAY - 1) / stepMinutes) * stepMinutes\n const clamped = Math.max(0, Math.min(next, lastOnGrid))\n const hh = String(Math.floor(clamped / 60)).padStart(2, '0')\n const mm = String(clamped % 60).padStart(2, '0')\n return `${hh}:${mm}`\n}\n\n/**\n * Round `HH:mm` to the nearest multiple of `step` (used to autofix a typed\n * off-grid value on blur). Already-on-grid values pass through unchanged (so a\n * seconds suffix is preserved); anything that isn't `HH:mm(:ss)` passes through.\n */\nfunction snapToNearestStep(value: string, step: number): string {\n const stepMinutes = Math.floor(step / 60)\n if (stepMinutes <= 1) return value\n const match = /^(\\d{1,2}):(\\d{2})/.exec(value)\n if (!match) return value\n const minutes = Number(match[2])\n if (minutes % stepMinutes === 0) return value\n const total = Number(match[1]) * 60 + minutes\n const lastOnGrid =\n Math.floor((MINUTES_PER_DAY - 1) / stepMinutes) * stepMinutes\n const snapped = Math.min(\n Math.round(total / stepMinutes) * stepMinutes,\n lastOnGrid,\n )\n const hh = String(Math.floor(snapped / 60)).padStart(2, '0')\n const mm = String(snapped % 60).padStart(2, '0')\n return `${hh}:${mm}`\n}\n\nconst TimePicker = React.forwardRef<HTMLInputElement, TimePickerProps>(\n (\n {\n 'aria-label': ariaLabel,\n className,\n disabled,\n id,\n onValueChange,\n step = 60,\n value,\n },\n ref,\n ) => {\n const stepMinutes = Math.floor(step / 60)\n return (\n <input\n ref={ref}\n id={id}\n type=\"time\"\n value={value}\n step={step}\n disabled={disabled}\n onChange={(event) => onValueChange(event.target.value)}\n onKeyDown={(event) => {\n // Native arrows step the focused segment by one unit and ignore step;\n // for a coarse grid, drive up/down through the grid instead.\n if (stepMinutes <= 1) return\n if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return\n event.preventDefault()\n onValueChange(\n stepGridValue(value, step, event.key === 'ArrowUp' ? 1 : -1),\n )\n }}\n onBlur={(event) => {\n // Autofix a typed off-grid value to the closest grid point on blur.\n if (stepMinutes <= 1) return\n const snapped = snapToNearestStep(event.currentTarget.value, step)\n if (snapped !== event.currentTarget.value) onValueChange(snapped)\n }}\n aria-label={ariaLabel}\n className={cn(\n 'h-10 w-full rounded-md bg-base-gray-soft px-3 text-base font-medium text-gray tabular-nums transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n />\n )\n },\n)\n\nTimePicker.displayName = 'TimePicker'\n\ninterface TimeRangePickerProps {\n start: string\n end: string\n onStartChange: (next: string) => void\n onEndChange: (next: string) => void\n disabled?: boolean\n startLabel?: string\n endLabel?: string\n /** Step in seconds, forwarded to both inputs (defaults to 60). */\n step?: number\n className?: string\n}\n\nfunction TimeRangePicker({\n className,\n disabled,\n end,\n endLabel = 'End',\n onEndChange,\n onStartChange,\n start,\n startLabel = 'Start',\n step,\n}: TimeRangePickerProps) {\n return (\n <div className={cn('grid grid-cols-2 gap-2', className)}>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-gray-light\">\n {startLabel}\n </span>\n <TimePicker\n value={start}\n onValueChange={onStartChange}\n disabled={disabled}\n step={step}\n aria-label={startLabel}\n />\n </label>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-gray-light\">{endLabel}</span>\n <TimePicker\n value={end}\n onValueChange={onEndChange}\n disabled={disabled}\n step={step}\n aria-label={endLabel}\n />\n </label>\n </div>\n )\n}\n\nexport { TimePicker, TimeRangePicker }\n"],"mappings":"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"}
@@ -61,7 +61,7 @@ const TimePicker = React$1.forwardRef(({ "aria-label": ariaLabel, className, dis
61
61
  if (snapped !== event.currentTarget.value) onValueChange(snapped);
62
62
  },
63
63
  "aria-label": ariaLabel,
64
- className: cn("h-10 w-full rounded-xl bg-base-gray-soft px-3 text-base font-medium text-gray tabular-nums transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50", className)
64
+ className: cn("h-10 w-full rounded-md bg-base-gray-soft px-3 text-base font-medium text-gray tabular-nums transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50", className)
65
65
  });
66
66
  });
67
67
  TimePicker.displayName = "TimePicker";
@@ -1 +1 @@
1
- {"version":3,"file":"time-picker.js","names":["React"],"sources":["../../src/components/time-picker.tsx"],"sourcesContent":["import * as React from 'react'\nimport { cn } from '../utils/cn'\n\ninterface TimePickerProps {\n /** `HH:MM` 24-hour string. */\n value: string\n onValueChange: (next: string) => void\n disabled?: boolean\n /** Step in seconds (defaults to 60 — minute-resolution). */\n step?: number\n className?: string\n id?: string\n 'aria-label'?: string\n}\n\nconst MINUTES_PER_DAY = 24 * 60\n\n/**\n * Move `HH:mm` one grid step in `direction`, aligning to the `step` grid first.\n * A native `<input type=\"time\">` steps each focused segment by one unit and\n * ignores `step`, so callers that want arrow keys to move by a coarse step\n * (e.g. 5 minutes) route the arrow keys through this instead. Clamped to\n * `00:00`–`23:55` (no wrap); an off-grid start lands on the next grid point in\n * the pressed direction.\n */\nfunction stepGridValue(value: string, step: number, direction: 1 | -1): string {\n const stepMinutes = Math.floor(step / 60)\n if (stepMinutes <= 1) return value\n const match = /^(\\d{1,2}):(\\d{2})/.exec(value)\n const base = match ? Number(match[1]) * 60 + Number(match[2]) : 0\n const next =\n direction === 1\n ? Math.floor(base / stepMinutes) * stepMinutes + stepMinutes\n : Math.ceil(base / stepMinutes) * stepMinutes - stepMinutes\n const lastOnGrid =\n Math.floor((MINUTES_PER_DAY - 1) / stepMinutes) * stepMinutes\n const clamped = Math.max(0, Math.min(next, lastOnGrid))\n const hh = String(Math.floor(clamped / 60)).padStart(2, '0')\n const mm = String(clamped % 60).padStart(2, '0')\n return `${hh}:${mm}`\n}\n\n/**\n * Round `HH:mm` to the nearest multiple of `step` (used to autofix a typed\n * off-grid value on blur). Already-on-grid values pass through unchanged (so a\n * seconds suffix is preserved); anything that isn't `HH:mm(:ss)` passes through.\n */\nfunction snapToNearestStep(value: string, step: number): string {\n const stepMinutes = Math.floor(step / 60)\n if (stepMinutes <= 1) return value\n const match = /^(\\d{1,2}):(\\d{2})/.exec(value)\n if (!match) return value\n const minutes = Number(match[2])\n if (minutes % stepMinutes === 0) return value\n const total = Number(match[1]) * 60 + minutes\n const lastOnGrid =\n Math.floor((MINUTES_PER_DAY - 1) / stepMinutes) * stepMinutes\n const snapped = Math.min(\n Math.round(total / stepMinutes) * stepMinutes,\n lastOnGrid,\n )\n const hh = String(Math.floor(snapped / 60)).padStart(2, '0')\n const mm = String(snapped % 60).padStart(2, '0')\n return `${hh}:${mm}`\n}\n\nconst TimePicker = React.forwardRef<HTMLInputElement, TimePickerProps>(\n (\n {\n 'aria-label': ariaLabel,\n className,\n disabled,\n id,\n onValueChange,\n step = 60,\n value,\n },\n ref,\n ) => {\n const stepMinutes = Math.floor(step / 60)\n return (\n <input\n ref={ref}\n id={id}\n type=\"time\"\n value={value}\n step={step}\n disabled={disabled}\n onChange={(event) => onValueChange(event.target.value)}\n onKeyDown={(event) => {\n // Native arrows step the focused segment by one unit and ignore step;\n // for a coarse grid, drive up/down through the grid instead.\n if (stepMinutes <= 1) return\n if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return\n event.preventDefault()\n onValueChange(\n stepGridValue(value, step, event.key === 'ArrowUp' ? 1 : -1),\n )\n }}\n onBlur={(event) => {\n // Autofix a typed off-grid value to the closest grid point on blur.\n if (stepMinutes <= 1) return\n const snapped = snapToNearestStep(event.currentTarget.value, step)\n if (snapped !== event.currentTarget.value) onValueChange(snapped)\n }}\n aria-label={ariaLabel}\n className={cn(\n 'h-10 w-full rounded-xl bg-base-gray-soft px-3 text-base font-medium text-gray tabular-nums transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n />\n )\n },\n)\n\nTimePicker.displayName = 'TimePicker'\n\ninterface TimeRangePickerProps {\n start: string\n end: string\n onStartChange: (next: string) => void\n onEndChange: (next: string) => void\n disabled?: boolean\n startLabel?: string\n endLabel?: string\n /** Step in seconds, forwarded to both inputs (defaults to 60). */\n step?: number\n className?: string\n}\n\nfunction TimeRangePicker({\n className,\n disabled,\n end,\n endLabel = 'End',\n onEndChange,\n onStartChange,\n start,\n startLabel = 'Start',\n step,\n}: TimeRangePickerProps) {\n return (\n <div className={cn('grid grid-cols-2 gap-2', className)}>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-gray-light\">\n {startLabel}\n </span>\n <TimePicker\n value={start}\n onValueChange={onStartChange}\n disabled={disabled}\n step={step}\n aria-label={startLabel}\n />\n </label>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-gray-light\">{endLabel}</span>\n <TimePicker\n value={end}\n onValueChange={onEndChange}\n disabled={disabled}\n step={step}\n aria-label={endLabel}\n />\n </label>\n </div>\n )\n}\n\nexport { TimePicker, TimeRangePicker }\n"],"mappings":"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"}
1
+ {"version":3,"file":"time-picker.js","names":["React"],"sources":["../../src/components/time-picker.tsx"],"sourcesContent":["import * as React from 'react'\nimport { cn } from '../utils/cn'\n\ninterface TimePickerProps {\n /** `HH:MM` 24-hour string. */\n value: string\n onValueChange: (next: string) => void\n disabled?: boolean\n /** Step in seconds (defaults to 60 — minute-resolution). */\n step?: number\n className?: string\n id?: string\n 'aria-label'?: string\n}\n\nconst MINUTES_PER_DAY = 24 * 60\n\n/**\n * Move `HH:mm` one grid step in `direction`, aligning to the `step` grid first.\n * A native `<input type=\"time\">` steps each focused segment by one unit and\n * ignores `step`, so callers that want arrow keys to move by a coarse step\n * (e.g. 5 minutes) route the arrow keys through this instead. Clamped to\n * `00:00`–`23:55` (no wrap); an off-grid start lands on the next grid point in\n * the pressed direction.\n */\nfunction stepGridValue(value: string, step: number, direction: 1 | -1): string {\n const stepMinutes = Math.floor(step / 60)\n if (stepMinutes <= 1) return value\n const match = /^(\\d{1,2}):(\\d{2})/.exec(value)\n const base = match ? Number(match[1]) * 60 + Number(match[2]) : 0\n const next =\n direction === 1\n ? Math.floor(base / stepMinutes) * stepMinutes + stepMinutes\n : Math.ceil(base / stepMinutes) * stepMinutes - stepMinutes\n const lastOnGrid =\n Math.floor((MINUTES_PER_DAY - 1) / stepMinutes) * stepMinutes\n const clamped = Math.max(0, Math.min(next, lastOnGrid))\n const hh = String(Math.floor(clamped / 60)).padStart(2, '0')\n const mm = String(clamped % 60).padStart(2, '0')\n return `${hh}:${mm}`\n}\n\n/**\n * Round `HH:mm` to the nearest multiple of `step` (used to autofix a typed\n * off-grid value on blur). Already-on-grid values pass through unchanged (so a\n * seconds suffix is preserved); anything that isn't `HH:mm(:ss)` passes through.\n */\nfunction snapToNearestStep(value: string, step: number): string {\n const stepMinutes = Math.floor(step / 60)\n if (stepMinutes <= 1) return value\n const match = /^(\\d{1,2}):(\\d{2})/.exec(value)\n if (!match) return value\n const minutes = Number(match[2])\n if (minutes % stepMinutes === 0) return value\n const total = Number(match[1]) * 60 + minutes\n const lastOnGrid =\n Math.floor((MINUTES_PER_DAY - 1) / stepMinutes) * stepMinutes\n const snapped = Math.min(\n Math.round(total / stepMinutes) * stepMinutes,\n lastOnGrid,\n )\n const hh = String(Math.floor(snapped / 60)).padStart(2, '0')\n const mm = String(snapped % 60).padStart(2, '0')\n return `${hh}:${mm}`\n}\n\nconst TimePicker = React.forwardRef<HTMLInputElement, TimePickerProps>(\n (\n {\n 'aria-label': ariaLabel,\n className,\n disabled,\n id,\n onValueChange,\n step = 60,\n value,\n },\n ref,\n ) => {\n const stepMinutes = Math.floor(step / 60)\n return (\n <input\n ref={ref}\n id={id}\n type=\"time\"\n value={value}\n step={step}\n disabled={disabled}\n onChange={(event) => onValueChange(event.target.value)}\n onKeyDown={(event) => {\n // Native arrows step the focused segment by one unit and ignore step;\n // for a coarse grid, drive up/down through the grid instead.\n if (stepMinutes <= 1) return\n if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return\n event.preventDefault()\n onValueChange(\n stepGridValue(value, step, event.key === 'ArrowUp' ? 1 : -1),\n )\n }}\n onBlur={(event) => {\n // Autofix a typed off-grid value to the closest grid point on blur.\n if (stepMinutes <= 1) return\n const snapped = snapToNearestStep(event.currentTarget.value, step)\n if (snapped !== event.currentTarget.value) onValueChange(snapped)\n }}\n aria-label={ariaLabel}\n className={cn(\n 'h-10 w-full rounded-md bg-base-gray-soft px-3 text-base font-medium text-gray tabular-nums transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n />\n )\n },\n)\n\nTimePicker.displayName = 'TimePicker'\n\ninterface TimeRangePickerProps {\n start: string\n end: string\n onStartChange: (next: string) => void\n onEndChange: (next: string) => void\n disabled?: boolean\n startLabel?: string\n endLabel?: string\n /** Step in seconds, forwarded to both inputs (defaults to 60). */\n step?: number\n className?: string\n}\n\nfunction TimeRangePicker({\n className,\n disabled,\n end,\n endLabel = 'End',\n onEndChange,\n onStartChange,\n start,\n startLabel = 'Start',\n step,\n}: TimeRangePickerProps) {\n return (\n <div className={cn('grid grid-cols-2 gap-2', className)}>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-gray-light\">\n {startLabel}\n </span>\n <TimePicker\n value={start}\n onValueChange={onStartChange}\n disabled={disabled}\n step={step}\n aria-label={startLabel}\n />\n </label>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-gray-light\">{endLabel}</span>\n <TimePicker\n value={end}\n onValueChange={onEndChange}\n disabled={disabled}\n step={step}\n aria-label={endLabel}\n />\n </label>\n </div>\n )\n}\n\nexport { TimePicker, TimeRangePicker }\n"],"mappings":"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"}
@@ -118,7 +118,7 @@ function ToastItem({ closeButton, richColors, toast: toastObject }) {
118
118
  const showClose = toastObject.data?.closeButton ?? closeButton;
119
119
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_base_ui_react_toast.Toast.Root, {
120
120
  "data-slot": "toast",
121
- className: (0, cnfast.cn)("flex items-start gap-2 rounded-md border border-gray-a5 bg-gray-1 p-3 text-gray shadow-md select-none", richColors && tone),
121
+ className: (0, cnfast.cn)("flex items-start gap-2 rounded-lg border border-gray-a5 bg-gray-1 p-3 text-gray shadow-md select-none", richColors && tone),
122
122
  swipeDirection: [
123
123
  "up",
124
124
  "down",
@@ -1 +1 @@
1
- {"version":3,"file":"toast.cjs","names":["ToastPrimitive","Spinner","MaterialSymbol","buttonVariants"],"sources":["../../src/components/toast.tsx"],"sourcesContent":["'use client'\n\nimport { Toast as ToastPrimitive } from '@base-ui/react/toast'\nimport * as React from 'react'\nimport {\n MaterialSymbol,\n type MaterialSymbolIconName,\n} from '../icons/material-symbol'\nimport { cn } from '../utils/cn'\nimport { buttonVariants } from './button'\nimport { Spinner } from './spinner'\n\ntype ToastType = 'success' | 'info' | 'warning' | 'error' | 'loading'\n\ntype ToastPosition =\n | 'top-left'\n | 'top-center'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-center'\n | 'bottom-right'\n\n// Per-toast overrides Base UI carries through untouched as opaque `data`.\ntype ToastData = { closeButton?: boolean }\n\n// `label` is the button's content; everything else a `<button>` takes passes\n// straight through, so a caller can set `className`, `disabled`, `type`, and\n// the rest without a new prop for each one.\ntype ToastAction = Omit<\n React.ComponentPropsWithoutRef<'button'>,\n 'children'\n> & {\n label: React.ReactNode\n}\n\ntype ToastOptions = {\n description?: React.ReactNode\n /** Auto-dismiss time in ms. `0` keeps the toast until dismissed. */\n duration?: number\n /** Reuse an id to update a toast in place instead of stacking a new one. */\n id?: string\n closeButton?: boolean\n action?: ToastAction\n onDismiss?: () => void\n /** `high` announces urgently (assertive); the default is polite. */\n priority?: 'low' | 'high'\n}\n\ntype ToastPromiseMessages<Value> = {\n loading: string\n success: string | ((value: Value) => string)\n error: string | ((error: unknown) => string)\n}\n\nconst TOAST_ICONS: Record<\n Exclude<ToastType, 'loading'>,\n { name: MaterialSymbolIconName; className: string }\n> = {\n success: { name: 'check_circle', className: 'text-success-light' },\n info: { name: 'info', className: 'text-info-light' },\n warning: { name: 'warning', className: 'text-warning-light' },\n error: { name: 'cancel', className: 'text-error-light' },\n}\n\n// Opaque radix steps (bg 2, border 6, text 11) so a floating toast never lets\n// page content bleed through the way the alpha `-soft` tokens would. The border\n// carries the tone too, otherwise a tinted toast keeps a grey outline.\nconst TONE_CLASSES: Record<Exclude<ToastType, 'loading'>, string> = {\n success: 'border-green-6 bg-green-2 text-green-11',\n info: 'border-blue-6 bg-blue-2 text-blue-11',\n warning: 'border-orange-6 bg-orange-2 text-orange-11',\n error: 'border-red-6 bg-red-2 text-red-11',\n}\n\n// Mobile-first: every position drops to a full-width stack at the top, which\n// is what the end-customer portal ships. `position` only takes effect from the\n// `sm` breakpoint up.\nconst POSITION_CLASSES: Record<ToastPosition, string> = {\n 'top-left': 'sm:top-4 sm:right-auto sm:bottom-auto sm:left-4',\n 'top-center':\n 'sm:top-4 sm:right-auto sm:bottom-auto sm:left-1/2 sm:-translate-x-1/2',\n 'top-right': 'sm:top-4 sm:right-4 sm:bottom-auto sm:left-auto',\n 'bottom-left': 'sm:top-auto sm:right-auto sm:bottom-4 sm:left-4',\n 'bottom-center':\n 'sm:top-auto sm:right-auto sm:bottom-4 sm:left-1/2 sm:-translate-x-1/2',\n 'bottom-right': 'sm:top-auto sm:right-4 sm:bottom-4 sm:left-auto',\n}\n\nconst manager = ToastPrimitive.createToastManager<ToastData>()\n\nlet sequence = 0\n\n// `label` names the content and `onClick` is wrapped, so neither reaches the\n// DOM button as-is; everything else does.\nfunction actionRest({\n label: _label,\n onClick: _onClick,\n ...rest\n}: ToastAction) {\n return rest\n}\n\nfunction toManagerOptions(\n id: string,\n title: React.ReactNode,\n type: ToastType | undefined,\n options: ToastOptions | undefined,\n) {\n const action = options?.action\n return {\n id,\n title,\n type,\n description: options?.description,\n timeout: options?.duration,\n priority: options?.priority,\n onClose: options?.onDismiss,\n // Base UI leaves the toast open after an action; dismissing matches what\n // callers expect from an \"Undo\" button.\n actionProps: action && {\n ...actionRest(action),\n children: action.label,\n onClick: (event: React.MouseEvent<HTMLButtonElement>) => {\n action.onClick?.(event)\n manager.close(id)\n },\n },\n data: { closeButton: options?.closeButton },\n }\n}\n\nconst emit =\n (type?: ToastType) =>\n (message: React.ReactNode, options?: ToastOptions): string => {\n // an id up front lets the action handler close the toast it belongs to\n const id = options?.id ?? `spark-toast-${(sequence += 1)}`\n return manager.add(toManagerOptions(id, message, type, options))\n }\n\n// A string phase becomes a titled toast of that type; an object phase keeps\n// whatever the caller set and only fills in the type.\nconst phase =\n <Value,>(\n value: ToastPromiseMessages<Value>[keyof ToastPromiseMessages<Value>],\n type: ToastType,\n ) =>\n (result: Value) => {\n const resolved = typeof value === 'function' ? value(result) : value\n return { title: resolved, type }\n }\n\nconst toast = Object.assign(emit(), {\n success: emit('success'),\n info: emit('info'),\n warning: emit('warning'),\n error: emit('error'),\n loading: emit('loading'),\n /** Dismiss one toast, or every toast when called without an id. */\n dismiss: (id?: string) => manager.close(id),\n promise: <Value,>(\n promiseValue: Promise<Value>,\n messages: ToastPromiseMessages<Value>,\n ) =>\n manager.promise(promiseValue, {\n loading: { title: messages.loading, type: 'loading' as const },\n success: phase(messages.success, 'success'),\n error: phase(messages.error as never, 'error'),\n }),\n})\n\nfunction ToastIcon({ type }: { type?: string }) {\n const icon = TOAST_ICONS[type as Exclude<ToastType, 'loading'>]\n if (type !== 'loading' && !icon) return null\n\n // Fixed box matching the title's line height, so the glyph and the spinner\n // both centre on the first line whether or not a description follows.\n return (\n <span\n aria-hidden=\"true\"\n className=\"flex h-5 w-5 shrink-0 items-center justify-center\"\n >\n {type === 'loading' ? (\n // Decorative: the toast already announces the loading message, so the\n // spinner must not add a second status live region.\n <Spinner\n className=\"text-gray-11\"\n label=\"\"\n role=\"presentation\"\n size=\"sm\"\n />\n ) : (\n <MaterialSymbol\n className={cn('[--spark-icon-size:20px]', icon.className)}\n name={icon.name}\n />\n )}\n </span>\n )\n}\n\nfunction ToastItem({\n closeButton,\n richColors,\n toast: toastObject,\n}: {\n closeButton: boolean\n richColors: boolean\n toast: ToastPrimitive.Root.ToastObject<ToastData>\n}) {\n const tone = TONE_CLASSES[toastObject.type as Exclude<ToastType, 'loading'>]\n const showClose = toastObject.data?.closeButton ?? closeButton\n\n return (\n <ToastPrimitive.Root\n data-slot=\"toast\"\n className={cn(\n // Skin only. All geometry (position, stacking, transitions, the\n // pointer bridge) lives in styles/index.css, because Tailwind's\n // `utilities` layer outranks `components` and a stray `bottom-0` here\n // would beat the stylesheet's `bottom: auto` on top-anchored stacks.\n // The border is what makes the cards behind the front one legible.\n 'flex items-start gap-2 rounded-md border border-gray-a5 bg-gray-1 p-3 text-gray shadow-md select-none',\n richColors && tone,\n )}\n // the stack is top-anchored on mobile and bottom-anchored above `sm`, so\n // both vertical directions have to dismiss\n swipeDirection={['up', 'down', 'right']}\n toast={toastObject}\n >\n <ToastIcon type={toastObject.type} />\n <ToastPrimitive.Content className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <ToastPrimitive.Title\n className=\"text-sm font-medium\"\n data-slot=\"toast-title\"\n />\n <ToastPrimitive.Description\n className={cn(\n 'text-sm',\n richColors && tone ? 'text-inherit' : 'text-gray-11',\n )}\n data-slot=\"toast-description\"\n />\n </ToastPrimitive.Content>\n {toastObject.actionProps ? (\n <ToastPrimitive.Action\n // -my-2 keeps the 36px control from stretching a single-line row past\n // the 20px text; self-center then lands it on the title when there is\n // no description, and mid-block when there is one\n className={cn(\n buttonVariants({ size: 'small', variant: 'primary' }),\n '-my-2 shrink-0 self-center rounded-full',\n )}\n data-slot=\"toast-action\"\n />\n ) : null}\n {showClose ? (\n <ToastPrimitive.Close\n aria-label=\"Close\"\n className={cn(\n buttonVariants({ size: 'icon-small', variant: 'tertiary' }),\n // -my-1: same reason as the action, for a 28px control\n '-my-1 -mr-1 size-7 shrink-0 self-center text-gray-11',\n )}\n data-slot=\"toast-close\"\n >\n <MaterialSymbol\n aria-hidden=\"true\"\n className=\"[--spark-icon-size:18px]\"\n name=\"close\"\n />\n </ToastPrimitive.Close>\n ) : null}\n </ToastPrimitive.Root>\n )\n}\n\nfunction ToastList({\n closeButton,\n richColors,\n}: {\n closeButton: boolean\n richColors: boolean\n}) {\n const { toasts } = ToastPrimitive.useToastManager<ToastData>()\n\n return toasts.map((toastObject) => (\n <ToastItem\n closeButton={closeButton}\n key={toastObject.id}\n richColors={richColors}\n toast={toastObject}\n />\n ))\n}\n\ntype ToasterProps = {\n className?: string\n /** Corner or edge the toasts stack in. */\n position?: ToastPosition\n /** Close button on every toast; a per-toast `closeButton` wins. */\n closeButton?: boolean\n /** Tinted surfaces for success/info/warning/error toasts. */\n richColors?: boolean\n /** Default auto-dismiss time in ms. `0` disables auto-dismiss. */\n duration?: number\n /** Toasts visible at once before older ones are marked `data-limited`. */\n limit?: number\n /**\n * Vertical edge below the `sm` breakpoint, where the stack is always\n * full-width and `position` does not apply. Defaults to `top`, matching the\n * end-customer portal.\n */\n mobilePosition?: 'top' | 'bottom'\n}\n\nfunction Toaster({\n className,\n closeButton = true,\n duration = 4000,\n limit,\n mobilePosition = 'top',\n position = 'bottom-right',\n richColors = true,\n}: ToasterProps) {\n return (\n <ToastPrimitive.Provider\n limit={limit}\n timeout={duration}\n toastManager={manager}\n >\n <ToastPrimitive.Portal>\n <ToastPrimitive.Viewport\n // block + zero height: the toasts are absolutely positioned against\n // this box's bottom edge, the way Base UI's stacked example works\n className={cn(\n 'fixed inset-x-4 z-50 block h-0 outline-none',\n mobilePosition === 'top' ? 'top-4' : 'bottom-4',\n 'sm:inset-x-auto sm:w-96 sm:max-w-[calc(100vw-2rem)]',\n POSITION_CLASSES[position],\n className,\n )}\n data-mobile-side={mobilePosition}\n data-side={position.startsWith('top') ? 'top' : 'bottom'}\n data-slot=\"toaster\"\n >\n <ToastList closeButton={closeButton} richColors={richColors} />\n </ToastPrimitive.Viewport>\n </ToastPrimitive.Portal>\n </ToastPrimitive.Provider>\n )\n}\n\nexport { Toaster, toast }\nexport type {\n ToastAction,\n ToasterProps,\n ToastOptions,\n ToastPosition,\n ToastPromiseMessages,\n ToastType,\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"toast.cjs","names":["ToastPrimitive","Spinner","MaterialSymbol","buttonVariants"],"sources":["../../src/components/toast.tsx"],"sourcesContent":["'use client'\n\nimport { Toast as ToastPrimitive } from '@base-ui/react/toast'\nimport * as React from 'react'\nimport {\n MaterialSymbol,\n type MaterialSymbolIconName,\n} from '../icons/material-symbol'\nimport { cn } from '../utils/cn'\nimport { buttonVariants } from './button'\nimport { Spinner } from './spinner'\n\ntype ToastType = 'success' | 'info' | 'warning' | 'error' | 'loading'\n\ntype ToastPosition =\n | 'top-left'\n | 'top-center'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-center'\n | 'bottom-right'\n\n// Per-toast overrides Base UI carries through untouched as opaque `data`.\ntype ToastData = { closeButton?: boolean }\n\n// `label` is the button's content; everything else a `<button>` takes passes\n// straight through, so a caller can set `className`, `disabled`, `type`, and\n// the rest without a new prop for each one.\ntype ToastAction = Omit<\n React.ComponentPropsWithoutRef<'button'>,\n 'children'\n> & {\n label: React.ReactNode\n}\n\ntype ToastOptions = {\n description?: React.ReactNode\n /** Auto-dismiss time in ms. `0` keeps the toast until dismissed. */\n duration?: number\n /** Reuse an id to update a toast in place instead of stacking a new one. */\n id?: string\n closeButton?: boolean\n action?: ToastAction\n onDismiss?: () => void\n /** `high` announces urgently (assertive); the default is polite. */\n priority?: 'low' | 'high'\n}\n\ntype ToastPromiseMessages<Value> = {\n loading: string\n success: string | ((value: Value) => string)\n error: string | ((error: unknown) => string)\n}\n\nconst TOAST_ICONS: Record<\n Exclude<ToastType, 'loading'>,\n { name: MaterialSymbolIconName; className: string }\n> = {\n success: { name: 'check_circle', className: 'text-success-light' },\n info: { name: 'info', className: 'text-info-light' },\n warning: { name: 'warning', className: 'text-warning-light' },\n error: { name: 'cancel', className: 'text-error-light' },\n}\n\n// Opaque radix steps (bg 2, border 6, text 11) so a floating toast never lets\n// page content bleed through the way the alpha `-soft` tokens would. The border\n// carries the tone too, otherwise a tinted toast keeps a grey outline.\nconst TONE_CLASSES: Record<Exclude<ToastType, 'loading'>, string> = {\n success: 'border-green-6 bg-green-2 text-green-11',\n info: 'border-blue-6 bg-blue-2 text-blue-11',\n warning: 'border-orange-6 bg-orange-2 text-orange-11',\n error: 'border-red-6 bg-red-2 text-red-11',\n}\n\n// Mobile-first: every position drops to a full-width stack at the top, which\n// is what the end-customer portal ships. `position` only takes effect from the\n// `sm` breakpoint up.\nconst POSITION_CLASSES: Record<ToastPosition, string> = {\n 'top-left': 'sm:top-4 sm:right-auto sm:bottom-auto sm:left-4',\n 'top-center':\n 'sm:top-4 sm:right-auto sm:bottom-auto sm:left-1/2 sm:-translate-x-1/2',\n 'top-right': 'sm:top-4 sm:right-4 sm:bottom-auto sm:left-auto',\n 'bottom-left': 'sm:top-auto sm:right-auto sm:bottom-4 sm:left-4',\n 'bottom-center':\n 'sm:top-auto sm:right-auto sm:bottom-4 sm:left-1/2 sm:-translate-x-1/2',\n 'bottom-right': 'sm:top-auto sm:right-4 sm:bottom-4 sm:left-auto',\n}\n\nconst manager = ToastPrimitive.createToastManager<ToastData>()\n\nlet sequence = 0\n\n// `label` names the content and `onClick` is wrapped, so neither reaches the\n// DOM button as-is; everything else does.\nfunction actionRest({\n label: _label,\n onClick: _onClick,\n ...rest\n}: ToastAction) {\n return rest\n}\n\nfunction toManagerOptions(\n id: string,\n title: React.ReactNode,\n type: ToastType | undefined,\n options: ToastOptions | undefined,\n) {\n const action = options?.action\n return {\n id,\n title,\n type,\n description: options?.description,\n timeout: options?.duration,\n priority: options?.priority,\n onClose: options?.onDismiss,\n // Base UI leaves the toast open after an action; dismissing matches what\n // callers expect from an \"Undo\" button.\n actionProps: action && {\n ...actionRest(action),\n children: action.label,\n onClick: (event: React.MouseEvent<HTMLButtonElement>) => {\n action.onClick?.(event)\n manager.close(id)\n },\n },\n data: { closeButton: options?.closeButton },\n }\n}\n\nconst emit =\n (type?: ToastType) =>\n (message: React.ReactNode, options?: ToastOptions): string => {\n // an id up front lets the action handler close the toast it belongs to\n const id = options?.id ?? `spark-toast-${(sequence += 1)}`\n return manager.add(toManagerOptions(id, message, type, options))\n }\n\n// A string phase becomes a titled toast of that type; an object phase keeps\n// whatever the caller set and only fills in the type.\nconst phase =\n <Value,>(\n value: ToastPromiseMessages<Value>[keyof ToastPromiseMessages<Value>],\n type: ToastType,\n ) =>\n (result: Value) => {\n const resolved = typeof value === 'function' ? value(result) : value\n return { title: resolved, type }\n }\n\nconst toast = Object.assign(emit(), {\n success: emit('success'),\n info: emit('info'),\n warning: emit('warning'),\n error: emit('error'),\n loading: emit('loading'),\n /** Dismiss one toast, or every toast when called without an id. */\n dismiss: (id?: string) => manager.close(id),\n promise: <Value,>(\n promiseValue: Promise<Value>,\n messages: ToastPromiseMessages<Value>,\n ) =>\n manager.promise(promiseValue, {\n loading: { title: messages.loading, type: 'loading' as const },\n success: phase(messages.success, 'success'),\n error: phase(messages.error as never, 'error'),\n }),\n})\n\nfunction ToastIcon({ type }: { type?: string }) {\n const icon = TOAST_ICONS[type as Exclude<ToastType, 'loading'>]\n if (type !== 'loading' && !icon) return null\n\n // Fixed box matching the title's line height, so the glyph and the spinner\n // both centre on the first line whether or not a description follows.\n return (\n <span\n aria-hidden=\"true\"\n className=\"flex h-5 w-5 shrink-0 items-center justify-center\"\n >\n {type === 'loading' ? (\n // Decorative: the toast already announces the loading message, so the\n // spinner must not add a second status live region.\n <Spinner\n className=\"text-gray-11\"\n label=\"\"\n role=\"presentation\"\n size=\"sm\"\n />\n ) : (\n <MaterialSymbol\n className={cn('[--spark-icon-size:20px]', icon.className)}\n name={icon.name}\n />\n )}\n </span>\n )\n}\n\nfunction ToastItem({\n closeButton,\n richColors,\n toast: toastObject,\n}: {\n closeButton: boolean\n richColors: boolean\n toast: ToastPrimitive.Root.ToastObject<ToastData>\n}) {\n const tone = TONE_CLASSES[toastObject.type as Exclude<ToastType, 'loading'>]\n const showClose = toastObject.data?.closeButton ?? closeButton\n\n return (\n <ToastPrimitive.Root\n data-slot=\"toast\"\n className={cn(\n // Skin only. All geometry (position, stacking, transitions, the\n // pointer bridge) lives in styles/index.css, because Tailwind's\n // `utilities` layer outranks `components` and a stray `bottom-0` here\n // would beat the stylesheet's `bottom: auto` on top-anchored stacks.\n // The border is what makes the cards behind the front one legible.\n 'flex items-start gap-2 rounded-lg border border-gray-a5 bg-gray-1 p-3 text-gray shadow-md select-none',\n richColors && tone,\n )}\n // the stack is top-anchored on mobile and bottom-anchored above `sm`, so\n // both vertical directions have to dismiss\n swipeDirection={['up', 'down', 'right']}\n toast={toastObject}\n >\n <ToastIcon type={toastObject.type} />\n <ToastPrimitive.Content className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <ToastPrimitive.Title\n className=\"text-sm font-medium\"\n data-slot=\"toast-title\"\n />\n <ToastPrimitive.Description\n className={cn(\n 'text-sm',\n richColors && tone ? 'text-inherit' : 'text-gray-11',\n )}\n data-slot=\"toast-description\"\n />\n </ToastPrimitive.Content>\n {toastObject.actionProps ? (\n <ToastPrimitive.Action\n // -my-2 keeps the 36px control from stretching a single-line row past\n // the 20px text; self-center then lands it on the title when there is\n // no description, and mid-block when there is one\n className={cn(\n buttonVariants({ size: 'small', variant: 'primary' }),\n '-my-2 shrink-0 self-center rounded-full',\n )}\n data-slot=\"toast-action\"\n />\n ) : null}\n {showClose ? (\n <ToastPrimitive.Close\n aria-label=\"Close\"\n className={cn(\n buttonVariants({ size: 'icon-small', variant: 'tertiary' }),\n // -my-1: same reason as the action, for a 28px control\n '-my-1 -mr-1 size-7 shrink-0 self-center text-gray-11',\n )}\n data-slot=\"toast-close\"\n >\n <MaterialSymbol\n aria-hidden=\"true\"\n className=\"[--spark-icon-size:18px]\"\n name=\"close\"\n />\n </ToastPrimitive.Close>\n ) : null}\n </ToastPrimitive.Root>\n )\n}\n\nfunction ToastList({\n closeButton,\n richColors,\n}: {\n closeButton: boolean\n richColors: boolean\n}) {\n const { toasts } = ToastPrimitive.useToastManager<ToastData>()\n\n return toasts.map((toastObject) => (\n <ToastItem\n closeButton={closeButton}\n key={toastObject.id}\n richColors={richColors}\n toast={toastObject}\n />\n ))\n}\n\ntype ToasterProps = {\n className?: string\n /** Corner or edge the toasts stack in. */\n position?: ToastPosition\n /** Close button on every toast; a per-toast `closeButton` wins. */\n closeButton?: boolean\n /** Tinted surfaces for success/info/warning/error toasts. */\n richColors?: boolean\n /** Default auto-dismiss time in ms. `0` disables auto-dismiss. */\n duration?: number\n /** Toasts visible at once before older ones are marked `data-limited`. */\n limit?: number\n /**\n * Vertical edge below the `sm` breakpoint, where the stack is always\n * full-width and `position` does not apply. Defaults to `top`, matching the\n * end-customer portal.\n */\n mobilePosition?: 'top' | 'bottom'\n}\n\nfunction Toaster({\n className,\n closeButton = true,\n duration = 4000,\n limit,\n mobilePosition = 'top',\n position = 'bottom-right',\n richColors = true,\n}: ToasterProps) {\n return (\n <ToastPrimitive.Provider\n limit={limit}\n timeout={duration}\n toastManager={manager}\n >\n <ToastPrimitive.Portal>\n <ToastPrimitive.Viewport\n // block + zero height: the toasts are absolutely positioned against\n // this box's bottom edge, the way Base UI's stacked example works\n className={cn(\n 'fixed inset-x-4 z-50 block h-0 outline-none',\n mobilePosition === 'top' ? 'top-4' : 'bottom-4',\n 'sm:inset-x-auto sm:w-96 sm:max-w-[calc(100vw-2rem)]',\n POSITION_CLASSES[position],\n className,\n )}\n data-mobile-side={mobilePosition}\n data-side={position.startsWith('top') ? 'top' : 'bottom'}\n data-slot=\"toaster\"\n >\n <ToastList closeButton={closeButton} richColors={richColors} />\n </ToastPrimitive.Viewport>\n </ToastPrimitive.Portal>\n </ToastPrimitive.Provider>\n )\n}\n\nexport { Toaster, toast }\nexport type {\n ToastAction,\n ToasterProps,\n ToastOptions,\n ToastPosition,\n ToastPromiseMessages,\n ToastType,\n}\n"],"mappings":"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"}
@@ -115,7 +115,7 @@ function ToastItem({ closeButton, richColors, toast: toastObject }) {
115
115
  const showClose = toastObject.data?.closeButton ?? closeButton;
116
116
  return /* @__PURE__ */ jsxs(Toast.Root, {
117
117
  "data-slot": "toast",
118
- className: cn("flex items-start gap-2 rounded-md border border-gray-a5 bg-gray-1 p-3 text-gray shadow-md select-none", richColors && tone),
118
+ className: cn("flex items-start gap-2 rounded-lg border border-gray-a5 bg-gray-1 p-3 text-gray shadow-md select-none", richColors && tone),
119
119
  swipeDirection: [
120
120
  "up",
121
121
  "down",