@uisatin/ui 0.3.0 → 0.5.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 (187) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/{chunk-NQL6SIIB.js → chunk-2643HEXD.js} +1 -1
  3. package/{chunk-UZ4DXU6W.js → chunk-3VVO5MY5.js} +4 -4
  4. package/{chunk-EF5GT4OG.js → chunk-47DDBME3.js} +3 -3
  5. package/{chunk-JBKBRAC4.js → chunk-5663JVE5.js} +3 -3
  6. package/chunk-67CBFB6Y.js +99 -0
  7. package/{chunk-T6L32XXH.js → chunk-6DWLTGRQ.js} +30 -7
  8. package/{chunk-S7QHBVPX.js → chunk-6GNMUJQ4.js} +3 -3
  9. package/{chunk-Z7S2KQZS.js → chunk-6JTSZAGO.js} +1 -1
  10. package/chunk-6RLSRMB5.js +14 -0
  11. package/{chunk-GI2SMFZL.js → chunk-6Y6CY2DP.js} +1 -1
  12. package/{chunk-XUOSJMEJ.js → chunk-7NV53EL5.js} +1 -1
  13. package/{chunk-LFGUJHFF.js → chunk-7SVMERPH.js} +2 -2
  14. package/chunk-A52HUWVM.js +24 -0
  15. package/chunk-AKEZCWNW.js +29 -0
  16. package/{chunk-NH3EHMIL.js → chunk-APRVUOD6.js} +1 -1
  17. package/{chunk-DPYIBFQD.js → chunk-C435UD7V.js} +4 -3
  18. package/{chunk-5XTUFBZI.js → chunk-C6WRJ7DG.js} +1 -1
  19. package/{chunk-X66KTATQ.js → chunk-CQFAMWZI.js} +2 -2
  20. package/{chunk-YJK4MGSI.js → chunk-DAKVTPYZ.js} +4 -4
  21. package/{chunk-W472DBMT.js → chunk-DMZW4LGU.js} +3 -3
  22. package/chunk-EBZHGRM5.js +46 -0
  23. package/{chunk-O46O6LFQ.js → chunk-EHEXE2UV.js} +20 -1
  24. package/{chunk-UCCNXGLG.js → chunk-EQAFDIPE.js} +9 -7
  25. package/{chunk-LB37KTJH.js → chunk-EXKSKYG3.js} +2 -2
  26. package/chunk-FB6DG3LR.js +35 -0
  27. package/chunk-GH2DEOGO.js +67 -0
  28. package/{chunk-J7RMFN54.js → chunk-GKDMCY2S.js} +1 -1
  29. package/chunk-GTFUAA6H.js +42 -0
  30. package/{chunk-SAYNV7B3.js → chunk-HI6QIG55.js} +4 -4
  31. package/{chunk-SDOTDMYG.js → chunk-HZV7EXGU.js} +2 -2
  32. package/{chunk-RHQHDYTE.js → chunk-IKJIR6VL.js} +2 -2
  33. package/{chunk-ISYKZCPJ.js → chunk-INJWE2LD.js} +2 -2
  34. package/chunk-J5UQPROI.js +56 -0
  35. package/{chunk-5725MFGQ.js → chunk-JCR5TWTF.js} +4 -4
  36. package/chunk-JKOBDLP3.js +25 -0
  37. package/{chunk-FAJ3OVL4.js → chunk-JR3VVDV6.js} +1 -1
  38. package/{chunk-CVNRZ2YV.js → chunk-JYGCZWET.js} +1 -1
  39. package/{chunk-SPGUZMCC.js → chunk-K5G5OEV5.js} +2 -2
  40. package/{chunk-GMETYACH.js → chunk-KDU7AT2T.js} +2 -2
  41. package/chunk-KITXKIYW.js +104 -0
  42. package/{chunk-JYOZUQNU.js → chunk-KQNA22D3.js} +2 -2
  43. package/{chunk-OURZQM27.js → chunk-L5PPN42A.js} +11 -4
  44. package/{chunk-HK6WINL6.js → chunk-LAOE6Y57.js} +3 -3
  45. package/{chunk-ZBZ3ZQRB.js → chunk-LI5VYDLN.js} +4 -4
  46. package/{chunk-M2HEVFQ3.js → chunk-LKSFTNPF.js} +1 -1
  47. package/chunk-LLW3X4ZJ.js +39 -0
  48. package/{chunk-5KTBSMQU.js → chunk-LWRB4DED.js} +1 -1
  49. package/{chunk-LB7Z6BSK.js → chunk-M7RILZVW.js} +6 -6
  50. package/{chunk-674SRBZK.js → chunk-MOGWOUCN.js} +3 -3
  51. package/chunk-NCIRJ5V2.js +108 -0
  52. package/{chunk-SSOFFQ5T.js → chunk-NTSU44FY.js} +8 -1
  53. package/{chunk-BR2B4OIT.js → chunk-P36KBUYD.js} +3 -3
  54. package/{chunk-3DHJXU45.js → chunk-P6RHT2VM.js} +1 -1
  55. package/{chunk-WLQD5BN2.js → chunk-PD2KD5OR.js} +1 -1
  56. package/{chunk-OVKPPXK5.js → chunk-PP46SY7M.js} +2 -2
  57. package/{chunk-FB5HTCO2.js → chunk-PTK4QAOQ.js} +4 -4
  58. package/{chunk-IKO3GQFE.js → chunk-Q7KVC5B4.js} +3 -3
  59. package/{chunk-UUCVRIVP.js → chunk-R3DTMBDT.js} +3 -3
  60. package/{chunk-UGIVCXGN.js → chunk-R4KPFBMK.js} +1 -1
  61. package/{chunk-XH56JGYC.js → chunk-R5TQ3HNB.js} +1 -1
  62. package/chunk-RFSPJECL.js +84 -0
  63. package/chunk-RPL6FRVX.js +88 -0
  64. package/{chunk-SZJIVBOD.js → chunk-STYOBAC7.js} +3 -3
  65. package/{chunk-W4RDTP6W.js → chunk-SVUWR3HD.js} +3 -3
  66. package/{chunk-7Q76HLRQ.js → chunk-T7P3OEBP.js} +4 -4
  67. package/{chunk-TT2N5752.js → chunk-TB3ZRV3Y.js} +2 -2
  68. package/{chunk-BN7FDKCJ.js → chunk-TOY6YPTG.js} +2 -2
  69. package/{chunk-PHNR6ZQ7.js → chunk-U6X6ODDJ.js} +2 -2
  70. package/{chunk-6VKV36OK.js → chunk-UAJ6M34K.js} +4 -4
  71. package/{chunk-PD6YPFYN.js → chunk-W2EH6RY5.js} +1 -1
  72. package/{chunk-X2GNMNZQ.js → chunk-W2QQQWNE.js} +2 -2
  73. package/{chunk-JCXI7VQL.js → chunk-WALANB3V.js} +2 -2
  74. package/{chunk-NL574STL.js → chunk-WCUR44O6.js} +2 -2
  75. package/{chunk-PUWSL5XW.js → chunk-WJYJMX5S.js} +1 -1
  76. package/{chunk-AIMQNLPY.js → chunk-WZSLDYUU.js} +6 -29
  77. package/chunk-XU6JJDMZ.js +117 -0
  78. package/{chunk-57QEOCDZ.js → chunk-XWPH7C2W.js} +1 -1
  79. package/{chunk-73Z7NMQQ.js → chunk-YXWXSRXG.js} +5 -5
  80. package/{chunk-CGOH5IYX.js → chunk-YY236ZSJ.js} +3 -3
  81. package/components/accordion.js +2 -2
  82. package/components/action-button.d.ts +37 -0
  83. package/components/action-button.js +5 -0
  84. package/components/agent-loading.js +2 -2
  85. package/components/agent-picker.js +5 -4
  86. package/components/agent-suggestion.js +5 -5
  87. package/components/alert.d.ts +37 -0
  88. package/components/alert.js +5 -0
  89. package/components/announcement-bar.js +6 -5
  90. package/components/attachment.js +5 -4
  91. package/components/avatar.js +4 -4
  92. package/components/badge.js +2 -2
  93. package/components/banner.d.ts +3 -2
  94. package/components/banner.js +5 -3
  95. package/components/bar-chart.js +9 -9
  96. package/components/breadcrumb.js +5 -5
  97. package/components/button-group.d.ts +26 -0
  98. package/components/button-group.js +5 -0
  99. package/components/button.d.ts +13 -1
  100. package/components/button.js +4 -2
  101. package/components/card.js +5 -3
  102. package/components/channel-chart.js +9 -9
  103. package/components/chart.js +8 -8
  104. package/components/checkbox.js +2 -2
  105. package/components/chip.js +2 -2
  106. package/components/citations.js +4 -4
  107. package/components/code-block.js +5 -3
  108. package/components/combobox.js +10 -9
  109. package/components/command-menu.js +5 -5
  110. package/components/context-menu.js +5 -5
  111. package/components/cookie-consent.js +5 -3
  112. package/components/date-picker.js +9 -8
  113. package/components/decision-card.js +6 -5
  114. package/components/dialog.d.ts +2 -7
  115. package/components/dialog.js +6 -4
  116. package/components/donut-chart.js +9 -9
  117. package/components/dot.js +2 -2
  118. package/components/dropdown.js +4 -4
  119. package/components/empty-state.js +2 -2
  120. package/components/field-group.d.ts +27 -0
  121. package/components/field-group.js +3 -0
  122. package/components/file-upload.js +7 -6
  123. package/components/form-field.d.ts +38 -1
  124. package/components/form-field.js +2 -2
  125. package/components/form.d.ts +47 -0
  126. package/components/form.js +3 -0
  127. package/components/hover-card.js +2 -2
  128. package/components/input-group.d.ts +21 -0
  129. package/components/input-group.js +6 -0
  130. package/components/input-otp.js +7 -7
  131. package/components/input.d.ts +5 -1
  132. package/components/input.js +3 -3
  133. package/components/kbd.js +2 -2
  134. package/components/labels.d.ts +7 -0
  135. package/components/labels.js +1 -1
  136. package/components/line-chart.js +10 -10
  137. package/components/link.d.ts +20 -0
  138. package/components/link.js +3 -0
  139. package/components/list.d.ts +46 -0
  140. package/components/list.js +2 -0
  141. package/components/message-actions.js +5 -4
  142. package/components/message.js +8 -7
  143. package/components/number-input.js +7 -7
  144. package/components/pagination.js +5 -3
  145. package/components/password-input.d.ts +16 -0
  146. package/components/password-input.js +7 -0
  147. package/components/popover.js +3 -3
  148. package/components/progress.js +2 -2
  149. package/components/prompt-bar.js +6 -5
  150. package/components/radio.js +2 -2
  151. package/components/search-bar.js +3 -3
  152. package/components/segmented-control.js +2 -2
  153. package/components/select.d.ts +2 -1
  154. package/components/select.js +6 -6
  155. package/components/selectable-card.d.ts +37 -0
  156. package/components/selectable-card.js +2 -0
  157. package/components/selectable-checkbox.d.ts +14 -0
  158. package/components/selectable-checkbox.js +4 -0
  159. package/components/selectable-radio.d.ts +16 -0
  160. package/components/selectable-radio.js +3 -0
  161. package/components/separator.d.ts +18 -0
  162. package/components/separator.js +2 -0
  163. package/components/sheet.js +7 -5
  164. package/components/sidebar.js +2 -2
  165. package/components/skeleton.js +2 -2
  166. package/components/slider.js +7 -7
  167. package/components/spinner.d.ts +18 -0
  168. package/components/spinner.js +3 -0
  169. package/components/split-button.d.ts +24 -0
  170. package/components/split-button.js +8 -0
  171. package/components/streaming-text.js +2 -2
  172. package/components/switch.js +2 -2
  173. package/components/table.js +4 -4
  174. package/components/tabs.js +2 -2
  175. package/components/textarea.js +3 -3
  176. package/components/thinking.js +3 -3
  177. package/components/toast.js +5 -4
  178. package/components/toggle.js +2 -2
  179. package/components/tooltip.js +3 -3
  180. package/index.d.ts +16 -2
  181. package/index.js +80 -65
  182. package/lib/utils.js +1 -1
  183. package/package.json +1 -1
  184. package/styles.css +1 -1
  185. package/theme/create-theme.d.ts +2 -1
  186. package/theme/index.js +1 -1
  187. package/chunk-VUOAPWTF.js +0 -86
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @uisatin/ui
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - f49c44d: The pill corner (`--radius-pill`: Button's `rounded` shape, chips, tabs, segmented controls, the sidebar's rows) now changes at every step of the theme's corner scale: square at 0, 6px at 0.5, 12px at Satin's default 1, and a full pill only at 1.5. It used to be a full pill from 1 up, so Default and Large looked the same on 32px controls. The base stylesheet follows: `--radius-pill` is 12px unless a theme sets Large corners.
8
+
9
+ ## 0.4.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 51f930e: New components built from the ones Satin already has:
14
+
15
+ - Buttons: `ButtonGroup` (attached or spaced, with `ButtonGroupSeparator`), `SplitButton`, `ActionButton` (arrow, spinner, checkmark in one slot), and `loading` on `Button`.
16
+ - Forms: `Form` (one layout, errors by `name`, focus on the first invalid field, `onSubmitValues`), `FormSection`, `FormActions`, `FieldGroup`, `InputGroup` with `InputGroupAddon`, `PasswordInput`, `leadingText` / `trailingText` on `Input`, and `name` on `FormField`.
17
+ - Choices: `SelectableRadio` and `SelectableCheckbox`, in `sm` and `md`.
18
+ - Feedback and content: `Alert`, `Spinner`, `Separator`, `Link`, `List` with `Item`.
19
+
20
+ Fixes: `cn` now knows Satin's theme names (`text-body`, `rounded-pill`, `h-control-height`…), so `text-body` is no longer dropped next to a text colour (Banner descriptions, StreamingText and table cells take the theme's body size again) and app classes replace them as they should. Checkbox and Radio texts dim inside a disabled fieldset.
21
+
3
22
  ## 0.3.0
