@epicbagel/saas-kit 1.3.0 → 1.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 (34) hide show
  1. package/README.md +91 -0
  2. package/dist/chunk-D5EHW3O2.cjs +52 -0
  3. package/dist/chunk-F3DAFAMD.js +271 -0
  4. package/dist/{chunk-JZOBIPFC.js → chunk-FGISSYXG.js} +61 -2
  5. package/dist/chunk-HAP6USTP.cjs +46 -0
  6. package/dist/chunk-HAQOT2CD.js +46 -0
  7. package/dist/{chunk-2AU7ZRGX.cjs → chunk-LAN3K2JI.cjs} +61 -2
  8. package/dist/chunk-TWCJMFST.js +260 -0
  9. package/dist/chunk-U3YFP6ZV.cjs +273 -0
  10. package/dist/chunk-X3PRMR5G.js +52 -0
  11. package/dist/chunk-ZJFYOXSM.cjs +260 -0
  12. package/dist/lib/neutral-theme.cjs +39 -236
  13. package/dist/lib/neutral-theme.d.cts +44 -2
  14. package/dist/lib/neutral-theme.d.ts +44 -2
  15. package/dist/lib/neutral-theme.js +23 -219
  16. package/dist/primitives/chat.cjs +65 -12
  17. package/dist/primitives/chat.d.cts +46 -2
  18. package/dist/primitives/chat.d.ts +46 -2
  19. package/dist/primitives/chat.js +55 -2
  20. package/dist/primitives/field.cjs +12 -239
  21. package/dist/primitives/field.js +16 -243
  22. package/dist/primitives/message.cjs +8 -2
  23. package/dist/primitives/message.d.cts +35 -1
  24. package/dist/primitives/message.d.ts +35 -1
  25. package/dist/primitives/message.js +7 -1
  26. package/dist/primitives/radio-group.cjs +4 -39
  27. package/dist/primitives/radio-group.js +4 -39
  28. package/dist/primitives/theme-selector.cjs +188 -0
  29. package/dist/primitives/theme-selector.d.cts +78 -0
  30. package/dist/primitives/theme-selector.d.ts +78 -0
  31. package/dist/primitives/theme-selector.js +188 -0
  32. package/dist/primitives/toggle-group.cjs +5 -45
  33. package/dist/primitives/toggle-group.js +5 -45
  34. package/package.json +11 -1
package/README.md CHANGED
@@ -160,6 +160,41 @@ public in 1.1.0, and these were the decisions about its props then:
160
160
  scroller neither anchors it nor tracks it. It has no time marker, files or
161
161
  rich `content`, and the turns either side of it keep their time grouping.
162
162
 
