@epicbagel/saas-kit 1.26.0 → 1.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -567,6 +567,32 @@ turn. The thread draws the avatar and name above the first of each run of
567
567
  turns by the same person on the same side, and again after a time marker, so
568
568
  a conversation with several people in it says who said what.
569
569
 
570
+ ### Next steps in the empty state (1.27.0)
571
+
572
+ `Chat` takes `emptyActions`, an array of `ChatEmptyAction`: what a returning
573
+ user can pick up, shown under the empty-state composer and before any
574
+ `examplePrompts`.
575
+
576
+ ```tsx
577
+ <Chat
578
+ messages={[]}
579
+ onSend={send}
580
+ emptyActions={[
581
+ { id: "review", icon: Users, label: "Review 3 new people", detail: "Head of Sales · Northwind", onSelect: openReview },
582
+ { id: "answer", icon: MessageCircleQuestion, label: "London", detail: "Where is the role based? · VP Finance", onSelect: answer },
583
+ ]}
584
+ />
585
+ ```
586
+
587
+ - **A row** is a button: the icon, the `label` and the muted `detail`, on one
588
+ line where there is room.
589
+ - **A pick** calls `onSelect` and sends nothing. Return a promise to show the
590
+ row's spinner and disable every row until it settles; a rejection
591
+ re-enables them and goes to `onSendError` (else `reportError`).
592
+ - **The heading** is `emptyActionsLabel`, default "Pick up where you left
593
+ off". `""` hides it and keeps the default as the list's accessible name.
594
+ - It hides while `pending` and once the conversation has started.
595
+
570
596
  ## Notes
571
597
 
572
598
  `primitives/notes` provides a reusable `Notes` area and `NoteComposer` for any