4
23
 
5
24
  ### Minor Changes
@@ -106,7 +106,7 @@ function radiusVars(scale) {
106
106
  const v = {};
107
107
  for (const [k, px] of Object.entries(RADII)) v[`--radius-${k}`] = `${Math.round(px * scale * 2) / 2}px`;
108
108
  v["--sa-radius"] = `${Math.round(10 * scale * 2) / 2}px`;
109
- v["--sa-radius-pill"] = scale >= 1 ? "9999px" : `${Math.round(16 * scale)}px`;
109
+ v["--sa-radius-pill"] = scale >= 1.5 ? "9999px" : `${Math.round(12 * scale)}px`;
110
110
  return v;
111
111
  }
112
112
  var VAR_PREFIX = "sa-";
@@ -1,7 +1,7 @@
1
- import { menuItemClass, MenuItemContent } from './chunk-BR2B4OIT.js';
2
- import { Kbd, KbdHint, KbdArrowUp, KbdArrowDown, KbdReturn } from './chunk-57QEOCDZ.js';
3
- import { useSatinLabels } from './chunk-SSOFFQ5T.js';
4
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { menuItemClass, MenuItemContent } from './chunk-P36KBUYD.js';
2
+ import { Kbd, KbdHint, KbdArrowUp, KbdArrowDown, KbdReturn } from './chunk-XWPH7C2W.js';
3
+ import { useSatinLabels } from './chunk-NTSU44FY.js';
4
+ import { cn } from './chunk-EHEXE2UV.js';
5
5
  import * as React from 'react';