163
+ ### A turn's actions (1.5.0)
164
+
165
+ - **Under a reply, a row of actions.** `messageActions(message)` returns the
166
+ actions under a turn, after prompt-kit's "Message with Actions": small
167
+ icon-only ghost buttons with tooltips, drawn in a `MessageActions` row at
168
+ the message's side. `ChatCopyAction` is the ready one: it copies the turn's
169
+ `text`, its Markdown source, and shows a check and "Copied" for a moment.
170
+ Add your own after it with `MessageAction` (an icon child, a `tooltip`, and
171
+ `label` when the tooltip isn't text).
172
+
173
+ ```tsx
174
+ <Chat
175
+ messages={messages}
176
+ onSend={send}
177
+ messageActions={(message) => (
178
+ <>
179
+ <ChatCopyAction message={message} onCopy={(ok) => ok && track("copy")} />
180
+ <MessageAction tooltip="Good reply" onClick={() => rate(message.id, "up")}>
181
+ <ThumbsUp />
182
+ </MessageAction>
183
+ </>
184
+ )}
185
+ />
186
+ ```
187
+
188
+ - **Which turns.** Assistant turns, by default. `ChatMessage.actions: false`
189
+ drops them from a turn that isn't a reply (a progress line), `true` gives
190
+ them to a user turn. The running line, a running turn, a turn with
191
+ `status: "sending"` (the user's own turn shown optimistically, until its
192
+ stored copy replaces it) and the footer never have them.
193
+ - **Always there.** The row shows on every screen, a phone included, rather
194
+ than on hover, so nothing moves when a pointer reaches it, and the copied
195
+ state swaps one icon for another of the same size. A button is 2rem
196
+ square, 2.75rem on a touch screen, where the tooltip can't show.
197
+
163
198
  ## File preview (1.3.0)
164
199
 
165
200
  `primitives/file-preview` shows a file in a dialog without leaving the page:
@@ -219,6 +254,62 @@ import { FilePreview } from "@epicbagel/saas-kit/primitives/file-preview";
219
254
  `primitives/document-preview` is the same dialog with every `src` in the
220
255
  browser's viewer, as it was in ui-kit; its API is unchanged.
221
256
 
257
+ ## Theme selector (1.4.0)
258
+
259
+ `primitives/theme-selector` is a page of appearance settings: light, dark or
260
+ system, then a grid of palettes, each previewing both modes. It owns no
261
+ state: it shows the `palette` and `mode` it is given and reports picks, and
262
+ the app applies and stores them. The palette is a `data-theme` attribute on
263
+ `<html>` and the mode the `.dark` class: two independent axes.
264
+
265
+ ```tsx
266
+ import { ThemeSelector, type ThemeSelectorMode } from "@epicbagel/saas-kit/primitives/theme-selector";
267
+ import { NEUTRAL_PALETTE, type ThemePalette } from "@epicbagel/saas-kit/lib/neutral-theme";
268
+
269
+ const PALETTES: ThemePalette[] = [NEUTRAL_PALETTE, ...yourPalettes];
270
+
271
+ export function Appearance() {
272
+ const [palette, setPalette] = useState(NEUTRAL_PALETTE.id);
273
+ const [mode, setMode] = useState<ThemeSelectorMode>("system");
274
+ // Apply them: set `data-theme` on <html> to the palette, and toggle
275
+ // `.dark` for the mode (next-themes does that part for you).
276
+ return (
277
+ <ThemeSelector
278
+ palettes={PALETTES}
279
+ palette={palette}
280
+ onPaletteChange={setPalette}
281
+ mode={mode}
282
+ onModeChange={setMode}
283
+ />
284
+ );
285
+ }
286
+ ```
287
+
288
+ - **Palettes come in.** The selector knows only the kit's neutral palette,
289
+ `NEUTRAL_PALETTE` (`lib/neutral-theme`), which it offers alone when given
290
+ no `palettes`. Its id is `minimal`, the value the stylesheet's default
291
+ already answers to, so storing it changes nothing on screen.
292
+ - **A `ThemePalette`** is an `id` (its `data-theme` value, and what you
293
+ store), a `label`, and optionally a `description`, a `radius` and each
294
+ mode's semantic tokens as hex (`light`, `dark`: the token contract in
295
+ `lib/neutral-theme`). Given the tokens, a preview paints from them inline
296
+ (`paletteStyle`), whatever palette the page is in. Without them it carries
297
+ `data-theme` and `data-mode`, so your palette CSS must select any element
298
+ (`[data-theme="<id>"]`, not `:root[data-theme="<id>"]`), re-declare the
299
+ `--color-*` aliases there (`paletteDeclarations` writes them) and answer
300
+ `[data-mode="light"]` and `[data-mode="dark"]`.
301
+ - **Before the stored pick is known**, pass `null` for `palette` or `mode`:
302
+ nothing is marked rather than the wrong option. Omitted, they default to
303
+ the neutral palette and `system`.
304
+ - **Layout.** One column on a phone (below `sm`). Otherwise the grid
305
+ follows the selector's own width, so the same component fits a dialog and
306
+ a settings page: one column while it is narrower than 24rem, two from
307
+ there, three from 42rem.
308
+ - **Words.** `modeLabel` ("Mode"), `paletteLabel` ("Theme"), `lightLabel`,
309
+ `darkLabel`, `systemLabel`, and optional `modeDescription` and
310
+ `paletteDescription`. Each palette's card is named by its `label` and
311
+ described by its `description`.
312
+
222
313
  ## License
