@timbal-ai/timbal-react 0.4.0 → 0.5.1
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 +111 -13
- package/dist/index.cjs +1720 -422
- package/dist/index.d.cts +255 -246
- package/dist/index.d.ts +255 -246
- package/dist/index.esm.js +1757 -405
- package/dist/styles.css +327 -29
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -32,13 +32,12 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
ARTIFACT_AGENT_INSTRUCTIONS: () => ARTIFACT_AGENT_INSTRUCTIONS,
|
|
34
34
|
ARTIFACT_FENCE_LANGUAGES: () => ARTIFACT_FENCE_LANGUAGES,
|
|
35
|
-
|
|
36
|
-
ActionBarPrimitive: () => import_react29.ActionBarPrimitive,
|
|
35
|
+
ActionBarPrimitive: () => import_react45.ActionBarPrimitive,
|
|
37
36
|
ArtifactCard: () => ArtifactCard,
|
|
38
37
|
ArtifactRegistryProvider: () => ArtifactRegistryProvider,
|
|
39
38
|
ArtifactView: () => ArtifactView,
|
|
40
|
-
AssistantRuntimeProvider: () =>
|
|
41
|
-
AuiIf: () =>
|
|
39
|
+
AssistantRuntimeProvider: () => import_react45.AssistantRuntimeProvider,
|
|
40
|
+
AuiIf: () => import_react45.AuiIf,
|
|
42
41
|
AuthGuard: () => AuthGuard,
|
|
43
42
|
Avatar: () => Avatar,
|
|
44
43
|
AvatarFallback: () => AvatarFallback,
|
|
@@ -46,9 +45,7 @@ __export(index_exports, {
|
|
|
46
45
|
Button: () => Button,
|
|
47
46
|
ChartArtifactView: () => ChartArtifactView,
|
|
48
47
|
Composer: () => Composer,
|
|
49
|
-
|
|
50
|
-
ComposerAttachments: () => ComposerAttachments,
|
|
51
|
-
ComposerPrimitive: () => import_react29.ComposerPrimitive,
|
|
48
|
+
ComposerPrimitive: () => import_react45.ComposerPrimitive,
|
|
52
49
|
DEFAULT_UPLOAD_ACCEPT: () => DEFAULT_UPLOAD_ACCEPT,
|
|
53
50
|
Dialog: () => Dialog,
|
|
54
51
|
DialogClose: () => DialogClose,
|
|
@@ -57,44 +54,27 @@ __export(index_exports, {
|
|
|
57
54
|
DialogPortal: () => DialogPortal,
|
|
58
55
|
DialogTitle: () => DialogTitle,
|
|
59
56
|
DialogTrigger: () => DialogTrigger,
|
|
60
|
-
ErrorPrimitive: () => import_react29.ErrorPrimitive,
|
|
61
57
|
HtmlArtifactView: () => HtmlArtifactView,
|
|
62
58
|
JsonArtifactView: () => JsonArtifactView,
|
|
63
59
|
MarkdownText: () => MarkdownText,
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
MessagePrimitive: () => import_react45.MessagePrimitive,
|
|
61
|
+
ModeToggle: () => ModeToggle,
|
|
66
62
|
QuestionArtifactView: () => QuestionArtifactView,
|
|
67
|
-
STUDIO_INSET_LEFT: () => STUDIO_INSET_LEFT,
|
|
68
|
-
STUDIO_PILL_HEIGHT: () => STUDIO_PILL_HEIGHT,
|
|
69
|
-
STUDIO_SIDEBAR_GAP: () => STUDIO_SIDEBAR_GAP,
|
|
70
|
-
STUDIO_SIDEBAR_WIDTH: () => STUDIO_SIDEBAR_WIDTH,
|
|
71
|
-
STUDIO_TOPBAR_GAP: () => STUDIO_TOPBAR_GAP,
|
|
72
|
-
STUDIO_TOPBAR_HEIGHT: () => STUDIO_TOPBAR_HEIGHT,
|
|
73
63
|
SessionProvider: () => SessionProvider,
|
|
74
64
|
Shimmer: () => Shimmer,
|
|
65
|
+
StudioSidebar: () => StudioSidebar,
|
|
66
|
+
StudioWelcome: () => StudioWelcome,
|
|
75
67
|
Suggestions: () => Suggestions,
|
|
76
|
-
SyntaxHighlighter: () => syntax_highlighter_default,
|
|
77
|
-
TIMBAL_V2_BORDER: () => TIMBAL_V2_BORDER,
|
|
78
|
-
TIMBAL_V2_FILL: () => TIMBAL_V2_FILL,
|
|
79
|
-
TIMBAL_V2_LABEL: () => TIMBAL_V2_LABEL,
|
|
80
|
-
TIMBAL_V2_PILL_SURFACE: () => TIMBAL_V2_PILL_SURFACE,
|
|
81
|
-
TIMBAL_V2_SECONDARY_CHROME: () => TIMBAL_V2_SECONDARY_CHROME,
|
|
82
|
-
TIMBAL_V2_SHADOW: () => TIMBAL_V2_SHADOW,
|
|
83
|
-
TIMBAL_V2_SIZE_HEIGHT: () => TIMBAL_V2_SIZE_HEIGHT,
|
|
84
|
-
TIMBAL_V2_SIZE_ICON: () => TIMBAL_V2_SIZE_ICON,
|
|
85
|
-
TIMBAL_V2_SIZE_LABEL_PX: () => TIMBAL_V2_SIZE_LABEL_PX,
|
|
86
68
|
TableArtifactView: () => TableArtifactView,
|
|
87
69
|
Thread: () => Thread,
|
|
88
|
-
ThreadPrimitive: () =>
|
|
70
|
+
ThreadPrimitive: () => import_react45.ThreadPrimitive,
|
|
89
71
|
TimbalChat: () => TimbalChat,
|
|
90
72
|
TimbalChatShell: () => TimbalChatShell,
|
|
73
|
+
TimbalMark: () => TimbalMark,
|
|
91
74
|
TimbalRuntimeProvider: () => TimbalRuntimeProvider,
|
|
92
|
-
|
|
75
|
+
TimbalStudioShell: () => TimbalStudioShell,
|
|
93
76
|
ToolArtifactFallback: () => ToolArtifactFallback,
|
|
94
|
-
ToolBodyPresence: () => ToolBodyPresence,
|
|
95
77
|
ToolFallback: () => ToolFallback,
|
|
96
|
-
ToolMotion: () => ToolMotion,
|
|
97
|
-
ToolPresence: () => ToolPresence,
|
|
98
78
|
Tooltip: () => Tooltip,
|
|
99
79
|
TooltipContent: () => TooltipContent,
|
|
100
80
|
TooltipIconButton: () => TooltipIconButton,
|
|
@@ -104,10 +84,8 @@ __export(index_exports, {
|
|
|
104
84
|
UiCustomNodeRegistryProvider: () => UiCustomNodeRegistryProvider,
|
|
105
85
|
UiEventProvider: () => UiEventProvider,
|
|
106
86
|
UiNodeView: () => UiNodeView,
|
|
107
|
-
UserMessageAttachments: () => UserMessageAttachments,
|
|
108
87
|
WorkforceSelector: () => WorkforceSelector,
|
|
109
88
|
authFetch: () => authFetch,
|
|
110
|
-
buttonVariants: () => buttonVariants,
|
|
111
89
|
clearTokens: () => clearTokens,
|
|
112
90
|
cn: () => cn,
|
|
113
91
|
createDefaultAttachmentAdapter: () => createDefaultAttachmentAdapter,
|
|
@@ -121,7 +99,6 @@ __export(index_exports, {
|
|
|
121
99
|
isArtifact: () => isArtifact,
|
|
122
100
|
isArtifactFenceLanguage: () => isArtifactFenceLanguage,
|
|
123
101
|
isUiBinding: () => isUiBinding,
|
|
124
|
-
luxuryEase: () => luxuryEase,
|
|
125
102
|
parseArtifactFromToolResult: () => parseArtifactFromToolResult,
|
|
126
103
|
parseSSELine: () => import_timbal_sdk2.parseSSELine,
|
|
127
104
|
refreshAccessToken: () => refreshAccessToken,
|
|
@@ -131,39 +108,14 @@ __export(index_exports, {
|
|
|
131
108
|
setPath: () => setPath,
|
|
132
109
|
setRefreshToken: () => setRefreshToken,
|
|
133
110
|
splitMarkdownByArtifacts: () => splitMarkdownByArtifacts,
|
|
134
|
-
studioArtifactShellClass: () => studioArtifactShellClass,
|
|
135
|
-
studioChromeShellStyle: () => studioChromeShellStyle,
|
|
136
|
-
studioComposeInputShellClass: () => studioComposeInputShellClass,
|
|
137
|
-
studioComposerIoWellClass: () => studioComposerIoWellClass,
|
|
138
|
-
studioIntegrationBorder: () => studioIntegrationBorder,
|
|
139
|
-
studioIntegrationCardClass: () => studioIntegrationCardClass,
|
|
140
|
-
studioIntegrationIconTileClass: () => studioIntegrationIconTileClass,
|
|
141
|
-
studioIntegrationSurfaceSolid: () => studioIntegrationSurfaceSolid,
|
|
142
|
-
studioListRowButtonClass: () => studioListRowButtonClass,
|
|
143
|
-
studioPillSurfaceClass: () => studioPillSurfaceClass,
|
|
144
|
-
studioPlaygroundGradientClass: () => studioPlaygroundGradientClass,
|
|
145
|
-
studioQuestionOptionClass: () => studioQuestionOptionClass,
|
|
146
|
-
studioQuestionOptionSelectedClass: () => studioQuestionOptionSelectedClass,
|
|
147
|
-
studioSecondaryChromeClass: () => studioSecondaryChromeClass,
|
|
148
|
-
studioTimelineActionClass: () => studioTimelineActionClass,
|
|
149
|
-
studioTimelineBodyPadClass: () => studioTimelineBodyPadClass,
|
|
150
|
-
studioTimelineChevronClass: () => studioTimelineChevronClass,
|
|
151
|
-
studioTimelineDetailClass: () => studioTimelineDetailClass,
|
|
152
|
-
studioTimelineRowButtonClass: () => studioTimelineRowButtonClass,
|
|
153
|
-
studioTimelineShimmerActionClass: () => studioTimelineShimmerActionClass,
|
|
154
|
-
studioTimelineTextClass: () => studioTimelineTextClass,
|
|
155
|
-
studioToolCardShellClass: () => studioToolCardShellClass,
|
|
156
|
-
studioTopbarIconPillClass: () => studioTopbarIconPillClass,
|
|
157
|
-
studioTopbarPillHeightClass: () => studioTopbarPillHeightClass,
|
|
158
|
-
toolPresenceTransition: () => toolPresenceTransition,
|
|
159
111
|
useArtifactRegistry: () => useArtifactRegistry,
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
112
|
+
useComposerRuntime: () => import_react45.useComposerRuntime,
|
|
113
|
+
useMessageRuntime: () => import_react45.useMessageRuntime,
|
|
114
|
+
useOptionalSession: () => useOptionalSession,
|
|
163
115
|
useResolvedSuggestions: () => useResolvedSuggestions,
|
|
164
116
|
useSession: () => useSession,
|
|
165
|
-
useThread: () =>
|
|
166
|
-
useThreadRuntime: () =>
|
|
117
|
+
useThread: () => import_react45.useThread,
|
|
118
|
+
useThreadRuntime: () => import_react45.useThreadRuntime,
|
|
167
119
|
useTimbalRuntime: () => useTimbalRuntime,
|
|
168
120
|
useTimbalStream: () => useTimbalStream,
|
|
169
121
|
useToolRunning: () => useToolRunning,
|
|
@@ -1034,9 +986,10 @@ function findParentIdFromAuiParent(messages, auiParentId) {
|
|
|
1034
986
|
var import_timbal_sdk2 = require("@timbal-ai/timbal-sdk");
|
|
1035
987
|
|
|
1036
988
|
// src/components/thread.tsx
|
|
1037
|
-
var import_react25 = require("
|
|
989
|
+
var import_react25 = require("react");
|
|
990
|
+
var import_react26 = require("@assistant-ui/react");
|
|
1038
991
|
var import_lucide_react8 = require("lucide-react");
|
|
1039
|
-
var
|
|
992
|
+
var import_react27 = require("motion/react");
|
|
1040
993
|
|
|
1041
994
|
// src/components/attachment.tsx
|
|
1042
995
|
var import_react4 = require("react");
|
|
@@ -1250,7 +1203,7 @@ var import_react3 = require("react");
|
|
|
1250
1203
|
var React = __toESM(require("react"), 1);
|
|
1251
1204
|
var import_radix_ui4 = require("radix-ui");
|
|
1252
1205
|
|
|
1253
|
-
// src/
|
|
1206
|
+
// src/design/button-tokens.ts
|
|
1254
1207
|
var TIMBAL_V2_SIZE_HEIGHT = {
|
|
1255
1208
|
xs: "min-h-8 h-8",
|
|
1256
1209
|
sm: "min-h-9 h-9",
|
|
@@ -1270,39 +1223,62 @@ var TIMBAL_V2_SIZE_LABEL_PX = {
|
|
|
1270
1223
|
lg: "px-6"
|
|
1271
1224
|
};
|
|
1272
1225
|
var TIMBAL_V2_FILL = {
|
|
1273
|
-
primary:
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1226
|
+
primary: [
|
|
1227
|
+
"bg-gradient-to-b from-primary-fill-from to-primary-fill-to",
|
|
1228
|
+
"group-hover/tbv2:from-primary-fill-hover-from group-hover/tbv2:to-primary-fill-hover-to",
|
|
1229
|
+
"group-active/tbv2:from-primary-fill-active-from group-active/tbv2:to-primary-fill-active-to"
|
|
1230
|
+
].join(" "),
|
|
1231
|
+
informative: [
|
|
1232
|
+
"bg-primary",
|
|
1233
|
+
"group-active/tbv2:[background-image:linear-gradient(to_top,rgba(0,0,0,0.08),transparent_55%)]"
|
|
1234
|
+
].join(" "),
|
|
1235
|
+
destructive: [
|
|
1236
|
+
"bg-gradient-to-b from-elevated-from to-elevated-to",
|
|
1237
|
+
"group-hover/tbv2:from-destructive-fill-hover-from group-hover/tbv2:to-destructive-fill-hover-to",
|
|
1238
|
+
"group-active/tbv2:from-destructive-fill-active-from group-active/tbv2:to-destructive-fill-active-to"
|
|
1239
|
+
].join(" "),
|
|
1240
|
+
secondary: [
|
|
1241
|
+
"bg-gradient-to-b from-elevated-from to-elevated-to",
|
|
1242
|
+
"group-hover/tbv2:from-secondary-fill-hover-from group-hover/tbv2:to-secondary-fill-hover-to",
|
|
1243
|
+
"group-active/tbv2:from-secondary-fill-active-from group-active/tbv2:to-secondary-fill-active-to"
|
|
1244
|
+
].join(" "),
|
|
1245
|
+
ghost: [
|
|
1246
|
+
"bg-transparent",
|
|
1247
|
+
"group-hover/tbv2:bg-ghost-fill-hover",
|
|
1248
|
+
"group-active/tbv2:bg-ghost-fill-active"
|
|
1249
|
+
].join(" "),
|
|
1278
1250
|
link: "bg-transparent"
|
|
1279
1251
|
};
|
|
1280
1252
|
var TIMBAL_V2_LABEL = {
|
|
1281
|
-
primary: "text-
|
|
1282
|
-
informative: "text-
|
|
1283
|
-
destructive: "text-destructive
|
|
1253
|
+
primary: "text-primary-foreground",
|
|
1254
|
+
informative: "text-primary-foreground",
|
|
1255
|
+
destructive: "text-destructive",
|
|
1284
1256
|
secondary: "text-foreground",
|
|
1285
1257
|
ghost: "text-foreground",
|
|
1286
|
-
link: "text-foreground underline decoration-
|
|
1258
|
+
link: "text-foreground underline decoration-foreground/25 underline-offset-2 group-hover/tbv2:decoration-foreground/45"
|
|
1287
1259
|
};
|
|
1288
1260
|
var TIMBAL_V2_BORDER = {
|
|
1289
1261
|
primary: "",
|
|
1290
|
-
informative: "border border-
|
|
1291
|
-
destructive: "border border-destructive/45
|
|
1292
|
-
secondary: "border border-
|
|
1262
|
+
informative: "border border-foreground/15",
|
|
1263
|
+
destructive: "border border-destructive/45",
|
|
1264
|
+
secondary: "border border-border",
|
|
1293
1265
|
ghost: "",
|
|
1294
1266
|
link: ""
|
|
1295
1267
|
};
|
|
1296
1268
|
var TIMBAL_V2_SHADOW = {
|
|
1297
|
-
primary: "shadow-
|
|
1298
|
-
informative: "shadow-
|
|
1299
|
-
destructive: "shadow-
|
|
1300
|
-
secondary: "shadow-
|
|
1269
|
+
primary: "shadow-card",
|
|
1270
|
+
informative: "shadow-card",
|
|
1271
|
+
destructive: "shadow-card",
|
|
1272
|
+
secondary: "shadow-card",
|
|
1301
1273
|
ghost: "",
|
|
1302
1274
|
link: ""
|
|
1303
1275
|
};
|
|
1304
|
-
var
|
|
1305
|
-
|
|
1276
|
+
var TIMBAL_V2_SECONDARY_CHROME = [
|
|
1277
|
+
"bg-gradient-to-b from-elevated-from to-elevated-to border border-border shadow-card",
|
|
1278
|
+
"transition-[background-color,box-shadow,border-color] duration-200 ease-in-out",
|
|
1279
|
+
"hover:from-secondary-fill-hover-from hover:to-secondary-fill-hover-to",
|
|
1280
|
+
"active:from-secondary-fill-active-from active:to-secondary-fill-active-to"
|
|
1281
|
+
].join(" ");
|
|
1306
1282
|
|
|
1307
1283
|
// src/ui/timbal-v2-button.tsx
|
|
1308
1284
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
@@ -1334,7 +1310,7 @@ var TimbalV2Button = React.forwardRef(function TimbalV2Button2({
|
|
|
1334
1310
|
"data-variant": variant,
|
|
1335
1311
|
className: cn(
|
|
1336
1312
|
"group/tbv2 relative box-border inline-flex flex-col items-stretch overflow-hidden border-0 bg-transparent p-0 text-sm font-normal shadow-none transition duration-200 ease-in-out",
|
|
1337
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-
|
|
1313
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/60 focus-visible:ring-offset-1 focus-visible:ring-offset-background",
|
|
1338
1314
|
sizeClass,
|
|
1339
1315
|
radiusClass,
|
|
1340
1316
|
TIMBAL_V2_BORDER[variant],
|
|
@@ -1511,9 +1487,9 @@ var AttachmentRemove = () => {
|
|
|
1511
1487
|
TooltipIconButton,
|
|
1512
1488
|
{
|
|
1513
1489
|
tooltip: "Remove file",
|
|
1514
|
-
className: "aui-attachment-tile-remove absolute top-1.5 right-1.5 size-3.5 rounded-full bg-
|
|
1490
|
+
className: "aui-attachment-tile-remove absolute top-1.5 right-1.5 size-3.5 rounded-full bg-card text-foreground opacity-100 shadow-card hover:bg-card! [&_svg]:text-foreground hover:[&_svg]:text-destructive",
|
|
1515
1491
|
side: "top",
|
|
1516
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.XIcon, { className: "aui-attachment-remove-icon size-3
|
|
1492
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.XIcon, { className: "aui-attachment-remove-icon size-3" })
|
|
1517
1493
|
}
|
|
1518
1494
|
) });
|
|
1519
1495
|
};
|
|
@@ -1535,7 +1511,7 @@ var ComposerAddAttachment = () => {
|
|
|
1535
1511
|
tooltip: "Add Attachment",
|
|
1536
1512
|
side: "bottom",
|
|
1537
1513
|
variant: "secondary",
|
|
1538
|
-
className: "aui-composer-add-attachment shrink-0 text-
|
|
1514
|
+
className: "aui-composer-add-attachment shrink-0 text-muted-foreground",
|
|
1539
1515
|
"aria-label": "Add Attachment",
|
|
1540
1516
|
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.PlusIcon, { className: "aui-attachment-add-icon size-4 stroke-[1.5]" })
|
|
1541
1517
|
}
|
|
@@ -1885,30 +1861,19 @@ var import_react7 = require("react");
|
|
|
1885
1861
|
var import_react8 = require("@assistant-ui/react");
|
|
1886
1862
|
var import_lucide_react3 = require("lucide-react");
|
|
1887
1863
|
|
|
1888
|
-
// src/
|
|
1889
|
-
var STUDIO_TOPBAR_GAP = "0.5rem";
|
|
1890
|
-
var STUDIO_TOPBAR_HEIGHT = "3rem";
|
|
1891
|
-
var STUDIO_PILL_HEIGHT = "2.5rem";
|
|
1892
|
-
var STUDIO_SIDEBAR_GAP = "0.5rem";
|
|
1893
|
-
var STUDIO_SIDEBAR_WIDTH = "3rem";
|
|
1894
|
-
var STUDIO_INSET_LEFT = `calc(${STUDIO_SIDEBAR_GAP} + ${STUDIO_SIDEBAR_WIDTH})`;
|
|
1895
|
-
var studioChromeShellStyle = {
|
|
1896
|
-
"--studio-topbar-gap": STUDIO_TOPBAR_GAP,
|
|
1897
|
-
"--studio-topbar-height": STUDIO_TOPBAR_HEIGHT,
|
|
1898
|
-
"--studio-chrome-pill-height": STUDIO_PILL_HEIGHT,
|
|
1899
|
-
"--studio-inset-top": `calc(${STUDIO_TOPBAR_GAP} + ${STUDIO_TOPBAR_HEIGHT})`,
|
|
1900
|
-
"--studio-sidebar-gap": STUDIO_SIDEBAR_GAP,
|
|
1901
|
-
"--studio-sidebar-width": STUDIO_SIDEBAR_WIDTH,
|
|
1902
|
-
"--studio-inset-left": STUDIO_INSET_LEFT
|
|
1903
|
-
};
|
|
1864
|
+
// src/design/classes.ts
|
|
1904
1865
|
var studioTopbarPillHeightClass = "h-[var(--studio-chrome-pill-height)] min-h-[var(--studio-chrome-pill-height)]";
|
|
1905
1866
|
var studioTopbarIconPillClass = "shrink-0 flex-none size-[var(--studio-chrome-pill-height)] min-h-[var(--studio-chrome-pill-height)] min-w-[var(--studio-chrome-pill-height)]";
|
|
1906
|
-
var studioPlaygroundGradientClass = "bg-gradient-to-b from-
|
|
1907
|
-
var studioComposeInputShellClass =
|
|
1908
|
-
|
|
1867
|
+
var studioPlaygroundGradientClass = "bg-gradient-to-b from-playground-from via-playground-via to-playground-to";
|
|
1868
|
+
var studioComposeInputShellClass = cn(
|
|
1869
|
+
"flex w-full flex-col rounded-2xl bg-composer-bg shadow-card-elevated outline-none",
|
|
1870
|
+
"border border-composer-border",
|
|
1871
|
+
"transition-[box-shadow,border-color]",
|
|
1872
|
+
"focus-within:border-composer-border-focus focus-within:ring-2 focus-within:ring-foreground/5"
|
|
1873
|
+
);
|
|
1909
1874
|
var studioSecondaryChromeClass = TIMBAL_V2_SECONDARY_CHROME;
|
|
1910
|
-
var studioIntegrationSurfaceSolid = "bg-
|
|
1911
|
-
var studioIntegrationBorder = "border border-
|
|
1875
|
+
var studioIntegrationSurfaceSolid = "bg-gradient-to-b from-elevated-from to-elevated-to shadow-card";
|
|
1876
|
+
var studioIntegrationBorder = "border border-border";
|
|
1912
1877
|
var studioIntegrationCardClass = cn(
|
|
1913
1878
|
"rounded-xl",
|
|
1914
1879
|
studioIntegrationSurfaceSolid,
|
|
@@ -1923,8 +1888,8 @@ var studioListRowButtonClass = cn(
|
|
|
1923
1888
|
"flex w-full cursor-pointer items-center gap-3 rounded-xl px-3 py-2.5 text-left",
|
|
1924
1889
|
studioIntegrationCardClass,
|
|
1925
1890
|
"transition-[background-color,box-shadow,border-color] duration-200 ease-in-out",
|
|
1926
|
-
"hover:border-
|
|
1927
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background
|
|
1891
|
+
"hover:border-foreground/20",
|
|
1892
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
1928
1893
|
);
|
|
1929
1894
|
var studioComposerIoWellClass = cn(
|
|
1930
1895
|
"rounded-lg",
|
|
@@ -1935,6 +1900,43 @@ var studioToolCardShellClass = cn(
|
|
|
1935
1900
|
studioIntegrationCardClass,
|
|
1936
1901
|
"my-2 min-h-0 overflow-hidden"
|
|
1937
1902
|
);
|
|
1903
|
+
var studioSidebarPanelClass = cn(
|
|
1904
|
+
"bg-sidebar text-sidebar-foreground",
|
|
1905
|
+
"border border-sidebar-border",
|
|
1906
|
+
"shadow-card-elevated"
|
|
1907
|
+
);
|
|
1908
|
+
var studioSidebarNavItemClass = cn(
|
|
1909
|
+
"flex items-center rounded-lg text-sm",
|
|
1910
|
+
"transition-[color,background-color,box-shadow,border-color] duration-200 ease-in-out",
|
|
1911
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2"
|
|
1912
|
+
);
|
|
1913
|
+
function studioSidebarNavItemLayout(iconOnly) {
|
|
1914
|
+
return iconOnly ? "box-border size-8 min-h-8 min-w-8 shrink-0 justify-center rounded-lg p-0 focus-visible:ring-offset-0" : "w-full gap-2 px-2.5 py-2";
|
|
1915
|
+
}
|
|
1916
|
+
var studioSidebarNavItemSurfaceClass = cn(
|
|
1917
|
+
"bg-gradient-to-b from-elevated-from to-elevated-to text-foreground",
|
|
1918
|
+
"border border-border",
|
|
1919
|
+
"shadow-card"
|
|
1920
|
+
);
|
|
1921
|
+
var studioSidebarNavItemIdleClass = cn(
|
|
1922
|
+
"border border-transparent text-muted-foreground shadow-none",
|
|
1923
|
+
"hover:text-foreground",
|
|
1924
|
+
"hover:bg-gradient-to-b hover:from-elevated-from hover:to-elevated-to",
|
|
1925
|
+
"hover:border-border hover:shadow-card"
|
|
1926
|
+
);
|
|
1927
|
+
var studioSidebarCollapsedRailItemClass = cn(
|
|
1928
|
+
"border border-border shadow-card bg-sidebar-accent"
|
|
1929
|
+
);
|
|
1930
|
+
var studioSidebarCollapsedRailItemIdleClass = cn(
|
|
1931
|
+
studioSidebarCollapsedRailItemClass,
|
|
1932
|
+
"text-muted-foreground hover:text-foreground"
|
|
1933
|
+
);
|
|
1934
|
+
var studioSidebarCollapsedRailItemActiveClass = cn(
|
|
1935
|
+
studioSidebarCollapsedRailItemClass,
|
|
1936
|
+
studioSidebarNavItemSurfaceClass,
|
|
1937
|
+
"text-foreground"
|
|
1938
|
+
);
|
|
1939
|
+
var studioSidebarNavItemActiveClass = studioSidebarNavItemSurfaceClass;
|
|
1938
1940
|
var studioTimelineRowButtonClass = "group flex w-full min-w-0 cursor-pointer items-center justify-start rounded-md border-0 bg-transparent py-1 text-left shadow-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2";
|
|
1939
1941
|
var studioTimelineTextClass = "text-xs font-normal leading-snug";
|
|
1940
1942
|
var studioTimelineActionClass = cn(
|
|
@@ -1960,10 +1962,10 @@ var studioArtifactShellClass = cn(
|
|
|
1960
1962
|
studioIntegrationCardClass,
|
|
1961
1963
|
"my-2 w-full min-w-0 overflow-hidden"
|
|
1962
1964
|
);
|
|
1963
|
-
var studioQuestionOptionClass = "flex w-full items-center gap-2 rounded-lg border border-transparent px-2 py-1.5 text-left text-sm transition-[background-color,border-color,box-shadow] duration-200 hover:bg-
|
|
1965
|
+
var studioQuestionOptionClass = "flex w-full items-center gap-2 rounded-lg border border-transparent px-2 py-1.5 text-left text-sm transition-[background-color,border-color,box-shadow] duration-200 hover:bg-muted/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2";
|
|
1964
1966
|
var studioQuestionOptionSelectedClass = cn(
|
|
1965
1967
|
studioQuestionOptionClass,
|
|
1966
|
-
"border-
|
|
1968
|
+
"border-border bg-accent ring-1 ring-foreground/10"
|
|
1967
1969
|
);
|
|
1968
1970
|
|
|
1969
1971
|
// src/artifacts/question-artifact.tsx
|
|
@@ -1977,7 +1979,7 @@ var OptionRadio = ({ selected }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx
|
|
|
1977
1979
|
{
|
|
1978
1980
|
className: cn(
|
|
1979
1981
|
"flex size-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
|
|
1980
|
-
selected ? "border-foreground bg-foreground text-background" : "border-
|
|
1982
|
+
selected ? "border-foreground bg-foreground text-background" : "border-border bg-background"
|
|
1981
1983
|
),
|
|
1982
1984
|
"aria-hidden": true,
|
|
1983
1985
|
children: selected ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.CheckIcon, { className: "size-2.5 stroke-[3]" }) : null
|
|
@@ -2233,15 +2235,15 @@ var import_class_variance_authority = require("class-variance-authority");
|
|
|
2233
2235
|
var import_radix_ui5 = require("radix-ui");
|
|
2234
2236
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2235
2237
|
var buttonVariants = (0, import_class_variance_authority.cva)(
|
|
2236
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/
|
|
2238
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/30 aria-invalid:border-destructive",
|
|
2237
2239
|
{
|
|
2238
2240
|
variants: {
|
|
2239
2241
|
variant: {
|
|
2240
2242
|
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
2241
|
-
destructive: "bg-destructive text-
|
|
2242
|
-
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground
|
|
2243
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:ring-destructive/30",
|
|
2244
|
+
outline: "border border-border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
|
|
2243
2245
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
2244
|
-
ghost: "hover:bg-accent hover:text-accent-foreground
|
|
2246
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
2245
2247
|
link: "text-primary underline-offset-4 hover:underline"
|
|
2246
2248
|
},
|
|
2247
2249
|
size: {
|
|
@@ -2873,7 +2875,7 @@ var CodeHeader = ({ language, code }) => {
|
|
|
2873
2875
|
if (!code || isCopied) return;
|
|
2874
2876
|
copyToClipboard(code);
|
|
2875
2877
|
};
|
|
2876
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "aui-code-header flex items-center justify-between rounded-t-lg border border-b-0 border-border/50 bg-
|
|
2878
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "aui-code-header flex items-center justify-between rounded-t-lg border border-b-0 border-border/50 bg-code-header-bg px-4 py-2", children: [
|
|
2877
2879
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "flex items-center gap-2 text-xs font-semibold tracking-wide text-muted-foreground/80 uppercase", children: [
|
|
2878
2880
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/40" }),
|
|
2879
2881
|
language
|
|
@@ -3080,7 +3082,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
3080
3082
|
"pre",
|
|
3081
3083
|
{
|
|
3082
3084
|
className: cn(
|
|
3083
|
-
"aui-md-pre overflow-x-auto rounded-t-none rounded-b-lg border border-t-0 border-border/50 bg-
|
|
3085
|
+
"aui-md-pre overflow-x-auto rounded-t-none rounded-b-lg border border-t-0 border-border/50 bg-code-block-bg p-4 text-[13px] leading-relaxed",
|
|
3084
3086
|
className
|
|
3085
3087
|
),
|
|
3086
3088
|
...props
|
|
@@ -3092,7 +3094,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
|
|
|
3092
3094
|
"code",
|
|
3093
3095
|
{
|
|
3094
3096
|
className: cn(
|
|
3095
|
-
!isCodeBlock && "aui-md-inline-code rounded-[5px] border border-border/60 bg-muted/60 px-[0.4em] py-[0.15em] font-mono text-[0.85em] font-medium text-foreground/90
|
|
3097
|
+
!isCodeBlock && "aui-md-inline-code rounded-[5px] border border-border/60 bg-muted/60 px-[0.4em] py-[0.15em] font-mono text-[0.85em] font-medium text-foreground/90",
|
|
3096
3098
|
className
|
|
3097
3099
|
),
|
|
3098
3100
|
...props
|
|
@@ -3508,7 +3510,7 @@ var ComposerInput = ({
|
|
|
3508
3510
|
import_react22.ComposerPrimitive.Input,
|
|
3509
3511
|
{
|
|
3510
3512
|
placeholder,
|
|
3511
|
-
className: "aui-composer-input max-h-60 min-h-14 w-full resize-none bg-
|
|
3513
|
+
className: "aui-composer-input max-h-60 min-h-14 w-full resize-none bg-composer-bg px-3 pt-3 pb-1 text-sm outline-none placeholder:text-muted-foreground/70 focus-visible:ring-0",
|
|
3512
3514
|
rows: 1,
|
|
3513
3515
|
autoFocus,
|
|
3514
3516
|
"aria-label": "Message input",
|
|
@@ -3518,7 +3520,7 @@ var ComposerInput = ({
|
|
|
3518
3520
|
);
|
|
3519
3521
|
};
|
|
3520
3522
|
var ComposerToolbar = ({ showAttachments, toolbar, sendTooltip }) => {
|
|
3521
|
-
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-composer-action-wrapper flex items-center justify-between gap-1 px-2.5 pb-2.5", children: [
|
|
3523
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-composer-action-wrapper relative z-[1] flex items-center justify-between gap-1 bg-composer-bg px-2.5 pb-2.5", children: [
|
|
3522
3524
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
3523
3525
|
showAttachments && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComposerAddAttachment, {}),
|
|
3524
3526
|
toolbar
|
|
@@ -3590,9 +3592,9 @@ var SuggestionRow = ({ suggestion }) => {
|
|
|
3590
3592
|
onClick,
|
|
3591
3593
|
className: cn("aui-thread-suggestion", studioListRowButtonClass),
|
|
3592
3594
|
children: [
|
|
3593
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "aui-thread-suggestion-icon shrink-0 text-
|
|
3595
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "aui-thread-suggestion-icon shrink-0 text-muted-foreground", children: suggestion.icon ?? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react7.ArrowUpIcon, { className: "size-4", strokeWidth: 1.75, "aria-hidden": true }) }),
|
|
3594
3596
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "aui-thread-suggestion-text min-w-0 flex-1 text-left", children: [
|
|
3595
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "aui-thread-suggestion-text-1 block truncate text-sm font-normal text-foreground
|
|
3597
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "aui-thread-suggestion-text-1 block truncate text-sm font-normal text-foreground", children: suggestion.title }),
|
|
3596
3598
|
suggestion.description && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "aui-thread-suggestion-text-2 mt-0.5 block truncate text-xs text-muted-foreground", children: suggestion.description })
|
|
3597
3599
|
] })
|
|
3598
3600
|
]
|
|
@@ -3625,6 +3627,75 @@ function useResolvedSuggestions(source) {
|
|
|
3625
3627
|
return (0, import_react23.useMemo)(() => resolved, [resolved]);
|
|
3626
3628
|
}
|
|
3627
3629
|
|
|
3630
|
+
// src/design/theme-sanity.ts
|
|
3631
|
+
var scheduled = false;
|
|
3632
|
+
var warned = false;
|
|
3633
|
+
function isDev() {
|
|
3634
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
|
|
3635
|
+
return false;
|
|
3636
|
+
}
|
|
3637
|
+
return true;
|
|
3638
|
+
}
|
|
3639
|
+
function parseLuminance(color) {
|
|
3640
|
+
const value = color.trim();
|
|
3641
|
+
if (!value) return null;
|
|
3642
|
+
const oklch = value.match(/oklch\(\s*([0-9.]+)/i);
|
|
3643
|
+
if (oklch) {
|
|
3644
|
+
const lightness = Number.parseFloat(oklch[1]);
|
|
3645
|
+
if (Number.isFinite(lightness)) return lightness;
|
|
3646
|
+
}
|
|
3647
|
+
const rgb = value.match(/rgba?\(\s*([0-9.]+)[\s,]+([0-9.]+)[\s,]+([0-9.]+)/i);
|
|
3648
|
+
if (rgb) {
|
|
3649
|
+
const r = Number.parseFloat(rgb[1]) / 255;
|
|
3650
|
+
const g = Number.parseFloat(rgb[2]) / 255;
|
|
3651
|
+
const b = Number.parseFloat(rgb[3]) / 255;
|
|
3652
|
+
if ([r, g, b].every(Number.isFinite)) {
|
|
3653
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
3654
|
+
}
|
|
3655
|
+
}
|
|
3656
|
+
const hsl = value.match(/hsla?\(\s*[0-9.]+[\s,]+[0-9.]+%[\s,]+([0-9.]+)%/i);
|
|
3657
|
+
if (hsl) {
|
|
3658
|
+
const lightness = Number.parseFloat(hsl[1]) / 100;
|
|
3659
|
+
if (Number.isFinite(lightness)) return lightness;
|
|
3660
|
+
}
|
|
3661
|
+
return null;
|
|
3662
|
+
}
|
|
3663
|
+
function runCheck() {
|
|
3664
|
+
if (warned) return;
|
|
3665
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
3666
|
+
const root = document.documentElement;
|
|
3667
|
+
const styles = window.getComputedStyle(root);
|
|
3668
|
+
const background = styles.getPropertyValue("--background").trim();
|
|
3669
|
+
if (!background) {
|
|
3670
|
+
warned = true;
|
|
3671
|
+
console.warn(
|
|
3672
|
+
'[@timbal-ai/timbal-react] No `--background` CSS variable found on `<html>`. Did you `import "@timbal-ai/timbal-react/styles.css"` in your app entry? Components rely on semantic tokens (bg-background, text-foreground, \u2026) and will fall back to browser defaults.'
|
|
3673
|
+
);
|
|
3674
|
+
return;
|
|
3675
|
+
}
|
|
3676
|
+
const luminance = parseLuminance(background);
|
|
3677
|
+
if (luminance === null) return;
|
|
3678
|
+
const hasDarkClass = root.classList.contains("dark");
|
|
3679
|
+
const looksDark = luminance < 0.5;
|
|
3680
|
+
if (hasDarkClass !== looksDark) {
|
|
3681
|
+
warned = true;
|
|
3682
|
+
console.warn(
|
|
3683
|
+
`[@timbal-ai/timbal-react] Theme mismatch detected. \`<html>\` has${hasDarkClass ? "" : " no"} \`.dark\` class but the resolved \`--background\` is ${looksDark ? "dark" : "light"} (${background}). This usually means the consumer's CSS overrides \`--background\` only in one mode. Import \`@timbal-ai/timbal-react/styles.css\` for a complete light + dark token set, or declare matching \`:root\` AND \`.dark\` blocks in your own CSS.`
|
|
3684
|
+
);
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3687
|
+
function scheduleThemeSanityCheck() {
|
|
3688
|
+
if (scheduled) return;
|
|
3689
|
+
if (!isDev()) return;
|
|
3690
|
+
if (typeof window === "undefined") return;
|
|
3691
|
+
scheduled = true;
|
|
3692
|
+
if (typeof queueMicrotask === "function") {
|
|
3693
|
+
queueMicrotask(() => setTimeout(runCheck, 0));
|
|
3694
|
+
} else {
|
|
3695
|
+
setTimeout(runCheck, 0);
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
|
|
3628
3699
|
// src/components/thread.tsx
|
|
3629
3700
|
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
3630
3701
|
var Thread = ({
|
|
@@ -3644,6 +3715,9 @@ var Thread = ({
|
|
|
3644
3715
|
const EditComposerSlot = components?.EditComposer ?? EditComposer;
|
|
3645
3716
|
const ScrollToBottomSlot = components?.ScrollToBottom ?? ThreadScrollToBottom;
|
|
3646
3717
|
const SuggestionsSlot = components?.Suggestions ?? Suggestions;
|
|
3718
|
+
(0, import_react25.useEffect)(() => {
|
|
3719
|
+
scheduleThemeSanityCheck();
|
|
3720
|
+
}, []);
|
|
3647
3721
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3648
3722
|
ArtifactRegistryProvider,
|
|
3649
3723
|
{
|
|
@@ -3651,7 +3725,7 @@ var Thread = ({
|
|
|
3651
3725
|
override: artifacts?.override,
|
|
3652
3726
|
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(UiEventProvider, { onEvent: onArtifactEvent ?? (() => {
|
|
3653
3727
|
}), children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3654
|
-
|
|
3728
|
+
import_react26.ThreadPrimitive.Root,
|
|
3655
3729
|
{
|
|
3656
3730
|
className: cn(
|
|
3657
3731
|
"aui-root aui-thread-root @container flex h-full flex-col bg-background",
|
|
@@ -3659,10 +3733,10 @@ var Thread = ({
|
|
|
3659
3733
|
),
|
|
3660
3734
|
style: { ["--thread-max-width"]: maxWidth },
|
|
3661
3735
|
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3662
|
-
|
|
3736
|
+
import_react26.ThreadPrimitive.Viewport,
|
|
3663
3737
|
{
|
|
3664
3738
|
turnAnchor: "bottom",
|
|
3665
|
-
className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll px-4 pt-4",
|
|
3739
|
+
className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-pb-4 px-4 pt-4",
|
|
3666
3740
|
children: [
|
|
3667
3741
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3668
3742
|
WelcomeSlot,
|
|
@@ -3673,7 +3747,7 @@ var Thread = ({
|
|
|
3673
3747
|
}
|
|
3674
3748
|
),
|
|
3675
3749
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3676
|
-
|
|
3750
|
+
import_react26.ThreadPrimitive.Messages,
|
|
3677
3751
|
{
|
|
3678
3752
|
components: {
|
|
3679
3753
|
UserMessage: UserMessageSlot,
|
|
@@ -3682,7 +3756,7 @@ var Thread = ({
|
|
|
3682
3756
|
}
|
|
3683
3757
|
}
|
|
3684
3758
|
),
|
|
3685
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3759
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react26.ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 z-10 mx-auto mt-auto flex w-full max-w-(--thread-max-width) isolate flex-col gap-4 bg-transparent pt-2 pb-4 md:pb-6", children: [
|
|
3686
3760
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ScrollToBottomSlot, {}),
|
|
3687
3761
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ComposerSlot, { placeholder: composerPlaceholder })
|
|
3688
3762
|
] })
|
|
@@ -3695,7 +3769,7 @@ var Thread = ({
|
|
|
3695
3769
|
);
|
|
3696
3770
|
};
|
|
3697
3771
|
var ThreadScrollToBottom = () => {
|
|
3698
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ThreadPrimitive.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3699
3773
|
TooltipIconButton,
|
|
3700
3774
|
{
|
|
3701
3775
|
tooltip: "Scroll to bottom",
|
|
@@ -3733,20 +3807,20 @@ var ThreadWelcome = ({
|
|
|
3733
3807
|
suggestions,
|
|
3734
3808
|
Suggestions: SuggestionsSlot = Suggestions
|
|
3735
3809
|
}) => {
|
|
3736
|
-
const isEmpty = (0,
|
|
3810
|
+
const isEmpty = (0, import_react26.useThread)((s) => s.messages.length === 0);
|
|
3737
3811
|
if (!isEmpty) return null;
|
|
3738
3812
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: [
|
|
3739
3813
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3740
|
-
|
|
3814
|
+
import_react27.motion.div,
|
|
3741
3815
|
{
|
|
3742
3816
|
className: "aui-thread-welcome-message flex flex-col items-center justify-center px-4 text-center",
|
|
3743
3817
|
variants: welcomeStagger,
|
|
3744
3818
|
initial: "initial",
|
|
3745
3819
|
animate: "animate",
|
|
3746
3820
|
children: [
|
|
3747
|
-
config?.icon && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3821
|
+
config?.icon && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react27.motion.div, { variants: welcomeIcon, className: "mb-5", children: config.icon }),
|
|
3748
3822
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3749
|
-
|
|
3823
|
+
import_react27.motion.h1,
|
|
3750
3824
|
{
|
|
3751
3825
|
variants: welcomeItem,
|
|
3752
3826
|
className: "aui-thread-welcome-message-inner font-semibold text-2xl",
|
|
@@ -3754,7 +3828,7 @@ var ThreadWelcome = ({
|
|
|
3754
3828
|
}
|
|
3755
3829
|
),
|
|
3756
3830
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3757
|
-
|
|
3831
|
+
import_react27.motion.p,
|
|
3758
3832
|
{
|
|
3759
3833
|
variants: welcomeItem,
|
|
3760
3834
|
className: "aui-thread-welcome-message-inner mt-2 text-muted-foreground",
|
|
@@ -3768,18 +3842,18 @@ var ThreadWelcome = ({
|
|
|
3768
3842
|
] });
|
|
3769
3843
|
};
|
|
3770
3844
|
var MessageError = () => {
|
|
3771
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3845
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.MessagePrimitive.Error, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ErrorPrimitive.Root, { className: "aui-message-error-root mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ErrorPrimitive.Message, { className: "aui-message-error-message line-clamp-2" }) }) });
|
|
3772
3846
|
};
|
|
3773
3847
|
var AssistantMessage = () => {
|
|
3774
3848
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3775
|
-
|
|
3849
|
+
import_react26.MessagePrimitive.Root,
|
|
3776
3850
|
{
|
|
3777
3851
|
className: "aui-assistant-message-root fade-in slide-in-from-bottom-1 relative mx-auto w-full max-w-(--thread-max-width) animate-in py-3 duration-150",
|
|
3778
3852
|
"data-role": "assistant",
|
|
3779
3853
|
children: [
|
|
3780
3854
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed", children: [
|
|
3781
3855
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3782
|
-
|
|
3856
|
+
import_react26.MessagePrimitive.Parts,
|
|
3783
3857
|
{
|
|
3784
3858
|
components: {
|
|
3785
3859
|
Text: MarkdownText,
|
|
@@ -3791,7 +3865,7 @@ var AssistantMessage = () => {
|
|
|
3791
3865
|
),
|
|
3792
3866
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MessageError, {})
|
|
3793
3867
|
] }),
|
|
3794
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "aui-assistant-message-footer mt-
|
|
3868
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "aui-assistant-message-footer mt-1 mb-3 ml-1 flex", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AssistantActionBar, {}) })
|
|
3795
3869
|
]
|
|
3796
3870
|
}
|
|
3797
3871
|
);
|
|
@@ -3801,30 +3875,29 @@ var ASSISTANT_ACTION_ICON_CLASS = cn(
|
|
|
3801
3875
|
// The v2 fill span sits inside `group/tbv2 > span:first-child`. We mute it
|
|
3802
3876
|
// here so action-bar buttons read as subtle icons rather than full pills.
|
|
3803
3877
|
"[&>span:first-child]:bg-transparent",
|
|
3804
|
-
"[&>span:first-child]:group-hover/tbv2:bg-
|
|
3805
|
-
"dark:[&>span:first-child]:group-hover/tbv2:bg-white/8"
|
|
3878
|
+
"[&>span:first-child]:group-hover/tbv2:bg-muted/70"
|
|
3806
3879
|
);
|
|
3807
3880
|
var AssistantActionBar = () => {
|
|
3808
3881
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3809
|
-
|
|
3882
|
+
import_react26.ActionBarPrimitive.Root,
|
|
3810
3883
|
{
|
|
3811
3884
|
hideWhenRunning: true,
|
|
3812
|
-
autohide: "
|
|
3885
|
+
autohide: "never",
|
|
3813
3886
|
className: "aui-assistant-action-bar-root flex items-center gap-0 bg-transparent px-0 py-0.5 text-muted-foreground/60",
|
|
3814
3887
|
children: [
|
|
3815
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3888
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ActionBarPrimitive.Copy, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3816
3889
|
TooltipIconButton,
|
|
3817
3890
|
{
|
|
3818
3891
|
tooltip: "Copy",
|
|
3819
3892
|
variant: "ghost",
|
|
3820
3893
|
className: ASSISTANT_ACTION_ICON_CLASS,
|
|
3821
3894
|
children: [
|
|
3822
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3823
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3895
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.AuiIf, { condition: (s) => s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.CheckIcon, { className: "size-3" }) }),
|
|
3896
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.AuiIf, { condition: (s) => !s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.CopyIcon, { className: "size-3" }) })
|
|
3824
3897
|
]
|
|
3825
3898
|
}
|
|
3826
3899
|
) }),
|
|
3827
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3900
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ActionBarPrimitive.Reload, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3828
3901
|
TooltipIconButton,
|
|
3829
3902
|
{
|
|
3830
3903
|
tooltip: "Regenerate",
|
|
@@ -3833,8 +3906,8 @@ var AssistantActionBar = () => {
|
|
|
3833
3906
|
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.RefreshCwIcon, { className: "size-3" })
|
|
3834
3907
|
}
|
|
3835
3908
|
) }),
|
|
3836
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3837
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3909
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react26.ActionBarMorePrimitive.Root, { children: [
|
|
3910
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ActionBarMorePrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3838
3911
|
TooltipIconButton,
|
|
3839
3912
|
{
|
|
3840
3913
|
tooltip: "More",
|
|
@@ -3847,12 +3920,12 @@ var AssistantActionBar = () => {
|
|
|
3847
3920
|
}
|
|
3848
3921
|
) }),
|
|
3849
3922
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3850
|
-
|
|
3923
|
+
import_react26.ActionBarMorePrimitive.Content,
|
|
3851
3924
|
{
|
|
3852
3925
|
side: "bottom",
|
|
3853
3926
|
align: "start",
|
|
3854
|
-
className: "aui-action-bar-more-content z-50 min-w-36 overflow-hidden rounded-lg border border-
|
|
3855
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3927
|
+
className: "aui-action-bar-more-content z-50 min-w-36 overflow-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-card-elevated",
|
|
3928
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ActionBarPrimitive.ExportMarkdown, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react26.ActionBarMorePrimitive.Item, { className: "aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-md px-2 py-1.5 text-sm outline-none hover:bg-muted focus:bg-muted", children: [
|
|
3856
3929
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.DownloadIcon, { className: "size-4 shrink-0" }),
|
|
3857
3930
|
"Export as Markdown"
|
|
3858
3931
|
] }) })
|
|
@@ -3864,25 +3937,25 @@ var AssistantActionBar = () => {
|
|
|
3864
3937
|
);
|
|
3865
3938
|
};
|
|
3866
3939
|
var UserMessageText = () => {
|
|
3867
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "whitespace-pre-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3940
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "whitespace-pre-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.MessagePartPrimitive.Text, { smooth: false }) });
|
|
3868
3941
|
};
|
|
3869
3942
|
var UserMessage = () => {
|
|
3870
3943
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3871
|
-
|
|
3944
|
+
import_react26.MessagePrimitive.Root,
|
|
3872
3945
|
{
|
|
3873
3946
|
className: "aui-user-message-root mx-auto flex w-full max-w-(--thread-max-width) flex-col items-end gap-2 px-2 py-3",
|
|
3874
3947
|
"data-role": "user",
|
|
3875
3948
|
children: [
|
|
3876
3949
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(UserMessageAttachments, {}),
|
|
3877
3950
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3878
|
-
|
|
3951
|
+
import_react27.motion.div,
|
|
3879
3952
|
{
|
|
3880
|
-
className: "aui-user-message-content relative inline-block max-w-[80%] rounded-2xl bg-
|
|
3953
|
+
className: "aui-user-message-content relative inline-block max-w-[80%] rounded-2xl bg-bubble-user px-4 py-2.5 text-bubble-user-foreground",
|
|
3881
3954
|
initial: { opacity: 0, y: 8, scale: 0.99 },
|
|
3882
3955
|
animate: { opacity: 1, y: 0, scale: 1 },
|
|
3883
3956
|
transition: { duration: 0.65, ease: luxuryEase },
|
|
3884
3957
|
children: [
|
|
3885
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3958
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.MessagePrimitive.Parts, { components: { Text: UserMessageText } }),
|
|
3886
3959
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "aui-user-action-bar-wrapper absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(UserActionBar, {}) })
|
|
3887
3960
|
]
|
|
3888
3961
|
}
|
|
@@ -3893,12 +3966,12 @@ var UserMessage = () => {
|
|
|
3893
3966
|
};
|
|
3894
3967
|
var UserActionBar = () => {
|
|
3895
3968
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3896
|
-
|
|
3969
|
+
import_react26.ActionBarPrimitive.Root,
|
|
3897
3970
|
{
|
|
3898
3971
|
hideWhenRunning: true,
|
|
3899
|
-
autohide: "
|
|
3972
|
+
autohide: "never",
|
|
3900
3973
|
className: "aui-user-action-bar-root flex flex-col items-end",
|
|
3901
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3974
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ActionBarPrimitive.Edit, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3902
3975
|
TooltipIconButton,
|
|
3903
3976
|
{
|
|
3904
3977
|
tooltip: "Edit",
|
|
@@ -3911,17 +3984,17 @@ var UserActionBar = () => {
|
|
|
3911
3984
|
);
|
|
3912
3985
|
};
|
|
3913
3986
|
var EditComposer = () => {
|
|
3914
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3987
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.MessagePrimitive.Root, { className: "aui-edit-composer-wrapper mx-auto flex w-full max-w-(--thread-max-width) flex-col px-2 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react26.ComposerPrimitive.Root, { className: "aui-edit-composer-root ml-auto flex w-full max-w-[85%] flex-col rounded-2xl bg-muted", children: [
|
|
3915
3988
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3916
|
-
|
|
3989
|
+
import_react26.ComposerPrimitive.Input,
|
|
3917
3990
|
{
|
|
3918
3991
|
className: "aui-edit-composer-input min-h-14 w-full resize-none bg-transparent p-4 text-foreground text-sm outline-none",
|
|
3919
3992
|
autoFocus: true
|
|
3920
3993
|
}
|
|
3921
3994
|
),
|
|
3922
3995
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "aui-edit-composer-footer mx-3 mb-3 flex items-center gap-2 self-end", children: [
|
|
3923
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3924
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3996
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TimbalV2Button, { variant: "ghost", size: "sm", children: "Cancel" }) }),
|
|
3997
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TimbalV2Button, { variant: "primary", size: "sm", children: "Update" }) })
|
|
3925
3998
|
] })
|
|
3926
3999
|
] }) });
|
|
3927
4000
|
};
|
|
@@ -3953,193 +4026,6 @@ function TimbalChat({
|
|
|
3953
4026
|
);
|
|
3954
4027
|
}
|
|
3955
4028
|
|
|
3956
|
-
// src/artifacts/agent-instructions.ts
|
|
3957
|
-
var ARTIFACT_AGENT_INSTRUCTIONS = `
|
|
3958
|
-
## Rich artifacts (Timbal chat UI)
|
|
3959
|
-
|
|
3960
|
-
When you need charts, tables, choice widgets, or interactive controls, return a **JSON artifact object** instead of plain prose. The chat UI renders these automatically.
|
|
3961
|
-
|
|
3962
|
-
### Delivery channels (either works)
|
|
3963
|
-
|
|
3964
|
-
1. **Tool result (preferred)** \u2014 return a single JSON object (or a JSON string) from a tool. The object must include a string \`type\` field.
|
|
3965
|
-
2. **Inline markdown fence** \u2014 embed the same JSON inside a fenced block:
|
|
3966
|
-
|
|
3967
|
-
\`\`\`timbal-artifact
|
|
3968
|
-
{"type":"chart","data":[{"month":"Jan","sales":120}]}
|
|
3969
|
-
\`\`\`
|
|
3970
|
-
|
|
3971
|
-
The alias \`\`\`timbal\`\`\` is also accepted.
|
|
3972
|
-
|
|
3973
|
-
### Built-in artifact types
|
|
3974
|
-
|
|
3975
|
-
| \`type\` | Use for |
|
|
3976
|
-
|---|---|
|
|
3977
|
-
| \`chart\` | Bar, line, area, or pie charts. Fields: \`data\`, optional \`chartType\`, \`xKey\`, \`dataKey\`, \`title\`, \`unit\`. |
|
|
3978
|
-
| \`table\` | Tabular data. Fields: \`rows\`, optional \`columns\`, \`title\`. |
|
|
3979
|
-
| \`question\` | In-thread multiple choice. Fields: \`options: [{ id, label, description? }]\`, optional \`prompt\`, \`multi\`. User replies are sent back as a normal user message. |
|
|
3980
|
-
| \`html\` | Custom HTML/CSS/JS in an iframe. Fields: \`content\` (HTML document or fragment), optional \`title\`, \`height\`, \`sandboxed\` (default \`true\`; set \`false\` for unrestricted scripts/CDN). |
|
|
3981
|
-
| \`json\` | Fallback structured view. Fields: \`data\`, optional \`title\`. |
|
|
3982
|
-
| \`ui\` | **Interactive UI** composed from a fixed node palette (hover, click, drag). See below. |
|
|
3983
|
-
|
|
3984
|
-
### When to use \`type: "html"\`
|
|
3985
|
-
|
|
3986
|
-
Use \`html\` when the user wants a **rich visual or interactive page** that does not fit the \`ui\` palette \u2014 e.g. styled layouts, SVG graphics, CSS animations, canvas, small games, calculators, or multi-section mockups. Pass a full HTML document or a body fragment in \`content\`.
|
|
3987
|
-
|
|
3988
|
-
- Inline \`<style>\`, \`<script>\`, SVG, and canvas are supported.
|
|
3989
|
-
- Default \`sandboxed: true\` runs in an isolated iframe with scripts enabled.
|
|
3990
|
-
- Set \`sandboxed: false\` only for trusted content that needs external CDN scripts/styles or full DOM freedom.
|
|
3991
|
-
- Prefer \`ui\` when controls should send chat messages or host events; prefer \`html\` for self-contained mini-apps and visual demos.
|
|
3992
|
-
|
|
3993
|
-
### When to use \`type: "ui"\`
|
|
3994
|
-
|
|
3995
|
-
Use a \`ui\` artifact when the user should **hover, click, drag, or adjust controls** in-thread and those actions should integrate with the chat runtime (messages, \`onArtifactEvent\`). For standalone visual/interactive HTML, use \`html\` instead.
|
|
3996
|
-
|
|
3997
|
-
Each \`ui\` artifact has:
|
|
3998
|
-
|
|
3999
|
-
- \`initialState\` \u2014 optional object seeding local state (per widget instance).
|
|
4000
|
-
- \`root\` \u2014 a single node tree (see node kinds below).
|
|
4001
|
-
- optional \`title\` \u2014 card heading.
|
|
4002
|
-
|
|
4003
|
-
**Bindings:** anywhere a primitive is accepted, you may use \`{ "$bind": "dotted.path" }\` to read from \`initialState\` / local state (e.g. \`{ "$bind": "qty" }\`).
|
|
4004
|
-
|
|
4005
|
-
**Actions:** nodes may attach \`onClick\`, \`onChange\`, or \`onDragEnd\` with one action or an array:
|
|
4006
|
-
|
|
4007
|
-
| Action | Shape | Effect |
|
|
4008
|
-
|---|---|---|
|
|
4009
|
-
| User message | \`{ "kind": "message", "text": "..." }\` or \`{ "kind": "message", "text": { "$bind": "path" } }\` | Sends text as the next user message. |
|
|
4010
|
-
| Set state | \`{ "kind": "set", "path": "foo", "value": 1 }\` | Writes local widget state. |
|
|
4011
|
-
| Toggle boolean | \`{ "kind": "toggle", "path": "enabled" }\` | Flips a boolean at \`path\`. |
|
|
4012
|
-
| Host event | \`{ "kind": "emit", "name": "event-name", "payload": { ... } }\` | Bubbles to the host app (\`onArtifactEvent\` on \`<Thread>\`). |
|
|
4013
|
-
|
|
4014
|
-
### \`ui\` node palette (\`root.kind\`)
|
|
4015
|
-
|
|
4016
|
-
| \`kind\` | Purpose | Key fields |
|
|
4017
|
-
|---|---|---|
|
|
4018
|
-
| \`box\` | Layout container | \`children\`, \`direction\` (\`row\`/\`col\`), \`gap\`, \`padding\`, \`align\`, \`justify\`, \`wrap\` |
|
|
4019
|
-
| \`text\` | Body text | \`value\`, optional \`muted\`, \`size\`, \`weight\` |
|
|
4020
|
-
| \`heading\` | Heading | \`value\`, optional \`level\` (1\u20134) |
|
|
4021
|
-
| \`badge\` | Pill label | \`value\`, optional \`tone\` (\`default\`, \`primary\`, \`success\`, \`warn\`, \`danger\`) |
|
|
4022
|
-
| \`button\` | Clickable button | \`label\`, optional \`variant\`, \`size\`, \`disabled\`, \`onClick\` |
|
|
4023
|
-
| \`toggle\` | Boolean switch | \`binding\` (state path), optional \`label\`, \`onChange\` |
|
|
4024
|
-
| \`slider\` | Numeric range | \`binding\`, optional \`min\`, \`max\`, \`step\`, \`label\`, \`showValue\`, \`onChange\` |
|
|
4025
|
-
| \`tooltip\` | Hover tooltip | \`content\`, \`child\` (single node), optional \`side\` |
|
|
4026
|
-
| \`draggable\` | Drag gesture | \`child\`, optional \`axis\` (\`x\`/\`y\`/\`both\`), \`snapBack\`, \`onDragEnd\` |
|
|
4027
|
-
| \`custom\` | Host-registered widget | \`name\`, optional \`props\`, \`children\` \u2014 only if the app registered that name |
|
|
4028
|
-
|
|
4029
|
-
### Example \`ui\` artifact
|
|
4030
|
-
|
|
4031
|
-
\`\`\`json
|
|
4032
|
-
{
|
|
4033
|
-
"type": "ui",
|
|
4034
|
-
"title": "Configure plan",
|
|
4035
|
-
"initialState": { "qty": 1, "premium": false },
|
|
4036
|
-
"root": {
|
|
4037
|
-
"kind": "box",
|
|
4038
|
-
"direction": "col",
|
|
4039
|
-
"gap": 3,
|
|
4040
|
-
"children": [
|
|
4041
|
-
{ "kind": "heading", "value": "Choose quantity", "level": 3 },
|
|
4042
|
-
{
|
|
4043
|
-
"kind": "tooltip",
|
|
4044
|
-
"content": "Drag to adjust quantity",
|
|
4045
|
-
"child": {
|
|
4046
|
-
"kind": "slider",
|
|
4047
|
-
"binding": "qty",
|
|
4048
|
-
"min": 1,
|
|
4049
|
-
"max": 50,
|
|
4050
|
-
"label": "Quantity",
|
|
4051
|
-
"onChange": { "kind": "emit", "name": "qty-changed" }
|
|
4052
|
-
}
|
|
4053
|
-
},
|
|
4054
|
-
{ "kind": "toggle", "binding": "premium", "label": "Premium support" },
|
|
4055
|
-
{
|
|
4056
|
-
"kind": "button",
|
|
4057
|
-
"label": "Confirm",
|
|
4058
|
-
"onClick": { "kind": "message", "text": { "$bind": "qty" } }
|
|
4059
|
-
}
|
|
4060
|
-
]
|
|
4061
|
-
}
|
|
4062
|
-
}
|
|
4063
|
-
\`\`\`
|
|
4064
|
-
|
|
4065
|
-
### Rules
|
|
4066
|
-
|
|
4067
|
-
- Always set \`type\` to a built-in value above unless the app documented a custom type.
|
|
4068
|
-
- Prefer \`ui\` over \`html\` when actions must bubble to the host chat (\`message\`, \`emit\`).
|
|
4069
|
-
- Prefer \`question\` for simple A/B/C choices; use \`ui\` when you need sliders, toggles, drag, or multi-control layouts.
|
|
4070
|
-
- Keep \`data\` arrays reasonably small (charts/tables).
|
|
4071
|
-
|
|
4072
|
-
### After calling an artifact tool (critical)
|
|
4073
|
-
|
|
4074
|
-
When you call a tool that returns an artifact (\`make_chart\`, \`ask_question\`, \`show_table\`, \`show_html\`, \`make_ui_demo\`, etc.):
|
|
4075
|
-
|
|
4076
|
-
1. **Do not** paste, quote, paraphrase as JSON, or fence the tool return value in your assistant message. The chat UI already renders it from the tool result.
|
|
4077
|
-
2. **Do not** emit a matching \`\`\`timbal-artifact\`\`\` block for the same payload \u2014 pick **one** channel (tool result only).
|
|
4078
|
-
3. Your follow-up text should be **empty**, or at most **one short sentence** (e.g. "Pick an option above." / "Try the controls."). Never include \`type\`, \`options\`, \`data\`, or dict/JSON syntax.
|
|
4079
|
-
4. Treat the widget as visible to the user; refer to it as "above" / "the chart" / "the choices" \u2014 never reproduce its contents.
|
|
4080
|
-
`.trim();
|
|
4081
|
-
|
|
4082
|
-
// src/index.ts
|
|
4083
|
-
var import_react29 = require("@assistant-ui/react");
|
|
4084
|
-
|
|
4085
|
-
// src/hooks/use-workforces.ts
|
|
4086
|
-
var import_react27 = require("react");
|
|
4087
|
-
function useWorkforces(options = {}) {
|
|
4088
|
-
const { baseUrl = "/api", fetch: fetchFn, pickInitial } = options;
|
|
4089
|
-
const [workforces, setWorkforces] = (0, import_react27.useState)([]);
|
|
4090
|
-
const [selectedId, setSelectedId] = (0, import_react27.useState)("");
|
|
4091
|
-
const [isLoading, setIsLoading] = (0, import_react27.useState)(true);
|
|
4092
|
-
const [error, setError] = (0, import_react27.useState)(null);
|
|
4093
|
-
const fetchFnRef = (0, import_react27.useRef)(fetchFn ?? authFetch);
|
|
4094
|
-
(0, import_react27.useEffect)(() => {
|
|
4095
|
-
fetchFnRef.current = fetchFn ?? authFetch;
|
|
4096
|
-
}, [fetchFn]);
|
|
4097
|
-
const pickInitialRef = (0, import_react27.useRef)(pickInitial);
|
|
4098
|
-
(0, import_react27.useEffect)(() => {
|
|
4099
|
-
pickInitialRef.current = pickInitial;
|
|
4100
|
-
}, [pickInitial]);
|
|
4101
|
-
const load = (0, import_react27.useMemo)(() => {
|
|
4102
|
-
return async () => {
|
|
4103
|
-
setIsLoading(true);
|
|
4104
|
-
setError(null);
|
|
4105
|
-
try {
|
|
4106
|
-
const res = await fetchFnRef.current(`${baseUrl}/workforce`);
|
|
4107
|
-
if (!res.ok) throw new Error(`Failed to load workforces (${res.status})`);
|
|
4108
|
-
const data = await res.json();
|
|
4109
|
-
setWorkforces(data);
|
|
4110
|
-
setSelectedId((current) => {
|
|
4111
|
-
if (current && data.some((w) => idOf(w) === current)) return current;
|
|
4112
|
-
const initial = pickInitialRef.current?.(data) ?? data.find((w) => w.type === "agent") ?? data[0];
|
|
4113
|
-
return initial ? idOf(initial) : "";
|
|
4114
|
-
});
|
|
4115
|
-
} catch (err) {
|
|
4116
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
4117
|
-
} finally {
|
|
4118
|
-
setIsLoading(false);
|
|
4119
|
-
}
|
|
4120
|
-
};
|
|
4121
|
-
}, [baseUrl]);
|
|
4122
|
-
(0, import_react27.useEffect)(() => {
|
|
4123
|
-
load();
|
|
4124
|
-
}, [load]);
|
|
4125
|
-
const selected = (0, import_react27.useMemo)(
|
|
4126
|
-
() => workforces.find((w) => idOf(w) === selectedId),
|
|
4127
|
-
[workforces, selectedId]
|
|
4128
|
-
);
|
|
4129
|
-
return {
|
|
4130
|
-
workforces,
|
|
4131
|
-
selectedId,
|
|
4132
|
-
setSelectedId,
|
|
4133
|
-
selected,
|
|
4134
|
-
isLoading,
|
|
4135
|
-
error,
|
|
4136
|
-
refresh: load
|
|
4137
|
-
};
|
|
4138
|
-
}
|
|
4139
|
-
function idOf(item) {
|
|
4140
|
-
return item.id ?? item.uid ?? item.name ?? "";
|
|
4141
|
-
}
|
|
4142
|
-
|
|
4143
4029
|
// src/components/workforce-selector.tsx
|
|
4144
4030
|
var import_lucide_react9 = require("lucide-react");
|
|
4145
4031
|
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
@@ -4174,7 +4060,7 @@ var WorkforceSelector = ({
|
|
|
4174
4060
|
children: [
|
|
4175
4061
|
!value && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: "", children: placeholder }),
|
|
4176
4062
|
workforces.map((w) => {
|
|
4177
|
-
const id =
|
|
4063
|
+
const id = idOf(w);
|
|
4178
4064
|
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: id, children: w.name ?? id }, id);
|
|
4179
4065
|
})
|
|
4180
4066
|
]
|
|
@@ -4191,10 +4077,113 @@ var WorkforceSelector = ({
|
|
|
4191
4077
|
}
|
|
4192
4078
|
);
|
|
4193
4079
|
};
|
|
4080
|
+
function idOf(item) {
|
|
4081
|
+
return item.id ?? item.uid ?? item.name ?? "";
|
|
4082
|
+
}
|
|
4083
|
+
|
|
4084
|
+
// src/hooks/use-workforces.ts
|
|
4085
|
+
var import_react28 = require("react");
|
|
4086
|
+
function useWorkforces(options = {}) {
|
|
4087
|
+
const { baseUrl = "/api", fetch: fetchFn, pickInitial, enabled = true } = options;
|
|
4088
|
+
const [workforces, setWorkforces] = (0, import_react28.useState)([]);
|
|
4089
|
+
const [selectedId, setSelectedId] = (0, import_react28.useState)("");
|
|
4090
|
+
const [isLoading, setIsLoading] = (0, import_react28.useState)(enabled);
|
|
4091
|
+
const [error, setError] = (0, import_react28.useState)(null);
|
|
4092
|
+
const fetchFnRef = (0, import_react28.useRef)(fetchFn ?? authFetch);
|
|
4093
|
+
(0, import_react28.useEffect)(() => {
|
|
4094
|
+
fetchFnRef.current = fetchFn ?? authFetch;
|
|
4095
|
+
}, [fetchFn]);
|
|
4096
|
+
const pickInitialRef = (0, import_react28.useRef)(pickInitial);
|
|
4097
|
+
(0, import_react28.useEffect)(() => {
|
|
4098
|
+
pickInitialRef.current = pickInitial;
|
|
4099
|
+
}, [pickInitial]);
|
|
4100
|
+
const load = (0, import_react28.useMemo)(() => {
|
|
4101
|
+
return async () => {
|
|
4102
|
+
if (!enabled) {
|
|
4103
|
+
setIsLoading(false);
|
|
4104
|
+
return;
|
|
4105
|
+
}
|
|
4106
|
+
setIsLoading(true);
|
|
4107
|
+
setError(null);
|
|
4108
|
+
try {
|
|
4109
|
+
const res = await fetchFnRef.current(`${baseUrl}/workforce`);
|
|
4110
|
+
if (!res.ok) throw new Error(`Failed to load workforces (${res.status})`);
|
|
4111
|
+
const data = await res.json();
|
|
4112
|
+
setWorkforces(data);
|
|
4113
|
+
setSelectedId((current) => {
|
|
4114
|
+
if (current && data.some((w) => idOf2(w) === current)) return current;
|
|
4115
|
+
const initial = pickInitialRef.current?.(data) ?? data.find((w) => w.type === "agent") ?? data[0];
|
|
4116
|
+
return initial ? idOf2(initial) : "";
|
|
4117
|
+
});
|
|
4118
|
+
} catch (err) {
|
|
4119
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
4120
|
+
} finally {
|
|
4121
|
+
setIsLoading(false);
|
|
4122
|
+
}
|
|
4123
|
+
};
|
|
4124
|
+
}, [baseUrl, enabled]);
|
|
4125
|
+
(0, import_react28.useEffect)(() => {
|
|
4126
|
+
load();
|
|
4127
|
+
}, [load]);
|
|
4128
|
+
const selected = (0, import_react28.useMemo)(
|
|
4129
|
+
() => workforces.find((w) => idOf2(w) === selectedId),
|
|
4130
|
+
[workforces, selectedId]
|
|
4131
|
+
);
|
|
4132
|
+
return {
|
|
4133
|
+
workforces,
|
|
4134
|
+
selectedId,
|
|
4135
|
+
setSelectedId,
|
|
4136
|
+
selected,
|
|
4137
|
+
isLoading,
|
|
4138
|
+
error,
|
|
4139
|
+
refresh: load
|
|
4140
|
+
};
|
|
4141
|
+
}
|
|
4194
4142
|
function idOf2(item) {
|
|
4195
4143
|
return item.id ?? item.uid ?? item.name ?? "";
|
|
4196
4144
|
}
|
|
4197
4145
|
|
|
4146
|
+
// src/design/tokens.ts
|
|
4147
|
+
var SIDEBAR_WIDTH_PX = 224;
|
|
4148
|
+
var SIDEBAR_WIDTH_COLLAPSED_PX = 52;
|
|
4149
|
+
var SIDEBAR_MOBILE_PX = 272;
|
|
4150
|
+
var SIDEBAR_GAP_PX = 12;
|
|
4151
|
+
var SIDEBAR_CONTENT_GAP_PX = 8;
|
|
4152
|
+
var TOPBAR_GAP_PX = 8;
|
|
4153
|
+
var TOPBAR_HEIGHT_PX = 48;
|
|
4154
|
+
var PILL_HEIGHT_PX = 40;
|
|
4155
|
+
var SIDEBAR_INSET_PX_EXPANDED = SIDEBAR_GAP_PX + SIDEBAR_WIDTH_PX + SIDEBAR_CONTENT_GAP_PX;
|
|
4156
|
+
var SIDEBAR_INSET_PX_COLLAPSED = SIDEBAR_GAP_PX + SIDEBAR_WIDTH_COLLAPSED_PX + SIDEBAR_CONTENT_GAP_PX;
|
|
4157
|
+
var px = (n) => `${n / 16}rem`;
|
|
4158
|
+
var SIDEBAR_WIDTH = px(SIDEBAR_WIDTH_PX);
|
|
4159
|
+
var SIDEBAR_WIDTH_COLLAPSED = px(SIDEBAR_WIDTH_COLLAPSED_PX);
|
|
4160
|
+
var SIDEBAR_GAP = px(SIDEBAR_GAP_PX);
|
|
4161
|
+
var SIDEBAR_CONTENT_GAP = px(SIDEBAR_CONTENT_GAP_PX);
|
|
4162
|
+
var TOPBAR_GAP = px(TOPBAR_GAP_PX);
|
|
4163
|
+
var TOPBAR_HEIGHT = px(TOPBAR_HEIGHT_PX);
|
|
4164
|
+
var PILL_HEIGHT = px(PILL_HEIGHT_PX);
|
|
4165
|
+
var SIDEBAR_INSET_EXPANDED = px(SIDEBAR_INSET_PX_EXPANDED);
|
|
4166
|
+
var SIDEBAR_INSET_COLLAPSED = px(SIDEBAR_INSET_PX_COLLAPSED);
|
|
4167
|
+
var studioChromeShellStyle = {
|
|
4168
|
+
"--studio-topbar-gap": TOPBAR_GAP,
|
|
4169
|
+
"--studio-topbar-height": TOPBAR_HEIGHT,
|
|
4170
|
+
"--studio-chrome-pill-height": PILL_HEIGHT,
|
|
4171
|
+
"--studio-inset-top": `calc(${TOPBAR_GAP} + ${TOPBAR_HEIGHT})`,
|
|
4172
|
+
"--studio-sidebar-gap": SIDEBAR_GAP,
|
|
4173
|
+
"--studio-sidebar-width": SIDEBAR_WIDTH,
|
|
4174
|
+
"--studio-sidebar-width-collapsed": SIDEBAR_WIDTH_COLLAPSED,
|
|
4175
|
+
"--studio-sidebar-content-gap": SIDEBAR_CONTENT_GAP,
|
|
4176
|
+
"--studio-inset-left": SIDEBAR_INSET_EXPANDED,
|
|
4177
|
+
"--studio-inset-left-collapsed": SIDEBAR_INSET_COLLAPSED
|
|
4178
|
+
};
|
|
4179
|
+
var STORAGE_KEYS = {
|
|
4180
|
+
sidebarCollapsed: "timbal-studio-sidebar-collapsed"
|
|
4181
|
+
};
|
|
4182
|
+
var DOM_IDS = {
|
|
4183
|
+
sidebarRuntimeAnchor: "timbal-studio-sidebar-runtime-anchor",
|
|
4184
|
+
topbarBrandAnchor: "timbal-studio-topbar-brand-anchor"
|
|
4185
|
+
};
|
|
4186
|
+
|
|
4198
4187
|
// src/components/chat-shell.tsx
|
|
4199
4188
|
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
4200
4189
|
var TimbalChatShell = ({
|
|
@@ -4273,9 +4262,234 @@ var TimbalChatShell = ({
|
|
|
4273
4262
|
);
|
|
4274
4263
|
};
|
|
4275
4264
|
|
|
4276
|
-
// src/
|
|
4277
|
-
var
|
|
4278
|
-
var
|
|
4265
|
+
// src/components/studio/studio-shell.tsx
|
|
4266
|
+
var import_react41 = require("react");
|
|
4267
|
+
var import_lucide_react13 = require("lucide-react");
|
|
4268
|
+
var import_react42 = require("motion/react");
|
|
4269
|
+
|
|
4270
|
+
// src/design/sidebar-motion.ts
|
|
4271
|
+
var STUDIO_SIDEBAR_EASE_ENTER = [0, 0, 0.2, 1];
|
|
4272
|
+
var STUDIO_SIDEBAR_EASE_EXIT = [0.4, 0, 1, 1];
|
|
4273
|
+
var STUDIO_SIDEBAR_EASE = [0.16, 1, 0.3, 1];
|
|
4274
|
+
var STUDIO_SIDEBAR_ENTRIES_OUT_S = 0.1;
|
|
4275
|
+
var STUDIO_SIDEBAR_WIDTH_S = 0.17;
|
|
4276
|
+
var STUDIO_SIDEBAR_ENTRY_ITEM_IN_S = 0.18;
|
|
4277
|
+
var STUDIO_SIDEBAR_STAGGER_S = 0.03;
|
|
4278
|
+
var STUDIO_SIDEBAR_EXPAND_REVEAL_FRAC = 0.5;
|
|
4279
|
+
var STUDIO_SIDEBAR_CONTENT_NUDGE_PX = 6;
|
|
4280
|
+
var studioSidebarEntriesContainerVariants = {
|
|
4281
|
+
hidden: {
|
|
4282
|
+
opacity: 0,
|
|
4283
|
+
transition: {
|
|
4284
|
+
duration: STUDIO_SIDEBAR_ENTRIES_OUT_S,
|
|
4285
|
+
ease: STUDIO_SIDEBAR_EASE_EXIT,
|
|
4286
|
+
staggerChildren: 0
|
|
4287
|
+
}
|
|
4288
|
+
},
|
|
4289
|
+
visible: {
|
|
4290
|
+
opacity: 1,
|
|
4291
|
+
transition: {
|
|
4292
|
+
duration: 0.06,
|
|
4293
|
+
ease: STUDIO_SIDEBAR_EASE_ENTER,
|
|
4294
|
+
staggerChildren: STUDIO_SIDEBAR_STAGGER_S,
|
|
4295
|
+
delayChildren: 0.02
|
|
4296
|
+
}
|
|
4297
|
+
}
|
|
4298
|
+
};
|
|
4299
|
+
var studioSidebarEntryItemVariants = {
|
|
4300
|
+
hidden: {
|
|
4301
|
+
opacity: 0,
|
|
4302
|
+
x: -STUDIO_SIDEBAR_CONTENT_NUDGE_PX,
|
|
4303
|
+
scale: 0.99
|
|
4304
|
+
},
|
|
4305
|
+
visible: {
|
|
4306
|
+
opacity: 1,
|
|
4307
|
+
x: 0,
|
|
4308
|
+
scale: 1,
|
|
4309
|
+
transition: {
|
|
4310
|
+
duration: STUDIO_SIDEBAR_ENTRY_ITEM_IN_S,
|
|
4311
|
+
ease: STUDIO_SIDEBAR_EASE_ENTER
|
|
4312
|
+
}
|
|
4313
|
+
}
|
|
4314
|
+
};
|
|
4315
|
+
function studioSidebarEntriesTransition(visible, reduced) {
|
|
4316
|
+
if (reduced) return { duration: 0.01 };
|
|
4317
|
+
return visible ? { duration: 0.06, ease: STUDIO_SIDEBAR_EASE_ENTER } : { duration: STUDIO_SIDEBAR_ENTRIES_OUT_S, ease: STUDIO_SIDEBAR_EASE_EXIT };
|
|
4318
|
+
}
|
|
4319
|
+
function studioSidebarWidthTransition(reduced, direction = "collapse") {
|
|
4320
|
+
if (reduced) return { duration: 0.01 };
|
|
4321
|
+
return {
|
|
4322
|
+
duration: direction === "expand" ? STUDIO_SIDEBAR_WIDTH_S : STUDIO_SIDEBAR_WIDTH_S * 0.94,
|
|
4323
|
+
ease: direction === "expand" ? STUDIO_SIDEBAR_EASE_ENTER : STUDIO_SIDEBAR_EASE_EXIT
|
|
4324
|
+
};
|
|
4325
|
+
}
|
|
4326
|
+
function studioSidebarDrawerTransition(reduced) {
|
|
4327
|
+
if (reduced) return { duration: 0.01 };
|
|
4328
|
+
return {
|
|
4329
|
+
duration: 0.22,
|
|
4330
|
+
ease: STUDIO_SIDEBAR_EASE
|
|
4331
|
+
};
|
|
4332
|
+
}
|
|
4333
|
+
function studioSidebarBackdropTransition(reduced) {
|
|
4334
|
+
if (reduced) return { duration: 0.01 };
|
|
4335
|
+
return { duration: 0.16, ease: STUDIO_SIDEBAR_EASE_EXIT };
|
|
4336
|
+
}
|
|
4337
|
+
|
|
4338
|
+
// src/hooks/use-sidebar-collapse-phase.ts
|
|
4339
|
+
var import_react29 = require("react");
|
|
4340
|
+
var WIDTH_OVERLAP_FRAC = 0.7;
|
|
4341
|
+
function useSidebarCollapsePhase(collapsed, reducedMotion) {
|
|
4342
|
+
const [widthCollapsed, setWidthCollapsed] = (0, import_react29.useState)(collapsed);
|
|
4343
|
+
const [entriesVisible, setEntriesVisible] = (0, import_react29.useState)(true);
|
|
4344
|
+
const collapsedTarget = (0, import_react29.useRef)(collapsed);
|
|
4345
|
+
const isFirstRender = (0, import_react29.useRef)(true);
|
|
4346
|
+
const widthTimerRef = (0, import_react29.useRef)(null);
|
|
4347
|
+
const revealTimerRef = (0, import_react29.useRef)(null);
|
|
4348
|
+
(0, import_react29.useEffect)(() => {
|
|
4349
|
+
collapsedTarget.current = collapsed;
|
|
4350
|
+
}, [collapsed]);
|
|
4351
|
+
const clearWidthTimer = () => {
|
|
4352
|
+
if (widthTimerRef.current !== null) {
|
|
4353
|
+
clearTimeout(widthTimerRef.current);
|
|
4354
|
+
widthTimerRef.current = null;
|
|
4355
|
+
}
|
|
4356
|
+
};
|
|
4357
|
+
const clearRevealTimer = () => {
|
|
4358
|
+
if (revealTimerRef.current !== null) {
|
|
4359
|
+
clearTimeout(revealTimerRef.current);
|
|
4360
|
+
revealTimerRef.current = null;
|
|
4361
|
+
}
|
|
4362
|
+
};
|
|
4363
|
+
const applyWidthTarget = (0, import_react29.useCallback)(() => {
|
|
4364
|
+
const willExpand = !collapsedTarget.current;
|
|
4365
|
+
setWidthCollapsed(collapsedTarget.current);
|
|
4366
|
+
clearRevealTimer();
|
|
4367
|
+
if (willExpand && !reducedMotion) {
|
|
4368
|
+
revealTimerRef.current = setTimeout(
|
|
4369
|
+
() => setEntriesVisible(true),
|
|
4370
|
+
STUDIO_SIDEBAR_WIDTH_S * 1e3 * STUDIO_SIDEBAR_EXPAND_REVEAL_FRAC
|
|
4371
|
+
);
|
|
4372
|
+
}
|
|
4373
|
+
}, [reducedMotion]);
|
|
4374
|
+
(0, import_react29.useEffect)(() => {
|
|
4375
|
+
clearWidthTimer();
|
|
4376
|
+
clearRevealTimer();
|
|
4377
|
+
if (reducedMotion) {
|
|
4378
|
+
setWidthCollapsed(collapsed);
|
|
4379
|
+
setEntriesVisible(true);
|
|
4380
|
+
return;
|
|
4381
|
+
}
|
|
4382
|
+
if (isFirstRender.current) {
|
|
4383
|
+
isFirstRender.current = false;
|
|
4384
|
+
setWidthCollapsed(collapsed);
|
|
4385
|
+
setEntriesVisible(true);
|
|
4386
|
+
return;
|
|
4387
|
+
}
|
|
4388
|
+
setEntriesVisible(false);
|
|
4389
|
+
widthTimerRef.current = setTimeout(
|
|
4390
|
+
applyWidthTarget,
|
|
4391
|
+
STUDIO_SIDEBAR_ENTRIES_OUT_S * 1e3 * WIDTH_OVERLAP_FRAC
|
|
4392
|
+
);
|
|
4393
|
+
return () => {
|
|
4394
|
+
clearWidthTimer();
|
|
4395
|
+
clearRevealTimer();
|
|
4396
|
+
};
|
|
4397
|
+
}, [collapsed, reducedMotion, applyWidthTarget]);
|
|
4398
|
+
const onEntriesBlurOutComplete = (0, import_react29.useCallback)(() => {
|
|
4399
|
+
applyWidthTarget();
|
|
4400
|
+
}, [applyWidthTarget]);
|
|
4401
|
+
const onPanelWidthComplete = (0, import_react29.useCallback)(() => {
|
|
4402
|
+
clearRevealTimer();
|
|
4403
|
+
setEntriesVisible(true);
|
|
4404
|
+
}, []);
|
|
4405
|
+
const isCollapsedRail = widthCollapsed;
|
|
4406
|
+
return {
|
|
4407
|
+
widthCollapsed,
|
|
4408
|
+
isCollapsedRail,
|
|
4409
|
+
entriesVisible,
|
|
4410
|
+
onEntriesBlurOutComplete,
|
|
4411
|
+
onPanelWidthComplete
|
|
4412
|
+
};
|
|
4413
|
+
}
|
|
4414
|
+
|
|
4415
|
+
// src/components/studio/sidebar-backdrop.tsx
|
|
4416
|
+
var import_react30 = require("motion/react");
|
|
4417
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
4418
|
+
var StudioSidebarBackdrop = ({
|
|
4419
|
+
open,
|
|
4420
|
+
onClose
|
|
4421
|
+
}) => {
|
|
4422
|
+
const reducedMotion = (0, import_react30.useReducedMotion)();
|
|
4423
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_react30.AnimatePresence, { children: open ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
4424
|
+
import_react30.motion.button,
|
|
4425
|
+
{
|
|
4426
|
+
type: "button",
|
|
4427
|
+
className: "fixed inset-0 z-40 bg-foreground/30 backdrop-blur-[2px] md:hidden",
|
|
4428
|
+
"aria-label": "Close menu",
|
|
4429
|
+
initial: { opacity: 0 },
|
|
4430
|
+
animate: { opacity: 1 },
|
|
4431
|
+
exit: { opacity: 0 },
|
|
4432
|
+
transition: studioSidebarBackdropTransition(!!reducedMotion),
|
|
4433
|
+
onClick: onClose
|
|
4434
|
+
}
|
|
4435
|
+
) : null });
|
|
4436
|
+
};
|
|
4437
|
+
|
|
4438
|
+
// src/components/studio/sidebar-context.tsx
|
|
4439
|
+
var import_react31 = require("react");
|
|
4440
|
+
var StudioSidebarContext = (0, import_react31.createContext)({
|
|
4441
|
+
collapsed: false,
|
|
4442
|
+
isMobile: false,
|
|
4443
|
+
isCollapsedRail: false,
|
|
4444
|
+
iconOnlyLayout: false
|
|
4445
|
+
});
|
|
4446
|
+
function useStudioSidebarLayout() {
|
|
4447
|
+
return (0, import_react31.useContext)(StudioSidebarContext);
|
|
4448
|
+
}
|
|
4449
|
+
|
|
4450
|
+
// src/components/studio/sidebar.tsx
|
|
4451
|
+
var import_react35 = require("react");
|
|
4452
|
+
var import_react36 = require("motion/react");
|
|
4453
|
+
|
|
4454
|
+
// src/components/studio/sidebar-entries.tsx
|
|
4455
|
+
var import_react32 = require("motion/react");
|
|
4456
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
4457
|
+
var StudioSidebarEntries = ({
|
|
4458
|
+
visible,
|
|
4459
|
+
onBlurOutComplete,
|
|
4460
|
+
children,
|
|
4461
|
+
className
|
|
4462
|
+
}) => {
|
|
4463
|
+
const reducedMotion = (0, import_react32.useReducedMotion)();
|
|
4464
|
+
if (reducedMotion) {
|
|
4465
|
+
return visible ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn("flex min-h-0 flex-1 flex-col", className), children }) : null;
|
|
4466
|
+
}
|
|
4467
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
4468
|
+
import_react32.motion.div,
|
|
4469
|
+
{
|
|
4470
|
+
className: cn("flex min-h-0 flex-1 flex-col", className),
|
|
4471
|
+
initial: false,
|
|
4472
|
+
variants: studioSidebarEntriesContainerVariants,
|
|
4473
|
+
animate: visible ? "visible" : "hidden",
|
|
4474
|
+
transition: studioSidebarEntriesTransition(visible, false),
|
|
4475
|
+
onAnimationComplete: (definition) => {
|
|
4476
|
+
if (definition === "hidden") {
|
|
4477
|
+
onBlurOutComplete();
|
|
4478
|
+
}
|
|
4479
|
+
},
|
|
4480
|
+
style: { pointerEvents: visible ? "auto" : "none" },
|
|
4481
|
+
"aria-hidden": !visible,
|
|
4482
|
+
children
|
|
4483
|
+
}
|
|
4484
|
+
);
|
|
4485
|
+
};
|
|
4486
|
+
|
|
4487
|
+
// src/components/studio/sidebar-footer.tsx
|
|
4488
|
+
var import_lucide_react10 = require("lucide-react");
|
|
4489
|
+
|
|
4490
|
+
// src/auth/provider.tsx
|
|
4491
|
+
var import_react33 = require("react");
|
|
4492
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
4279
4493
|
function isInsideIframe() {
|
|
4280
4494
|
try {
|
|
4281
4495
|
return typeof window !== "undefined" && window.self !== window.top;
|
|
@@ -4283,22 +4497,26 @@ function isInsideIframe() {
|
|
|
4283
4497
|
return true;
|
|
4284
4498
|
}
|
|
4285
4499
|
}
|
|
4286
|
-
var SessionContext = (0,
|
|
4500
|
+
var SessionContext = (0, import_react33.createContext)(void 0);
|
|
4287
4501
|
var useSession = () => {
|
|
4288
|
-
const context = (0,
|
|
4502
|
+
const context = (0, import_react33.useContext)(SessionContext);
|
|
4289
4503
|
if (context === void 0) {
|
|
4290
4504
|
throw new Error("useSession must be used within a SessionProvider");
|
|
4291
4505
|
}
|
|
4292
4506
|
return context;
|
|
4293
4507
|
};
|
|
4508
|
+
var useOptionalSession = () => {
|
|
4509
|
+
const context = (0, import_react33.useContext)(SessionContext);
|
|
4510
|
+
return context ?? null;
|
|
4511
|
+
};
|
|
4294
4512
|
var SessionProvider = ({
|
|
4295
4513
|
children,
|
|
4296
4514
|
enabled = true
|
|
4297
4515
|
}) => {
|
|
4298
|
-
const [user, setUser] = (0,
|
|
4299
|
-
const [loading, setLoading] = (0,
|
|
4300
|
-
const [embedded] = (0,
|
|
4301
|
-
(0,
|
|
4516
|
+
const [user, setUser] = (0, import_react33.useState)(null);
|
|
4517
|
+
const [loading, setLoading] = (0, import_react33.useState)(enabled);
|
|
4518
|
+
const [embedded] = (0, import_react33.useState)(isInsideIframe);
|
|
4519
|
+
(0, import_react33.useEffect)(() => {
|
|
4302
4520
|
if (!enabled) {
|
|
4303
4521
|
setLoading(false);
|
|
4304
4522
|
return;
|
|
@@ -4359,7 +4577,7 @@ var SessionProvider = ({
|
|
|
4359
4577
|
messageCleanup?.();
|
|
4360
4578
|
};
|
|
4361
4579
|
}, [enabled, embedded]);
|
|
4362
|
-
const logout = (0,
|
|
4580
|
+
const logout = (0, import_react33.useCallback)(() => {
|
|
4363
4581
|
clearTokens();
|
|
4364
4582
|
setUser(null);
|
|
4365
4583
|
const returnTo = encodeURIComponent(
|
|
@@ -4369,7 +4587,7 @@ var SessionProvider = ({
|
|
|
4369
4587
|
() => window.location.href = `/api/auth/login?return_to=${returnTo}`
|
|
4370
4588
|
);
|
|
4371
4589
|
}, []);
|
|
4372
|
-
return /* @__PURE__ */ (0,
|
|
4590
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
4373
4591
|
SessionContext.Provider,
|
|
4374
4592
|
{
|
|
4375
4593
|
value: {
|
|
@@ -4384,9 +4602,1134 @@ var SessionProvider = ({
|
|
|
4384
4602
|
);
|
|
4385
4603
|
};
|
|
4386
4604
|
|
|
4605
|
+
// src/components/studio/sidebar-layout.ts
|
|
4606
|
+
function studioSidebarIconOnlyLayout(isMobile, isCollapsedRail) {
|
|
4607
|
+
if (isMobile) return false;
|
|
4608
|
+
return isCollapsedRail;
|
|
4609
|
+
}
|
|
4610
|
+
var studioSidebarCollapsedRailInsetClass = "box-border w-full px-1.5";
|
|
4611
|
+
var studioSidebarCollapsedRailChipRowClass = "flex w-full justify-center";
|
|
4612
|
+
function studioSidebarNavItemClasses(iconOnly, isActive) {
|
|
4613
|
+
if (iconOnly) {
|
|
4614
|
+
return cn(
|
|
4615
|
+
studioSidebarNavItemClass,
|
|
4616
|
+
studioSidebarNavItemLayout(true),
|
|
4617
|
+
isActive ? studioSidebarCollapsedRailItemActiveClass : studioSidebarCollapsedRailItemIdleClass
|
|
4618
|
+
);
|
|
4619
|
+
}
|
|
4620
|
+
return cn(
|
|
4621
|
+
studioSidebarNavItemClass,
|
|
4622
|
+
studioSidebarNavItemLayout(false),
|
|
4623
|
+
isActive ? studioSidebarNavItemActiveClass : studioSidebarNavItemIdleClass
|
|
4624
|
+
);
|
|
4625
|
+
}
|
|
4626
|
+
|
|
4627
|
+
// src/components/studio/sidebar-entry-motion.tsx
|
|
4628
|
+
var import_react34 = require("motion/react");
|
|
4629
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
4630
|
+
var StudioSidebarEntryMotion = ({
|
|
4631
|
+
children,
|
|
4632
|
+
className
|
|
4633
|
+
}) => {
|
|
4634
|
+
const reducedMotion = (0, import_react34.useReducedMotion)();
|
|
4635
|
+
if (reducedMotion) {
|
|
4636
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className, children });
|
|
4637
|
+
}
|
|
4638
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_react34.motion.div, { variants: studioSidebarEntryItemVariants, className: cn(className), children });
|
|
4639
|
+
};
|
|
4640
|
+
|
|
4641
|
+
// src/components/studio/sidebar-tooltip.tsx
|
|
4642
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
4643
|
+
var StudioSidebarTooltip = ({
|
|
4644
|
+
label,
|
|
4645
|
+
enabled,
|
|
4646
|
+
children
|
|
4647
|
+
}) => {
|
|
4648
|
+
if (!enabled) return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_jsx_runtime35.Fragment, { children });
|
|
4649
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Tooltip, { children: [
|
|
4650
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipTrigger, { asChild: true, children }),
|
|
4651
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipContent, { side: "right", className: "text-xs", children: label })
|
|
4652
|
+
] });
|
|
4653
|
+
};
|
|
4654
|
+
|
|
4655
|
+
// src/components/studio/sidebar-footer.tsx
|
|
4656
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
4657
|
+
function userInitials(name, email) {
|
|
4658
|
+
const fromName = name.trim().split(/\s+/).map((part) => part.charAt(0)).join("").slice(0, 2).toUpperCase();
|
|
4659
|
+
if (fromName) return fromName;
|
|
4660
|
+
return email.charAt(0).toUpperCase() || "?";
|
|
4661
|
+
}
|
|
4662
|
+
var StudioSidebarFooter = ({
|
|
4663
|
+
iconOnlyLayout,
|
|
4664
|
+
showTooltips,
|
|
4665
|
+
onSignOut,
|
|
4666
|
+
emptyCaption = null
|
|
4667
|
+
}) => {
|
|
4668
|
+
const session = useOptionalSession();
|
|
4669
|
+
const user = session?.user ?? null;
|
|
4670
|
+
const handleSignOut = () => {
|
|
4671
|
+
session?.logout();
|
|
4672
|
+
onSignOut?.();
|
|
4673
|
+
};
|
|
4674
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(StudioSidebarEntryMotion, { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
4675
|
+
"footer",
|
|
4676
|
+
{
|
|
4677
|
+
className: cn(
|
|
4678
|
+
"mt-auto w-full shrink-0 py-2.5",
|
|
4679
|
+
iconOnlyLayout ? studioSidebarCollapsedRailInsetClass : "px-2.5"
|
|
4680
|
+
),
|
|
4681
|
+
children: user ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
4682
|
+
iconOnlyLayout ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: studioSidebarCollapsedRailChipRowClass, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(Avatar, { size: "sm", className: "size-8", children: [
|
|
4683
|
+
user.user_photo_url ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AvatarImage, { src: user.user_photo_url, alt: user.user_name }) : null,
|
|
4684
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AvatarFallback, { className: "text-[10px]", children: userInitials(user.user_name, user.user_email) })
|
|
4685
|
+
] }) }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex min-w-0 items-center gap-2.5", children: [
|
|
4686
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(Avatar, { size: "sm", children: [
|
|
4687
|
+
user.user_photo_url ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AvatarImage, { src: user.user_photo_url, alt: user.user_name }) : null,
|
|
4688
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AvatarFallback, { children: userInitials(user.user_name, user.user_email) })
|
|
4689
|
+
] }),
|
|
4690
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
4691
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "truncate text-sm font-medium text-foreground", children: user.user_name }),
|
|
4692
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "truncate text-xs text-muted-foreground", children: user.user_email })
|
|
4693
|
+
] })
|
|
4694
|
+
] }),
|
|
4695
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
4696
|
+
"div",
|
|
4697
|
+
{
|
|
4698
|
+
className: iconOnlyLayout ? studioSidebarCollapsedRailChipRowClass : void 0,
|
|
4699
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(StudioSidebarTooltip, { label: "Sign out", enabled: showTooltips, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
4700
|
+
"button",
|
|
4701
|
+
{
|
|
4702
|
+
type: "button",
|
|
4703
|
+
onClick: handleSignOut,
|
|
4704
|
+
className: cn(
|
|
4705
|
+
studioSidebarNavItemClasses(iconOnlyLayout, false),
|
|
4706
|
+
iconOnlyLayout && "inline-flex"
|
|
4707
|
+
),
|
|
4708
|
+
"aria-label": "Sign out",
|
|
4709
|
+
children: [
|
|
4710
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react10.LogOut, { className: "size-3.5 shrink-0" }),
|
|
4711
|
+
!iconOnlyLayout ? "Sign out" : null
|
|
4712
|
+
]
|
|
4713
|
+
}
|
|
4714
|
+
) })
|
|
4715
|
+
}
|
|
4716
|
+
)
|
|
4717
|
+
] }) : !iconOnlyLayout && emptyCaption ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "px-1 text-xs text-muted-foreground", children: emptyCaption }) : null
|
|
4718
|
+
}
|
|
4719
|
+
) });
|
|
4720
|
+
};
|
|
4721
|
+
|
|
4722
|
+
// src/components/studio/sidebar-header.tsx
|
|
4723
|
+
var import_lucide_react11 = require("lucide-react");
|
|
4724
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
4725
|
+
var sidebarHeaderClass = "flex h-12 shrink-0 items-center px-2";
|
|
4726
|
+
var toggleButtonClass = cn(
|
|
4727
|
+
"flex shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors",
|
|
4728
|
+
"hover:bg-muted hover:text-foreground",
|
|
4729
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15"
|
|
4730
|
+
);
|
|
4731
|
+
var SidebarToggleButton = ({ ariaLabel, expanded, onClick, children }) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
4732
|
+
"button",
|
|
4733
|
+
{
|
|
4734
|
+
type: "button",
|
|
4735
|
+
onClick,
|
|
4736
|
+
className: cn(toggleButtonClass, "size-7"),
|
|
4737
|
+
"aria-label": ariaLabel,
|
|
4738
|
+
"aria-expanded": expanded,
|
|
4739
|
+
children
|
|
4740
|
+
}
|
|
4741
|
+
);
|
|
4742
|
+
var CollapsedBrandToggle = ({
|
|
4743
|
+
onExpand,
|
|
4744
|
+
brand
|
|
4745
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: studioSidebarCollapsedRailChipRowClass, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(StudioSidebarTooltip, { label: "Expand sidebar", enabled: true, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
4746
|
+
"button",
|
|
4747
|
+
{
|
|
4748
|
+
type: "button",
|
|
4749
|
+
onClick: onExpand,
|
|
4750
|
+
"aria-label": "Expand sidebar",
|
|
4751
|
+
"aria-expanded": false,
|
|
4752
|
+
className: cn(
|
|
4753
|
+
toggleButtonClass,
|
|
4754
|
+
"group relative inline-flex size-8 items-center justify-center overflow-hidden rounded-lg"
|
|
4755
|
+
),
|
|
4756
|
+
children: [
|
|
4757
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
4758
|
+
"span",
|
|
4759
|
+
{
|
|
4760
|
+
"aria-hidden": true,
|
|
4761
|
+
className: cn(
|
|
4762
|
+
"pointer-events-none flex items-center justify-center",
|
|
4763
|
+
"transition-[opacity,transform] duration-200 ease-out",
|
|
4764
|
+
"group-hover:scale-90 group-hover:opacity-0"
|
|
4765
|
+
),
|
|
4766
|
+
children: brand
|
|
4767
|
+
}
|
|
4768
|
+
),
|
|
4769
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
4770
|
+
import_lucide_react11.ChevronRight,
|
|
4771
|
+
{
|
|
4772
|
+
"aria-hidden": true,
|
|
4773
|
+
className: cn(
|
|
4774
|
+
"pointer-events-none absolute inset-0 m-auto size-4",
|
|
4775
|
+
"opacity-0 transition-[opacity,transform] duration-200 ease-out",
|
|
4776
|
+
"group-hover:opacity-100"
|
|
4777
|
+
)
|
|
4778
|
+
}
|
|
4779
|
+
)
|
|
4780
|
+
]
|
|
4781
|
+
}
|
|
4782
|
+
) }) });
|
|
4783
|
+
var StudioSidebarHeader = ({
|
|
4784
|
+
isCollapsedRail,
|
|
4785
|
+
isMobile,
|
|
4786
|
+
mobileOpen,
|
|
4787
|
+
onToggle,
|
|
4788
|
+
brand
|
|
4789
|
+
}) => {
|
|
4790
|
+
if (isMobile) {
|
|
4791
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("header", { className: cn(sidebarHeaderClass, "justify-between gap-2 pr-2"), children: [
|
|
4792
|
+
brand,
|
|
4793
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
4794
|
+
SidebarToggleButton,
|
|
4795
|
+
{
|
|
4796
|
+
ariaLabel: "Close menu",
|
|
4797
|
+
expanded: mobileOpen,
|
|
4798
|
+
onClick: onToggle,
|
|
4799
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react11.X, { className: "size-3.5" })
|
|
4800
|
+
}
|
|
4801
|
+
)
|
|
4802
|
+
] });
|
|
4803
|
+
}
|
|
4804
|
+
if (isCollapsedRail) {
|
|
4805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
4806
|
+
"header",
|
|
4807
|
+
{
|
|
4808
|
+
className: cn(
|
|
4809
|
+
"flex h-12 shrink-0 items-center",
|
|
4810
|
+
studioSidebarCollapsedRailInsetClass
|
|
4811
|
+
),
|
|
4812
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CollapsedBrandToggle, { onExpand: onToggle, brand })
|
|
4813
|
+
}
|
|
4814
|
+
);
|
|
4815
|
+
}
|
|
4816
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("header", { className: cn(sidebarHeaderClass, "justify-between gap-1 pr-2"), children: [
|
|
4817
|
+
brand,
|
|
4818
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
4819
|
+
SidebarToggleButton,
|
|
4820
|
+
{
|
|
4821
|
+
ariaLabel: "Collapse sidebar",
|
|
4822
|
+
expanded: true,
|
|
4823
|
+
onClick: onToggle,
|
|
4824
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react11.ChevronLeft, { className: "size-4" })
|
|
4825
|
+
}
|
|
4826
|
+
)
|
|
4827
|
+
] });
|
|
4828
|
+
};
|
|
4829
|
+
|
|
4830
|
+
// src/components/studio/sidebar-workforce.ts
|
|
4831
|
+
function workforceItemId(w) {
|
|
4832
|
+
return w.id ?? w.uid ?? w.name ?? "";
|
|
4833
|
+
}
|
|
4834
|
+
function workforceItemLabel(w) {
|
|
4835
|
+
return w.name ?? workforceItemId(w);
|
|
4836
|
+
}
|
|
4837
|
+
function workforceItemInitial(w) {
|
|
4838
|
+
const label = workforceItemLabel(w);
|
|
4839
|
+
return label.charAt(0).toUpperCase() || "?";
|
|
4840
|
+
}
|
|
4841
|
+
|
|
4842
|
+
// src/components/studio/sidebar-nav.tsx
|
|
4843
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
4844
|
+
var StudioSidebarNav = ({
|
|
4845
|
+
workforces,
|
|
4846
|
+
selectedId,
|
|
4847
|
+
onSelect,
|
|
4848
|
+
iconOnlyLayout,
|
|
4849
|
+
showTooltips
|
|
4850
|
+
}) => {
|
|
4851
|
+
if (workforces.length === 0) return null;
|
|
4852
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
4853
|
+
"nav",
|
|
4854
|
+
{
|
|
4855
|
+
className: cn(
|
|
4856
|
+
"flex min-h-0 flex-1 flex-col overflow-y-auto py-1",
|
|
4857
|
+
iconOnlyLayout ? cn(studioSidebarCollapsedRailInsetClass, "gap-1") : "gap-0.5 px-2"
|
|
4858
|
+
),
|
|
4859
|
+
"aria-label": "Agents",
|
|
4860
|
+
children: workforces.map((w) => {
|
|
4861
|
+
const id = workforceItemId(w);
|
|
4862
|
+
const isActive = id === selectedId;
|
|
4863
|
+
const label = workforceItemLabel(w);
|
|
4864
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
4865
|
+
StudioSidebarEntryMotion,
|
|
4866
|
+
{
|
|
4867
|
+
className: iconOnlyLayout ? studioSidebarCollapsedRailChipRowClass : void 0,
|
|
4868
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(StudioSidebarTooltip, { label, enabled: showTooltips, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
4869
|
+
"button",
|
|
4870
|
+
{
|
|
4871
|
+
type: "button",
|
|
4872
|
+
onClick: () => onSelect(id),
|
|
4873
|
+
"aria-pressed": isActive,
|
|
4874
|
+
"aria-label": label,
|
|
4875
|
+
className: cn(
|
|
4876
|
+
studioSidebarNavItemClasses(iconOnlyLayout, isActive),
|
|
4877
|
+
iconOnlyLayout && "inline-flex"
|
|
4878
|
+
),
|
|
4879
|
+
children: iconOnlyLayout ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-xs font-semibold leading-none", children: workforceItemInitial(w) }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "min-w-0 truncate", children: label })
|
|
4880
|
+
}
|
|
4881
|
+
) })
|
|
4882
|
+
},
|
|
4883
|
+
id
|
|
4884
|
+
);
|
|
4885
|
+
})
|
|
4886
|
+
}
|
|
4887
|
+
);
|
|
4888
|
+
};
|
|
4889
|
+
|
|
4890
|
+
// src/components/studio/timbal-mark.tsx
|
|
4891
|
+
var import_shaders_react = require("@paper-design/shaders-react");
|
|
4892
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
4893
|
+
var DEFAULT_SIZE = 64;
|
|
4894
|
+
var TRANSPARENT_BACK = "#00000000";
|
|
4895
|
+
var TIMBAL_SYMBOL_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAACWCAYAAAA8AXHiAAAH6ElEQVR4Aeyci7EcNRBFFxIBIgEygUiASCATyASIBOa4rFrZntmPPq1W93218o5nZyTd26dbmnX5fX3TjxyY4IDAmmCqurzdBJYomOKAwJpiqzoVWGJgigMCa4qt6lRgZWHAWKfAMjY8y3ACK0ukjXUKLGPDswwnsLJE2linwDI2PMtwAitLpI11Cixjw+/DxT4SWLHju0ydwHrP+p/euzzE1T8cKr492lsvgfWaXZj733Hp90fL9Pr1EPvn0QTWYcLoF8bS6Pdf/kjQAAnNv7RqVcW6do4q9ffxMe/HW5oXy323boF1zkvzEnDe3RZnS5X6fcRsBdbdRY6oTl1LAJ1s2NDdXaVq3QLr7kapUph8Pxv/iESiDVUqsG63sgQ0b1Rve/6QQEOrVG1DdrCGbFRrQzc5Zh9FlSKppkw5M1gYi8FTjHXaaalSJNTUKWYEC3P5spP3qeY667zsIadVqVpvNrCoUrTag+jHgIRm0z2ka7AGRpzqNG2jOnCeo7uiSi3RnQEszCVjydzRgfPaH1rRbFqlajMig0WVWmpubbThMRvzJVWq1hgVrFKlgKvWG/2YRHLxpBsNrOVLwCJySSBXT7qRwHKxBCwAiypFWzD09ZARwCpVysUScG318E+oUsv3Uleq3gPrqpd1512bO9GWsockqSYO0971zmBR/mnt6ve7k0RC87KvEV61bEewMNftEvCq8Q3XlSqF/obbbW/ZDSz2UWSs2yVgQvjQimb3VarWvgtYZCnm8uRXzz/6MXq3rM47gLXVEjCI9FKlqNCDurTtxjNYxdytloAB4aM6r65S3TK8grXtEtAZEZZ7Wmc362/3BlapUtsuAY0hDVGlau2ewApnbm30g+OyhySpHly210dewKL80/Zyr2+2JBKaQ+4hV4OFudtvVBv4KlUK/Q23+79lJVjso8jYUEvAk5CjFc0hq1StfQVYZCnm8uRXzyX6MXqbq/Nu5liDFX4JOAGgVCkq9MnHMU9ZgVXMDb8EfIYJ1TlNlaq1W4BFlcpoLss9rfY7zfFMsFSl0mD0pdBZYKXaqFa2so+iSpFU1el8hzPAwlgMzuQmeyl0k1ARdf/zrqiRYGGuq/+C9K4Zb11/v5g9JFCh/342+dEosDCWlslOljs0Z3vSfSnGvWCRpRmf+KhSGXW/BBUX9YCFuWQsmUtfGdo3h0g0q0odRjx6tYAFSFnNZXNOlX7kqT47HGgB67jtJnNv+nnkQCtYj/rUZ3LgFggsRdOTAwLLUzQCzUVgBQqmJykCy1M0As1FYAUKpicpAstTNALNRWAFCqYnKTPB8qRTczF2QGAZG55lOIGVJdLGOgWWseFZhhNYWSJtrFNgGRueZTiBlSXSM3We9C2wTkzRqX4HBFa/h+rhxAGBdWKKTvU7ILD6PVQPJw4IrBNTdKrfAYHV76F6OHFAYJ2Ysv+p9QoE1voYhJyBwAoZ1vWiBNb6GIScgcAKGdb1ogTW+hiEnIHAChnW9aIElk0M0o0isNKF3EawwLLxOd0oAitdyN8W/Ndxx9LfmnyMH/aFuX+EVXct7Lfjox+P9vZLFeu5ZcXcf59fGuYKKhRA8Xtmm0QJrGvbqFJd5l537foTKvN3xwzRf7y1vdKC9cSuUqW6zH0yhsePSaSfR0xMYH3qYvcS8Gl32/yNBPrqmC3vx1v/S2DdPRyyBNy72+aIKkUbOuEWsPg970MnsbizUqWGLAGLtbwzPNWpey91NWALWFd97Xh+qrmODSl7SJJqyjQzg0X5p00x1mmnJBKam79GeFVXRrAwd9oS8KrxC64rVQr904f3A9Z0qR8GYB9Fxk5bAj6M4usPtKJ5epWqZWcBiyzFXJ78av3Rj9G7pDpnAMt0CXBCaqlSVOglU4oMVjHXdAlYEsVPB6U6L6lS9TSigkWVWm5ubbTRMcs9zWi462GigaUqdR1r008igbVso2oasS8HYx9FlSKpvvx00ZkHYC2aUduwGIvBbXfveRd7KXSTUO4U7A4W5g79V3l3ETqfEHtIoEL/+RWLz+4MFsbSFltoOjzLHZrdP+nuCBZZmvGJjyVvG927gVWWADLXtFQsHAytVKmt9pC7gEWVwlz3S8BgANG9TZWqte8AVqlSmFzPPfoxiUSbrnPGAJ7BKkuAqtSMyE/u0ytYW21UB8aIfRRViqQa2K19Vx7BwlgMtndj3Ygs8+gmodbNYuDInsDCXH3ZOTC4K7vyAhbZSlvphfXYLHdoDrmHXA0WVWrLx+lOCnnSDa17JViYS8aSuZ1x2uZ2tKL5cZXaRs71RFeARZVKYe5ntrMxD12lar3WYJUqBVz1PKIfk0ipnnStwEqzBHyWISRQxifdmwVYqZaACiyqFK06ledwJlilSqVaAg50qFJp9lKH3tPXLLCymlv2kCTVqeFZTs4Ai/JPC+ThUykkEprDf43w1ImPF4wEC3MzLgGlSqH/o616GwUW+ygyNtMSgFY0q0qd5FEvWGQp5vLkd9J92FPozVidXw5oD1hZlwASiQr9sskZL2wBK+sSgO6UX3a2JEYrWCyBLePtfA/L387zN517C1imE7wYTKedOyCwnAdo1+kJrF0j53zeAst5gHadnsDaNXLO5y2wnAdo1+kJrF0j53zew8ByrlPTM3ZAYBkbnmU4gZUl0sY6BZax4VmGE1hZIm2sU2AZG55lOIGVJdLDdL7W0f8AAAD//x3VUCQAAAAGSURBVAMArsj7LTb9pqMAAAAASUVORK5CYII=";
|
|
4896
|
+
function TimbalMark({
|
|
4897
|
+
className,
|
|
4898
|
+
size = DEFAULT_SIZE,
|
|
4899
|
+
src = TIMBAL_SYMBOL_DATA_URI
|
|
4900
|
+
}) {
|
|
4901
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
4902
|
+
"div",
|
|
4903
|
+
{
|
|
4904
|
+
className: cn("relative shrink-0 bg-transparent", className),
|
|
4905
|
+
style: { width: size, height: size },
|
|
4906
|
+
role: "img",
|
|
4907
|
+
"aria-label": "Timbal",
|
|
4908
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
4909
|
+
import_shaders_react.LiquidMetal,
|
|
4910
|
+
{
|
|
4911
|
+
width: size,
|
|
4912
|
+
height: size,
|
|
4913
|
+
image: src,
|
|
4914
|
+
colorBack: TRANSPARENT_BACK,
|
|
4915
|
+
colorTint: "#ffffff",
|
|
4916
|
+
shape: "none",
|
|
4917
|
+
repetition: 2,
|
|
4918
|
+
softness: 0.1,
|
|
4919
|
+
shiftRed: 0.3,
|
|
4920
|
+
shiftBlue: 0.3,
|
|
4921
|
+
distortion: 0.07,
|
|
4922
|
+
contour: 0.4,
|
|
4923
|
+
angle: 70,
|
|
4924
|
+
speed: 1,
|
|
4925
|
+
scale: 0.6,
|
|
4926
|
+
fit: "contain",
|
|
4927
|
+
className: "size-full bg-transparent",
|
|
4928
|
+
style: { background: "transparent" },
|
|
4929
|
+
webGlContextAttributes: {
|
|
4930
|
+
alpha: true,
|
|
4931
|
+
premultipliedAlpha: false
|
|
4932
|
+
}
|
|
4933
|
+
}
|
|
4934
|
+
)
|
|
4935
|
+
}
|
|
4936
|
+
);
|
|
4937
|
+
}
|
|
4938
|
+
|
|
4939
|
+
// src/components/studio/sidebar.tsx
|
|
4940
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
4941
|
+
var DEFAULT_BREAKPOINT_PX = 768;
|
|
4942
|
+
function readPersistedCollapsed(key) {
|
|
4943
|
+
if (!key || typeof window === "undefined") return false;
|
|
4944
|
+
try {
|
|
4945
|
+
return window.localStorage.getItem(key) === "1";
|
|
4946
|
+
} catch {
|
|
4947
|
+
return false;
|
|
4948
|
+
}
|
|
4949
|
+
}
|
|
4950
|
+
function writePersistedCollapsed(key, collapsed) {
|
|
4951
|
+
if (!key || typeof window === "undefined") return;
|
|
4952
|
+
try {
|
|
4953
|
+
window.localStorage.setItem(key, collapsed ? "1" : "0");
|
|
4954
|
+
} catch {
|
|
4955
|
+
}
|
|
4956
|
+
}
|
|
4957
|
+
var StudioSidebarPanel = ({
|
|
4958
|
+
workforces,
|
|
4959
|
+
selectedId,
|
|
4960
|
+
onSelect,
|
|
4961
|
+
collapsed,
|
|
4962
|
+
onCollapsedChange,
|
|
4963
|
+
isMobile,
|
|
4964
|
+
mobileOpen,
|
|
4965
|
+
onMobileOpenChange,
|
|
4966
|
+
widthCollapsed,
|
|
4967
|
+
entriesVisible,
|
|
4968
|
+
onEntriesBlurOutComplete,
|
|
4969
|
+
onPanelWidthComplete,
|
|
4970
|
+
brand,
|
|
4971
|
+
emptyCaption = null
|
|
4972
|
+
}) => {
|
|
4973
|
+
const reducedMotion = (0, import_react36.useReducedMotion)();
|
|
4974
|
+
const isCollapsedRail = widthCollapsed && !isMobile;
|
|
4975
|
+
const iconOnlyLayout = studioSidebarIconOnlyLayout(isMobile, isCollapsedRail);
|
|
4976
|
+
const isDrawerOpen = isMobile && mobileOpen;
|
|
4977
|
+
const widthDirection = widthCollapsed ? "collapse" : "expand";
|
|
4978
|
+
const widthTransition = studioSidebarWidthTransition(
|
|
4979
|
+
!!reducedMotion,
|
|
4980
|
+
widthDirection
|
|
4981
|
+
);
|
|
4982
|
+
const handleToggle = () => {
|
|
4983
|
+
if (isMobile) {
|
|
4984
|
+
onMobileOpenChange(false);
|
|
4985
|
+
return;
|
|
4986
|
+
}
|
|
4987
|
+
onCollapsedChange(!collapsed);
|
|
4988
|
+
};
|
|
4989
|
+
const panelWidthPx = isMobile ? SIDEBAR_MOBILE_PX : widthCollapsed ? SIDEBAR_WIDTH_COLLAPSED_PX : SIDEBAR_WIDTH_PX;
|
|
4990
|
+
const brandNode = brand ?? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(TimbalMark, { size: 32 });
|
|
4991
|
+
const panel = /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
4992
|
+
import_react36.motion.div,
|
|
4993
|
+
{
|
|
4994
|
+
"data-sidebar-collapsed": isCollapsedRail ? "" : void 0,
|
|
4995
|
+
className: cn(
|
|
4996
|
+
"flex h-full flex-col overflow-hidden",
|
|
4997
|
+
studioSidebarPanelClass,
|
|
4998
|
+
isMobile ? "rounded-none rounded-r-2xl" : "rounded-2xl"
|
|
4999
|
+
),
|
|
5000
|
+
initial: false,
|
|
5001
|
+
animate: { width: panelWidthPx },
|
|
5002
|
+
transition: widthTransition,
|
|
5003
|
+
style: { willChange: entriesVisible ? void 0 : "width" },
|
|
5004
|
+
onAnimationComplete: isMobile || entriesVisible ? void 0 : () => onPanelWidthComplete(),
|
|
5005
|
+
children: [
|
|
5006
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
5007
|
+
StudioSidebarHeader,
|
|
5008
|
+
{
|
|
5009
|
+
isCollapsedRail,
|
|
5010
|
+
isMobile,
|
|
5011
|
+
mobileOpen,
|
|
5012
|
+
onToggle: handleToggle,
|
|
5013
|
+
brand: brandNode
|
|
5014
|
+
}
|
|
5015
|
+
),
|
|
5016
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
5017
|
+
StudioSidebarEntries,
|
|
5018
|
+
{
|
|
5019
|
+
visible: entriesVisible,
|
|
5020
|
+
onBlurOutComplete: onEntriesBlurOutComplete,
|
|
5021
|
+
children: [
|
|
5022
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
5023
|
+
"div",
|
|
5024
|
+
{
|
|
5025
|
+
id: DOM_IDS.sidebarRuntimeAnchor,
|
|
5026
|
+
className: cn(
|
|
5027
|
+
"min-h-0 shrink-0 empty:hidden",
|
|
5028
|
+
iconOnlyLayout ? "px-1.5 pt-1.5" : "px-2 pt-1.5"
|
|
5029
|
+
)
|
|
5030
|
+
}
|
|
5031
|
+
),
|
|
5032
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
5033
|
+
StudioSidebarNav,
|
|
5034
|
+
{
|
|
5035
|
+
workforces,
|
|
5036
|
+
selectedId,
|
|
5037
|
+
onSelect,
|
|
5038
|
+
iconOnlyLayout,
|
|
5039
|
+
showTooltips: isCollapsedRail
|
|
5040
|
+
}
|
|
5041
|
+
),
|
|
5042
|
+
workforces.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "min-h-0 flex-1" }) : null,
|
|
5043
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
5044
|
+
StudioSidebarFooter,
|
|
5045
|
+
{
|
|
5046
|
+
iconOnlyLayout,
|
|
5047
|
+
showTooltips: isCollapsedRail,
|
|
5048
|
+
onSignOut: isMobile ? () => onMobileOpenChange(false) : void 0,
|
|
5049
|
+
emptyCaption
|
|
5050
|
+
}
|
|
5051
|
+
)
|
|
5052
|
+
]
|
|
5053
|
+
}
|
|
5054
|
+
)
|
|
5055
|
+
]
|
|
5056
|
+
}
|
|
5057
|
+
);
|
|
5058
|
+
if (isMobile) {
|
|
5059
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
5060
|
+
import_react36.motion.aside,
|
|
5061
|
+
{
|
|
5062
|
+
className: "fixed inset-y-0 left-0 z-[60] flex",
|
|
5063
|
+
"aria-label": "Studio navigation",
|
|
5064
|
+
"aria-hidden": !mobileOpen,
|
|
5065
|
+
initial: false,
|
|
5066
|
+
animate: {
|
|
5067
|
+
x: isDrawerOpen ? 0 : -(SIDEBAR_MOBILE_PX + 32)
|
|
5068
|
+
},
|
|
5069
|
+
transition: studioSidebarDrawerTransition(!!reducedMotion),
|
|
5070
|
+
style: { pointerEvents: isDrawerOpen ? "auto" : "none" },
|
|
5071
|
+
children: panel
|
|
5072
|
+
}
|
|
5073
|
+
);
|
|
5074
|
+
}
|
|
5075
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
5076
|
+
"aside",
|
|
5077
|
+
{
|
|
5078
|
+
className: "absolute inset-y-0 left-0 z-[60] flex py-[var(--studio-sidebar-gap)] pl-[var(--studio-sidebar-gap)]",
|
|
5079
|
+
"aria-label": "Studio navigation",
|
|
5080
|
+
children: panel
|
|
5081
|
+
}
|
|
5082
|
+
);
|
|
5083
|
+
};
|
|
5084
|
+
var StudioSidebar = ({
|
|
5085
|
+
workforces: workforcesProp,
|
|
5086
|
+
selectedId: selectedIdProp,
|
|
5087
|
+
onSelect,
|
|
5088
|
+
defaultCollapsed = false,
|
|
5089
|
+
persistKey = STORAGE_KEYS.sidebarCollapsed,
|
|
5090
|
+
mobileBreakpointPx = DEFAULT_BREAKPOINT_PX,
|
|
5091
|
+
brand,
|
|
5092
|
+
emptyCaption,
|
|
5093
|
+
mobileOpen: mobileOpenProp,
|
|
5094
|
+
onMobileOpenChange: onMobileOpenChangeProp
|
|
5095
|
+
}) => {
|
|
5096
|
+
const reducedMotion = (0, import_react36.useReducedMotion)();
|
|
5097
|
+
const fetched = useWorkforces({ enabled: workforcesProp === void 0 });
|
|
5098
|
+
const workforces = workforcesProp ?? fetched.workforces;
|
|
5099
|
+
const [internalSelected, setInternalSelected] = (0, import_react35.useState)(
|
|
5100
|
+
selectedIdProp ?? ""
|
|
5101
|
+
);
|
|
5102
|
+
(0, import_react35.useEffect)(() => {
|
|
5103
|
+
if (selectedIdProp !== void 0) return;
|
|
5104
|
+
if (internalSelected) return;
|
|
5105
|
+
const first = workforces[0]?.id ?? workforces[0]?.uid ?? workforces[0]?.name;
|
|
5106
|
+
if (first) setInternalSelected(first);
|
|
5107
|
+
}, [workforces, selectedIdProp, internalSelected]);
|
|
5108
|
+
const selectedId = selectedIdProp ?? internalSelected ?? workforces[0]?.id ?? workforces[0]?.uid ?? workforces[0]?.name ?? "";
|
|
5109
|
+
const handleSelect = (0, import_react35.useCallback)(
|
|
5110
|
+
(id) => {
|
|
5111
|
+
if (selectedIdProp === void 0) setInternalSelected(id);
|
|
5112
|
+
onSelect?.(id);
|
|
5113
|
+
},
|
|
5114
|
+
[selectedIdProp, onSelect]
|
|
5115
|
+
);
|
|
5116
|
+
const [collapsed, setCollapsed] = (0, import_react35.useState)(() => {
|
|
5117
|
+
const persisted = readPersistedCollapsed(persistKey);
|
|
5118
|
+
return persisted || defaultCollapsed;
|
|
5119
|
+
});
|
|
5120
|
+
const handleCollapsedChange = (0, import_react35.useCallback)(
|
|
5121
|
+
(next) => {
|
|
5122
|
+
setCollapsed(next);
|
|
5123
|
+
writePersistedCollapsed(persistKey, next);
|
|
5124
|
+
},
|
|
5125
|
+
[persistKey]
|
|
5126
|
+
);
|
|
5127
|
+
const [isMobile, setIsMobile] = (0, import_react35.useState)(() => {
|
|
5128
|
+
if (typeof window === "undefined") return false;
|
|
5129
|
+
return window.innerWidth < mobileBreakpointPx;
|
|
5130
|
+
});
|
|
5131
|
+
(0, import_react35.useEffect)(() => {
|
|
5132
|
+
if (typeof window === "undefined") return;
|
|
5133
|
+
const onResize = () => setIsMobile(window.innerWidth < mobileBreakpointPx);
|
|
5134
|
+
onResize();
|
|
5135
|
+
window.addEventListener("resize", onResize);
|
|
5136
|
+
return () => window.removeEventListener("resize", onResize);
|
|
5137
|
+
}, [mobileBreakpointPx]);
|
|
5138
|
+
const [internalMobileOpen, setInternalMobileOpen] = (0, import_react35.useState)(false);
|
|
5139
|
+
const mobileOpen = mobileOpenProp ?? internalMobileOpen;
|
|
5140
|
+
const setMobileOpen = (0, import_react35.useCallback)(
|
|
5141
|
+
(next) => {
|
|
5142
|
+
if (mobileOpenProp === void 0) setInternalMobileOpen(next);
|
|
5143
|
+
onMobileOpenChangeProp?.(next);
|
|
5144
|
+
},
|
|
5145
|
+
[mobileOpenProp, onMobileOpenChangeProp]
|
|
5146
|
+
);
|
|
5147
|
+
const effectiveCollapsed = isMobile ? false : collapsed;
|
|
5148
|
+
const {
|
|
5149
|
+
widthCollapsed,
|
|
5150
|
+
entriesVisible: phaseEntriesVisible,
|
|
5151
|
+
onEntriesBlurOutComplete,
|
|
5152
|
+
onPanelWidthComplete
|
|
5153
|
+
} = useSidebarCollapsePhase(effectiveCollapsed, !!reducedMotion);
|
|
5154
|
+
const entriesVisible = isMobile || phaseEntriesVisible;
|
|
5155
|
+
const isCollapsedRail = widthCollapsed && !isMobile;
|
|
5156
|
+
const iconOnlyLayout = studioSidebarIconOnlyLayout(isMobile, isCollapsedRail);
|
|
5157
|
+
const contextValue = (0, import_react35.useMemo)(
|
|
5158
|
+
() => ({
|
|
5159
|
+
collapsed: effectiveCollapsed,
|
|
5160
|
+
isMobile,
|
|
5161
|
+
isCollapsedRail,
|
|
5162
|
+
iconOnlyLayout
|
|
5163
|
+
}),
|
|
5164
|
+
[effectiveCollapsed, isMobile, isCollapsedRail, iconOnlyLayout]
|
|
5165
|
+
);
|
|
5166
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(StudioSidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
5167
|
+
StudioSidebarPanel,
|
|
5168
|
+
{
|
|
5169
|
+
workforces,
|
|
5170
|
+
selectedId,
|
|
5171
|
+
onSelect: handleSelect,
|
|
5172
|
+
collapsed: effectiveCollapsed,
|
|
5173
|
+
onCollapsedChange: handleCollapsedChange,
|
|
5174
|
+
isMobile,
|
|
5175
|
+
mobileOpen,
|
|
5176
|
+
onMobileOpenChange: setMobileOpen,
|
|
5177
|
+
widthCollapsed,
|
|
5178
|
+
entriesVisible,
|
|
5179
|
+
onEntriesBlurOutComplete,
|
|
5180
|
+
onPanelWidthComplete,
|
|
5181
|
+
brand,
|
|
5182
|
+
emptyCaption
|
|
5183
|
+
}
|
|
5184
|
+
) });
|
|
5185
|
+
};
|
|
5186
|
+
|
|
5187
|
+
// src/components/studio/sidebar-runtime-portal.tsx
|
|
5188
|
+
var import_react37 = require("react");
|
|
5189
|
+
var import_react_dom = require("react-dom");
|
|
5190
|
+
var import_lucide_react12 = require("lucide-react");
|
|
5191
|
+
var import_react38 = require("@assistant-ui/react");
|
|
5192
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
5193
|
+
var StudioSidebarRuntimePortal = ({
|
|
5194
|
+
label = "New chat"
|
|
5195
|
+
}) => {
|
|
5196
|
+
const { iconOnlyLayout } = useStudioSidebarLayout();
|
|
5197
|
+
const hasMessages = (0, import_react38.useThread)((s) => s.messages.length > 0);
|
|
5198
|
+
const { clear } = useTimbalRuntime();
|
|
5199
|
+
const [anchor, setAnchor] = (0, import_react37.useState)(null);
|
|
5200
|
+
const startNewChat = (0, import_react37.useCallback)(() => {
|
|
5201
|
+
clear();
|
|
5202
|
+
}, [clear]);
|
|
5203
|
+
(0, import_react37.useLayoutEffect)(() => {
|
|
5204
|
+
setAnchor(document.getElementById(DOM_IDS.sidebarRuntimeAnchor));
|
|
5205
|
+
}, []);
|
|
5206
|
+
if (!anchor || !hasMessages) return null;
|
|
5207
|
+
const button = /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
|
|
5208
|
+
"button",
|
|
5209
|
+
{
|
|
5210
|
+
type: "button",
|
|
5211
|
+
onClick: startNewChat,
|
|
5212
|
+
"aria-label": label,
|
|
5213
|
+
className: studioSidebarNavItemClasses(iconOnlyLayout, false),
|
|
5214
|
+
children: [
|
|
5215
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react12.MessageSquarePlus, { className: "size-3.5 shrink-0" }),
|
|
5216
|
+
!iconOnlyLayout ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "min-w-0 truncate", children: label }) : null
|
|
5217
|
+
]
|
|
5218
|
+
}
|
|
5219
|
+
);
|
|
5220
|
+
return (0, import_react_dom.createPortal)(
|
|
5221
|
+
iconOnlyLayout ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(Tooltip, { children: [
|
|
5222
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(TooltipTrigger, { asChild: true, children: button }),
|
|
5223
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(TooltipContent, { side: "right", className: "text-xs", children: label })
|
|
5224
|
+
] }) : button,
|
|
5225
|
+
anchor
|
|
5226
|
+
);
|
|
5227
|
+
};
|
|
5228
|
+
|
|
5229
|
+
// src/components/studio/welcome.tsx
|
|
5230
|
+
var import_react39 = require("motion/react");
|
|
5231
|
+
var import_react40 = require("@assistant-ui/react");
|
|
5232
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
5233
|
+
var luxuryEase2 = [0.16, 1, 0.3, 1];
|
|
5234
|
+
var welcomeStagger2 = {
|
|
5235
|
+
initial: {},
|
|
5236
|
+
animate: {
|
|
5237
|
+
transition: { staggerChildren: 0.16, delayChildren: 0.18 }
|
|
5238
|
+
}
|
|
5239
|
+
};
|
|
5240
|
+
var welcomeItem2 = {
|
|
5241
|
+
initial: { opacity: 0, y: 14 },
|
|
5242
|
+
animate: {
|
|
5243
|
+
opacity: 1,
|
|
5244
|
+
y: 0,
|
|
5245
|
+
transition: { duration: 0.9, ease: luxuryEase2 }
|
|
5246
|
+
}
|
|
5247
|
+
};
|
|
5248
|
+
var welcomeIcon2 = {
|
|
5249
|
+
initial: { opacity: 0, y: 10, scale: 0.96 },
|
|
5250
|
+
animate: {
|
|
5251
|
+
opacity: 1,
|
|
5252
|
+
y: 0,
|
|
5253
|
+
scale: 1,
|
|
5254
|
+
transition: { duration: 1.1, ease: luxuryEase2 }
|
|
5255
|
+
}
|
|
5256
|
+
};
|
|
5257
|
+
var StudioWelcome = ({ config, icon }) => {
|
|
5258
|
+
const isEmpty = (0, import_react40.useThread)((s) => s.messages.length === 0);
|
|
5259
|
+
if (!isEmpty) return null;
|
|
5260
|
+
const iconNode = icon ?? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
5261
|
+
TimbalMark,
|
|
5262
|
+
{
|
|
5263
|
+
size: 112,
|
|
5264
|
+
className: "max-md:scale-[0.58] max-md:origin-center"
|
|
5265
|
+
}
|
|
5266
|
+
);
|
|
5267
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
5268
|
+
import_react39.motion.div,
|
|
5269
|
+
{
|
|
5270
|
+
className: "aui-thread-welcome-message flex flex-col items-center justify-center px-2 text-center sm:px-4",
|
|
5271
|
+
variants: welcomeStagger2,
|
|
5272
|
+
initial: "initial",
|
|
5273
|
+
animate: "animate",
|
|
5274
|
+
children: [
|
|
5275
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_react39.motion.div, { variants: welcomeIcon2, className: "mb-4 md:mb-5", children: iconNode }),
|
|
5276
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
5277
|
+
import_react39.motion.h1,
|
|
5278
|
+
{
|
|
5279
|
+
variants: welcomeItem2,
|
|
5280
|
+
className: "aui-thread-welcome-message-inner text-xl font-semibold sm:text-2xl",
|
|
5281
|
+
children: config?.heading ?? "How can I help you today?"
|
|
5282
|
+
}
|
|
5283
|
+
),
|
|
5284
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
5285
|
+
import_react39.motion.p,
|
|
5286
|
+
{
|
|
5287
|
+
variants: welcomeItem2,
|
|
5288
|
+
className: "aui-thread-welcome-message-inner mt-2 text-muted-foreground",
|
|
5289
|
+
children: config?.subheading ?? "Send a message to start a conversation."
|
|
5290
|
+
}
|
|
5291
|
+
)
|
|
5292
|
+
]
|
|
5293
|
+
}
|
|
5294
|
+
) }) });
|
|
5295
|
+
};
|
|
5296
|
+
|
|
5297
|
+
// src/components/studio/studio-shell.tsx
|
|
5298
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
5299
|
+
var import_react43 = require("react");
|
|
5300
|
+
var DEFAULT_BREAKPOINT_PX2 = 768;
|
|
5301
|
+
function readPersistedCollapsed2(key) {
|
|
5302
|
+
if (!key || typeof window === "undefined") return false;
|
|
5303
|
+
try {
|
|
5304
|
+
return window.localStorage.getItem(key) === "1";
|
|
5305
|
+
} catch {
|
|
5306
|
+
return false;
|
|
5307
|
+
}
|
|
5308
|
+
}
|
|
5309
|
+
function writePersistedCollapsed2(key, collapsed) {
|
|
5310
|
+
if (!key || typeof window === "undefined") return;
|
|
5311
|
+
try {
|
|
5312
|
+
window.localStorage.setItem(key, collapsed ? "1" : "0");
|
|
5313
|
+
} catch {
|
|
5314
|
+
}
|
|
5315
|
+
}
|
|
5316
|
+
function makeComposerWithPortal(BaseComposer) {
|
|
5317
|
+
const Resolved = BaseComposer ?? Composer;
|
|
5318
|
+
return function StudioComposerWithSidebar(props) {
|
|
5319
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
|
|
5320
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(StudioSidebarRuntimePortal, {}),
|
|
5321
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Resolved, { ...props })
|
|
5322
|
+
] });
|
|
5323
|
+
};
|
|
5324
|
+
}
|
|
5325
|
+
var TimbalStudioShell = ({
|
|
5326
|
+
workforceId,
|
|
5327
|
+
workforces: workforcesProp,
|
|
5328
|
+
workforcesFetch,
|
|
5329
|
+
workforcesBaseUrl,
|
|
5330
|
+
brand,
|
|
5331
|
+
headerActions,
|
|
5332
|
+
headerStart,
|
|
5333
|
+
defaultCollapsed = false,
|
|
5334
|
+
persistKey = STORAGE_KEYS.sidebarCollapsed,
|
|
5335
|
+
mobileBreakpointPx = DEFAULT_BREAKPOINT_PX2,
|
|
5336
|
+
sidebarEmptyCaption = null,
|
|
5337
|
+
welcome,
|
|
5338
|
+
components,
|
|
5339
|
+
...chatProps
|
|
5340
|
+
}) => {
|
|
5341
|
+
const reducedMotion = (0, import_react42.useReducedMotion)();
|
|
5342
|
+
const shouldFetchWorkforces = !workforceId && workforcesProp === void 0;
|
|
5343
|
+
const fetched = useWorkforces({
|
|
5344
|
+
enabled: shouldFetchWorkforces,
|
|
5345
|
+
fetch: workforcesFetch,
|
|
5346
|
+
baseUrl: workforcesBaseUrl
|
|
5347
|
+
});
|
|
5348
|
+
const workforces = workforcesProp ?? fetched.workforces;
|
|
5349
|
+
const [internalSelected, setInternalSelected] = (0, import_react41.useState)(
|
|
5350
|
+
workforceId ?? ""
|
|
5351
|
+
);
|
|
5352
|
+
(0, import_react41.useEffect)(() => {
|
|
5353
|
+
if (workforceId) return;
|
|
5354
|
+
if (internalSelected) return;
|
|
5355
|
+
const first = workforces[0]?.id ?? workforces[0]?.uid ?? workforces[0]?.name;
|
|
5356
|
+
if (first) setInternalSelected(first);
|
|
5357
|
+
}, [workforces, workforceId, internalSelected]);
|
|
5358
|
+
const activeWorkforceId = workforceId ?? internalSelected ?? fetched.selectedId ?? "";
|
|
5359
|
+
const [collapsed, setCollapsed] = (0, import_react41.useState)(() => {
|
|
5360
|
+
const persisted = readPersistedCollapsed2(persistKey);
|
|
5361
|
+
return persisted || defaultCollapsed;
|
|
5362
|
+
});
|
|
5363
|
+
const [isMobile, setIsMobile] = (0, import_react41.useState)(() => {
|
|
5364
|
+
if (typeof window === "undefined") return false;
|
|
5365
|
+
return window.innerWidth < mobileBreakpointPx;
|
|
5366
|
+
});
|
|
5367
|
+
const [mobileSidebarOpen, setMobileSidebarOpen] = (0, import_react41.useState)(false);
|
|
5368
|
+
(0, import_react41.useEffect)(() => {
|
|
5369
|
+
if (typeof window === "undefined") return;
|
|
5370
|
+
const onResize = () => setIsMobile(window.innerWidth < mobileBreakpointPx);
|
|
5371
|
+
onResize();
|
|
5372
|
+
window.addEventListener("resize", onResize);
|
|
5373
|
+
return () => window.removeEventListener("resize", onResize);
|
|
5374
|
+
}, [mobileBreakpointPx]);
|
|
5375
|
+
(0, import_react41.useEffect)(() => {
|
|
5376
|
+
if (!isMobile) setMobileSidebarOpen(false);
|
|
5377
|
+
}, [isMobile]);
|
|
5378
|
+
(0, import_react41.useEffect)(() => {
|
|
5379
|
+
if (!mobileSidebarOpen) return;
|
|
5380
|
+
const onKeyDown = (e) => {
|
|
5381
|
+
if (e.key === "Escape") setMobileSidebarOpen(false);
|
|
5382
|
+
};
|
|
5383
|
+
window.addEventListener("keydown", onKeyDown);
|
|
5384
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
5385
|
+
}, [mobileSidebarOpen]);
|
|
5386
|
+
const effectiveCollapsed = isMobile ? false : collapsed;
|
|
5387
|
+
const {
|
|
5388
|
+
widthCollapsed,
|
|
5389
|
+
entriesVisible: phaseEntriesVisible,
|
|
5390
|
+
onEntriesBlurOutComplete,
|
|
5391
|
+
onPanelWidthComplete
|
|
5392
|
+
} = useSidebarCollapsePhase(effectiveCollapsed, !!reducedMotion);
|
|
5393
|
+
const entriesVisible = isMobile || phaseEntriesVisible;
|
|
5394
|
+
const isCollapsedRail = widthCollapsed && !isMobile;
|
|
5395
|
+
const iconOnlyLayout = studioSidebarIconOnlyLayout(isMobile, isCollapsedRail);
|
|
5396
|
+
const layoutDirection = widthCollapsed ? "collapse" : "expand";
|
|
5397
|
+
const layoutTransition = studioSidebarWidthTransition(
|
|
5398
|
+
!!reducedMotion,
|
|
5399
|
+
layoutDirection
|
|
5400
|
+
);
|
|
5401
|
+
const desktopInsetPx = widthCollapsed ? SIDEBAR_INSET_PX_COLLAPSED : SIDEBAR_INSET_PX_EXPANDED;
|
|
5402
|
+
const onCollapsedChange = (0, import_react41.useCallback)(
|
|
5403
|
+
(next) => {
|
|
5404
|
+
setCollapsed(next);
|
|
5405
|
+
writePersistedCollapsed2(persistKey, next);
|
|
5406
|
+
},
|
|
5407
|
+
[persistKey]
|
|
5408
|
+
);
|
|
5409
|
+
const handleSelectWorkforce = (0, import_react41.useCallback)(
|
|
5410
|
+
(id) => {
|
|
5411
|
+
if (!workforceId) setInternalSelected(id);
|
|
5412
|
+
if (isMobile) setMobileSidebarOpen(false);
|
|
5413
|
+
},
|
|
5414
|
+
[workforceId, isMobile]
|
|
5415
|
+
);
|
|
5416
|
+
const sidebarContext = (0, import_react41.useMemo)(
|
|
5417
|
+
() => ({
|
|
5418
|
+
collapsed: effectiveCollapsed,
|
|
5419
|
+
isMobile,
|
|
5420
|
+
isCollapsedRail,
|
|
5421
|
+
iconOnlyLayout
|
|
5422
|
+
}),
|
|
5423
|
+
[effectiveCollapsed, isMobile, isCollapsedRail, iconOnlyLayout]
|
|
5424
|
+
);
|
|
5425
|
+
const resolvedComponents = (0, import_react41.useMemo)(() => {
|
|
5426
|
+
const next = { Welcome: StudioWelcome, ...components };
|
|
5427
|
+
next.Composer = makeComposerWithPortal(components?.Composer);
|
|
5428
|
+
return next;
|
|
5429
|
+
}, [components]);
|
|
5430
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(StudioSidebarContext.Provider, { value: sidebarContext, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
5431
|
+
"div",
|
|
5432
|
+
{
|
|
5433
|
+
className: cn(
|
|
5434
|
+
"relative h-dvh overflow-hidden bg-background",
|
|
5435
|
+
isMobile && mobileSidebarOpen && "max-md:overflow-hidden"
|
|
5436
|
+
),
|
|
5437
|
+
style: studioChromeShellStyle,
|
|
5438
|
+
children: [
|
|
5439
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
5440
|
+
"div",
|
|
5441
|
+
{
|
|
5442
|
+
className: "pointer-events-none absolute inset-0 z-0 bg-background",
|
|
5443
|
+
"aria-hidden": true
|
|
5444
|
+
}
|
|
5445
|
+
),
|
|
5446
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
5447
|
+
"div",
|
|
5448
|
+
{
|
|
5449
|
+
className: cn(
|
|
5450
|
+
"pointer-events-none absolute inset-0 z-0",
|
|
5451
|
+
studioPlaygroundGradientClass
|
|
5452
|
+
),
|
|
5453
|
+
"aria-hidden": true
|
|
5454
|
+
}
|
|
5455
|
+
),
|
|
5456
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
5457
|
+
StudioSidebarBackdrop,
|
|
5458
|
+
{
|
|
5459
|
+
open: isMobile && mobileSidebarOpen,
|
|
5460
|
+
onClose: () => setMobileSidebarOpen(false)
|
|
5461
|
+
}
|
|
5462
|
+
),
|
|
5463
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
5464
|
+
StudioSidebarPanel,
|
|
5465
|
+
{
|
|
5466
|
+
workforces,
|
|
5467
|
+
selectedId: activeWorkforceId,
|
|
5468
|
+
onSelect: handleSelectWorkforce,
|
|
5469
|
+
collapsed: effectiveCollapsed,
|
|
5470
|
+
onCollapsedChange,
|
|
5471
|
+
isMobile,
|
|
5472
|
+
mobileOpen: mobileSidebarOpen,
|
|
5473
|
+
onMobileOpenChange: setMobileSidebarOpen,
|
|
5474
|
+
widthCollapsed,
|
|
5475
|
+
entriesVisible,
|
|
5476
|
+
onEntriesBlurOutComplete,
|
|
5477
|
+
onPanelWidthComplete,
|
|
5478
|
+
brand,
|
|
5479
|
+
emptyCaption: sidebarEmptyCaption
|
|
5480
|
+
}
|
|
5481
|
+
),
|
|
5482
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
5483
|
+
import_react42.motion.header,
|
|
5484
|
+
{
|
|
5485
|
+
className: cn(
|
|
5486
|
+
"absolute top-0 right-0 z-40 flex items-start justify-between gap-2",
|
|
5487
|
+
"px-3 pt-[var(--studio-topbar-gap)] md:px-4",
|
|
5488
|
+
"left-0"
|
|
5489
|
+
),
|
|
5490
|
+
initial: false,
|
|
5491
|
+
animate: { left: isMobile ? 0 : desktopInsetPx },
|
|
5492
|
+
transition: layoutTransition,
|
|
5493
|
+
children: [
|
|
5494
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
5495
|
+
"div",
|
|
5496
|
+
{
|
|
5497
|
+
className: cn(
|
|
5498
|
+
"flex min-w-0 flex-1 items-center gap-2",
|
|
5499
|
+
studioTopbarPillHeightClass
|
|
5500
|
+
),
|
|
5501
|
+
children: [
|
|
5502
|
+
isMobile && !mobileSidebarOpen ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
5503
|
+
TimbalV2Button,
|
|
5504
|
+
{
|
|
5505
|
+
variant: "secondary",
|
|
5506
|
+
size: "sm",
|
|
5507
|
+
isIconOnly: true,
|
|
5508
|
+
className: studioTopbarIconPillClass,
|
|
5509
|
+
onClick: () => setMobileSidebarOpen(true),
|
|
5510
|
+
"aria-label": "Open menu",
|
|
5511
|
+
"aria-expanded": false,
|
|
5512
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react13.Menu, { className: "size-4" })
|
|
5513
|
+
}
|
|
5514
|
+
) : null,
|
|
5515
|
+
headerStart
|
|
5516
|
+
]
|
|
5517
|
+
}
|
|
5518
|
+
),
|
|
5519
|
+
headerActions ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "flex shrink-0 items-center gap-1", children: headerActions }) : null
|
|
5520
|
+
]
|
|
5521
|
+
}
|
|
5522
|
+
),
|
|
5523
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
5524
|
+
import_react42.motion.main,
|
|
5525
|
+
{
|
|
5526
|
+
className: cn(
|
|
5527
|
+
"relative z-10 flex h-full min-w-0 flex-col",
|
|
5528
|
+
"pt-[var(--studio-inset-top)]",
|
|
5529
|
+
"px-3 md:px-0"
|
|
5530
|
+
),
|
|
5531
|
+
initial: false,
|
|
5532
|
+
animate: { paddingLeft: isMobile ? 12 : desktopInsetPx },
|
|
5533
|
+
transition: layoutTransition,
|
|
5534
|
+
children: activeWorkforceId ? /* @__PURE__ */ (0, import_react43.createElement)(
|
|
5535
|
+
TimbalChat,
|
|
5536
|
+
{
|
|
5537
|
+
...chatProps,
|
|
5538
|
+
workforceId: activeWorkforceId,
|
|
5539
|
+
key: activeWorkforceId,
|
|
5540
|
+
welcome,
|
|
5541
|
+
components: resolvedComponents,
|
|
5542
|
+
className: cn("min-h-0 flex-1 bg-transparent", chatProps.className)
|
|
5543
|
+
}
|
|
5544
|
+
) : null
|
|
5545
|
+
}
|
|
5546
|
+
)
|
|
5547
|
+
]
|
|
5548
|
+
}
|
|
5549
|
+
) });
|
|
5550
|
+
};
|
|
5551
|
+
|
|
5552
|
+
// src/components/studio/mode-toggle.tsx
|
|
5553
|
+
var import_react44 = require("react");
|
|
5554
|
+
var import_lucide_react14 = require("lucide-react");
|
|
5555
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
5556
|
+
var ModeToggle = ({
|
|
5557
|
+
theme,
|
|
5558
|
+
setTheme,
|
|
5559
|
+
className,
|
|
5560
|
+
label = "Toggle theme"
|
|
5561
|
+
}) => {
|
|
5562
|
+
const isControlled = theme !== void 0;
|
|
5563
|
+
const [internalIsDark, setInternalIsDark] = (0, import_react44.useState)(false);
|
|
5564
|
+
(0, import_react44.useEffect)(() => {
|
|
5565
|
+
if (isControlled) return;
|
|
5566
|
+
if (typeof document === "undefined") return;
|
|
5567
|
+
setInternalIsDark(document.documentElement.classList.contains("dark"));
|
|
5568
|
+
}, [isControlled]);
|
|
5569
|
+
const isDark = isControlled ? theme === "dark" : internalIsDark;
|
|
5570
|
+
const onClick = (0, import_react44.useCallback)(() => {
|
|
5571
|
+
const next = isDark ? "light" : "dark";
|
|
5572
|
+
if (setTheme) {
|
|
5573
|
+
setTheme(next);
|
|
5574
|
+
return;
|
|
5575
|
+
}
|
|
5576
|
+
if (typeof document === "undefined") return;
|
|
5577
|
+
document.documentElement.classList.toggle("dark", next === "dark");
|
|
5578
|
+
setInternalIsDark(next === "dark");
|
|
5579
|
+
}, [isDark, setTheme]);
|
|
5580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
5581
|
+
TimbalV2Button,
|
|
5582
|
+
{
|
|
5583
|
+
variant: "secondary",
|
|
5584
|
+
size: "sm",
|
|
5585
|
+
isIconOnly: true,
|
|
5586
|
+
onClick,
|
|
5587
|
+
className: cn(
|
|
5588
|
+
studioTopbarPillHeightClass,
|
|
5589
|
+
studioTopbarIconPillClass,
|
|
5590
|
+
"relative",
|
|
5591
|
+
className
|
|
5592
|
+
),
|
|
5593
|
+
"aria-label": label,
|
|
5594
|
+
title: label,
|
|
5595
|
+
children: [
|
|
5596
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react14.Sun, { className: "size-3.5 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" }),
|
|
5597
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react14.Moon, { className: "absolute size-3.5 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" }),
|
|
5598
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "sr-only", children: label })
|
|
5599
|
+
]
|
|
5600
|
+
}
|
|
5601
|
+
);
|
|
5602
|
+
};
|
|
5603
|
+
|
|
5604
|
+
// src/artifacts/agent-instructions.ts
|
|
5605
|
+
var ARTIFACT_AGENT_INSTRUCTIONS = `
|
|
5606
|
+
## Rich artifacts (Timbal chat UI)
|
|
5607
|
+
|
|
5608
|
+
When you need charts, tables, choice widgets, or interactive controls, return a **JSON artifact object** instead of plain prose. The chat UI renders these automatically.
|
|
5609
|
+
|
|
5610
|
+
### Delivery channels (either works)
|
|
5611
|
+
|
|
5612
|
+
1. **Tool result (preferred)** \u2014 return a single JSON object (or a JSON string) from a tool. The object must include a string \`type\` field.
|
|
5613
|
+
2. **Inline markdown fence** \u2014 embed the same JSON inside a fenced block:
|
|
5614
|
+
|
|
5615
|
+
\`\`\`timbal-artifact
|
|
5616
|
+
{"type":"chart","data":[{"month":"Jan","sales":120}]}
|
|
5617
|
+
\`\`\`
|
|
5618
|
+
|
|
5619
|
+
The alias \`\`\`timbal\`\`\` is also accepted.
|
|
5620
|
+
|
|
5621
|
+
### Built-in artifact types
|
|
5622
|
+
|
|
5623
|
+
| \`type\` | Use for |
|
|
5624
|
+
|---|---|
|
|
5625
|
+
| \`chart\` | Bar, line, area, or pie charts. Fields: \`data\`, optional \`chartType\`, \`xKey\`, \`dataKey\`, \`title\`, \`unit\`. |
|
|
5626
|
+
| \`table\` | Tabular data. Fields: \`rows\`, optional \`columns\`, \`title\`. |
|
|
5627
|
+
| \`question\` | In-thread multiple choice. Fields: \`options: [{ id, label, description? }]\`, optional \`prompt\`, \`multi\`. User replies are sent back as a normal user message. |
|
|
5628
|
+
| \`html\` | Custom HTML/CSS/JS in an iframe. Fields: \`content\` (HTML document or fragment), optional \`title\`, \`height\`, \`sandboxed\` (default \`true\`; set \`false\` for unrestricted scripts/CDN). |
|
|
5629
|
+
| \`json\` | Fallback structured view. Fields: \`data\`, optional \`title\`. |
|
|
5630
|
+
| \`ui\` | **Interactive UI** composed from a fixed node palette (hover, click, drag). See below. |
|
|
5631
|
+
|
|
5632
|
+
### When to use \`type: "html"\`
|
|
5633
|
+
|
|
5634
|
+
Use \`html\` when the user wants a **rich visual or interactive page** that does not fit the \`ui\` palette \u2014 e.g. styled layouts, SVG graphics, CSS animations, canvas, small games, calculators, or multi-section mockups. Pass a full HTML document or a body fragment in \`content\`.
|
|
5635
|
+
|
|
5636
|
+
- Inline \`<style>\`, \`<script>\`, SVG, and canvas are supported.
|
|
5637
|
+
- Default \`sandboxed: true\` runs in an isolated iframe with scripts enabled.
|
|
5638
|
+
- Set \`sandboxed: false\` only for trusted content that needs external CDN scripts/styles or full DOM freedom.
|
|
5639
|
+
- Prefer \`ui\` when controls should send chat messages or host events; prefer \`html\` for self-contained mini-apps and visual demos.
|
|
5640
|
+
|
|
5641
|
+
### When to use \`type: "ui"\`
|
|
5642
|
+
|
|
5643
|
+
Use a \`ui\` artifact when the user should **hover, click, drag, or adjust controls** in-thread and those actions should integrate with the chat runtime (messages, \`onArtifactEvent\`). For standalone visual/interactive HTML, use \`html\` instead.
|
|
5644
|
+
|
|
5645
|
+
Each \`ui\` artifact has:
|
|
5646
|
+
|
|
5647
|
+
- \`initialState\` \u2014 optional object seeding local state (per widget instance).
|
|
5648
|
+
- \`root\` \u2014 a single node tree (see node kinds below).
|
|
5649
|
+
- optional \`title\` \u2014 card heading.
|
|
5650
|
+
|
|
5651
|
+
**Bindings:** anywhere a primitive is accepted, you may use \`{ "$bind": "dotted.path" }\` to read from \`initialState\` / local state (e.g. \`{ "$bind": "qty" }\`).
|
|
5652
|
+
|
|
5653
|
+
**Actions:** nodes may attach \`onClick\`, \`onChange\`, or \`onDragEnd\` with one action or an array:
|
|
5654
|
+
|
|
5655
|
+
| Action | Shape | Effect |
|
|
5656
|
+
|---|---|---|
|
|
5657
|
+
| User message | \`{ "kind": "message", "text": "..." }\` or \`{ "kind": "message", "text": { "$bind": "path" } }\` | Sends text as the next user message. |
|
|
5658
|
+
| Set state | \`{ "kind": "set", "path": "foo", "value": 1 }\` | Writes local widget state. |
|
|
5659
|
+
| Toggle boolean | \`{ "kind": "toggle", "path": "enabled" }\` | Flips a boolean at \`path\`. |
|
|
5660
|
+
| Host event | \`{ "kind": "emit", "name": "event-name", "payload": { ... } }\` | Bubbles to the host app (\`onArtifactEvent\` on \`<Thread>\`). |
|
|
5661
|
+
|
|
5662
|
+
### \`ui\` node palette (\`root.kind\`)
|
|
5663
|
+
|
|
5664
|
+
| \`kind\` | Purpose | Key fields |
|
|
5665
|
+
|---|---|---|
|
|
5666
|
+
| \`box\` | Layout container | \`children\`, \`direction\` (\`row\`/\`col\`), \`gap\`, \`padding\`, \`align\`, \`justify\`, \`wrap\` |
|
|
5667
|
+
| \`text\` | Body text | \`value\`, optional \`muted\`, \`size\`, \`weight\` |
|
|
5668
|
+
| \`heading\` | Heading | \`value\`, optional \`level\` (1\u20134) |
|
|
5669
|
+
| \`badge\` | Pill label | \`value\`, optional \`tone\` (\`default\`, \`primary\`, \`success\`, \`warn\`, \`danger\`) |
|
|
5670
|
+
| \`button\` | Clickable button | \`label\`, optional \`variant\`, \`size\`, \`disabled\`, \`onClick\` |
|
|
5671
|
+
| \`toggle\` | Boolean switch | \`binding\` (state path), optional \`label\`, \`onChange\` |
|
|
5672
|
+
| \`slider\` | Numeric range | \`binding\`, optional \`min\`, \`max\`, \`step\`, \`label\`, \`showValue\`, \`onChange\` |
|
|
5673
|
+
| \`tooltip\` | Hover tooltip | \`content\`, \`child\` (single node), optional \`side\` |
|
|
5674
|
+
| \`draggable\` | Drag gesture | \`child\`, optional \`axis\` (\`x\`/\`y\`/\`both\`), \`snapBack\`, \`onDragEnd\` |
|
|
5675
|
+
| \`custom\` | Host-registered widget | \`name\`, optional \`props\`, \`children\` \u2014 only if the app registered that name |
|
|
5676
|
+
|
|
5677
|
+
### Example \`ui\` artifact
|
|
5678
|
+
|
|
5679
|
+
\`\`\`json
|
|
5680
|
+
{
|
|
5681
|
+
"type": "ui",
|
|
5682
|
+
"title": "Configure plan",
|
|
5683
|
+
"initialState": { "qty": 1, "premium": false },
|
|
5684
|
+
"root": {
|
|
5685
|
+
"kind": "box",
|
|
5686
|
+
"direction": "col",
|
|
5687
|
+
"gap": 3,
|
|
5688
|
+
"children": [
|
|
5689
|
+
{ "kind": "heading", "value": "Choose quantity", "level": 3 },
|
|
5690
|
+
{
|
|
5691
|
+
"kind": "tooltip",
|
|
5692
|
+
"content": "Drag to adjust quantity",
|
|
5693
|
+
"child": {
|
|
5694
|
+
"kind": "slider",
|
|
5695
|
+
"binding": "qty",
|
|
5696
|
+
"min": 1,
|
|
5697
|
+
"max": 50,
|
|
5698
|
+
"label": "Quantity",
|
|
5699
|
+
"onChange": { "kind": "emit", "name": "qty-changed" }
|
|
5700
|
+
}
|
|
5701
|
+
},
|
|
5702
|
+
{ "kind": "toggle", "binding": "premium", "label": "Premium support" },
|
|
5703
|
+
{
|
|
5704
|
+
"kind": "button",
|
|
5705
|
+
"label": "Confirm",
|
|
5706
|
+
"onClick": { "kind": "message", "text": { "$bind": "qty" } }
|
|
5707
|
+
}
|
|
5708
|
+
]
|
|
5709
|
+
}
|
|
5710
|
+
}
|
|
5711
|
+
\`\`\`
|
|
5712
|
+
|
|
5713
|
+
### Rules
|
|
5714
|
+
|
|
5715
|
+
- Always set \`type\` to a built-in value above unless the app documented a custom type.
|
|
5716
|
+
- Prefer \`ui\` over \`html\` when actions must bubble to the host chat (\`message\`, \`emit\`).
|
|
5717
|
+
- Prefer \`question\` for simple A/B/C choices; use \`ui\` when you need sliders, toggles, drag, or multi-control layouts.
|
|
5718
|
+
- Keep \`data\` arrays reasonably small (charts/tables).
|
|
5719
|
+
|
|
5720
|
+
### After calling an artifact tool (critical)
|
|
5721
|
+
|
|
5722
|
+
When you call a tool that returns an artifact (\`make_chart\`, \`ask_question\`, \`show_table\`, \`show_html\`, \`make_ui_demo\`, etc.):
|
|
5723
|
+
|
|
5724
|
+
1. **Do not** paste, quote, paraphrase as JSON, or fence the tool return value in your assistant message. The chat UI already renders it from the tool result.
|
|
5725
|
+
2. **Do not** emit a matching \`\`\`timbal-artifact\`\`\` block for the same payload \u2014 pick **one** channel (tool result only).
|
|
5726
|
+
3. Your follow-up text should be **empty**, or at most **one short sentence** (e.g. "Pick an option above." / "Try the controls."). Never include \`type\`, \`options\`, \`data\`, or dict/JSON syntax.
|
|
5727
|
+
4. Treat the widget as visible to the user; refer to it as "above" / "the chart" / "the choices" \u2014 never reproduce its contents.
|
|
5728
|
+
`.trim();
|
|
5729
|
+
|
|
4387
5730
|
// src/auth/guard.tsx
|
|
4388
|
-
var
|
|
4389
|
-
var
|
|
5731
|
+
var import_lucide_react15 = require("lucide-react");
|
|
5732
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
4390
5733
|
var AuthGuard = ({
|
|
4391
5734
|
children,
|
|
4392
5735
|
requireAuth = false,
|
|
@@ -4397,7 +5740,7 @@ var AuthGuard = ({
|
|
|
4397
5740
|
return children;
|
|
4398
5741
|
}
|
|
4399
5742
|
if (loading) {
|
|
4400
|
-
return /* @__PURE__ */ (0,
|
|
5743
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react15.Loader2, { className: "w-8 h-8 animate-spin" }) });
|
|
4401
5744
|
}
|
|
4402
5745
|
if (requireAuth && !isAuthenticated && !isEmbedded) {
|
|
4403
5746
|
const returnTo = encodeURIComponent(
|
|
@@ -4408,11 +5751,13 @@ var AuthGuard = ({
|
|
|
4408
5751
|
}
|
|
4409
5752
|
return children;
|
|
4410
5753
|
};
|
|
5754
|
+
|
|
5755
|
+
// src/index.ts
|
|
5756
|
+
var import_react45 = require("@assistant-ui/react");
|
|
4411
5757
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4412
5758
|
0 && (module.exports = {
|
|
4413
5759
|
ARTIFACT_AGENT_INSTRUCTIONS,
|
|
4414
5760
|
ARTIFACT_FENCE_LANGUAGES,
|
|
4415
|
-
ActionBarMorePrimitive,
|
|
4416
5761
|
ActionBarPrimitive,
|
|
4417
5762
|
ArtifactCard,
|
|
4418
5763
|
ArtifactRegistryProvider,
|
|
@@ -4426,8 +5771,6 @@ var AuthGuard = ({
|
|
|
4426
5771
|
Button,
|
|
4427
5772
|
ChartArtifactView,
|
|
4428
5773
|
Composer,
|
|
4429
|
-
ComposerAddAttachment,
|
|
4430
|
-
ComposerAttachments,
|
|
4431
5774
|
ComposerPrimitive,
|
|
4432
5775
|
DEFAULT_UPLOAD_ACCEPT,
|
|
4433
5776
|
Dialog,
|
|
@@ -4437,44 +5780,27 @@ var AuthGuard = ({
|
|
|
4437
5780
|
DialogPortal,
|
|
4438
5781
|
DialogTitle,
|
|
4439
5782
|
DialogTrigger,
|
|
4440
|
-
ErrorPrimitive,
|
|
4441
5783
|
HtmlArtifactView,
|
|
4442
5784
|
JsonArtifactView,
|
|
4443
5785
|
MarkdownText,
|
|
4444
|
-
MessagePartPrimitive,
|
|
4445
5786
|
MessagePrimitive,
|
|
5787
|
+
ModeToggle,
|
|
4446
5788
|
QuestionArtifactView,
|
|
4447
|
-
STUDIO_INSET_LEFT,
|
|
4448
|
-
STUDIO_PILL_HEIGHT,
|
|
4449
|
-
STUDIO_SIDEBAR_GAP,
|
|
4450
|
-
STUDIO_SIDEBAR_WIDTH,
|
|
4451
|
-
STUDIO_TOPBAR_GAP,
|
|
4452
|
-
STUDIO_TOPBAR_HEIGHT,
|
|
4453
5789
|
SessionProvider,
|
|
4454
5790
|
Shimmer,
|
|
5791
|
+
StudioSidebar,
|
|
5792
|
+
StudioWelcome,
|
|
4455
5793
|
Suggestions,
|
|
4456
|
-
SyntaxHighlighter,
|
|
4457
|
-
TIMBAL_V2_BORDER,
|
|
4458
|
-
TIMBAL_V2_FILL,
|
|
4459
|
-
TIMBAL_V2_LABEL,
|
|
4460
|
-
TIMBAL_V2_PILL_SURFACE,
|
|
4461
|
-
TIMBAL_V2_SECONDARY_CHROME,
|
|
4462
|
-
TIMBAL_V2_SHADOW,
|
|
4463
|
-
TIMBAL_V2_SIZE_HEIGHT,
|
|
4464
|
-
TIMBAL_V2_SIZE_ICON,
|
|
4465
|
-
TIMBAL_V2_SIZE_LABEL_PX,
|
|
4466
5794
|
TableArtifactView,
|
|
4467
5795
|
Thread,
|
|
4468
5796
|
ThreadPrimitive,
|
|
4469
5797
|
TimbalChat,
|
|
4470
5798
|
TimbalChatShell,
|
|
5799
|
+
TimbalMark,
|
|
4471
5800
|
TimbalRuntimeProvider,
|
|
4472
|
-
|
|
5801
|
+
TimbalStudioShell,
|
|
4473
5802
|
ToolArtifactFallback,
|
|
4474
|
-
ToolBodyPresence,
|
|
4475
5803
|
ToolFallback,
|
|
4476
|
-
ToolMotion,
|
|
4477
|
-
ToolPresence,
|
|
4478
5804
|
Tooltip,
|
|
4479
5805
|
TooltipContent,
|
|
4480
5806
|
TooltipIconButton,
|
|
@@ -4484,10 +5810,8 @@ var AuthGuard = ({
|
|
|
4484
5810
|
UiCustomNodeRegistryProvider,
|
|
4485
5811
|
UiEventProvider,
|
|
4486
5812
|
UiNodeView,
|
|
4487
|
-
UserMessageAttachments,
|
|
4488
5813
|
WorkforceSelector,
|
|
4489
5814
|
authFetch,
|
|
4490
|
-
buttonVariants,
|
|
4491
5815
|
clearTokens,
|
|
4492
5816
|
cn,
|
|
4493
5817
|
createDefaultAttachmentAdapter,
|
|
@@ -4501,7 +5825,6 @@ var AuthGuard = ({
|
|
|
4501
5825
|
isArtifact,
|
|
4502
5826
|
isArtifactFenceLanguage,
|
|
4503
5827
|
isUiBinding,
|
|
4504
|
-
luxuryEase,
|
|
4505
5828
|
parseArtifactFromToolResult,
|
|
4506
5829
|
parseSSELine,
|
|
4507
5830
|
refreshAccessToken,
|
|
@@ -4511,35 +5834,10 @@ var AuthGuard = ({
|
|
|
4511
5834
|
setPath,
|
|
4512
5835
|
setRefreshToken,
|
|
4513
5836
|
splitMarkdownByArtifacts,
|
|
4514
|
-
studioArtifactShellClass,
|
|
4515
|
-
studioChromeShellStyle,
|
|
4516
|
-
studioComposeInputShellClass,
|
|
4517
|
-
studioComposerIoWellClass,
|
|
4518
|
-
studioIntegrationBorder,
|
|
4519
|
-
studioIntegrationCardClass,
|
|
4520
|
-
studioIntegrationIconTileClass,
|
|
4521
|
-
studioIntegrationSurfaceSolid,
|
|
4522
|
-
studioListRowButtonClass,
|
|
4523
|
-
studioPillSurfaceClass,
|
|
4524
|
-
studioPlaygroundGradientClass,
|
|
4525
|
-
studioQuestionOptionClass,
|
|
4526
|
-
studioQuestionOptionSelectedClass,
|
|
4527
|
-
studioSecondaryChromeClass,
|
|
4528
|
-
studioTimelineActionClass,
|
|
4529
|
-
studioTimelineBodyPadClass,
|
|
4530
|
-
studioTimelineChevronClass,
|
|
4531
|
-
studioTimelineDetailClass,
|
|
4532
|
-
studioTimelineRowButtonClass,
|
|
4533
|
-
studioTimelineShimmerActionClass,
|
|
4534
|
-
studioTimelineTextClass,
|
|
4535
|
-
studioToolCardShellClass,
|
|
4536
|
-
studioTopbarIconPillClass,
|
|
4537
|
-
studioTopbarPillHeightClass,
|
|
4538
|
-
toolPresenceTransition,
|
|
4539
5837
|
useArtifactRegistry,
|
|
4540
|
-
useAuiState,
|
|
4541
5838
|
useComposerRuntime,
|
|
4542
5839
|
useMessageRuntime,
|
|
5840
|
+
useOptionalSession,
|
|
4543
5841
|
useResolvedSuggestions,
|
|
4544
5842
|
useSession,
|
|
4545
5843
|
useThread,
|