6
6
  import { Dialog } from 'radix-ui';
7
7
  import { Search } from 'iconoir-react';
@@ -1,6 +1,6 @@
1
- import { HoverCard } from './chunk-PD6YPFYN.js';
2
- import { useSatinLabels } from './chunk-SSOFFQ5T.js';
3
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { HoverCard } from './chunk-W2EH6RY5.js';
2
+ import { useSatinLabels } from './chunk-NTSU44FY.js';
3
+ import { cn } from './chunk-EHEXE2UV.js';
4
4
  import * as React from 'react';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';
6
6
 
@@ -1,6 +1,6 @@
1
- import { niceMax } from './chunk-ISYKZCPJ.js';
2
- import { ChartCard, defaultFormat, ChartTooltip } from './chunk-ZBZ3ZQRB.js';
3
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { niceMax } from './chunk-INJWE2LD.js';
2
+ import { ChartCard, defaultFormat, ChartTooltip } from './chunk-LI5VYDLN.js';
3
+ import { cn } from './chunk-EHEXE2UV.js';
4
4
  import * as React from 'react';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
6
 
@@ -0,0 +1,99 @@
1
+ import { cn } from './chunk-EHEXE2UV.js';
2
+ import * as React from 'react';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+
5
+ var ListContext = React.createContext(null);
6
+ function Item({
7
+ title,
8
+ description,
9
+ icon,
10
+ media,
11
+ meta,
12
+ actions,
13
+ href,
14
+ target,
15
+ onClick,
16
+ selected = false,
17
+ disabled = false,
18
+ size: ownSize,
19
+ variant = "plain",
20
+ className,
21
+ children,
22
+ ...props
23
+ }) {
24
+ const list = React.useContext(ListContext);
25
+ const size = ownSize ?? list?.size ?? "md";
26
+ const sm = size === "sm";
27
+ const interactive = (href !== void 0 || onClick !== void 0) && !disabled;
28
+ const Root = list ? "li" : "div";
29
+ const flush = list?.variant === "divided" || list?.variant === "card";
30
+ const target_ = "sa:outline-none sa:after:absolute sa:after:inset-0";
31
+ const titleText = /* @__PURE__ */ jsx("span", { className: "sa:block sa:truncate", children: title });
32
+ const titleNode = href !== void 0 && !disabled ? /* @__PURE__ */ jsx("a", { href, target, rel: target === "_blank" ? "noopener noreferrer" : void 0, "data-slot": "item-target", "aria-current": selected ? "page" : void 0, className: cn(target_, "sa:no-underline sa:text-inherit"), children: titleText }) : onClick && !disabled ? /* @__PURE__ */ jsx("button", { type: "button", "data-slot": "item-target", "aria-pressed": selected || void 0, onClick, className: cn(target_, "sa:block sa:w-full sa:cursor-pointer sa:text-left"), children: titleText }) : titleText;
33
+ return /* @__PURE__ */ jsxs(
34
+ Root,
35
+ {
36
+ "data-slot": "item",
37
+ "data-size": size,
38
+ "data-selected": selected || void 0,
39
+ "data-disabled": disabled || void 0,
40
+ className: cn(
41
+ "sa:relative sa:flex sa:min-w-0 sa:items-center",
42
+ sm ? "sa:min-h-10 sa:gap-2.5 sa:px-2 sa:py-1.5" : "sa:min-h-14 sa:gap-3 sa:px-3 sa:py-2.5",
43
+ flush ? list?.variant === "card" ? sm ? "sa:px-3" : "sa:px-4" : "sa:px-0" : "sa:rounded-lg",
44
+ variant === "sa:outline" && !list && "sa:border sa:border-border-default sa:bg-bg-card sa:[box-shadow:0_1px_2px_0_var(--effect-shadow-xs)]",
45
+ "sa:transition-colors sa:duration-(--sa-duration-fast) sa:ease-(--sa-ease-out)",
46
+ interactive && "sa:hover:bg-bg-hover",
47
+ interactive && flush && list?.variant === "divided" && "sa:hover:bg-transparent sa:[&:hover_[data-slot=item-title]]:underline",
48
+ selected && "sa:bg-bg-selected sa:hover:bg-bg-selected",
49
+ // The focus ring of the stretched link, drawn on the row.
50
+ "sa:has-[[data-slot=item-target]:focus-visible]:[box-shadow:inset_0_0_0_2px_var(--action-focus-ring)]",
51
+ disabled && "sa:opacity-50",
52
+ className
53
+ ),
54
+ ...props,
55
+ children: [
56
+ media ? /* @__PURE__ */ jsx("span", { className: "sa:flex sa:shrink-0 sa:items-center", children: media }) : icon ? /* @__PURE__ */ jsx(
57
+ "span",
58
+ {
59
+ "aria-hidden": true,
60
+ className: cn(
61
+ "sa:grid sa:shrink-0 sa:place-items-center sa:rounded-lg sa:bg-bg-muted sa:text-text-muted sa:[&_svg]:size-icon-size sa:[&_svg]:[stroke-width:1.875]",
62
+ sm ? "sa:size-7" : "sa:size-8"
63
+ ),
64
+ children: icon
65
+ }
66
+ ) : null,
67
+ /* @__PURE__ */ jsxs("div", { className: "sa:min-w-0 sa:flex-1", children: [
68
+ /* @__PURE__ */ jsx("div", { "data-slot": "item-title", className: "sa:text-sm sa:leading-5 sa:font-medium sa:text-text-default sa:underline-offset-[3px]", children: titleNode }),
69
+ description && /* @__PURE__ */ jsx("p", { className: "sa:truncate sa:text-sm sa:leading-5 sa:text-text-muted", children: description }),
70
+ children && /* @__PURE__ */ jsx("div", { className: "sa:mt-1.5", children })
71
+ ] }),
72
+ meta && /* @__PURE__ */ jsx("div", { className: "sa:shrink-0 sa:text-sm sa:text-text-muted sa:tabular-nums", children: meta }),
73
+ actions && // Above the stretched target, so they stay their own controls.
74
+ /* @__PURE__ */ jsx("div", { className: "sa:relative sa:z-10 sa:flex sa:shrink-0 sa:items-center sa:gap-1", children: actions })
75
+ ]
76
+ }
77
+ );
78
+ }
79
+ function List({ variant = "plain", size = "md", className, ...props }) {
80
+ const context = React.useMemo(() => ({ variant, size }), [variant, size]);
81
+ return /* @__PURE__ */ jsx(ListContext.Provider, { value: context, children: /* @__PURE__ */ jsx(
82
+ "ul",
83
+ {
84
+ role: "list",
85
+ "data-slot": "list",
86
+ "data-variant": variant,
87
+ className: cn(
88
+ "sa:m-0 sa:flex sa:w-full sa:list-none sa:flex-col sa:p-0",
89
+ variant === "plain" && "sa:gap-0.5",
90
+ variant !== "plain" && "sa:divide-y sa:divide-border-default",
91
+ variant === "card" && "sa:overflow-hidden sa:rounded-xl sa:border sa:border-border-default sa:bg-bg-card sa:[box-shadow:0_1px_2px_0_var(--effect-shadow-xs)]",
92
+ className
93
+ ),
94
+ ...props
95
+ }
96
+ ) });
97
+ }
98
+
99
+ export { Item, List };
@@ -1,8 +1,9 @@
1
- import { cn } from './chunk-O46O6LFQ.js';
2
- import 'react';
1
+ import { Spinner } from './chunk-AKEZCWNW.js';
2
+ import { cn } from './chunk-EHEXE2UV.js';
3
+ import * as React from 'react';
3
4
  import { Slot } from 'radix-ui';