223
314
 
224
315
  MIT. Some components and styles are adapted from shadcn/ui, and the file
@@ -0,0 +1,52 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } }"use client";
2
+
3
+
4
+ var _chunkGXHGMI3Zcjs = require('./chunk-GXHGMI3Z.cjs');
5
+
6
+
7
+ var _chunkKWLSBTB2cjs = require('./chunk-KWLSBTB2.cjs');
8
+
9
+ // src/primitives/toggle-group.tsx
10
+ var _react = require('react'); var React = _interopRequireWildcard(_react);
11
+ var _reacttogglegroup = require('@radix-ui/react-toggle-group'); var ToggleGroupPrimitive = _interopRequireWildcard(_reacttogglegroup);
12
+ var _jsxruntime = require('react/jsx-runtime');
13
+ var ToggleGroupContext = React.createContext({
14
+ size: "default",
15
+ variant: "default"
16
+ });
17
+ var ToggleGroup = React.forwardRef(({ className, variant, size, children, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
18
+ ToggleGroupPrimitive.Root,
19
+ {
20
+ ref,
21
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex items-center justify-center gap-1", className),
22
+ ...props,
23
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ToggleGroupContext.Provider, { value: { variant, size }, children })
24
+ }
25
+ ));
26
+ ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
27
+ var ToggleGroupItem = React.forwardRef(({ className, children, variant, size, grow = false, textSize = "inherit", ...props }, ref) => {
28
+ const context = React.useContext(ToggleGroupContext);
29
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
30
+ ToggleGroupPrimitive.Item,
31
+ {
32
+ ref,
33
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
34
+ _chunkGXHGMI3Zcjs.toggleVariants.call(void 0, {
35
+ variant: context.variant || variant,
36
+ size: context.size || size
37
+ }),
38
+ grow && "flex-1",
39
+ textSize === "xs" && "text-xs",
40
+ className
41
+ ),
42
+ ...props,
43
+ children
44
+ }
45
+ );
46
+ });
47
+ ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
48
+
49
+
50
+
51
+
52
+ exports.ToggleGroup = ToggleGroup; exports.ToggleGroupItem = ToggleGroupItem;
@@ -0,0 +1,271 @@
1
+ // src/lib/neutral-theme.ts
2
+ var SEMANTIC_TOKENS = [
3
+ "background",
4
+ "foreground",
5
+ "card",
6
+ "card-foreground",
7
+ "popover",
8
+ "popover-foreground",
9
+ "primary",
10
+ "primary-foreground",
11
+ "secondary",
12
+ "secondary-foreground",
13
+ "muted",
14
+ "muted-foreground",
15
+ "accent",
16
+ "accent-foreground",
17
+ "destructive",
18
+ "destructive-foreground",
19
+ "border",
20
+ "input",
21
+ "ring",
22
+ "chart-1",
23
+ "chart-2",
24
+ "chart-3",
25
+ "chart-4",
26
+ "chart-5",
27
+ "sidebar-background",
28
+ "sidebar-foreground",
29
+ "sidebar-primary",
30
+ "sidebar-primary-foreground",
31
+ "sidebar-accent",
32
+ "sidebar-accent-foreground",
33
+ "sidebar-border",
34
+ "sidebar-ring"
35
+ ];
36
+ function hexToRgb(hex) {
37
+ const h = hex.replace("#", "").trim();
38
+ const full = h.length === 3 ? h.split("").map((c) => c + c).join("") : h;
39
+ if (!/^[0-9a-fA-F]{6}$/.test(full)) {
40
+ throw new Error(`Not a hex colour: ${hex}`);
41
+ }
42
+ return [
43
+ parseInt(full.slice(0, 2), 16),
44
+ parseInt(full.slice(2, 4), 16),
45
+ parseInt(full.slice(4, 6), 16)
46
+ ];
47
+ }
48
+ function hexToHsl(hex) {
49
+ const [r255, g255, b255] = hexToRgb(hex);
50
+ const r = r255 / 255;
51
+ const g = g255 / 255;
52
+ const b = b255 / 255;
53
+ const max = Math.max(r, g, b);
54
+ const min = Math.min(r, g, b);
55
+ const l = (max + min) / 2;
56
+ const d = max - min;
57
+ let h = 0;
58
+ let s = 0;
59
+ if (d !== 0) {
60
+ s = d / (1 - Math.abs(2 * l - 1));
61
+ if (max === r) h = (g - b) / d % 6;
62
+ else if (max === g) h = (b - r) / d + 2;
63
+ else h = (r - g) / d + 4;
64
+ h *= 60;
65
+ if (h < 0) h += 360;
66
+ }
67
+ const round = (n) => Math.round(n * 10) / 10;
68
+ return `${round(h)} ${round(s * 100)}% ${round(l * 100)}%`;
69
+ }
70
+ function luminance(hex) {
71
+ const [r, g, b] = hexToRgb(hex).map((v) => {
72
+ const c = v / 255;
73
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
74
+ });
75
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
76
+ }
77
+ function contrastRatio(a, b) {
78
+ const la = luminance(a);
79
+ const lb = luminance(b);
80
+ const [hi, lo] = la > lb ? [la, lb] : [lb, la];
81
+ return (hi + 0.05) / (lo + 0.05);
82
+ }
83
+ function bestForeground(bg, candidates) {
84
+ let best = candidates[0];
85
+ let bestRatio = 0;
86
+ for (const c of candidates) {
87
+ const ratio = contrastRatio(bg, c);
88
+ if (ratio > bestRatio) {
89
+ best = c;
90
+ bestRatio = ratio;
91
+ }
92
+ }
93
+ return best;
94
+ }
95
+ var NEUTRAL_RADIUS = "0rem";
96
+ function neutral(mode) {
97
+ const light = mode === "light";
98
+ const danger = "#d71921";
99
+ const mono = light ? {
100
+ bg: "#ffffff",
101
+ fg: "#000000",
102
+ surface: "#f5f5f5",
103
+ subtle: "#666666",
104
+ border: "#e5e5e5",
105
+ sidebar: "#fafafa",
106
+ strong: "#333333"
107
+ } : {
108
+ bg: "#000000",
109
+ fg: "#ffffff",
110
+ surface: "#1a1a1a",
111
+ subtle: "#999999",
112
+ border: "#333333",
113
+ sidebar: "#0d0d0d",
114
+ strong: "#cccccc"
115
+ };
116
+ return {
117
+ background: mono.bg,
118
+ foreground: mono.fg,
119
+ card: mono.bg,
120
+ "card-foreground": mono.fg,
121
+ popover: mono.bg,
122
+ "popover-foreground": mono.fg,
123
+ primary: mono.fg,
124
+ "primary-foreground": mono.bg,
125
+ secondary: mono.surface,
126
+ "secondary-foreground": mono.fg,
127
+ muted: mono.surface,
128
+ "muted-foreground": mono.subtle,
129
+ accent: mono.surface,
130
+ "accent-foreground": mono.fg,
131
+ destructive: danger,
132
+ "destructive-foreground": bestForeground(danger, ["#ffffff", "#000000"]),
133
+ border: mono.border,
134
+ input: mono.border,
135
+ ring: mono.fg,
136
+ "chart-1": light ? "#333333" : "#cccccc",
137
+ "chart-2": light ? "#4d4d4d" : "#b3b3b3",
138
+ "chart-3": light ? "#666666" : "#999999",
139
+ "chart-4": light ? "#808080" : "#808080",
140
+ "chart-5": light ? "#999999" : "#666666",
141
+ "sidebar-background": mono.sidebar,
142
+ "sidebar-foreground": mono.fg,
143
+ "sidebar-primary": mono.fg,
144
+ "sidebar-primary-foreground": mono.bg,
145
+ "sidebar-accent": mono.surface,
146
+ "sidebar-accent-foreground": mono.fg,
147
+ "sidebar-border": mono.border,
148
+ "sidebar-ring": mono.border
149
+ };
150
+ }
151
+ var NEUTRAL = {
152
+ light: neutral("light"),
153
+ dark: neutral("dark")
154
+ };
155
+ var NEUTRAL_THEME_ID = "minimal";
156
+ var NEUTRAL_PALETTE = {
157
+ id: NEUTRAL_THEME_ID,
158
+ label: "Neutral",
159
+ description: "Black and white, square corners.",
160
+ radius: NEUTRAL_RADIUS,
161
+ light: NEUTRAL.light,
162
+ dark: NEUTRAL.dark
163
+ };
164
+ function colorAlias(token) {
165
+ if (token.startsWith("chart-")) return null;
166
+ if (token === "sidebar-background") return "--color-sidebar";
167
+ return `--color-${token}`;
168
+ }
169
+ var RADIUS_SCALE = [
170
+ ["--radius-sm", "calc(var(--radius) - 4px)"],
171
+ ["--radius-md", "calc(var(--radius) - 2px)"],
172
+ ["--radius-lg", "var(--radius)"],
173
+ ["--radius-xl", "calc(var(--radius) + 4px)"],
174
+ ["--radius-2xl", "calc(var(--radius) + 8px)"]
175
+ ];
176
+ function paletteDeclarations(tokens, names, radius, { indent = " ", aliasSource = "neutral-theme.ts" } = {}) {
177
+ const value = (token) => {
178
+ const hex = tokens[token];
179
+ if (hex === void 0) throw new Error(`Missing token: ${token}`);
180
+ return hexToHsl(hex);
181
+ };
182
+ const lines = [`${indent}--radius: ${radius};`];
183
+ for (const token of names) {
184
+ lines.push(`${indent}--${token}: ${value(token)};`);
185
+ }
186
+ lines.push(`${indent}--sidebar: ${value("sidebar-background")};`);
187
+ lines.push(`${indent}/* Tailwind-facing aliases \u2014 see ${aliasSource} */`);
188
+ for (const token of names) {
189
+ const alias = colorAlias(token);
190
+ if (alias) lines.push(`${indent}${alias}: hsl(var(--${token}));`);
191
+ }
192
+ for (const [name, scale] of RADIUS_SCALE) {
193
+ lines.push(`${indent}${name}: ${scale};`);
194
+ }
195
+ return lines.join("\n");
196
+ }
197
+ function paletteStyle(tokens, radius, names = SEMANTIC_TOKENS) {
198
+ const value = (token) => {
199
+ const hex = tokens[token];
200
+ if (hex === void 0) throw new Error(`Missing token: ${token}`);
201
+ return hexToHsl(hex);
202
+ };
203
+ const style = {};
204
+ if (radius !== void 0) style["--radius"] = radius;
205
+ for (const token of names) style[`--${token}`] = value(token);
206
+ style["--sidebar"] = value("sidebar-background");
207
+ for (const token of names) {
208
+ const alias = colorAlias(token);
209
+ if (alias) style[alias] = `hsl(var(--${token}))`;
210
+ }
211
+ for (const [name, scale] of RADIUS_SCALE) style[name] = scale;
212
+ return style;
213
+ }
214
+ function paletteBlock(selector, declarations, indent = "") {
215
+ const head = selector.split("\n").map((line) => indent + line).join("\n");
216
+ return `${head} {
217
+ ${declarations}
218
+ ${indent}}
219
+ `;
220
+ }
221
+ function layerBlock(name, rules) {
222
+ return `@layer ${name} {
223
+ ${rules.join("\n")}}
224
+ `;
225
+ }
226
+ var DARK_ROOT_SELECTOR = ":root:where(.dark)";
227
+ function baseLayerPalette(light, dark, indent = " ") {
228
+ return layerBlock("base", [
229
+ paletteBlock(":root", light, indent),
230
+ paletteBlock(DARK_ROOT_SELECTOR, dark, indent)
231
+ ]);
232
+ }
233
+ var PALETTE_GENERATED_HEADER = `/* GENERATED FILE \u2014 do not edit.
234
+ * Source: src/lib/neutral-theme.ts \xB7 Regenerate: pnpm gen:themes
235
+ *
236
+ * The neutral palette: light on :root, dark when the root carries the
237
+ * \`.dark\` class. It sits in \`@layer base\`, so any unlayered palette rule
238
+ * or a host's own :root overrides wins on layer order alone. Imported by
239
+ * tokens.css; every --color-* alias and the radius scale are re-declared
240
+ * alongside the tokens they read.
241
+ */`;
242
+ function renderPaletteCss() {
243
+ const declarations = (mode) => paletteDeclarations(NEUTRAL[mode], SEMANTIC_TOKENS, NEUTRAL_RADIUS, {
244
+ indent: " "
245
+ });
246
+ return [
247
+ PALETTE_GENERATED_HEADER,
248
+ baseLayerPalette(declarations("light"), declarations("dark"))
249
+ ].join("\n");
250
+ }
251
+
252
+ export {
253
+ SEMANTIC_TOKENS,
254
+ hexToRgb,
255
+ hexToHsl,
256
+ luminance,
257
+ contrastRatio,
258
+ bestForeground,
259
+ NEUTRAL_RADIUS,
260
+ NEUTRAL,
261
+ NEUTRAL_THEME_ID,
262
+ NEUTRAL_PALETTE,
263
+ colorAlias,
264
+ paletteDeclarations,
265
+ paletteStyle,
266
+ paletteBlock,
267
+ layerBlock,
268
+ baseLayerPalette,
269
+ PALETTE_GENERATED_HEADER,
270
+ renderPaletteCss
271
+ };
@@ -1,10 +1,20 @@
1
1
  "use client";