@@ -0,0 +1,198 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
2
+
3
+
4
+ var _chunkNQK5ZWC7cjs = require('./chunk-NQK5ZWC7.cjs');
5
+
6
+
7
+ var _chunkKWLSBTB2cjs = require('./chunk-KWLSBTB2.cjs');
8
+
9
+ // src/primitives/item.tsx
10
+ var _classvarianceauthority = require('class-variance-authority');
11
+ var _radixui = require('radix-ui');
12
+ var _jsxruntime = require('react/jsx-runtime');
13
+ function ItemGroup({ className, ...props }) {
14
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
15
+ "div",
16
+ {
17
+ role: "list",
18
+ "data-slot": "item-group",
19
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
20
+ "group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
21
+ className
22
+ ),
23
+ ...props
24
+ }
25
+ );
26
+ }
27
+ function ItemSeparator({
28
+ className,
29
+ ...props
30
+ }) {
31
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
32
+ _chunkNQK5ZWC7cjs.Separator,
33
+ {
34
+ "data-slot": "item-separator",
35
+ orientation: "horizontal",
36
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, "my-2", className),
37
+ ...props
38
+ }
39
+ );
40
+ }
41
+ var itemVariants = _classvarianceauthority.cva.call(void 0,
42
+ "group/item flex w-full flex-wrap items-center rounded-md border text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
43
+ {
44
+ variants: {
45
+ variant: {
46
+ default: "border-transparent",
47
+ outline: "border-border",
48
+ muted: "border-transparent bg-muted/50"
49
+ },
50
+ size: {
51
+ default: "gap-3.5 px-4 py-3.5",
52
+ sm: "gap-2.5 px-3 py-2.5",
53
+ xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0"
54
+ }
55
+ },
56
+ defaultVariants: {
57
+ variant: "default",
58
+ size: "default"
59
+ }
60
+ }
61
+ );
62
+ function Item({
63
+ className,
64
+ variant = "default",
65
+ size = "default",
66
+ asChild = false,
67
+ ...props
68
+ }) {
69
+ const Comp = asChild ? _radixui.Slot.Root : "div";
70
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
71
+ Comp,
72
+ {
73
+ "data-slot": "item",
74
+ "data-variant": variant,
75
+ "data-size": size,
76
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, itemVariants({ variant, size, className })),
77
+ ...props
78
+ }
79
+ );
80
+ }
81
+ var itemMediaVariants = _classvarianceauthority.cva.call(void 0,
82
+ "flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none",
83
+ {
84
+ variants: {
85
+ variant: {
86
+ default: "bg-transparent",
87
+ icon: "[&_svg:not([class*='size-'])]:size-4",
88
+ image: "size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover"
89
+ }
90
+ },
91
+ defaultVariants: {
92
+ variant: "default"
93
+ }
94
+ }
95
+ );
96
+ function ItemMedia({
97
+ className,
98
+ variant = "default",
99
+ ...props
100
+ }) {
101
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
102
+ "div",
103
+ {
104
+ "data-slot": "item-media",
105
+ "data-variant": variant,
106
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, itemMediaVariants({ variant, className })),
107
+ ...props
108
+ }
109
+ );
110
+ }
111
+ function ItemContent({ className, ...props }) {
112
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
113
+ "div",
114
+ {
115
+ "data-slot": "item-content",
116
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
117
+ "flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none",
118
+ className
119
+ ),
120
+ ...props
121
+ }
122
+ );
123
+ }
124
+ function ItemTitle({ className, ...props }) {
125
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
126
+ "div",
127
+ {
128
+ "data-slot": "item-title",
129
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
130
+ "line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
131
+ className
132
+ ),
133
+ ...props
134
+ }
135
+ );
136
+ }
137
+ function ItemDescription({ className, ...props }) {
138
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
139
+ "p",
140
+ {
141
+ "data-slot": "item-description",
142
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
143
+ "line-clamp-2 text-left text-sm leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
144
+ className
145
+ ),
146
+ ...props
147
+ }
148
+ );
149
+ }
150
+ function ItemActions({ className, ...props }) {
151
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
152
+ "div",
153
+ {
154
+ "data-slot": "item-actions",
155
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex items-center gap-2", className),
156
+ ...props
157
+ }
158
+ );
159
+ }
160
+ function ItemHeader({ className, ...props }) {
161
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
162
+ "div",
163
+ {
164
+ "data-slot": "item-header",
165
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
166
+ "flex basis-full items-center justify-between gap-2",
167
+ className
168
+ ),
169
+ ...props
170
+ }
171
+ );
172
+ }
173
+ function ItemFooter({ className, ...props }) {
174
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
175
+ "div",
176
+ {
177
+ "data-slot": "item-footer",
178
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
179
+ "flex basis-full items-center justify-between gap-2",
180
+ className
181
+ ),
182
+ ...props
183
+ }
184
+ );
185
+ }
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+
195
+
196
+
197
+
198
+ exports.ItemGroup = ItemGroup; exports.ItemSeparator = ItemSeparator; exports.Item = Item; exports.ItemMedia = ItemMedia; exports.ItemContent = ItemContent; exports.ItemTitle = ItemTitle; exports.ItemDescription = ItemDescription; exports.ItemActions = ItemActions; exports.ItemHeader = ItemHeader; exports.ItemFooter = ItemFooter;
@@ -0,0 +1,198 @@
1
+ "use client";
2
+ import {
3
+ Separator
4
+ } from "./chunk-HYTILYE5.js";
5
+ import {
6
+ cn
7
+ } from "./chunk-G6SRSWXB.js";
8
+
9
+ // src/primitives/item.tsx
10
+ import { cva } from "class-variance-authority";
11
+ import { Slot } from "radix-ui";
12
+ import { jsx } from "react/jsx-runtime";
13
+ function ItemGroup({ className, ...props }) {
14
+ return /* @__PURE__ */ jsx(
15
+ "div",
16
+ {
17
+ role: "list",
18
+ "data-slot": "item-group",
19
+ className: cn(
20
+ "group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
21
+ className
22
+ ),
23
+ ...props
24
+ }
25
+ );
26
+ }
27
+ function ItemSeparator({
28
+ className,
29
+ ...props
30
+ }) {
31
+ return /* @__PURE__ */ jsx(
32
+ Separator,
33
+ {
34
+ "data-slot": "item-separator",
35
+ orientation: "horizontal",
36
+ className: cn("my-2", className),
37
+ ...props
38
+ }
39
+ );
40
+ }
41
+ var itemVariants = cva(
42
+ "group/item flex w-full flex-wrap items-center rounded-md border text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
43
+ {
44
+ variants: {
45
+ variant: {
46
+ default: "border-transparent",
47
+ outline: "border-border",
48
+ muted: "border-transparent bg-muted/50"
49
+ },
50
+ size: {
51
+ default: "gap-3.5 px-4 py-3.5",
52
+ sm: "gap-2.5 px-3 py-2.5",
53
+ xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0"
54
+ }
55
+ },
56
+ defaultVariants: {
57
+ variant: "default",
58
+ size: "default"
59
+ }
60
+ }
61
+ );
62
+ function Item({
63
+ className,
64
+ variant = "default",
65
+ size = "default",
66
+ asChild = false,
67
+ ...props
68
+ }) {
69
+ const Comp = asChild ? Slot.Root : "div";
70
+ return /* @__PURE__ */ jsx(
71
+ Comp,
72
+ {
73
+ "data-slot": "item",
74
+ "data-variant": variant,
75
+ "data-size": size,
76
+ className: cn(itemVariants({ variant, size, className })),
77
+ ...props
78
+ }
79
+ );
80
+ }
81
+ var itemMediaVariants = cva(
82
+ "flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none",
83
+ {
84
+ variants: {
85
+ variant: {
86
+ default: "bg-transparent",
87
+ icon: "[&_svg:not([class*='size-'])]:size-4",
88
+ image: "size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover"
89
+ }
90
+ },
91
+ defaultVariants: {
92
+ variant: "default"
93
+ }
94
+ }
95
+ );
96
+ function ItemMedia({
97
+ className,
98
+ variant = "default",
99
+ ...props
100
+ }) {
101
+ return /* @__PURE__ */ jsx(
102
+ "div",
103
+ {
104
+ "data-slot": "item-media",
105
+ "data-variant": variant,
106
+ className: cn(itemMediaVariants({ variant, className })),
107
+ ...props
108
+ }
109
+ );
110
+ }
111
+ function ItemContent({ className, ...props }) {
112
+ return /* @__PURE__ */ jsx(
113
+ "div",
114
+ {
115
+ "data-slot": "item-content",
116
+ className: cn(
117
+ "flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none",
118
+ className
119
+ ),
120
+ ...props
121
+ }
122
+ );
123
+ }
124
+ function ItemTitle({ className, ...props }) {
125
+ return /* @__PURE__ */ jsx(
126
+ "div",
127
+ {
128
+ "data-slot": "item-title",
129
+ className: cn(
130
+ "line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
131
+ className
132
+ ),
133
+ ...props
134
+ }
135
+ );
136
+ }
137
+ function ItemDescription({ className, ...props }) {
138
+ return /* @__PURE__ */ jsx(
139
+ "p",
140
+ {
141
+ "data-slot": "item-description",
142
+ className: cn(
143
+ "line-clamp-2 text-left text-sm leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
144
+ className
145
+ ),
146
+ ...props
147
+ }
148
+ );
149
+ }
150
+ function ItemActions({ className, ...props }) {
151
+ return /* @__PURE__ */ jsx(
152
+ "div",
153
+ {
154
+ "data-slot": "item-actions",
155
+ className: cn("flex items-center gap-2", className),
156
+ ...props
157
+ }
158
+ );
159
+ }
160
+ function ItemHeader({ className, ...props }) {
161
+ return /* @__PURE__ */ jsx(
162
+ "div",
163
+ {
164
+ "data-slot": "item-header",
165
+ className: cn(
166
+ "flex basis-full items-center justify-between gap-2",
167
+ className
168
+ ),
169
+ ...props
170
+ }
171
+ );
172
+ }
173
+ function ItemFooter({ className, ...props }) {
174
+ return /* @__PURE__ */ jsx(
175
+ "div",
176
+ {
177
+ "data-slot": "item-footer",
178
+ className: cn(
179
+ "flex basis-full items-center justify-between gap-2",
180
+ className
181
+ ),
182
+ ...props
183
+ }
184
+ );
185
+ }
186
+
187
+ export {
188
+ ItemGroup,
189
+ ItemSeparator,
190
+ Item,
191
+ ItemMedia,
192
+ ItemContent,
193
+ ItemTitle,
194
+ ItemDescription,
195
+ ItemActions,
196
+ ItemHeader,
197
+ ItemFooter
198
+ };
@@ -17,6 +17,9 @@ var _chunkPNI354BYcjs = require('../chunk-PNI354BY.cjs');
17
17
  var _chunkM4V7OJNFcjs = require('../chunk-M4V7OJNF.cjs');