4
5
  import { cva } from 'class-variance-authority';
5
- import { jsx } from 'react/jsx-runtime';
6
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
7
 
7
8
  var buttonVariants = cva(
8
9
  [
@@ -91,17 +92,39 @@ var buttonVariants = cva(
91
92
  defaultVariants: { variant: "primary", size: "md", shape: "default", iconOnly: false }
92
93
  }
93
94
  );
94
- function Button({ className, variant, size, shape, iconOnly, asChild = false, type, ...props }) {
95
+ var ButtonDefaultsContext = React.createContext(null);
96
+ function Button({ className, variant, size, shape, iconOnly, asChild = false, loading = false, type, onClick, children, "aria-disabled": ariaDisabled, ...props }) {
95
97
  const Comp = asChild ? Slot.Root : "button";
98
+ const group = React.useContext(ButtonDefaultsContext);
99
+ const resolved = variant ?? group?.variant ?? "primary";
96
100
  return /* @__PURE__ */ jsx(
97
101
  Comp,
98
102
  {
99
103
  "data-slot": "button",
104
+ "data-variant": resolved,
100
105
  type: asChild ? void 0 : type ?? "button",
101
- className: cn(buttonVariants({ variant, size, shape, iconOnly }), className),
102
- ...props
106
+ "aria-busy": loading || void 0,
107
+ "aria-disabled": loading || ariaDisabled || void 0,
108
+ "data-loading": loading || void 0,
109
+ className: cn(
110
+ buttonVariants({ variant: resolved, size: size ?? group?.size, shape: shape ?? group?.shape, iconOnly }),
111
+ loading && "sa:relative sa:cursor-progress",
112
+ className
113
+ ),
114
+ onClick: (event) => {
115
+ if (loading) {
116
+ event.preventDefault();
117
+ return;
118
+ }
119
+ onClick?.(event);
120
+ },
121
+ ...props,
122
+ children: loading && !asChild ? /* @__PURE__ */ jsxs(Fragment, { children: [
123
+ /* @__PURE__ */ jsx("span", { className: "sa:invisible sa:contents", children }),
124
+ /* @__PURE__ */ jsx("span", { className: "sa:absolute sa:inset-0 sa:grid sa:place-items-center", children: /* @__PURE__ */ jsx(Spinner, { size: (size ?? group?.size) === "xs" ? "sm" : "md", label: null }) })
125
+ ] }) : children
103
126
  }
104
127
  );
105
128
  }
106
129
 
107
- export { Button, buttonVariants };
130
+ export { Button, ButtonDefaultsContext, buttonVariants };
@@ -1,6 +1,6 @@
1
- import { Thinking } from './chunk-NL574STL.js';
2
- import { MessageActions } from './chunk-SZJIVBOD.js';
3
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { Thinking } from './chunk-WCUR44O6.js';
2
+ import { MessageActions } from './chunk-STYOBAC7.js';
3
+ import { cn } from './chunk-EHEXE2UV.js';
4
4
  import 'react';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
6
 
@@ -1,4 +1,4 @@
1
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { cn } from './chunk-EHEXE2UV.js';
2
2
  import 'react';
3
3
  import { cva } from 'class-variance-authority';
4
4
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
@@ -0,0 +1,14 @@
1
+ import { useSelectableIds, SelectableCardBody } from './chunk-EBZHGRM5.js';
2
+ import { Checkbox } from './chunk-W2QQQWNE.js';
3
+ import 'react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ function SelectableCheckbox({ title, description, icon, size = "md", className, children, id, ...props }) {
7
+ const { controlId, ...aria } = useSelectableIds(id, description);
8
+ return /* @__PURE__ */ jsxs("label", { htmlFor: controlId, "data-slot": "selectable-card", "data-size": size, "data-kind": "checkbox", className, children: [
9
+ /* @__PURE__ */ jsx(SelectableCardBody, { id: controlId, title, description, icon, size, children }),
10
+ /* @__PURE__ */ jsx(Checkbox, { id: controlId, ...aria, ...props })
11
+ ] });
12
+ }
13
+
14
+ export { SelectableCheckbox };
@@ -1,4 +1,4 @@
1
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { cn } from './chunk-EHEXE2UV.js';
2
2
  import 'react';
3
3
  import { Accordion as Accordion$1 } from 'radix-ui';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { cn } from './chunk-EHEXE2UV.js';
2
2
  import 'react';
3
3
  import { cva } from 'class-variance-authority';
4
4
  import { jsx } from 'react/jsx-runtime';
@@ -1,5 +1,5 @@
1
- import { useSatinLabels } from './chunk-SSOFFQ5T.js';
2
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { useSatinLabels } from './chunk-NTSU44FY.js';
2
+ import { cn } from './chunk-EHEXE2UV.js';
3
3
  import * as React from 'react';
4
4
  import { Popover as Popover$1 } from 'radix-ui';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -0,0 +1,24 @@
1
+ import { useSelectableIds, SelectableCardBody } from './chunk-EBZHGRM5.js';
2
+ import { cn } from './chunk-EHEXE2UV.js';
3
+ import 'react';
4
+ import { RadioGroup } from 'radix-ui';
5
+ import { jsx } from 'react/jsx-runtime';
6
+
7
+ function SelectableRadio({ title, description, icon, size = "md", className, children, id, ...props }) {
8
+ const { controlId, ...aria } = useSelectableIds(id, description);
9
+ return /* @__PURE__ */ jsx(
10
+ RadioGroup.Item,
11
+ {
12
+ id: controlId,
13
+ "data-slot": "selectable-card",
14
+ "data-size": size,
15
+ "data-kind": "radio",
16
+ ...aria,
17
+ ...props,
18
+ className: cn("sa:w-full sa:text-left", className),
19
+ children: /* @__PURE__ */ jsx(SelectableCardBody, { id: controlId, title, description, icon, size, children })
20
+ }
21
+ );
22
+ }
23
+
24
+ export { SelectableRadio };
@@ -0,0 +1,29 @@
1
+ import { useSatinLabels } from './chunk-NTSU44FY.js';
2
+ import { cn } from './chunk-EHEXE2UV.js';
3
+ import 'react';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ var px = { xs: 12, sm: 14, md: 16, lg: 20 };
7
+ function Spinner({ size = "md", label, className, ...props }) {
8
+ const labels = useSatinLabels();
9
+ const s = px[size];
10
+ const hidden = label === null;
11
+ return /* @__PURE__ */ jsx(
12
+ "span",
13
+ {
14
+ "data-slot": "spinner",
15
+ "data-size": size,
16
+ role: hidden ? void 0 : "status",
17
+ "aria-label": hidden ? void 0 : label ?? labels.loading,
18
+ "aria-hidden": hidden || void 0,
19
+ className: cn("sa:inline-grid sa:shrink-0 sa:place-items-center", className),
20
+ ...props,
21
+ children: /* @__PURE__ */ jsxs("svg", { width: s, height: s, viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: [
22
+ /* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "6.25", stroke: "currentColor", strokeOpacity: "0.2", style: { strokeWidth: 1.5 } }),
23
+ /* @__PURE__ */ jsx("path", { d: "M8 1.75A6.25 6.25 0 0 1 14.25 8", stroke: "currentColor", strokeLinecap: "round", style: { strokeWidth: 1.5 } })
24
+ ] })
25
+ }
26
+ );
27
+ }
28
+
29
+ export { Spinner };
@@ -1,4 +1,4 @@
1
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { cn } from './chunk-EHEXE2UV.js';
2
2
  import * as React from 'react';
3
3
  import { Switch as Switch$1 } from 'radix-ui';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -1,5 +1,5 @@
1
- import { useFormField } from './chunk-VUOAPWTF.js';
2
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { useFormField } from './chunk-KITXKIYW.js';
2
+ import { cn } from './chunk-EHEXE2UV.js';
3
3
  import * as React from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
@@ -65,7 +65,8 @@ function Textarea({
65
65
  if (value == null) setUncontrolled(e.target.value);
66
66
  onChange?.(e.target.value);
67
67
  },
68
- ...props
68
+ ...props,
69
+ name: props.name ?? field?.name
69
70
  }
70
71
  ),