2
+ import {
3
+ Tooltip,
4
+ TooltipContent,
5
+ TooltipProvider,
6
+ TooltipTrigger
7
+ } from "./chunk-ZRLUUZHK.js";
8
+ import {
9
+ Button
10
+ } from "./chunk-HQRWRRZJ.js";
2
11
  import {
3
12
  cn
4
13
  } from "./chunk-G6SRSWXB.js";
5
14
 
6
15
  // src/primitives/message.tsx
7
- import { jsx } from "react/jsx-runtime";
16
+ import * as React from "react";
17
+ import { jsx, jsxs } from "react/jsx-runtime";
8
18
  function MessageGroup({ className, ...props }) {
9
19
  return /* @__PURE__ */ jsx(
10
20
  "div",
@@ -85,6 +95,53 @@ function MessageFooter({ className, ...props }) {
85
95
  }
86
96
  );
87
97
  }
98
+ function MessageActions({ className, ...props }) {
99
+ return /* @__PURE__ */ jsx(
100
+ "div",
101
+ {
102
+ "data-slot": "message-actions",
103
+ className: cn(
104
+ "cn-message-actions flex max-w-full min-w-0 items-center gap-0.5 text-muted-foreground empty:hidden group-data-[align=end]/message:justify-end",
105
+ className
106
+ ),
107
+ ...props
108
+ }
109
+ );
110
+ }
111
+ var MessageAction = React.forwardRef(
112
+ function MessageAction2({
113
+ tooltip,
114
+ label,
115
+ side = "bottom",
116
+ variant = "quiet",
117
+ type = "button",
118
+ className,
119
+ children,
120
+ ...props
121
+ }, ref) {
122
+ const name = label ?? (typeof tooltip === "string" ? tooltip : void 0);
123
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
124
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
125
+ Button,
126
+ {
127
+ ref,
128
+ type,
129
+ variant,
130
+ size: "icon-compact",
131
+ "aria-label": name,
132
+ "data-slot": "message-action",
133
+ className: cn(
134
+ "cn-message-action size-8 shrink-0 rounded-full pointer-coarse:size-11",
135
+ className
136
+ ),
137
+ ...props,
138
+ children
139
+ }
140
+ ) }),
141
+ /* @__PURE__ */ jsx(TooltipContent, { side, children: tooltip })
142
+ ] }) });
143
+ }
144
+ );
88
145
 