18
18
 
19
19
 
20
+ var _chunkVMXKT67Ecjs = require('../chunk-VMXKT67E.cjs');
21
+
22
+
20
23
  var _chunkU7XNNLVPcjs = require('../chunk-U7XNNLVP.cjs');
21
24
 
22
25
 
@@ -37,6 +40,14 @@ require('../chunk-2HV2KKOE.cjs');
37
40
 
38
41
 
39
42
 
43
+
44
+
45
+
46
+ var _chunkDHXKCMKYcjs = require('../chunk-DHXKCMKY.cjs');
47
+ require('../chunk-NQK5ZWC7.cjs');
48
+
49
+
50
+
40
51
  var _chunkZLEM2SAUcjs = require('../chunk-ZLEM2SAU.cjs');
41
52
 
42
53
 
@@ -120,6 +131,7 @@ var _chunkH2UFRLLNcjs = require('../chunk-H2UFRLLN.cjs');
120
131
 
121
132
 
122
133
 
134
+
123
135
  var _react = require('react');
124
136
 
125
137
 
@@ -758,6 +770,92 @@ function ChatSuggestions({
758
770
  )
759
771
  ] });
760
772
  }
773
+ var DEFAULT_EMPTY_ACTIONS_LABEL = "Pick up where you left off";
774
+ function ChatEmptyActionIcon({ icon }) {
775
+ if (!icon) return null;
776
+ if (_react.isValidElement.call(void 0, icon)) return icon;
777
+ if (typeof icon === "function" || typeof icon === "object" && icon !== null && "render" in icon) {
778
+ const IconComp = icon;
779
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconComp, { "aria-hidden": true });
780
+ }
781
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: icon });
782
+ }
783
+ function ChatEmptyActions({
784
+ items,
785
+ label,
786
+ onError,
787
+ className
788
+ }) {
789
+ const labelId = _react.useId.call(void 0, );
790
+ const [running, setRunning] = _react.useState.call(void 0, null);
791
+ if (items.length === 0) return null;
792
+ const showLabel = label.length > 0;
793
+ const pick = async (item) => {
794
+ if (running !== null) return;
795
+ let result;
796
+ try {
797
+ result = item.onSelect();
798
+ } catch (cause) {
799
+ onError(cause);
800
+ return;
801
+ }
802
+ if (!result || typeof result.then !== "function") return;
803
+ setRunning(item.id);
804
+ try {
805
+ await result;
806
+ } catch (cause) {
807
+ onError(cause);
808
+ } finally {
809
+ setRunning(null);
810
+ }
811
+ };
812
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { "data-slot": "chat-empty-actions", className: _chunkKWLSBTB2cjs.cn.call(void 0, "w-full text-left", className), children: [
813
+ showLabel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { id: labelId, "data-slot": "chat-empty-actions-label", className: "mb-1.5 px-3 text-xs text-muted-foreground", children: label }),
814
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
815
+ "div",
816
+ {
817
+ role: "group",
818
+ "aria-labelledby": showLabel ? labelId : void 0,
819
+ "aria-label": showLabel ? void 0 : DEFAULT_EMPTY_ACTIONS_LABEL,
820
+ className: "flex flex-col gap-0.5",
821
+ children: items.map((item) => {
822
+ const busy = running === item.id;
823
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDHXKCMKYcjs.Item, { asChild: true, size: "sm", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
824
+ "button",
825
+ {
826
+ type: "button",
827
+ "data-slot": "chat-empty-action",
828
+ "data-state": busy ? "loading" : void 0,
829
+ "aria-busy": busy || void 0,
830
+ disabled: item.disabled || running !== null,
831
+ onClick: () => void pick(item),
832
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
833
+ "min-h-11 cursor-pointer flex-nowrap text-left",
834
+ "hover:bg-muted focus-visible:bg-muted",
835
+ "disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent",
836
+ busy && "disabled:opacity-100"
837
+ ),
838
+ children: [
839
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
840
+ _chunkDHXKCMKYcjs.ItemMedia,
841
+ {
842
+ variant: "icon",
843
+ className: "size-8 self-center rounded-md bg-muted text-muted-foreground group-has-data-[slot=item-description]/item:translate-y-0 group-has-data-[slot=item-description]/item:self-center",
844
+ children: busy ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVMXKT67Ecjs.Spinner, { "aria-hidden": true }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ChatEmptyActionIcon, { icon: item.icon })
845
+ }
846
+ ),
847
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkDHXKCMKYcjs.ItemContent, { className: "min-w-0 flex-row flex-wrap items-baseline gap-x-2 gap-y-0.5 md:flex-nowrap", children: [
848
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDHXKCMKYcjs.ItemTitle, { className: "w-auto min-w-0 shrink-0 font-normal text-foreground md:max-w-[60%] md:truncate", children: item.label }),
849
+ item.detail && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDHXKCMKYcjs.ItemDescription, { className: "line-clamp-1 min-w-0 flex-1 truncate text-xs md:text-sm", children: item.detail })
850
+ ] })
851
+ ]
852
+ }
853
+ ) }, item.id);
854
+ })
855
+ }
856
+ )
857
+ ] });
858
+ }
761
859
  function MobileReplySuggestions({
762
860
  items,
763
861
  onSelect,
@@ -913,6 +1011,8 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
913
1011
  emptySubtitle,
914
1012
  examplePrompts = [],
915
1013
  examplePromptsLabel = "Try",
1014
+ emptyActions = [],
1015
+ emptyActionsLabel = DEFAULT_EMPTY_ACTIONS_LABEL,
916
1016
  examplePromptsVariant = "chips",
917
1017
  examplePromptsLoading = false,
918
1018
  examplePromptsLoadingLabel = "Loading suggestions\u2026",
@@ -1152,6 +1252,15 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
1152
1252
  }
1153
1253
  ),