71
72
  /* @__PURE__ */ jsx("svg", { className: "satin-textarea-grip", viewBox: "0 0 7 7", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M6.5 0.5L0.5 6.5M6.5 4L4 6.5", stroke: "currentColor", strokeLinecap: "round" }) })
@@ -1,4 +1,4 @@
1
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { cn } from './chunk-EHEXE2UV.js';
2
2
  import 'react';
3
3
  import { cva } from 'class-variance-authority';
4
4
  import { jsx } from 'react/jsx-runtime';
@@ -1,5 +1,5 @@
1
- import { menuSurfaceClass, MenuItemContent, menuItemClass } from './chunk-BR2B4OIT.js';
2
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { menuSurfaceClass, MenuItemContent, menuItemClass } from './chunk-P36KBUYD.js';
2
+ import { cn } from './chunk-EHEXE2UV.js';
3
3
  import 'react';
4
4
  import { ContextMenu as ContextMenu$1 } from 'radix-ui';
5
5
  import { NavArrowRight } from 'iconoir-react';
@@ -1,7 +1,7 @@
1
- import { CloseIcon } from './chunk-AIMQNLPY.js';
2
- import { Button } from './chunk-T6L32XXH.js';
3
- import { useSatinLabels } from './chunk-SSOFFQ5T.js';
4
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { CloseIcon } from './chunk-RPL6FRVX.js';
2
+ import { Button } from './chunk-6DWLTGRQ.js';
3
+ import { useSatinLabels } from './chunk-NTSU44FY.js';
4
+ import { cn } from './chunk-EHEXE2UV.js';
5
5
  import 'react';
6
6
  import { Dialog } from 'radix-ui';
7
7
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,6 +1,6 @@
1
- import { Button } from './chunk-T6L32XXH.js';
2
- import { useSatinLabels } from './chunk-SSOFFQ5T.js';
3
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { Button } from './chunk-6DWLTGRQ.js';
2
+ import { useSatinLabels } from './chunk-NTSU44FY.js';
3
+ import { cn } from './chunk-EHEXE2UV.js';
4
4
  import * as React from 'react';
5
5
  import { DropdownMenu } from 'radix-ui';
6
6
  import { NavArrowDown, Check, Plus } from 'iconoir-react';
@@ -0,0 +1,46 @@
1
+ import { cn } from './chunk-EHEXE2UV.js';
2
+ import * as React from 'react';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ function SelectableCardBody({
6
+ id,
7
+ title,
8
+ description,
9
+ icon,
10
+ size = "md",
11
+ children
12
+ }) {
13
+ const sm = size === "sm";
14
+ const tile = description ? sm ? 36 : 40 : 20;
15
+ const titleLine = description ? "sa:leading-[18px]" : "sa:leading-5";
16
+ return /* @__PURE__ */ jsxs("span", { className: cn("sa:flex sa:min-w-0 sa:flex-1 sa:items-start", sm ? "sa:gap-2.5" : "sa:gap-3"), children: [
17
+ icon && /* @__PURE__ */ jsx(
18
+ "span",
19
+ {
20
+ "data-slot": "selectable-card-icon",
21
+ "aria-hidden": true,
22
+ style: { width: tile, height: tile, borderRadius: tile === 20 ? "var(--sa-radius-sm)" : sm ? "var(--sa-radius-md)" : void 0 },
23
+ children: icon
24
+ }
25
+ ),
26
+ /* @__PURE__ */ jsxs("span", { className: "sa:min-w-0 sa:flex-1 sa:text-left", children: [
27
+ /* @__PURE__ */ jsxs("span", { className: cn("sa:grid", !sm && "sa:gap-0.5"), children: [
28
+ /* @__PURE__ */ jsx("span", { id: `${id}-title`, className: cn("sa:block sa:font-medium sa:text-text-default", sm ? "sa:text-sm" : "sa:text-base", titleLine), children: title }),
29
+ description && // md: the theme's body size, like Banner, Card and Alert; sm: 13px.
30
+ /* @__PURE__ */ jsx("span", { id: `${id}-description`, className: cn("sa:block sa:text-text-muted", sm ? "sa:text-sm sa:leading-[18px]" : "sa:text-body sa:leading-5"), children: description })
31
+ ] }),
32
+ children && /* @__PURE__ */ jsx("span", { className: cn("sa:block", sm ? "sa:mt-1.5" : "sa:mt-2"), children })
33
+ ] })
34
+ ] });
35
+ }
36
+ function useSelectableIds(id, description) {
37
+ const autoId = React.useId();
38
+ const controlId = id ?? autoId;
39
+ return {
40
+ controlId,
41
+ "aria-labelledby": `${controlId}-title`,
42
+ "aria-describedby": description ? `${controlId}-description` : void 0
43
+ };
44
+ }
45
+
46
+ export { SelectableCardBody, useSelectableIds };
@@ -1,7 +1,26 @@
1
1
  import { clsx } from 'clsx';
2
- import { twMerge } from 'tailwind-merge';
2
+ import { extendTailwindMerge } from 'tailwind-merge';
3
3
 
4
4
  // src/lib/utils.ts
5
+ var twMerge = extendTailwindMerge({
6
+ extend: {
7
+ theme: {
8
+ text: ["body", "body-lg", "title", "heading", "display"],
9
+ radius: ["pill"],
10
+ spacing: [
11
+ "control-height",
12
+ "control-height-xs",
13
+ "control-height-lg",
14
+ "control-height-xl",
15
+ "icon-size",
16
+ "icon-size-sm",
17
+ "menu-row",
18
+ "toast-height"
19
+ ],
20
+ shadow: ["primary", "primary-focus", "destructive", "destructive-focus", "border-focus", "xs-focus"]
21
+ }
22
+ }
23
+ });
5
24
  var PREFIX = "sa:";
6
25
  function cn(...inputs) {
7
26
  const joined = clsx(inputs);
@@ -1,7 +1,7 @@
1
- import { useFormField } from './chunk-VUOAPWTF.js';
2
- import { MenuItemContent, menuItemClass, menuGroupClass, menuGroupLabelClass, menuSurfaceClass } from './chunk-BR2B4OIT.js';
3
- import { useSatinLabels } from './chunk-SSOFFQ5T.js';
4
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { useFormField, FieldSizeContext } from './chunk-KITXKIYW.js';
2
+ import { MenuItemContent, menuItemClass, menuGroupClass, menuGroupLabelClass, menuSurfaceClass } from './chunk-P36KBUYD.js';
3
+ import { useSatinLabels } from './chunk-NTSU44FY.js';
4
+ import { cn } from './chunk-EHEXE2UV.js';
5
5
  import * as React from 'react';
6
6
  import { Select as Select$1 } from 'radix-ui';
7
7
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -24,6 +24,7 @@ function useFieldChrome({
24
24
  disabled: disabled ?? field?.disabled ?? false,
25
25
  invalid: Boolean(error) || (field?.invalid ?? false),
26
26
  required: field?.required,
27
+ name: field?.name,
27
28
  describedBy: [field?.describedBy, messageId].filter(Boolean).join(" ") || void 0,
28
29
  message,
29
30
  messageId,
@@ -37,7 +38,7 @@ function FieldChrome({
37
38
  className,
38
39
  children
39
40
  }) {
40
- return /* @__PURE__ */ jsxs("div", { className: cn("sa:grid sa:w-full sa:gap-2", className), children: [
41
+ return /* @__PURE__ */ jsxs("div", { "data-slot": "field-chrome", className: cn("sa:grid sa:w-full sa:gap-2", className), children: [
41
42
  label && // The row keeps the label's 18px whatever the action, so the field never moves.
42
43
  /* @__PURE__ */ jsxs("div", { className: "sa:flex sa:h-[18px] sa:items-center sa:justify-between sa:gap-2", children: [
43
44
  /* @__PURE__ */ jsx("label", { htmlFor: chrome.controlId, className: "sa:text-sm sa:leading-[18px] sa:font-medium sa:text-text-default", children: label }),
@@ -59,7 +60,7 @@ function Select({
59
60
  label,
60
61
  hint,
61
62
  error,
62
- size = "md",
63
+ size: ownSize,
63
64
  leadingIcon,
64
65
  layout = "inline",
65
66
  iconSize = 16,
@@ -78,6 +79,7 @@ function Select({
78
79
  ...props
79
80
  }) {
80
81
  const chrome = useFieldChrome({ id, disabled, error, hint });
82
+ const size = ownSize ?? React.useContext(FieldSizeContext) ?? "md";
81
83
  const labels = useSatinLabels();
82
84
  const [uncontrolled, setUncontrolled] = React.useState(defaultValue);
83
85
  const current = value ?? uncontrolled;
@@ -97,7 +99,7 @@ function Select({
97
99
  onOpenChange,
98
100
  disabled: chrome.disabled,
99
101
  required: required ?? chrome.required,
100
- name,
102
+ name: name ?? chrome.name,
101
103
  children: [
102
104
  /* @__PURE__ */ jsxs(
103
105
  Select$1.Trigger,
@@ -1,4 +1,4 @@
1
- import { cn } from './chunk-O46O6LFQ.js';
1
+ import { cn } from './chunk-EHEXE2UV.js';
2
2
  import * as React from 'react';
3
3
  import { RadioGroup as RadioGroup$1 } from 'radix-ui';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -35,7 +35,7 @@ function Radio({ className, label, description, placement = "left", id, disabled
35
35
  className: cn("sa:flex sa:cursor-pointer sa:items-start sa:gap-2 sa:has-disabled:cursor-not-allowed sa:has-data-disabled:cursor-not-allowed sa:[&>:first-child]:mt-0.5", placement === "right" && "sa:flex-row-reverse sa:justify-between"),
36
36
  children: [
37
37
  circle,
38
- /* @__PURE__ */ jsxs("div", { className: "sa:grid sa:min-w-0 sa:gap-0.5 sa:text-base sa:text-text-default sa:peer-data-disabled:text-text-subtle sa:peer-data-disabled:*:text-text-subtle", children: [
38
+ /* @__PURE__ */ jsxs("div", { className: "sa:grid sa:min-w-0 sa:gap-0.5 sa:text-base sa:text-text-default sa:peer-data-disabled:text-text-subtle sa:peer-data-disabled:*:text-text-subtle sa:peer-disabled:*:text-text-subtle", children: [
39
39
  label && /* @__PURE__ */ jsx("span", { id: labelId, className: "sa:block sa:leading-5 sa:font-medium", children: label }),
40
40
  description && /* @__PURE__ */ jsx("span", { id: descriptionId, className: "sa:block sa:leading-5 sa:text-text-muted", children: description })
41
41
  ] })
@@ -0,0 +1,35 @@
1
+ import { ButtonGroup } from './chunk-GH2DEOGO.js';
2
+ import { DropdownMenu } from './chunk-P36KBUYD.js';
3
+ import { Button } from './chunk-6DWLTGRQ.js';
4
+ import { useSatinLabels } from './chunk-NTSU44FY.js';
5
+ import 'react';
6
+ import { jsxs, jsx } from 'react/jsx-runtime';
7
+
8
+ function SplitButton({
9
+ menu,
10
+ menuLabel,
11
+ menuProps,
12
+ groupClassName,
13
+ variant = "primary",
14
+ size,
15
+ shape,
16
+ disabled,
17
+ children,
18
+ ...props
19
+ }) {
20
+ const labels = useSatinLabels();
21
+ return /* @__PURE__ */ jsxs(ButtonGroup, { variant, size, shape, className: groupClassName, "data-slot": "split-button", children: [
22
+ /* @__PURE__ */ jsx(Button, { disabled, ...props, children }),
23
+ /* @__PURE__ */ jsx(
24
+ DropdownMenu,
25
+ {
26
+ align: "end",
27
+ ...menuProps,
28
+ trigger: /* @__PURE__ */ jsx(Button, { iconOnly: true, "aria-label": menuLabel ?? labels.moreOptions, disabled, children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M4 6L8 10L12 6", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
29
+ children: menu
30
+ }
31
+ )
32
+ ] });
33
+ }
34
+
35
+ export { SplitButton };