89
146
  export {
90
147
  MessageGroup,
@@ -92,5 +149,7 @@ export {
92
149
  MessageAvatar,
93
150
  MessageContent,
94
151
  MessageHeader,
95
- MessageFooter
152
+ MessageFooter,
153
+ MessageActions,
154
+ MessageAction
96
155
  };
@@ -0,0 +1,46 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } }"use client";
2
+
3
+
4
+ var _chunkKWLSBTB2cjs = require('./chunk-KWLSBTB2.cjs');
5
+
6
+ // src/primitives/radio-group.tsx
7
+ var _reactradiogroup = require('@radix-ui/react-radio-group'); var RadioGroupPrimitive = _interopRequireWildcard(_reactradiogroup);
8
+ var _react = require('react'); var React = _interopRequireWildcard(_react);
9
+ var _lucidereact = require('lucide-react');
10
+ var _jsxruntime = require('react/jsx-runtime');
11
+ var RadioGroup = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
12
+ RadioGroupPrimitive.Root,
13
+ {
14
+ ref,
15
+ "data-slot": "radio-group",
16
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, "grid gap-3", className),
17
+ ...props
18
+ }
19
+ ));
20
+ RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
21
+ var RadioGroupItem = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
22
+ RadioGroupPrimitive.Item,
23
+ {
24
+ ref,
25
+ "data-slot": "radio-group-item",
26
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
27
+ "aspect-square size-4 shrink-0 rounded-full border border-input text-primary shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:aria-invalid:ring-destructive/40",
28
+ className
29
+ ),
30
+ ...props,
31
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
32
+ RadioGroupPrimitive.Indicator,
33
+ {
34
+ "data-slot": "radio-group-indicator",
35
+ className: "relative flex items-center justify-center",
36
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.CircleIcon, { className: "absolute left-1/2 top-1/2 size-2 -translate-x-1/2 -translate-y-1/2 fill-primary" })
37
+ }
38
+ )
39
+ }
40
+ ));
41
+ RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
42
+
43
+
44
+
45
+
46
+ exports.RadioGroup = RadioGroup; exports.RadioGroupItem = RadioGroupItem;
@@ -0,0 +1,46 @@
1
+ "use client";
2
+ import {
3
+ cn
4
+ } from "./chunk-G6SRSWXB.js";
5
+
6
+ // src/primitives/radio-group.tsx
7
+ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
8
+ import * as React from "react";
9
+ import { CircleIcon } from "lucide-react";
10
+ import { jsx } from "react/jsx-runtime";
11
+ var RadioGroup = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
12
+ RadioGroupPrimitive.Root,
13
+ {
14
+ ref,
15
+ "data-slot": "radio-group",
16
+ className: cn("grid gap-3", className),
17
+ ...props
18
+ }
19
+ ));
20
+ RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
21
+ var RadioGroupItem = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
22
+ RadioGroupPrimitive.Item,
23
+ {
24
+ ref,
25
+ "data-slot": "radio-group-item",
26
+ className: cn(
27
+ "aspect-square size-4 shrink-0 rounded-full border border-input text-primary shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:aria-invalid:ring-destructive/40",
28
+ className
29
+ ),
30
+ ...props,
31
+ children: /* @__PURE__ */ jsx(
32
+ RadioGroupPrimitive.Indicator,
33
+ {
34
+ "data-slot": "radio-group-indicator",
35
+ className: "relative flex items-center justify-center",
36
+ children: /* @__PURE__ */ jsx(CircleIcon, { className: "absolute left-1/2 top-1/2 size-2 -translate-x-1/2 -translate-y-1/2 fill-primary" })
37
+ }
38
+ )
39
+ }
40
+ ));
41
+ RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
42
+
43
+ export {
44
+ RadioGroup,
45
+ RadioGroupItem
46
+ };
@@ -1,9 +1,19 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }"use client";
2
+
3
+
4
+
5
+
6
+
7
+ var _chunkU2NES7VRcjs = require('./chunk-U2NES7VR.cjs');
8
+
9
+
10
+ var _chunkL4DH72UFcjs = require('./chunk-L4DH72UF.cjs');
2
11
 