1154
1254
  error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ChatError, { children: error }),
1255
+ !pending && emptyActions.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1256
+ ChatEmptyActions,
1257
+ {
1258
+ items: emptyActions,
1259
+ label: emptyActionsLabel,
1260
+ onError: reportSendError,
1261
+ className: "mt-3"
1262
+ }
1263
+ ),
1155
1264
  !pending && examplePromptsLoading && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ExamplePromptsLoading, { label: examplePromptsLoadingLabel }),
1156
1265
  !pending && !examplePromptsLoading && examplePrompts.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1157
1266
  ChatSuggestions,
@@ -1,6 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React$1 from 'react';
3
3
  import { ReactNode } from 'react';
4
+ import { LucideIcon } from 'lucide-react';
4
5
  import { VoiceSessionControlsProps } from './voice-session-controls.cjs';
5
6
  import { ChatNavigatorItem } from './chat-turn-navigator.cjs';
6
7
  import { MarkdownComponents } from './markdown.cjs';
@@ -259,6 +260,24 @@ interface ChatInputProps {
259
260
  * device-aware default modes.
260
261
  */
261
262
  declare function ChatInput({ value, onChange, onSend, pending, disabled, placeholder, size, uploadingLabel, voice, voiceSession, voiceTitle, voiceLang, submitLabel, autoFocus, className, inputRef, attachments, onFilesSelected, onRemoveAttachment, accept, multiple, addFilesLabel, appearance, compactOnBlur, header, helperText, privacyNote, }: ChatInputProps): react_jsx_runtime.JSX.Element;
263
+ /** A next step offered in the empty state, under the composer (`emptyActions`). */
264
+ interface ChatEmptyAction {
265
+ /** Stable key. */
266
+ id: string;
267
+ /** What picking it does, e.g. "Review 3 new people". */
268
+ label: ReactNode;
269
+ /** Where it applies, muted after the label, e.g. "Head of Sales · Northwind". One line, truncated. */
270
+ detail?: ReactNode;
271
+ /** Leading icon: a Lucide component or an element. */
272
+ icon?: LucideIcon | ReactNode;
273
+ /**
274
+ * Called when picked. While a returned promise is pending, that row shows a
275
+ * spinner and every row is disabled; a rejection re-enables them and is
276
+ * reported.
277
+ */
278
+ onSelect: () => void | Promise<void>;
279
+ disabled?: boolean;
280
+ }
262
281
  interface ChatProps {
263
282
  /** Conversation messages. */
264
283
  messages: ChatMessage[];
@@ -304,6 +323,21 @@ interface ChatProps {
304
323
  examplePrompts?: ReadonlyArray<string>;
305
324
  /** Label above the example prompts. Defaults to "Try". */
306
325
  examplePromptsLabel?: string;
326
+ /**
327
+ * Next steps under the empty-state composer, before `examplePrompts`,
328
+ * ChatGPT-style: a quiet list of rows, each an icon, what picking it does
329
+ * and where it applies (`ChatEmptyAction`). Picking one calls its
330
+ * `onSelect`; nothing is sent here. While a returned promise is pending
331
+ * the row shows a spinner and every row is disabled. Hidden while
332
+ * `pending`, like the example prompts.
333
+ */
334
+ emptyActions?: ReadonlyArray<ChatEmptyAction>;
335
+ /**
336
+ * The actions' small heading and accessible name. Defaults to "Pick up
337
+ * where you left off"; `""` hides the heading and keeps that default as
338
+ * the list's accessible name.
339
+ */
340
+ emptyActionsLabel?: string;
307
341
  /**
308
342
  * `chips` (the default) wrap onto as many lines as they need; `row` is one
309
343
  * line that scrolls sideways, for a few short prompts where height is
@@ -500,4 +534,4 @@ interface ChatHandle {
500
534
  */
501
535
  declare const Chat: React$1.ForwardRefExoticComponent<ChatProps & React$1.RefAttributes<ChatHandle>>;
502
536
 
503
- export { Chat, type ChatAttachment, type ChatAttachmentAction, ChatCopyAction, type ChatCopyActionProps, type ChatHandle, ChatInput, type ChatInputProps, type ChatMessage, type ChatMessageAuthor, ChatNavigatorItem, type ChatProps, type ChatRole, ChatThread, type ChatThreadProps, authorLines };
537
+ export { Chat, type ChatAttachment, type ChatAttachmentAction, ChatCopyAction, type ChatCopyActionProps, type ChatEmptyAction, type ChatHandle, ChatInput, type ChatInputProps, type ChatMessage, type ChatMessageAuthor, ChatNavigatorItem, type ChatProps, type ChatRole, ChatThread, type ChatThreadProps, authorLines };
@@ -1,6 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React$1 from 'react';
3
3
  import { ReactNode } from 'react';
4
+ import { LucideIcon } from 'lucide-react';
4
5
  import { VoiceSessionControlsProps } from './voice-session-controls.js';
5
6
  import { ChatNavigatorItem } from './chat-turn-navigator.js';
6
7
  import { MarkdownComponents } from './markdown.js';
@@ -259,6 +260,24 @@ interface ChatInputProps {
259
260
  * device-aware default modes.
260
261
  */
261
262
  declare function ChatInput({ value, onChange, onSend, pending, disabled, placeholder, size, uploadingLabel, voice, voiceSession, voiceTitle, voiceLang, submitLabel, autoFocus, className, inputRef, attachments, onFilesSelected, onRemoveAttachment, accept, multiple, addFilesLabel, appearance, compactOnBlur, header, helperText, privacyNote, }: ChatInputProps): react_jsx_runtime.JSX.Element;
263
+ /** A next step offered in the empty state, under the composer (`emptyActions`). */
264
+ interface ChatEmptyAction {
265
+ /** Stable key. */
266
+ id: string;
267
+ /** What picking it does, e.g. "Review 3 new people". */
268
+ label: ReactNode;
269
+ /** Where it applies, muted after the label, e.g. "Head of Sales · Northwind". One line, truncated. */
270
+ detail?: ReactNode;
271
+ /** Leading icon: a Lucide component or an element. */
272
+ icon?: LucideIcon | ReactNode;
273
+ /**
274
+ * Called when picked. While a returned promise is pending, that row shows a
275
+ * spinner and every row is disabled; a rejection re-enables them and is
276
+ * reported.
277
+ */
278
+ onSelect: () => void | Promise<void>;
279
+ disabled?: boolean;
280
+ }
262
281
  interface ChatProps {
263
282
  /** Conversation messages. */
264
283
  messages: ChatMessage[];
@@ -304,6 +323,21 @@ interface ChatProps {
304
323
  examplePrompts?: ReadonlyArray<string>;
305
324
  /** Label above the example prompts. Defaults to "Try". */
306
325
  examplePromptsLabel?: string;
326
+ /**
327
+ * Next steps under the empty-state composer, before `examplePrompts`,
328
+ * ChatGPT-style: a quiet list of rows, each an icon, what picking it does
329
+ * and where it applies (`ChatEmptyAction`). Picking one calls its
330
+ * `onSelect`; nothing is sent here. While a returned promise is pending
331
+ * the row shows a spinner and every row is disabled. Hidden while
332
+ * `pending`, like the example prompts.
333
+ */
334
+ emptyActions?: ReadonlyArray<ChatEmptyAction>;
335
+ /**
336
+ * The actions' small heading and accessible name. Defaults to "Pick up
337
+ * where you left off"; `""` hides the heading and keeps that default as
338
+ * the list's accessible name.
339
+ */
340
+ emptyActionsLabel?: string;
307
341
  /**
308
342
  * `chips` (the default) wrap onto as many lines as they need; `row` is one
309
343
  * line that scrolls sideways, for a few short prompts where height is
@@ -500,4 +534,4 @@ interface ChatHandle {
500
534
  */
501
535
  declare const Chat: React$1.ForwardRefExoticComponent<ChatProps & React$1.RefAttributes<ChatHandle>>;
502
536
 
503
- export { Chat, type ChatAttachment, type ChatAttachmentAction, ChatCopyAction, type ChatCopyActionProps, type ChatHandle, ChatInput, type ChatInputProps, type ChatMessage, type ChatMessageAuthor, ChatNavigatorItem, type ChatProps, type ChatRole, ChatThread, type ChatThreadProps, authorLines };
537
+ export { Chat, type ChatAttachment, type ChatAttachmentAction, ChatCopyAction, type ChatCopyActionProps, type ChatEmptyAction, type ChatHandle, ChatInput, type ChatInputProps, type ChatMessage, type ChatMessageAuthor, ChatNavigatorItem, type ChatProps, type ChatRole, ChatThread, type ChatThreadProps, authorLines };
@@ -15,6 +15,9 @@ import {
15
15
  Suggestion,
16
16
  Suggestions
17
17
  } from "../chunk-IJG2B3Y2.js";
18
+ import {
19
+ Spinner
20
+ } from "../chunk-QZBPZLAB.js";
18
21
  import {
19
22
  PersonAvatar
20
23
  } from "../chunk-NXFZULS3.js";
@@ -34,6 +37,14 @@ import {
34
37
  InputGroupTextarea
35
38
  } from "../chunk-QTPPNK6F.js";
36
39
  import "../chunk-6FC65AZQ.js";
40
+ import {
41
+ Item,
42
+ ItemContent,
43
+ ItemDescription,
44
+ ItemMedia,
45
+ ItemTitle
46
+ } from "../chunk-SG4ZE2EN.js";
47
+ import "../chunk-HYTILYE5.js";
37
48
  import {
38
49
  FileDropArea,
39
50
  FileDropzone
@@ -114,6 +125,7 @@ import {
114
125
  // src/primitives/chat.tsx
115
126
  import {
116
127
  forwardRef,
128
+ isValidElement,
117
129
  useCallback,
118
130
  useEffect,
119
131
  useId,
@@ -758,6 +770,92 @@ function ChatSuggestions({
758
770
  )
759
771
  ] });
760
772
  }
773
+ var DEFAULT_EMPTY_ACTIONS_LABEL = "Pick up where you left off";
774
+ function ChatEmptyActionIcon({ icon }) {
775
+ if (!icon) return null;
776
+ if (isValidElement(icon)) return icon;
777
+ if (typeof icon === "function" || typeof icon === "object" && icon !== null && "render" in icon) {
778
+ const IconComp = icon;
779
+ return /* @__PURE__ */ jsx(IconComp, { "aria-hidden": true });
780
+ }
781
+ return /* @__PURE__ */ jsx(Fragment, { children: icon });
782
+ }
783
+ function ChatEmptyActions({
784
+ items,
785
+ label,
786
+ onError,
787
+ className
788
+ }) {
789
+ const labelId = useId();
790
+ const [running, setRunning] = useState(null);
791
+ if (items.length === 0) return null;
792
+ const showLabel = label.length > 0;
793
+ const pick = async (item) => {
794
+ if (running !== null) return;
795
+ let result;
796
+ try {
797
+ result = item.onSelect();
798
+ } catch (cause) {
799
+ onError(cause);
800
+ return;
801
+ }
802
+ if (!result || typeof result.then !== "function") return;
803
+ setRunning(item.id);
804
+ try {
805
+ await result;
806
+ } catch (cause) {
807
+ onError(cause);
808
+ } finally {
809
+ setRunning(null);
810
+ }
811
+ };
812
+ return /* @__PURE__ */ jsxs("div", { "data-slot": "chat-empty-actions", className: cn("w-full text-left", className), children: [
813
+ showLabel && /* @__PURE__ */ jsx("p", { id: labelId, "data-slot": "chat-empty-actions-label", className: "mb-1.5 px-3 text-xs text-muted-foreground", children: label }),
814
+ /* @__PURE__ */ jsx(
815
+ "div",
816
+ {
817
+ role: "group",
818
+ "aria-labelledby": showLabel ? labelId : void 0,
819
+ "aria-label": showLabel ? void 0 : DEFAULT_EMPTY_ACTIONS_LABEL,
820
+ className: "flex flex-col gap-0.5",
821
+ children: items.map((item) => {
822
+ const busy = running === item.id;
823
+ return /* @__PURE__ */ jsx(Item, { asChild: true, size: "sm", children: /* @__PURE__ */ jsxs(
824
+ "button",
825
+ {
826
+ type: "button",
827
+ "data-slot": "chat-empty-action",
828
+ "data-state": busy ? "loading" : void 0,
829
+ "aria-busy": busy || void 0,
830
+ disabled: item.disabled || running !== null,
831
+ onClick: () => void pick(item),
832
+ className: cn(
833
+ "min-h-11 cursor-pointer flex-nowrap text-left",
834
+ "hover:bg-muted focus-visible:bg-muted",
835
+ "disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent",
836
+ busy && "disabled:opacity-100"
837
+ ),
838
+ children: [
839
+ /* @__PURE__ */ jsx(
840
+ ItemMedia,
841
+ {
842
+ variant: "icon",
843
+ className: "size-8 self-center rounded-md bg-muted text-muted-foreground group-has-data-[slot=item-description]/item:translate-y-0 group-has-data-[slot=item-description]/item:self-center",
844
+ children: busy ? /* @__PURE__ */ jsx(Spinner, { "aria-hidden": true }) : /* @__PURE__ */ jsx(ChatEmptyActionIcon, { icon: item.icon })
845
+ }
846
+ ),
847
+ /* @__PURE__ */ jsxs(ItemContent, { className: "min-w-0 flex-row flex-wrap items-baseline gap-x-2 gap-y-0.5 md:flex-nowrap", children: [
848
+ /* @__PURE__ */ jsx(ItemTitle, { className: "w-auto min-w-0 shrink-0 font-normal text-foreground md:max-w-[60%] md:truncate", children: item.label }),
849
+ item.detail && /* @__PURE__ */ jsx(ItemDescription, { className: "line-clamp-1 min-w-0 flex-1 truncate text-xs md:text-sm", children: item.detail })
850
+ ] })
851
+ ]
852
+ }
853
+ ) }, item.id);
854
+ })
855
+ }
856
+ )
857
+ ] });
858
+ }
761
859
  function MobileReplySuggestions({
762
860
  items,
763
861
  onSelect,
@@ -913,6 +1011,8 @@ var Chat = forwardRef(function Chat2({
913
1011
  emptySubtitle,
914
1012
  examplePrompts = [],
915
1013
  examplePromptsLabel = "Try",
1014
+ emptyActions = [],
1015
+ emptyActionsLabel = DEFAULT_EMPTY_ACTIONS_LABEL,
916
1016
  examplePromptsVariant = "chips",
917
1017
  examplePromptsLoading = false,
918
1018
  examplePromptsLoadingLabel = "Loading suggestions\u2026",
@@ -1152,6 +1252,15 @@ var Chat = forwardRef(function Chat2({
1152
1252
  }
1153
1253
  ),
1154
1254
  error && /* @__PURE__ */ jsx(ChatError, { children: error }),
1255
+ !pending && emptyActions.length > 0 && /* @__PURE__ */ jsx(
1256
+ ChatEmptyActions,
1257
+ {
1258
+ items: emptyActions,
1259
+ label: emptyActionsLabel,
1260
+ onError: reportSendError,
1261
+ className: "mt-3"
1262
+ }
1263
+ ),
1155
1264
  !pending && examplePromptsLoading && /* @__PURE__ */ jsx(ExamplePromptsLoading, { label: examplePromptsLoadingLabel }),
1156
1265
  !pending && !examplePromptsLoading && examplePrompts.length > 0 && /* @__PURE__ */ jsx(
1157
1266
  ChatSuggestions,
@@ -1,197 +1,27 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
2
2
 
3
3
 
4
- var _chunkNQK5ZWC7cjs = require('../chunk-NQK5ZWC7.cjs');
5
-
6
-
7
- var _chunkKWLSBTB2cjs = require('../chunk-KWLSBTB2.cjs');
8
-
9
- // src/primitives/item.tsx
10
- var _classvarianceauthority = require('class-variance-authority');
11
- var _radixui = require('radix-ui');
12
- var _jsxruntime = require('react/jsx-runtime');
13
- function ItemGroup({ className, ...props }) {
14
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
15
- "div",
16
- {
17
- role: "list",
18
- "data-slot": "item-group",
19
- className: _chunkKWLSBTB2cjs.cn.call(void 0,
20
- "group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
21
- className
22
- ),
23
- ...props
24
- }
25
- );
26
- }
27
- function ItemSeparator({
28
- className,
29
- ...props
30
- }) {
31
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
32
- _chunkNQK5ZWC7cjs.Separator,
33
- {
34
- "data-slot": "item-separator",
35
- orientation: "horizontal",
36
- className: _chunkKWLSBTB2cjs.cn.call(void 0, "my-2", className),
37
- ...props
38
- }
39
- );
40
- }
41
- var itemVariants = _classvarianceauthority.cva.call(void 0,
42
- "group/item flex w-full flex-wrap items-center rounded-md border text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
43
- {
44
- variants: {
45
- variant: {
46
- default: "border-transparent",
47
- outline: "border-border",
48
- muted: "border-transparent bg-muted/50"
49
- },
50
- size: {
51
- default: "gap-3.5 px-4 py-3.5",
52
- sm: "gap-2.5 px-3 py-2.5",
53
- xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0"
54
- }
55
- },
56
- defaultVariants: {
57
- variant: "default",
58
- size: "default"
59
- }
60
- }
61
- );
62
- function Item({
63
- className,
64
- variant = "default",
65
- size = "default",
66
- asChild = false,
67
- ...props
68
- }) {
69
- const Comp = asChild ? _radixui.Slot.Root : "div";
70
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
71
- Comp,
72
- {
73
- "data-slot": "item",
74
- "data-variant": variant,
75
- "data-size": size,
76
- className: _chunkKWLSBTB2cjs.cn.call(void 0, itemVariants({ variant, size, className })),
77
- ...props
78
- }
79
- );
80
- }
81
- var itemMediaVariants = _classvarianceauthority.cva.call(void 0,
82
- "flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none",
83
- {
84
- variants: {
85
- variant: {
86
- default: "bg-transparent",
87
- icon: "[&_svg:not([class*='size-'])]:size-4",
88
- image: "size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover"
89
- }
90
- },
91
- defaultVariants: {
92
- variant: "default"
93
- }
94
- }
95
- );
96
- function ItemMedia({
97
- className,
98
- variant = "default",
99
- ...props
100
- }) {
101
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
102
- "div",
103
- {
104
- "data-slot": "item-media",
105
- "data-variant": variant,
106
- className: _chunkKWLSBTB2cjs.cn.call(void 0, itemMediaVariants({ variant, className })),
107
- ...props
108
- }
109
- );
110
- }
111
- function ItemContent({ className, ...props }) {
112
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
113
- "div",
114
- {
115
- "data-slot": "item-content",
116
- className: _chunkKWLSBTB2cjs.cn.call(void 0,
117
- "flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none",
118
- className
119
- ),
120
- ...props
121
- }
122
- );
123
- }
124
- function ItemTitle({ className, ...props }) {
125
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
126
- "div",
127
- {
128
- "data-slot": "item-title",
129
- className: _chunkKWLSBTB2cjs.cn.call(void 0,
130
- "line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
131
- className
132
- ),
133
- ...props
134
- }
135
- );
136
- }
137
- function ItemDescription({ className, ...props }) {
138
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
139
- "p",
140
- {
141
- "data-slot": "item-description",
142
- className: _chunkKWLSBTB2cjs.cn.call(void 0,
143
- "line-clamp-2 text-left text-sm leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
144
- className
145
- ),
146
- ...props
147
- }
148
- );
149
- }
150
- function ItemActions({ className, ...props }) {
151
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
152
- "div",
153
- {
154
- "data-slot": "item-actions",
155
- className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex items-center gap-2", className),
156
- ...props
157
- }
158
- );
159
- }
160
- function ItemHeader({ className, ...props }) {
161
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
162
- "div",
163
- {
164
- "data-slot": "item-header",
165
- className: _chunkKWLSBTB2cjs.cn.call(void 0,
166
- "flex basis-full items-center justify-between gap-2",
167
- className
168
- ),
169
- ...props
170
- }
171
- );
172
- }
173
- function ItemFooter({ className, ...props }) {
174
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
175
- "div",
176
- {
177
- "data-slot": "item-footer",
178
- className: _chunkKWLSBTB2cjs.cn.call(void 0,
179
- "flex basis-full items-center justify-between gap-2",
180
- className
181
- ),
182
- ...props
183
- }
184
- );
185
- }
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
- exports.Item = Item; exports.ItemActions = ItemActions; exports.ItemContent = ItemContent; exports.ItemDescription = ItemDescription; exports.ItemFooter = ItemFooter; exports.ItemGroup = ItemGroup; exports.ItemHeader = ItemHeader; exports.ItemMedia = ItemMedia; exports.ItemSeparator = ItemSeparator; exports.ItemTitle = ItemTitle;
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+ var _chunkDHXKCMKYcjs = require('../chunk-DHXKCMKY.cjs');
14
+ require('../chunk-NQK5ZWC7.cjs');
15
+ require('../chunk-KWLSBTB2.cjs');
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+ exports.Item = _chunkDHXKCMKYcjs.Item; exports.ItemActions = _chunkDHXKCMKYcjs.ItemActions; exports.ItemContent = _chunkDHXKCMKYcjs.ItemContent; exports.ItemDescription = _chunkDHXKCMKYcjs.ItemDescription; exports.ItemFooter = _chunkDHXKCMKYcjs.ItemFooter; exports.ItemGroup = _chunkDHXKCMKYcjs.ItemGroup; exports.ItemHeader = _chunkDHXKCMKYcjs.ItemHeader; exports.ItemMedia = _chunkDHXKCMKYcjs.ItemMedia; exports.ItemSeparator = _chunkDHXKCMKYcjs.ItemSeparator; exports.ItemTitle = _chunkDHXKCMKYcjs.ItemTitle;
@@ -1,188 +1,18 @@
1
1
  "use client";
2
2
  import {
3
- Separator
4
- } from "../chunk-HYTILYE5.js";
5
- import {
6
- cn
7
- } from "../chunk-G6SRSWXB.js";
8
-
9
- // src/primitives/item.tsx
10
- import { cva } from "class-variance-authority";
11
- import { Slot } from "radix-ui";
12
- import { jsx } from "react/jsx-runtime";
13
- function ItemGroup({ className, ...props }) {
14
- return /* @__PURE__ */ jsx(
15
- "div",
16
- {
17
- role: "list",
18
- "data-slot": "item-group",
19
- className: cn(
20
- "group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
21
- className
22
- ),
23
- ...props
24
- }
25
- );
26
- }
27
- function ItemSeparator({
28
- className,
29
- ...props
30
- }) {
31
- return /* @__PURE__ */ jsx(
32
- Separator,
33
- {
34
- "data-slot": "item-separator",
35
- orientation: "horizontal",
36
- className: cn("my-2", className),
37
- ...props
38
- }
39
- );
40
- }
41
- var itemVariants = cva(
42
- "group/item flex w-full flex-wrap items-center rounded-md border text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
43
- {
44
- variants: {
45
- variant: {
46
- default: "border-transparent",
47
- outline: "border-border",
48
- muted: "border-transparent bg-muted/50"
49
- },
50
- size: {
51
- default: "gap-3.5 px-4 py-3.5",
52
- sm: "gap-2.5 px-3 py-2.5",
53
- xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0"
54
- }
55
- },
56
- defaultVariants: {
57
- variant: "default",
58
- size: "default"
59
- }
60
- }
61
- );
62
- function Item({
63
- className,
64
- variant = "default",
65
- size = "default",
66
- asChild = false,
67
- ...props
68
- }) {
69
- const Comp = asChild ? Slot.Root : "div";
70
- return /* @__PURE__ */ jsx(
71
- Comp,
72
- {
73
- "data-slot": "item",
74
- "data-variant": variant,
75
- "data-size": size,
76
- className: cn(itemVariants({ variant, size, className })),
77
- ...props
78
- }
79
- );
80
- }
81
- var itemMediaVariants = cva(
82
- "flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none",
83
- {
84
- variants: {
85
- variant: {
86
- default: "bg-transparent",
87
- icon: "[&_svg:not([class*='size-'])]:size-4",
88
- image: "size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover"
89
- }
90
- },
91
- defaultVariants: {
92
- variant: "default"
93
- }
94
- }
95
- );
96
- function ItemMedia({
97
- className,
98
- variant = "default",
99
- ...props
100
- }) {
101
- return /* @__PURE__ */ jsx(
102
- "div",
103
- {
104
- "data-slot": "item-media",
105
- "data-variant": variant,
106
- className: cn(itemMediaVariants({ variant, className })),
107
- ...props
108
- }
109
- );
110
- }
111
- function ItemContent({ className, ...props }) {
112
- return /* @__PURE__ */ jsx(
113
- "div",
114
- {
115
- "data-slot": "item-content",
116
- className: cn(
117
- "flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none",
118
- className
119
- ),
120
- ...props
121
- }
122
- );
123
- }
124
- function ItemTitle({ className, ...props }) {
125
- return /* @__PURE__ */ jsx(
126
- "div",
127
- {
128
- "data-slot": "item-title",
129
- className: cn(
130
- "line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
131
- className
132
- ),
133
- ...props
134
- }
135
- );
136
- }
137
- function ItemDescription({ className, ...props }) {
138
- return /* @__PURE__ */ jsx(
139
- "p",
140
- {
141
- "data-slot": "item-description",
142
- className: cn(
143
- "line-clamp-2 text-left text-sm leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
144
- className
145
- ),
146
- ...props
147
- }
148
- );
149
- }
150
- function ItemActions({ className, ...props }) {
151
- return /* @__PURE__ */ jsx(
152
- "div",
153
- {
154
- "data-slot": "item-actions",
155
- className: cn("flex items-center gap-2", className),
156
- ...props
157
- }
158
- );
159
- }
160
- function ItemHeader({ className, ...props }) {
161
- return /* @__PURE__ */ jsx(
162
- "div",
163
- {
164
- "data-slot": "item-header",
165
- className: cn(
166
- "flex basis-full items-center justify-between gap-2",
167
- className
168
- ),
169
- ...props
170
- }
171
- );
172
- }
173
- function ItemFooter({ className, ...props }) {
174
- return /* @__PURE__ */ jsx(
175
- "div",
176
- {
177
- "data-slot": "item-footer",
178
- className: cn(
179
- "flex basis-full items-center justify-between gap-2",
180
- className
181
- ),
182
- ...props
183
- }
184
- );
185
- }
3
+ Item,
4
+ ItemActions,
5
+ ItemContent,
6
+ ItemDescription,
7
+ ItemFooter,
8
+ ItemGroup,
9
+ ItemHeader,
10
+ ItemMedia,
11
+ ItemSeparator,
12
+ ItemTitle
13
+ } from "../chunk-SG4ZE2EN.js";
14
+ import "../chunk-HYTILYE5.js";
15
+ import "../chunk-G6SRSWXB.js";
186
16
  export {
187
17
  Item,
188
18
  ItemActions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epicbagel/saas-kit",
3
- "version": "1.26.0",
3
+ "version": "1.27.0",
4
4
  "description": "Accessible React primitives, layout components and design tokens for SaaS apps, built on Radix UI and Tailwind CSS v4.",
5
5
  "license": "MIT",
6
6
  "keywords": [