3
12
 
4
13
  var _chunkKWLSBTB2cjs = require('./chunk-KWLSBTB2.cjs');
5
14
 
6
15
  // src/primitives/message.tsx
16
+ var _react = require('react'); var React = _interopRequireWildcard(_react);
7
17
  var _jsxruntime = require('react/jsx-runtime');
8
18
  function MessageGroup({ className, ...props }) {
9
19
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -85,6 +95,55 @@ function MessageFooter({ className, ...props }) {
85
95
  }
86
96
  );
87
97
  }
98
+ function MessageActions({ className, ...props }) {
99
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
100
+ "div",
101
+ {
102
+ "data-slot": "message-actions",
103
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
104
+ "cn-message-actions flex max-w-full min-w-0 items-center gap-0.5 text-muted-foreground empty:hidden group-data-[align=end]/message:justify-end",
105
+ className
106
+ ),
107
+ ...props
108
+ }
109
+ );
110
+ }
111
+ var MessageAction = React.forwardRef(
112
+ function MessageAction2({
113
+ tooltip,
114
+ label,
115
+ side = "bottom",
116
+ variant = "quiet",
117
+ type = "button",
118
+ className,
119
+ children,
120
+ ...props
121
+ }, ref) {
122
+ const name = _nullishCoalesce(label, () => ( (typeof tooltip === "string" ? tooltip : void 0)));
123
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkU2NES7VRcjs.TooltipProvider, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkU2NES7VRcjs.Tooltip, { children: [
124
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkU2NES7VRcjs.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
125
+ _chunkL4DH72UFcjs.Button,
126
+ {
127
+ ref,
128
+ type,
129
+ variant,
130
+ size: "icon-compact",
131
+ "aria-label": name,
132
+ "data-slot": "message-action",
133
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
134
+ "cn-message-action size-8 shrink-0 rounded-full pointer-coarse:size-11",
135
+ className
136
+ ),
137
+ ...props,
138
+ children
139
+ }
140
+ ) }),
141
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkU2NES7VRcjs.TooltipContent, { side, children: tooltip })
142
+ ] }) });
143
+ }
144
+ );
145
+
146
+
88
147
 
89
148
 
90
149
 
@@ -93,4 +152,4 @@ function MessageFooter({ className, ...props }) {
93
152
 
94
153
 
95
154
 
96
- exports.MessageGroup = MessageGroup; exports.Message = Message; exports.MessageAvatar = MessageAvatar; exports.MessageContent = MessageContent; exports.MessageHeader = MessageHeader; exports.MessageFooter = MessageFooter;
155
+ exports.MessageGroup = MessageGroup; exports.Message = Message; exports.MessageAvatar = MessageAvatar; exports.MessageContent = MessageContent; exports.MessageHeader = MessageHeader; exports.MessageFooter = MessageFooter; exports.MessageActions = MessageActions; exports.MessageAction = MessageAction;