@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.esm.js
CHANGED
|
@@ -868,6 +868,7 @@ function findParentIdFromAuiParent(messages, auiParentId) {
|
|
|
868
868
|
import { parseSSELine as parseSSELine2 } from "@timbal-ai/timbal-sdk";
|
|
869
869
|
|
|
870
870
|
// src/components/thread.tsx
|
|
871
|
+
import { useEffect as useEffect5 } from "react";
|
|
871
872
|
import {
|
|
872
873
|
ActionBarMorePrimitive,
|
|
873
874
|
ActionBarPrimitive,
|
|
@@ -1108,7 +1109,7 @@ import { forwardRef as forwardRef2 } from "react";
|
|
|
1108
1109
|
import * as React from "react";
|
|
1109
1110
|
import { Slot } from "radix-ui";
|
|
1110
1111
|
|
|
1111
|
-
// src/
|
|
1112
|
+
// src/design/button-tokens.ts
|
|
1112
1113
|
var TIMBAL_V2_SIZE_HEIGHT = {
|
|
1113
1114
|
xs: "min-h-8 h-8",
|
|
1114
1115
|
sm: "min-h-9 h-9",
|
|
@@ -1128,39 +1129,62 @@ var TIMBAL_V2_SIZE_LABEL_PX = {
|
|
|
1128
1129
|
lg: "px-6"
|
|
1129
1130
|
};
|
|
1130
1131
|
var TIMBAL_V2_FILL = {
|
|
1131
|
-
primary:
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1132
|
+
primary: [
|
|
1133
|
+
"bg-gradient-to-b from-primary-fill-from to-primary-fill-to",
|
|
1134
|
+
"group-hover/tbv2:from-primary-fill-hover-from group-hover/tbv2:to-primary-fill-hover-to",
|
|
1135
|
+
"group-active/tbv2:from-primary-fill-active-from group-active/tbv2:to-primary-fill-active-to"
|
|
1136
|
+
].join(" "),
|
|
1137
|
+
informative: [
|
|
1138
|
+
"bg-primary",
|
|
1139
|
+
"group-active/tbv2:[background-image:linear-gradient(to_top,rgba(0,0,0,0.08),transparent_55%)]"
|
|
1140
|
+
].join(" "),
|
|
1141
|
+
destructive: [
|
|
1142
|
+
"bg-gradient-to-b from-elevated-from to-elevated-to",
|
|
1143
|
+
"group-hover/tbv2:from-destructive-fill-hover-from group-hover/tbv2:to-destructive-fill-hover-to",
|
|
1144
|
+
"group-active/tbv2:from-destructive-fill-active-from group-active/tbv2:to-destructive-fill-active-to"
|
|
1145
|
+
].join(" "),
|
|
1146
|
+
secondary: [
|
|
1147
|
+
"bg-gradient-to-b from-elevated-from to-elevated-to",
|
|
1148
|
+
"group-hover/tbv2:from-secondary-fill-hover-from group-hover/tbv2:to-secondary-fill-hover-to",
|
|
1149
|
+
"group-active/tbv2:from-secondary-fill-active-from group-active/tbv2:to-secondary-fill-active-to"
|
|
1150
|
+
].join(" "),
|
|
1151
|
+
ghost: [
|
|
1152
|
+
"bg-transparent",
|
|
1153
|
+
"group-hover/tbv2:bg-ghost-fill-hover",
|
|
1154
|
+
"group-active/tbv2:bg-ghost-fill-active"
|
|
1155
|
+
].join(" "),
|
|
1136
1156
|
link: "bg-transparent"
|
|
1137
1157
|
};
|
|
1138
1158
|
var TIMBAL_V2_LABEL = {
|
|
1139
|
-
primary: "text-
|
|
1140
|
-
informative: "text-
|
|
1141
|
-
destructive: "text-destructive
|
|
1159
|
+
primary: "text-primary-foreground",
|
|
1160
|
+
informative: "text-primary-foreground",
|
|
1161
|
+
destructive: "text-destructive",
|
|
1142
1162
|
secondary: "text-foreground",
|
|
1143
1163
|
ghost: "text-foreground",
|
|
1144
|
-
link: "text-foreground underline decoration-
|
|
1164
|
+
link: "text-foreground underline decoration-foreground/25 underline-offset-2 group-hover/tbv2:decoration-foreground/45"
|
|
1145
1165
|
};
|
|
1146
1166
|
var TIMBAL_V2_BORDER = {
|
|
1147
1167
|
primary: "",
|
|
1148
|
-
informative: "border border-
|
|
1149
|
-
destructive: "border border-destructive/45
|
|
1150
|
-
secondary: "border border-
|
|
1168
|
+
informative: "border border-foreground/15",
|
|
1169
|
+
destructive: "border border-destructive/45",
|
|
1170
|
+
secondary: "border border-border",
|
|
1151
1171
|
ghost: "",
|
|
1152
1172
|
link: ""
|
|
1153
1173
|
};
|
|
1154
1174
|
var TIMBAL_V2_SHADOW = {
|
|
1155
|
-
primary: "shadow-
|
|
1156
|
-
informative: "shadow-
|
|
1157
|
-
destructive: "shadow-
|
|
1158
|
-
secondary: "shadow-
|
|
1175
|
+
primary: "shadow-card",
|
|
1176
|
+
informative: "shadow-card",
|
|
1177
|
+
destructive: "shadow-card",
|
|
1178
|
+
secondary: "shadow-card",
|
|
1159
1179
|
ghost: "",
|
|
1160
1180
|
link: ""
|
|
1161
1181
|
};
|
|
1162
|
-
var
|
|
1163
|
-
|
|
1182
|
+
var TIMBAL_V2_SECONDARY_CHROME = [
|
|
1183
|
+
"bg-gradient-to-b from-elevated-from to-elevated-to border border-border shadow-card",
|
|
1184
|
+
"transition-[background-color,box-shadow,border-color] duration-200 ease-in-out",
|
|
1185
|
+
"hover:from-secondary-fill-hover-from hover:to-secondary-fill-hover-to",
|
|
1186
|
+
"active:from-secondary-fill-active-from active:to-secondary-fill-active-to"
|
|
1187
|
+
].join(" ");
|
|
1164
1188
|
|
|
1165
1189
|
// src/ui/timbal-v2-button.tsx
|
|
1166
1190
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -1192,7 +1216,7 @@ var TimbalV2Button = React.forwardRef(function TimbalV2Button2({
|
|
|
1192
1216
|
"data-variant": variant,
|
|
1193
1217
|
className: cn(
|
|
1194
1218
|
"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",
|
|
1195
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-
|
|
1219
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/60 focus-visible:ring-offset-1 focus-visible:ring-offset-background",
|
|
1196
1220
|
sizeClass,
|
|
1197
1221
|
radiusClass,
|
|
1198
1222
|
TIMBAL_V2_BORDER[variant],
|
|
@@ -1369,9 +1393,9 @@ var AttachmentRemove = () => {
|
|
|
1369
1393
|
TooltipIconButton,
|
|
1370
1394
|
{
|
|
1371
1395
|
tooltip: "Remove file",
|
|
1372
|
-
className: "aui-attachment-tile-remove absolute top-1.5 right-1.5 size-3.5 rounded-full bg-
|
|
1396
|
+
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",
|
|
1373
1397
|
side: "top",
|
|
1374
|
-
children: /* @__PURE__ */ jsx7(XIcon2, { className: "aui-attachment-remove-icon size-3
|
|
1398
|
+
children: /* @__PURE__ */ jsx7(XIcon2, { className: "aui-attachment-remove-icon size-3" })
|
|
1375
1399
|
}
|
|
1376
1400
|
) });
|
|
1377
1401
|
};
|
|
@@ -1393,7 +1417,7 @@ var ComposerAddAttachment = () => {
|
|
|
1393
1417
|
tooltip: "Add Attachment",
|
|
1394
1418
|
side: "bottom",
|
|
1395
1419
|
variant: "secondary",
|
|
1396
|
-
className: "aui-composer-add-attachment shrink-0 text-
|
|
1420
|
+
className: "aui-composer-add-attachment shrink-0 text-muted-foreground",
|
|
1397
1421
|
"aria-label": "Add Attachment",
|
|
1398
1422
|
children: /* @__PURE__ */ jsx7(PlusIcon, { className: "aui-attachment-add-icon size-4 stroke-[1.5]" })
|
|
1399
1423
|
}
|
|
@@ -1747,30 +1771,19 @@ import { useCallback as useCallback2, useState as useState3 } from "react";
|
|
|
1747
1771
|
import { useThreadRuntime } from "@assistant-ui/react";
|
|
1748
1772
|
import { CheckIcon } from "lucide-react";
|
|
1749
1773
|
|
|
1750
|
-
// src/
|
|
1751
|
-
var STUDIO_TOPBAR_GAP = "0.5rem";
|
|
1752
|
-
var STUDIO_TOPBAR_HEIGHT = "3rem";
|
|
1753
|
-
var STUDIO_PILL_HEIGHT = "2.5rem";
|
|
1754
|
-
var STUDIO_SIDEBAR_GAP = "0.5rem";
|
|
1755
|
-
var STUDIO_SIDEBAR_WIDTH = "3rem";
|
|
1756
|
-
var STUDIO_INSET_LEFT = `calc(${STUDIO_SIDEBAR_GAP} + ${STUDIO_SIDEBAR_WIDTH})`;
|
|
1757
|
-
var studioChromeShellStyle = {
|
|
1758
|
-
"--studio-topbar-gap": STUDIO_TOPBAR_GAP,
|
|
1759
|
-
"--studio-topbar-height": STUDIO_TOPBAR_HEIGHT,
|
|
1760
|
-
"--studio-chrome-pill-height": STUDIO_PILL_HEIGHT,
|
|
1761
|
-
"--studio-inset-top": `calc(${STUDIO_TOPBAR_GAP} + ${STUDIO_TOPBAR_HEIGHT})`,
|
|
1762
|
-
"--studio-sidebar-gap": STUDIO_SIDEBAR_GAP,
|
|
1763
|
-
"--studio-sidebar-width": STUDIO_SIDEBAR_WIDTH,
|
|
1764
|
-
"--studio-inset-left": STUDIO_INSET_LEFT
|
|
1765
|
-
};
|
|
1774
|
+
// src/design/classes.ts
|
|
1766
1775
|
var studioTopbarPillHeightClass = "h-[var(--studio-chrome-pill-height)] min-h-[var(--studio-chrome-pill-height)]";
|
|
1767
1776
|
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)]";
|
|
1768
|
-
var studioPlaygroundGradientClass = "bg-gradient-to-b from-
|
|
1769
|
-
var studioComposeInputShellClass =
|
|
1770
|
-
|
|
1777
|
+
var studioPlaygroundGradientClass = "bg-gradient-to-b from-playground-from via-playground-via to-playground-to";
|
|
1778
|
+
var studioComposeInputShellClass = cn(
|
|
1779
|
+
"flex w-full flex-col rounded-2xl bg-composer-bg shadow-card-elevated outline-none",
|
|
1780
|
+
"border border-composer-border",
|
|
1781
|
+
"transition-[box-shadow,border-color]",
|
|
1782
|
+
"focus-within:border-composer-border-focus focus-within:ring-2 focus-within:ring-foreground/5"
|
|
1783
|
+
);
|
|
1771
1784
|
var studioSecondaryChromeClass = TIMBAL_V2_SECONDARY_CHROME;
|
|
1772
|
-
var studioIntegrationSurfaceSolid = "bg-
|
|
1773
|
-
var studioIntegrationBorder = "border border-
|
|
1785
|
+
var studioIntegrationSurfaceSolid = "bg-gradient-to-b from-elevated-from to-elevated-to shadow-card";
|
|
1786
|
+
var studioIntegrationBorder = "border border-border";
|
|
1774
1787
|
var studioIntegrationCardClass = cn(
|
|
1775
1788
|
"rounded-xl",
|
|
1776
1789
|
studioIntegrationSurfaceSolid,
|
|
@@ -1785,8 +1798,8 @@ var studioListRowButtonClass = cn(
|
|
|
1785
1798
|
"flex w-full cursor-pointer items-center gap-3 rounded-xl px-3 py-2.5 text-left",
|
|
1786
1799
|
studioIntegrationCardClass,
|
|
1787
1800
|
"transition-[background-color,box-shadow,border-color] duration-200 ease-in-out",
|
|
1788
|
-
"hover:border-
|
|
1789
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background
|
|
1801
|
+
"hover:border-foreground/20",
|
|
1802
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
1790
1803
|
);
|
|
1791
1804
|
var studioComposerIoWellClass = cn(
|
|
1792
1805
|
"rounded-lg",
|
|
@@ -1797,6 +1810,43 @@ var studioToolCardShellClass = cn(
|
|
|
1797
1810
|
studioIntegrationCardClass,
|
|
1798
1811
|
"my-2 min-h-0 overflow-hidden"
|
|
1799
1812
|
);
|
|
1813
|
+
var studioSidebarPanelClass = cn(
|
|
1814
|
+
"bg-sidebar text-sidebar-foreground",
|
|
1815
|
+
"border border-sidebar-border",
|
|
1816
|
+
"shadow-card-elevated"
|
|
1817
|
+
);
|
|
1818
|
+
var studioSidebarNavItemClass = cn(
|
|
1819
|
+
"flex items-center rounded-lg text-sm",
|
|
1820
|
+
"transition-[color,background-color,box-shadow,border-color] duration-200 ease-in-out",
|
|
1821
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2"
|
|
1822
|
+
);
|
|
1823
|
+
function studioSidebarNavItemLayout(iconOnly) {
|
|
1824
|
+
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";
|
|
1825
|
+
}
|
|
1826
|
+
var studioSidebarNavItemSurfaceClass = cn(
|
|
1827
|
+
"bg-gradient-to-b from-elevated-from to-elevated-to text-foreground",
|
|
1828
|
+
"border border-border",
|
|
1829
|
+
"shadow-card"
|
|
1830
|
+
);
|
|
1831
|
+
var studioSidebarNavItemIdleClass = cn(
|
|
1832
|
+
"border border-transparent text-muted-foreground shadow-none",
|
|
1833
|
+
"hover:text-foreground",
|
|
1834
|
+
"hover:bg-gradient-to-b hover:from-elevated-from hover:to-elevated-to",
|
|
1835
|
+
"hover:border-border hover:shadow-card"
|
|
1836
|
+
);
|
|
1837
|
+
var studioSidebarCollapsedRailItemClass = cn(
|
|
1838
|
+
"border border-border shadow-card bg-sidebar-accent"
|
|
1839
|
+
);
|
|
1840
|
+
var studioSidebarCollapsedRailItemIdleClass = cn(
|
|
1841
|
+
studioSidebarCollapsedRailItemClass,
|
|
1842
|
+
"text-muted-foreground hover:text-foreground"
|
|
1843
|
+
);
|
|
1844
|
+
var studioSidebarCollapsedRailItemActiveClass = cn(
|
|
1845
|
+
studioSidebarCollapsedRailItemClass,
|
|
1846
|
+
studioSidebarNavItemSurfaceClass,
|
|
1847
|
+
"text-foreground"
|
|
1848
|
+
);
|
|
1849
|
+
var studioSidebarNavItemActiveClass = studioSidebarNavItemSurfaceClass;
|
|
1800
1850
|
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";
|
|
1801
1851
|
var studioTimelineTextClass = "text-xs font-normal leading-snug";
|
|
1802
1852
|
var studioTimelineActionClass = cn(
|
|
@@ -1822,10 +1872,10 @@ var studioArtifactShellClass = cn(
|
|
|
1822
1872
|
studioIntegrationCardClass,
|
|
1823
1873
|
"my-2 w-full min-w-0 overflow-hidden"
|
|
1824
1874
|
);
|
|
1825
|
-
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-
|
|
1875
|
+
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";
|
|
1826
1876
|
var studioQuestionOptionSelectedClass = cn(
|
|
1827
1877
|
studioQuestionOptionClass,
|
|
1828
|
-
"border-
|
|
1878
|
+
"border-border bg-accent ring-1 ring-foreground/10"
|
|
1829
1879
|
);
|
|
1830
1880
|
|
|
1831
1881
|
// src/artifacts/question-artifact.tsx
|
|
@@ -1839,7 +1889,7 @@ var OptionRadio = ({ selected }) => /* @__PURE__ */ jsx10(
|
|
|
1839
1889
|
{
|
|
1840
1890
|
className: cn(
|
|
1841
1891
|
"flex size-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
|
|
1842
|
-
selected ? "border-foreground bg-foreground text-background" : "border-
|
|
1892
|
+
selected ? "border-foreground bg-foreground text-background" : "border-border bg-background"
|
|
1843
1893
|
),
|
|
1844
1894
|
"aria-hidden": true,
|
|
1845
1895
|
children: selected ? /* @__PURE__ */ jsx10(CheckIcon, { className: "size-2.5 stroke-[3]" }) : null
|
|
@@ -2098,15 +2148,15 @@ import { cva } from "class-variance-authority";
|
|
|
2098
2148
|
import { Slot as Slot2 } from "radix-ui";
|
|
2099
2149
|
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
2100
2150
|
var buttonVariants = cva(
|
|
2101
|
-
"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/
|
|
2151
|
+
"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",
|
|
2102
2152
|
{
|
|
2103
2153
|
variants: {
|
|
2104
2154
|
variant: {
|
|
2105
2155
|
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
2106
|
-
destructive: "bg-destructive text-
|
|
2107
|
-
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground
|
|
2156
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:ring-destructive/30",
|
|
2157
|
+
outline: "border border-border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
|
|
2108
2158
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
2109
|
-
ghost: "hover:bg-accent hover:text-accent-foreground
|
|
2159
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
2110
2160
|
link: "text-primary underline-offset-4 hover:underline"
|
|
2111
2161
|
},
|
|
2112
2162
|
size: {
|
|
@@ -2738,7 +2788,7 @@ var CodeHeader = ({ language, code }) => {
|
|
|
2738
2788
|
if (!code || isCopied) return;
|
|
2739
2789
|
copyToClipboard(code);
|
|
2740
2790
|
};
|
|
2741
|
-
return /* @__PURE__ */ jsxs11("div", { className: "aui-code-header flex items-center justify-between rounded-t-lg border border-b-0 border-border/50 bg-
|
|
2791
|
+
return /* @__PURE__ */ jsxs11("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: [
|
|
2742
2792
|
/* @__PURE__ */ jsxs11("span", { className: "flex items-center gap-2 text-xs font-semibold tracking-wide text-muted-foreground/80 uppercase", children: [
|
|
2743
2793
|
/* @__PURE__ */ jsx20("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/40" }),
|
|
2744
2794
|
language
|
|
@@ -2945,7 +2995,7 @@ var defaultComponents = memoizeMarkdownComponents({
|
|
|
2945
2995
|
"pre",
|
|
2946
2996
|
{
|
|
2947
2997
|
className: cn(
|
|
2948
|
-
"aui-md-pre overflow-x-auto rounded-t-none rounded-b-lg border border-t-0 border-border/50 bg-
|
|
2998
|
+
"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",
|
|
2949
2999
|
className
|
|
2950
3000
|
),
|
|
2951
3001
|
...props
|
|
@@ -2957,7 +3007,7 @@ var defaultComponents = memoizeMarkdownComponents({
|
|
|
2957
3007
|
"code",
|
|
2958
3008
|
{
|
|
2959
3009
|
className: cn(
|
|
2960
|
-
!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
|
|
3010
|
+
!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",
|
|
2961
3011
|
className
|
|
2962
3012
|
),
|
|
2963
3013
|
...props
|
|
@@ -3382,7 +3432,7 @@ var ComposerInput = ({
|
|
|
3382
3432
|
ComposerPrimitive2.Input,
|
|
3383
3433
|
{
|
|
3384
3434
|
placeholder,
|
|
3385
|
-
className: "aui-composer-input max-h-60 min-h-14 w-full resize-none bg-
|
|
3435
|
+
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",
|
|
3386
3436
|
rows: 1,
|
|
3387
3437
|
autoFocus,
|
|
3388
3438
|
"aria-label": "Message input",
|
|
@@ -3392,7 +3442,7 @@ var ComposerInput = ({
|
|
|
3392
3442
|
);
|
|
3393
3443
|
};
|
|
3394
3444
|
var ComposerToolbar = ({ showAttachments, toolbar, sendTooltip }) => {
|
|
3395
|
-
return /* @__PURE__ */ jsxs13("div", { className: "aui-composer-action-wrapper flex items-center justify-between gap-1 px-2.5 pb-2.5", children: [
|
|
3445
|
+
return /* @__PURE__ */ jsxs13("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: [
|
|
3396
3446
|
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1", children: [
|
|
3397
3447
|
showAttachments && /* @__PURE__ */ jsx25(ComposerAddAttachment, {}),
|
|
3398
3448
|
toolbar
|
|
@@ -3468,9 +3518,9 @@ var SuggestionRow = ({ suggestion }) => {
|
|
|
3468
3518
|
onClick,
|
|
3469
3519
|
className: cn("aui-thread-suggestion", studioListRowButtonClass),
|
|
3470
3520
|
children: [
|
|
3471
|
-
/* @__PURE__ */ jsx26("span", { className: "aui-thread-suggestion-icon shrink-0 text-
|
|
3521
|
+
/* @__PURE__ */ jsx26("span", { className: "aui-thread-suggestion-icon shrink-0 text-muted-foreground", children: suggestion.icon ?? /* @__PURE__ */ jsx26(ArrowUpIcon2, { className: "size-4", strokeWidth: 1.75, "aria-hidden": true }) }),
|
|
3472
3522
|
/* @__PURE__ */ jsxs14("span", { className: "aui-thread-suggestion-text min-w-0 flex-1 text-left", children: [
|
|
3473
|
-
/* @__PURE__ */ jsx26("span", { className: "aui-thread-suggestion-text-1 block truncate text-sm font-normal text-foreground
|
|
3523
|
+
/* @__PURE__ */ jsx26("span", { className: "aui-thread-suggestion-text-1 block truncate text-sm font-normal text-foreground", children: suggestion.title }),
|
|
3474
3524
|
suggestion.description && /* @__PURE__ */ jsx26("span", { className: "aui-thread-suggestion-text-2 mt-0.5 block truncate text-xs text-muted-foreground", children: suggestion.description })
|
|
3475
3525
|
] })
|
|
3476
3526
|
]
|
|
@@ -3503,6 +3553,75 @@ function useResolvedSuggestions(source) {
|
|
|
3503
3553
|
return useMemo6(() => resolved, [resolved]);
|
|
3504
3554
|
}
|
|
3505
3555
|
|
|
3556
|
+
// src/design/theme-sanity.ts
|
|
3557
|
+
var scheduled = false;
|
|
3558
|
+
var warned = false;
|
|
3559
|
+
function isDev() {
|
|
3560
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
|
|
3561
|
+
return false;
|
|
3562
|
+
}
|
|
3563
|
+
return true;
|
|
3564
|
+
}
|
|
3565
|
+
function parseLuminance(color) {
|
|
3566
|
+
const value = color.trim();
|
|
3567
|
+
if (!value) return null;
|
|
3568
|
+
const oklch = value.match(/oklch\(\s*([0-9.]+)/i);
|
|
3569
|
+
if (oklch) {
|
|
3570
|
+
const lightness = Number.parseFloat(oklch[1]);
|
|
3571
|
+
if (Number.isFinite(lightness)) return lightness;
|
|
3572
|
+
}
|
|
3573
|
+
const rgb = value.match(/rgba?\(\s*([0-9.]+)[\s,]+([0-9.]+)[\s,]+([0-9.]+)/i);
|
|
3574
|
+
if (rgb) {
|
|
3575
|
+
const r = Number.parseFloat(rgb[1]) / 255;
|
|
3576
|
+
const g = Number.parseFloat(rgb[2]) / 255;
|
|
3577
|
+
const b = Number.parseFloat(rgb[3]) / 255;
|
|
3578
|
+
if ([r, g, b].every(Number.isFinite)) {
|
|
3579
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
const hsl = value.match(/hsla?\(\s*[0-9.]+[\s,]+[0-9.]+%[\s,]+([0-9.]+)%/i);
|
|
3583
|
+
if (hsl) {
|
|
3584
|
+
const lightness = Number.parseFloat(hsl[1]) / 100;
|
|
3585
|
+
if (Number.isFinite(lightness)) return lightness;
|
|
3586
|
+
}
|
|
3587
|
+
return null;
|
|
3588
|
+
}
|
|
3589
|
+
function runCheck() {
|
|
3590
|
+
if (warned) return;
|
|
3591
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
3592
|
+
const root = document.documentElement;
|
|
3593
|
+
const styles = window.getComputedStyle(root);
|
|
3594
|
+
const background = styles.getPropertyValue("--background").trim();
|
|
3595
|
+
if (!background) {
|
|
3596
|
+
warned = true;
|
|
3597
|
+
console.warn(
|
|
3598
|
+
'[@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.'
|
|
3599
|
+
);
|
|
3600
|
+
return;
|
|
3601
|
+
}
|
|
3602
|
+
const luminance = parseLuminance(background);
|
|
3603
|
+
if (luminance === null) return;
|
|
3604
|
+
const hasDarkClass = root.classList.contains("dark");
|
|
3605
|
+
const looksDark = luminance < 0.5;
|
|
3606
|
+
if (hasDarkClass !== looksDark) {
|
|
3607
|
+
warned = true;
|
|
3608
|
+
console.warn(
|
|
3609
|
+
`[@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.`
|
|
3610
|
+
);
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
function scheduleThemeSanityCheck() {
|
|
3614
|
+
if (scheduled) return;
|
|
3615
|
+
if (!isDev()) return;
|
|
3616
|
+
if (typeof window === "undefined") return;
|
|
3617
|
+
scheduled = true;
|
|
3618
|
+
if (typeof queueMicrotask === "function") {
|
|
3619
|
+
queueMicrotask(() => setTimeout(runCheck, 0));
|
|
3620
|
+
} else {
|
|
3621
|
+
setTimeout(runCheck, 0);
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
|
|
3506
3625
|
// src/components/thread.tsx
|
|
3507
3626
|
import { jsx as jsx27, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3508
3627
|
var Thread = ({
|
|
@@ -3522,6 +3641,9 @@ var Thread = ({
|
|
|
3522
3641
|
const EditComposerSlot = components?.EditComposer ?? EditComposer;
|
|
3523
3642
|
const ScrollToBottomSlot = components?.ScrollToBottom ?? ThreadScrollToBottom;
|
|
3524
3643
|
const SuggestionsSlot = components?.Suggestions ?? Suggestions;
|
|
3644
|
+
useEffect5(() => {
|
|
3645
|
+
scheduleThemeSanityCheck();
|
|
3646
|
+
}, []);
|
|
3525
3647
|
return /* @__PURE__ */ jsx27(
|
|
3526
3648
|
ArtifactRegistryProvider,
|
|
3527
3649
|
{
|
|
@@ -3540,7 +3662,7 @@ var Thread = ({
|
|
|
3540
3662
|
ThreadPrimitive.Viewport,
|
|
3541
3663
|
{
|
|
3542
3664
|
turnAnchor: "bottom",
|
|
3543
|
-
className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll px-4 pt-4",
|
|
3665
|
+
className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-pb-4 px-4 pt-4",
|
|
3544
3666
|
children: [
|
|
3545
3667
|
/* @__PURE__ */ jsx27(
|
|
3546
3668
|
WelcomeSlot,
|
|
@@ -3560,7 +3682,7 @@ var Thread = ({
|
|
|
3560
3682
|
}
|
|
3561
3683
|
}
|
|
3562
3684
|
),
|
|
3563
|
-
/* @__PURE__ */ jsxs15(ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4
|
|
3685
|
+
/* @__PURE__ */ jsxs15(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: [
|
|
3564
3686
|
/* @__PURE__ */ jsx27(ScrollToBottomSlot, {}),
|
|
3565
3687
|
/* @__PURE__ */ jsx27(ComposerSlot, { placeholder: composerPlaceholder })
|
|
3566
3688
|
] })
|
|
@@ -3646,7 +3768,7 @@ var ThreadWelcome = ({
|
|
|
3646
3768
|
] });
|
|
3647
3769
|
};
|
|
3648
3770
|
var MessageError = () => {
|
|
3649
|
-
return /* @__PURE__ */ jsx27(MessagePrimitive2.Error, { children: /* @__PURE__ */ jsx27(ErrorPrimitive.Root, { className: "aui-message-error-root mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm
|
|
3771
|
+
return /* @__PURE__ */ jsx27(MessagePrimitive2.Error, { children: /* @__PURE__ */ jsx27(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__ */ jsx27(ErrorPrimitive.Message, { className: "aui-message-error-message line-clamp-2" }) }) });
|
|
3650
3772
|
};
|
|
3651
3773
|
var AssistantMessage = () => {
|
|
3652
3774
|
return /* @__PURE__ */ jsxs15(
|
|
@@ -3669,7 +3791,7 @@ var AssistantMessage = () => {
|
|
|
3669
3791
|
),
|
|
3670
3792
|
/* @__PURE__ */ jsx27(MessageError, {})
|
|
3671
3793
|
] }),
|
|
3672
|
-
/* @__PURE__ */ jsx27("div", { className: "aui-assistant-message-footer mt-
|
|
3794
|
+
/* @__PURE__ */ jsx27("div", { className: "aui-assistant-message-footer mt-1 mb-3 ml-1 flex", children: /* @__PURE__ */ jsx27(AssistantActionBar, {}) })
|
|
3673
3795
|
]
|
|
3674
3796
|
}
|
|
3675
3797
|
);
|
|
@@ -3679,15 +3801,14 @@ var ASSISTANT_ACTION_ICON_CLASS = cn(
|
|
|
3679
3801
|
// The v2 fill span sits inside `group/tbv2 > span:first-child`. We mute it
|
|
3680
3802
|
// here so action-bar buttons read as subtle icons rather than full pills.
|
|
3681
3803
|
"[&>span:first-child]:bg-transparent",
|
|
3682
|
-
"[&>span:first-child]:group-hover/tbv2:bg-
|
|
3683
|
-
"dark:[&>span:first-child]:group-hover/tbv2:bg-white/8"
|
|
3804
|
+
"[&>span:first-child]:group-hover/tbv2:bg-muted/70"
|
|
3684
3805
|
);
|
|
3685
3806
|
var AssistantActionBar = () => {
|
|
3686
3807
|
return /* @__PURE__ */ jsxs15(
|
|
3687
3808
|
ActionBarPrimitive.Root,
|
|
3688
3809
|
{
|
|
3689
3810
|
hideWhenRunning: true,
|
|
3690
|
-
autohide: "
|
|
3811
|
+
autohide: "never",
|
|
3691
3812
|
className: "aui-assistant-action-bar-root flex items-center gap-0 bg-transparent px-0 py-0.5 text-muted-foreground/60",
|
|
3692
3813
|
children: [
|
|
3693
3814
|
/* @__PURE__ */ jsx27(ActionBarPrimitive.Copy, { asChild: true, children: /* @__PURE__ */ jsxs15(
|
|
@@ -3729,8 +3850,8 @@ var AssistantActionBar = () => {
|
|
|
3729
3850
|
{
|
|
3730
3851
|
side: "bottom",
|
|
3731
3852
|
align: "start",
|
|
3732
|
-
className: "aui-action-bar-more-content z-50 min-w-36 overflow-hidden rounded-lg border border-
|
|
3733
|
-
children: /* @__PURE__ */ jsx27(ActionBarPrimitive.ExportMarkdown, { asChild: true, children: /* @__PURE__ */ jsxs15(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-
|
|
3853
|
+
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",
|
|
3854
|
+
children: /* @__PURE__ */ jsx27(ActionBarPrimitive.ExportMarkdown, { asChild: true, children: /* @__PURE__ */ jsxs15(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: [
|
|
3734
3855
|
/* @__PURE__ */ jsx27(DownloadIcon, { className: "size-4 shrink-0" }),
|
|
3735
3856
|
"Export as Markdown"
|
|
3736
3857
|
] }) })
|
|
@@ -3755,7 +3876,7 @@ var UserMessage = () => {
|
|
|
3755
3876
|
/* @__PURE__ */ jsxs15(
|
|
3756
3877
|
motion4.div,
|
|
3757
3878
|
{
|
|
3758
|
-
className: "aui-user-message-content relative inline-block max-w-[80%] rounded-2xl bg-
|
|
3879
|
+
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",
|
|
3759
3880
|
initial: { opacity: 0, y: 8, scale: 0.99 },
|
|
3760
3881
|
animate: { opacity: 1, y: 0, scale: 1 },
|
|
3761
3882
|
transition: { duration: 0.65, ease: luxuryEase },
|
|
@@ -3774,7 +3895,7 @@ var UserActionBar = () => {
|
|
|
3774
3895
|
ActionBarPrimitive.Root,
|
|
3775
3896
|
{
|
|
3776
3897
|
hideWhenRunning: true,
|
|
3777
|
-
autohide: "
|
|
3898
|
+
autohide: "never",
|
|
3778
3899
|
className: "aui-user-action-bar-root flex flex-col items-end",
|
|
3779
3900
|
children: /* @__PURE__ */ jsx27(ActionBarPrimitive.Edit, { asChild: true, children: /* @__PURE__ */ jsx27(
|
|
3780
3901
|
TooltipIconButton,
|
|
@@ -3831,208 +3952,6 @@ function TimbalChat({
|
|
|
3831
3952
|
);
|
|
3832
3953
|
}
|
|
3833
3954
|
|
|
3834
|
-
// src/artifacts/agent-instructions.ts
|
|
3835
|
-
var ARTIFACT_AGENT_INSTRUCTIONS = `
|
|
3836
|
-
## Rich artifacts (Timbal chat UI)
|
|
3837
|
-
|
|
3838
|
-
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.
|
|
3839
|
-
|
|
3840
|
-
### Delivery channels (either works)
|
|
3841
|
-
|
|
3842
|
-
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.
|
|
3843
|
-
2. **Inline markdown fence** \u2014 embed the same JSON inside a fenced block:
|
|
3844
|
-
|
|
3845
|
-
\`\`\`timbal-artifact
|
|
3846
|
-
{"type":"chart","data":[{"month":"Jan","sales":120}]}
|
|
3847
|
-
\`\`\`
|
|
3848
|
-
|
|
3849
|
-
The alias \`\`\`timbal\`\`\` is also accepted.
|
|
3850
|
-
|
|
3851
|
-
### Built-in artifact types
|
|
3852
|
-
|
|
3853
|
-
| \`type\` | Use for |
|
|
3854
|
-
|---|---|
|
|
3855
|
-
| \`chart\` | Bar, line, area, or pie charts. Fields: \`data\`, optional \`chartType\`, \`xKey\`, \`dataKey\`, \`title\`, \`unit\`. |
|
|
3856
|
-
| \`table\` | Tabular data. Fields: \`rows\`, optional \`columns\`, \`title\`. |
|
|
3857
|
-
| \`question\` | In-thread multiple choice. Fields: \`options: [{ id, label, description? }]\`, optional \`prompt\`, \`multi\`. User replies are sent back as a normal user message. |
|
|
3858
|
-
| \`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). |
|
|
3859
|
-
| \`json\` | Fallback structured view. Fields: \`data\`, optional \`title\`. |
|
|
3860
|
-
| \`ui\` | **Interactive UI** composed from a fixed node palette (hover, click, drag). See below. |
|
|
3861
|
-
|
|
3862
|
-
### When to use \`type: "html"\`
|
|
3863
|
-
|
|
3864
|
-
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\`.
|
|
3865
|
-
|
|
3866
|
-
- Inline \`<style>\`, \`<script>\`, SVG, and canvas are supported.
|
|
3867
|
-
- Default \`sandboxed: true\` runs in an isolated iframe with scripts enabled.
|
|
3868
|
-
- Set \`sandboxed: false\` only for trusted content that needs external CDN scripts/styles or full DOM freedom.
|
|
3869
|
-
- Prefer \`ui\` when controls should send chat messages or host events; prefer \`html\` for self-contained mini-apps and visual demos.
|
|
3870
|
-
|
|
3871
|
-
### When to use \`type: "ui"\`
|
|
3872
|
-
|
|
3873
|
-
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.
|
|
3874
|
-
|
|
3875
|
-
Each \`ui\` artifact has:
|
|
3876
|
-
|
|
3877
|
-
- \`initialState\` \u2014 optional object seeding local state (per widget instance).
|
|
3878
|
-
- \`root\` \u2014 a single node tree (see node kinds below).
|
|
3879
|
-
- optional \`title\` \u2014 card heading.
|
|
3880
|
-
|
|
3881
|
-
**Bindings:** anywhere a primitive is accepted, you may use \`{ "$bind": "dotted.path" }\` to read from \`initialState\` / local state (e.g. \`{ "$bind": "qty" }\`).
|
|
3882
|
-
|
|
3883
|
-
**Actions:** nodes may attach \`onClick\`, \`onChange\`, or \`onDragEnd\` with one action or an array:
|
|
3884
|
-
|
|
3885
|
-
| Action | Shape | Effect |
|
|
3886
|
-
|---|---|---|
|
|
3887
|
-
| User message | \`{ "kind": "message", "text": "..." }\` or \`{ "kind": "message", "text": { "$bind": "path" } }\` | Sends text as the next user message. |
|
|
3888
|
-
| Set state | \`{ "kind": "set", "path": "foo", "value": 1 }\` | Writes local widget state. |
|
|
3889
|
-
| Toggle boolean | \`{ "kind": "toggle", "path": "enabled" }\` | Flips a boolean at \`path\`. |
|
|
3890
|
-
| Host event | \`{ "kind": "emit", "name": "event-name", "payload": { ... } }\` | Bubbles to the host app (\`onArtifactEvent\` on \`<Thread>\`). |
|
|
3891
|
-
|
|
3892
|
-
### \`ui\` node palette (\`root.kind\`)
|
|
3893
|
-
|
|
3894
|
-
| \`kind\` | Purpose | Key fields |
|
|
3895
|
-
|---|---|---|
|
|
3896
|
-
| \`box\` | Layout container | \`children\`, \`direction\` (\`row\`/\`col\`), \`gap\`, \`padding\`, \`align\`, \`justify\`, \`wrap\` |
|
|
3897
|
-
| \`text\` | Body text | \`value\`, optional \`muted\`, \`size\`, \`weight\` |
|
|
3898
|
-
| \`heading\` | Heading | \`value\`, optional \`level\` (1\u20134) |
|
|
3899
|
-
| \`badge\` | Pill label | \`value\`, optional \`tone\` (\`default\`, \`primary\`, \`success\`, \`warn\`, \`danger\`) |
|
|
3900
|
-
| \`button\` | Clickable button | \`label\`, optional \`variant\`, \`size\`, \`disabled\`, \`onClick\` |
|
|
3901
|
-
| \`toggle\` | Boolean switch | \`binding\` (state path), optional \`label\`, \`onChange\` |
|
|
3902
|
-
| \`slider\` | Numeric range | \`binding\`, optional \`min\`, \`max\`, \`step\`, \`label\`, \`showValue\`, \`onChange\` |
|
|
3903
|
-
| \`tooltip\` | Hover tooltip | \`content\`, \`child\` (single node), optional \`side\` |
|
|
3904
|
-
| \`draggable\` | Drag gesture | \`child\`, optional \`axis\` (\`x\`/\`y\`/\`both\`), \`snapBack\`, \`onDragEnd\` |
|
|
3905
|
-
| \`custom\` | Host-registered widget | \`name\`, optional \`props\`, \`children\` \u2014 only if the app registered that name |
|
|
3906
|
-
|
|
3907
|
-
### Example \`ui\` artifact
|
|
3908
|
-
|
|
3909
|
-
\`\`\`json
|
|
3910
|
-
{
|
|
3911
|
-
"type": "ui",
|
|
3912
|
-
"title": "Configure plan",
|
|
3913
|
-
"initialState": { "qty": 1, "premium": false },
|
|
3914
|
-
"root": {
|
|
3915
|
-
"kind": "box",
|
|
3916
|
-
"direction": "col",
|
|
3917
|
-
"gap": 3,
|
|
3918
|
-
"children": [
|
|
3919
|
-
{ "kind": "heading", "value": "Choose quantity", "level": 3 },
|
|
3920
|
-
{
|
|
3921
|
-
"kind": "tooltip",
|
|
3922
|
-
"content": "Drag to adjust quantity",
|
|
3923
|
-
"child": {
|
|
3924
|
-
"kind": "slider",
|
|
3925
|
-
"binding": "qty",
|
|
3926
|
-
"min": 1,
|
|
3927
|
-
"max": 50,
|
|
3928
|
-
"label": "Quantity",
|
|
3929
|
-
"onChange": { "kind": "emit", "name": "qty-changed" }
|
|
3930
|
-
}
|
|
3931
|
-
},
|
|
3932
|
-
{ "kind": "toggle", "binding": "premium", "label": "Premium support" },
|
|
3933
|
-
{
|
|
3934
|
-
"kind": "button",
|
|
3935
|
-
"label": "Confirm",
|
|
3936
|
-
"onClick": { "kind": "message", "text": { "$bind": "qty" } }
|
|
3937
|
-
}
|
|
3938
|
-
]
|
|
3939
|
-
}
|
|
3940
|
-
}
|
|
3941
|
-
\`\`\`
|
|
3942
|
-
|
|
3943
|
-
### Rules
|
|
3944
|
-
|
|
3945
|
-
- Always set \`type\` to a built-in value above unless the app documented a custom type.
|
|
3946
|
-
- Prefer \`ui\` over \`html\` when actions must bubble to the host chat (\`message\`, \`emit\`).
|
|
3947
|
-
- Prefer \`question\` for simple A/B/C choices; use \`ui\` when you need sliders, toggles, drag, or multi-control layouts.
|
|
3948
|
-
- Keep \`data\` arrays reasonably small (charts/tables).
|
|
3949
|
-
|
|
3950
|
-
### After calling an artifact tool (critical)
|
|
3951
|
-
|
|
3952
|
-
When you call a tool that returns an artifact (\`make_chart\`, \`ask_question\`, \`show_table\`, \`show_html\`, \`make_ui_demo\`, etc.):
|
|
3953
|
-
|
|
3954
|
-
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.
|
|
3955
|
-
2. **Do not** emit a matching \`\`\`timbal-artifact\`\`\` block for the same payload \u2014 pick **one** channel (tool result only).
|
|
3956
|
-
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.
|
|
3957
|
-
4. Treat the widget as visible to the user; refer to it as "above" / "the chart" / "the choices" \u2014 never reproduce its contents.
|
|
3958
|
-
`.trim();
|
|
3959
|
-
|
|
3960
|
-
// src/index.ts
|
|
3961
|
-
import {
|
|
3962
|
-
ThreadPrimitive as ThreadPrimitive2,
|
|
3963
|
-
MessagePrimitive as MessagePrimitive3,
|
|
3964
|
-
MessagePartPrimitive as MessagePartPrimitive2,
|
|
3965
|
-
ComposerPrimitive as ComposerPrimitive4,
|
|
3966
|
-
ActionBarPrimitive as ActionBarPrimitive2,
|
|
3967
|
-
ActionBarMorePrimitive as ActionBarMorePrimitive2,
|
|
3968
|
-
ErrorPrimitive as ErrorPrimitive2,
|
|
3969
|
-
AuiIf as AuiIf3,
|
|
3970
|
-
AssistantRuntimeProvider as AssistantRuntimeProvider2,
|
|
3971
|
-
useThread as useThread2,
|
|
3972
|
-
useThreadRuntime as useThreadRuntime4,
|
|
3973
|
-
useMessageRuntime,
|
|
3974
|
-
useComposerRuntime as useComposerRuntime2,
|
|
3975
|
-
useAuiState as useAuiState3
|
|
3976
|
-
} from "@assistant-ui/react";
|
|
3977
|
-
|
|
3978
|
-
// src/hooks/use-workforces.ts
|
|
3979
|
-
import { useEffect as useEffect5, useMemo as useMemo7, useRef as useRef2, useState as useState8 } from "react";
|
|
3980
|
-
function useWorkforces(options = {}) {
|
|
3981
|
-
const { baseUrl = "/api", fetch: fetchFn, pickInitial } = options;
|
|
3982
|
-
const [workforces, setWorkforces] = useState8([]);
|
|
3983
|
-
const [selectedId, setSelectedId] = useState8("");
|
|
3984
|
-
const [isLoading, setIsLoading] = useState8(true);
|
|
3985
|
-
const [error, setError] = useState8(null);
|
|
3986
|
-
const fetchFnRef = useRef2(fetchFn ?? authFetch);
|
|
3987
|
-
useEffect5(() => {
|
|
3988
|
-
fetchFnRef.current = fetchFn ?? authFetch;
|
|
3989
|
-
}, [fetchFn]);
|
|
3990
|
-
const pickInitialRef = useRef2(pickInitial);
|
|
3991
|
-
useEffect5(() => {
|
|
3992
|
-
pickInitialRef.current = pickInitial;
|
|
3993
|
-
}, [pickInitial]);
|
|
3994
|
-
const load = useMemo7(() => {
|
|
3995
|
-
return async () => {
|
|
3996
|
-
setIsLoading(true);
|
|
3997
|
-
setError(null);
|
|
3998
|
-
try {
|
|
3999
|
-
const res = await fetchFnRef.current(`${baseUrl}/workforce`);
|
|
4000
|
-
if (!res.ok) throw new Error(`Failed to load workforces (${res.status})`);
|
|
4001
|
-
const data = await res.json();
|
|
4002
|
-
setWorkforces(data);
|
|
4003
|
-
setSelectedId((current) => {
|
|
4004
|
-
if (current && data.some((w) => idOf(w) === current)) return current;
|
|
4005
|
-
const initial = pickInitialRef.current?.(data) ?? data.find((w) => w.type === "agent") ?? data[0];
|
|
4006
|
-
return initial ? idOf(initial) : "";
|
|
4007
|
-
});
|
|
4008
|
-
} catch (err) {
|
|
4009
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
4010
|
-
} finally {
|
|
4011
|
-
setIsLoading(false);
|
|
4012
|
-
}
|
|
4013
|
-
};
|
|
4014
|
-
}, [baseUrl]);
|
|
4015
|
-
useEffect5(() => {
|
|
4016
|
-
load();
|
|
4017
|
-
}, [load]);
|
|
4018
|
-
const selected = useMemo7(
|
|
4019
|
-
() => workforces.find((w) => idOf(w) === selectedId),
|
|
4020
|
-
[workforces, selectedId]
|
|
4021
|
-
);
|
|
4022
|
-
return {
|
|
4023
|
-
workforces,
|
|
4024
|
-
selectedId,
|
|
4025
|
-
setSelectedId,
|
|
4026
|
-
selected,
|
|
4027
|
-
isLoading,
|
|
4028
|
-
error,
|
|
4029
|
-
refresh: load
|
|
4030
|
-
};
|
|
4031
|
-
}
|
|
4032
|
-
function idOf(item) {
|
|
4033
|
-
return item.id ?? item.uid ?? item.name ?? "";
|
|
4034
|
-
}
|
|
4035
|
-
|
|
4036
3955
|
// src/components/workforce-selector.tsx
|
|
4037
3956
|
import { ChevronDownIcon } from "lucide-react";
|
|
4038
3957
|
import { jsx as jsx29, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
@@ -4067,7 +3986,7 @@ var WorkforceSelector = ({
|
|
|
4067
3986
|
children: [
|
|
4068
3987
|
!value && /* @__PURE__ */ jsx29("option", { value: "", children: placeholder }),
|
|
4069
3988
|
workforces.map((w) => {
|
|
4070
|
-
const id =
|
|
3989
|
+
const id = idOf(w);
|
|
4071
3990
|
return /* @__PURE__ */ jsx29("option", { value: id, children: w.name ?? id }, id);
|
|
4072
3991
|
})
|
|
4073
3992
|
]
|
|
@@ -4084,43 +4003,146 @@ var WorkforceSelector = ({
|
|
|
4084
4003
|
}
|
|
4085
4004
|
);
|
|
4086
4005
|
};
|
|
4087
|
-
function
|
|
4006
|
+
function idOf(item) {
|
|
4088
4007
|
return item.id ?? item.uid ?? item.name ?? "";
|
|
4089
4008
|
}
|
|
4090
4009
|
|
|
4091
|
-
// src/
|
|
4092
|
-
import {
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4010
|
+
// src/hooks/use-workforces.ts
|
|
4011
|
+
import { useEffect as useEffect6, useMemo as useMemo7, useRef as useRef2, useState as useState8 } from "react";
|
|
4012
|
+
function useWorkforces(options = {}) {
|
|
4013
|
+
const { baseUrl = "/api", fetch: fetchFn, pickInitial, enabled = true } = options;
|
|
4014
|
+
const [workforces, setWorkforces] = useState8([]);
|
|
4015
|
+
const [selectedId, setSelectedId] = useState8("");
|
|
4016
|
+
const [isLoading, setIsLoading] = useState8(enabled);
|
|
4017
|
+
const [error, setError] = useState8(null);
|
|
4018
|
+
const fetchFnRef = useRef2(fetchFn ?? authFetch);
|
|
4019
|
+
useEffect6(() => {
|
|
4020
|
+
fetchFnRef.current = fetchFn ?? authFetch;
|
|
4021
|
+
}, [fetchFn]);
|
|
4022
|
+
const pickInitialRef = useRef2(pickInitial);
|
|
4023
|
+
useEffect6(() => {
|
|
4024
|
+
pickInitialRef.current = pickInitial;
|
|
4025
|
+
}, [pickInitial]);
|
|
4026
|
+
const load = useMemo7(() => {
|
|
4027
|
+
return async () => {
|
|
4028
|
+
if (!enabled) {
|
|
4029
|
+
setIsLoading(false);
|
|
4030
|
+
return;
|
|
4031
|
+
}
|
|
4032
|
+
setIsLoading(true);
|
|
4033
|
+
setError(null);
|
|
4034
|
+
try {
|
|
4035
|
+
const res = await fetchFnRef.current(`${baseUrl}/workforce`);
|
|
4036
|
+
if (!res.ok) throw new Error(`Failed to load workforces (${res.status})`);
|
|
4037
|
+
const data = await res.json();
|
|
4038
|
+
setWorkforces(data);
|
|
4039
|
+
setSelectedId((current) => {
|
|
4040
|
+
if (current && data.some((w) => idOf2(w) === current)) return current;
|
|
4041
|
+
const initial = pickInitialRef.current?.(data) ?? data.find((w) => w.type === "agent") ?? data[0];
|
|
4042
|
+
return initial ? idOf2(initial) : "";
|
|
4043
|
+
});
|
|
4044
|
+
} catch (err) {
|
|
4045
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
4046
|
+
} finally {
|
|
4047
|
+
setIsLoading(false);
|
|
4048
|
+
}
|
|
4049
|
+
};
|
|
4050
|
+
}, [baseUrl, enabled]);
|
|
4051
|
+
useEffect6(() => {
|
|
4052
|
+
load();
|
|
4053
|
+
}, [load]);
|
|
4054
|
+
const selected = useMemo7(
|
|
4055
|
+
() => workforces.find((w) => idOf2(w) === selectedId),
|
|
4056
|
+
[workforces, selectedId]
|
|
4057
|
+
);
|
|
4058
|
+
return {
|
|
4059
|
+
workforces,
|
|
4060
|
+
selectedId,
|
|
4061
|
+
setSelectedId,
|
|
4062
|
+
selected,
|
|
4063
|
+
isLoading,
|
|
4064
|
+
error,
|
|
4065
|
+
refresh: load
|
|
4066
|
+
};
|
|
4067
|
+
}
|
|
4068
|
+
function idOf2(item) {
|
|
4069
|
+
return item.id ?? item.uid ?? item.name ?? "";
|
|
4070
|
+
}
|
|
4071
|
+
|
|
4072
|
+
// src/design/tokens.ts
|
|
4073
|
+
var SIDEBAR_WIDTH_PX = 224;
|
|
4074
|
+
var SIDEBAR_WIDTH_COLLAPSED_PX = 52;
|
|
4075
|
+
var SIDEBAR_MOBILE_PX = 272;
|
|
4076
|
+
var SIDEBAR_GAP_PX = 12;
|
|
4077
|
+
var SIDEBAR_CONTENT_GAP_PX = 8;
|
|
4078
|
+
var TOPBAR_GAP_PX = 8;
|
|
4079
|
+
var TOPBAR_HEIGHT_PX = 48;
|
|
4080
|
+
var PILL_HEIGHT_PX = 40;
|
|
4081
|
+
var SIDEBAR_INSET_PX_EXPANDED = SIDEBAR_GAP_PX + SIDEBAR_WIDTH_PX + SIDEBAR_CONTENT_GAP_PX;
|
|
4082
|
+
var SIDEBAR_INSET_PX_COLLAPSED = SIDEBAR_GAP_PX + SIDEBAR_WIDTH_COLLAPSED_PX + SIDEBAR_CONTENT_GAP_PX;
|
|
4083
|
+
var px = (n) => `${n / 16}rem`;
|
|
4084
|
+
var SIDEBAR_WIDTH = px(SIDEBAR_WIDTH_PX);
|
|
4085
|
+
var SIDEBAR_WIDTH_COLLAPSED = px(SIDEBAR_WIDTH_COLLAPSED_PX);
|
|
4086
|
+
var SIDEBAR_GAP = px(SIDEBAR_GAP_PX);
|
|
4087
|
+
var SIDEBAR_CONTENT_GAP = px(SIDEBAR_CONTENT_GAP_PX);
|
|
4088
|
+
var TOPBAR_GAP = px(TOPBAR_GAP_PX);
|
|
4089
|
+
var TOPBAR_HEIGHT = px(TOPBAR_HEIGHT_PX);
|
|
4090
|
+
var PILL_HEIGHT = px(PILL_HEIGHT_PX);
|
|
4091
|
+
var SIDEBAR_INSET_EXPANDED = px(SIDEBAR_INSET_PX_EXPANDED);
|
|
4092
|
+
var SIDEBAR_INSET_COLLAPSED = px(SIDEBAR_INSET_PX_COLLAPSED);
|
|
4093
|
+
var studioChromeShellStyle = {
|
|
4094
|
+
"--studio-topbar-gap": TOPBAR_GAP,
|
|
4095
|
+
"--studio-topbar-height": TOPBAR_HEIGHT,
|
|
4096
|
+
"--studio-chrome-pill-height": PILL_HEIGHT,
|
|
4097
|
+
"--studio-inset-top": `calc(${TOPBAR_GAP} + ${TOPBAR_HEIGHT})`,
|
|
4098
|
+
"--studio-sidebar-gap": SIDEBAR_GAP,
|
|
4099
|
+
"--studio-sidebar-width": SIDEBAR_WIDTH,
|
|
4100
|
+
"--studio-sidebar-width-collapsed": SIDEBAR_WIDTH_COLLAPSED,
|
|
4101
|
+
"--studio-sidebar-content-gap": SIDEBAR_CONTENT_GAP,
|
|
4102
|
+
"--studio-inset-left": SIDEBAR_INSET_EXPANDED,
|
|
4103
|
+
"--studio-inset-left-collapsed": SIDEBAR_INSET_COLLAPSED
|
|
4104
|
+
};
|
|
4105
|
+
var STORAGE_KEYS = {
|
|
4106
|
+
sidebarCollapsed: "timbal-studio-sidebar-collapsed"
|
|
4107
|
+
};
|
|
4108
|
+
var DOM_IDS = {
|
|
4109
|
+
sidebarRuntimeAnchor: "timbal-studio-sidebar-runtime-anchor",
|
|
4110
|
+
topbarBrandAnchor: "timbal-studio-topbar-brand-anchor"
|
|
4111
|
+
};
|
|
4112
|
+
|
|
4113
|
+
// src/components/chat-shell.tsx
|
|
4114
|
+
import { jsx as jsx30, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
4115
|
+
var TimbalChatShell = ({
|
|
4116
|
+
workforceId,
|
|
4117
|
+
brand,
|
|
4118
|
+
headerActions,
|
|
4119
|
+
hideWorkforceSelector,
|
|
4120
|
+
className,
|
|
4121
|
+
headerClassName,
|
|
4122
|
+
baseUrl,
|
|
4123
|
+
fetch: fetch2,
|
|
4124
|
+
...chatProps
|
|
4125
|
+
}) => {
|
|
4126
|
+
const { workforces, selectedId, setSelectedId } = useWorkforces({
|
|
4127
|
+
baseUrl,
|
|
4128
|
+
fetch: fetch2
|
|
4129
|
+
});
|
|
4130
|
+
const effectiveId = workforceId ?? selectedId;
|
|
4131
|
+
const showSelector = !hideWorkforceSelector && !workforceId && workforces.length > 0;
|
|
4132
|
+
return /* @__PURE__ */ jsxs17(
|
|
4133
|
+
"div",
|
|
4134
|
+
{
|
|
4135
|
+
className: cn(
|
|
4136
|
+
"aui-chat-shell relative flex h-dvh flex-col overflow-hidden bg-background",
|
|
4137
|
+
className
|
|
4138
|
+
),
|
|
4139
|
+
style: studioChromeShellStyle,
|
|
4140
|
+
children: [
|
|
4141
|
+
/* @__PURE__ */ jsx30(
|
|
4142
|
+
"div",
|
|
4143
|
+
{
|
|
4144
|
+
className: cn(
|
|
4145
|
+
"pointer-events-none absolute inset-0 z-0",
|
|
4124
4146
|
studioPlaygroundGradientClass
|
|
4125
4147
|
),
|
|
4126
4148
|
"aria-hidden": true
|
|
@@ -4166,15 +4188,250 @@ var TimbalChatShell = ({
|
|
|
4166
4188
|
);
|
|
4167
4189
|
};
|
|
4168
4190
|
|
|
4169
|
-
// src/
|
|
4191
|
+
// src/components/studio/studio-shell.tsx
|
|
4170
4192
|
import {
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
useState as useState9
|
|
4193
|
+
useCallback as useCallback8,
|
|
4194
|
+
useEffect as useEffect10,
|
|
4195
|
+
useMemo as useMemo9,
|
|
4196
|
+
useState as useState13
|
|
4176
4197
|
} from "react";
|
|
4198
|
+
import { Menu } from "lucide-react";
|
|
4199
|
+
import { motion as motion10, useReducedMotion as useReducedMotion6 } from "motion/react";
|
|
4200
|
+
|
|
4201
|
+
// src/design/sidebar-motion.ts
|
|
4202
|
+
var STUDIO_SIDEBAR_EASE_ENTER = [0, 0, 0.2, 1];
|
|
4203
|
+
var STUDIO_SIDEBAR_EASE_EXIT = [0.4, 0, 1, 1];
|
|
4204
|
+
var STUDIO_SIDEBAR_EASE = [0.16, 1, 0.3, 1];
|
|
4205
|
+
var STUDIO_SIDEBAR_ENTRIES_OUT_S = 0.1;
|
|
4206
|
+
var STUDIO_SIDEBAR_WIDTH_S = 0.17;
|
|
4207
|
+
var STUDIO_SIDEBAR_ENTRY_ITEM_IN_S = 0.18;
|
|
4208
|
+
var STUDIO_SIDEBAR_STAGGER_S = 0.03;
|
|
4209
|
+
var STUDIO_SIDEBAR_EXPAND_REVEAL_FRAC = 0.5;
|
|
4210
|
+
var STUDIO_SIDEBAR_CONTENT_NUDGE_PX = 6;
|
|
4211
|
+
var studioSidebarEntriesContainerVariants = {
|
|
4212
|
+
hidden: {
|
|
4213
|
+
opacity: 0,
|
|
4214
|
+
transition: {
|
|
4215
|
+
duration: STUDIO_SIDEBAR_ENTRIES_OUT_S,
|
|
4216
|
+
ease: STUDIO_SIDEBAR_EASE_EXIT,
|
|
4217
|
+
staggerChildren: 0
|
|
4218
|
+
}
|
|
4219
|
+
},
|
|
4220
|
+
visible: {
|
|
4221
|
+
opacity: 1,
|
|
4222
|
+
transition: {
|
|
4223
|
+
duration: 0.06,
|
|
4224
|
+
ease: STUDIO_SIDEBAR_EASE_ENTER,
|
|
4225
|
+
staggerChildren: STUDIO_SIDEBAR_STAGGER_S,
|
|
4226
|
+
delayChildren: 0.02
|
|
4227
|
+
}
|
|
4228
|
+
}
|
|
4229
|
+
};
|
|
4230
|
+
var studioSidebarEntryItemVariants = {
|
|
4231
|
+
hidden: {
|
|
4232
|
+
opacity: 0,
|
|
4233
|
+
x: -STUDIO_SIDEBAR_CONTENT_NUDGE_PX,
|
|
4234
|
+
scale: 0.99
|
|
4235
|
+
},
|
|
4236
|
+
visible: {
|
|
4237
|
+
opacity: 1,
|
|
4238
|
+
x: 0,
|
|
4239
|
+
scale: 1,
|
|
4240
|
+
transition: {
|
|
4241
|
+
duration: STUDIO_SIDEBAR_ENTRY_ITEM_IN_S,
|
|
4242
|
+
ease: STUDIO_SIDEBAR_EASE_ENTER
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4245
|
+
};
|
|
4246
|
+
function studioSidebarEntriesTransition(visible, reduced) {
|
|
4247
|
+
if (reduced) return { duration: 0.01 };
|
|
4248
|
+
return visible ? { duration: 0.06, ease: STUDIO_SIDEBAR_EASE_ENTER } : { duration: STUDIO_SIDEBAR_ENTRIES_OUT_S, ease: STUDIO_SIDEBAR_EASE_EXIT };
|
|
4249
|
+
}
|
|
4250
|
+
function studioSidebarWidthTransition(reduced, direction = "collapse") {
|
|
4251
|
+
if (reduced) return { duration: 0.01 };
|
|
4252
|
+
return {
|
|
4253
|
+
duration: direction === "expand" ? STUDIO_SIDEBAR_WIDTH_S : STUDIO_SIDEBAR_WIDTH_S * 0.94,
|
|
4254
|
+
ease: direction === "expand" ? STUDIO_SIDEBAR_EASE_ENTER : STUDIO_SIDEBAR_EASE_EXIT
|
|
4255
|
+
};
|
|
4256
|
+
}
|
|
4257
|
+
function studioSidebarDrawerTransition(reduced) {
|
|
4258
|
+
if (reduced) return { duration: 0.01 };
|
|
4259
|
+
return {
|
|
4260
|
+
duration: 0.22,
|
|
4261
|
+
ease: STUDIO_SIDEBAR_EASE
|
|
4262
|
+
};
|
|
4263
|
+
}
|
|
4264
|
+
function studioSidebarBackdropTransition(reduced) {
|
|
4265
|
+
if (reduced) return { duration: 0.01 };
|
|
4266
|
+
return { duration: 0.16, ease: STUDIO_SIDEBAR_EASE_EXIT };
|
|
4267
|
+
}
|
|
4268
|
+
|
|
4269
|
+
// src/hooks/use-sidebar-collapse-phase.ts
|
|
4270
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef3, useState as useState9 } from "react";
|
|
4271
|
+
var WIDTH_OVERLAP_FRAC = 0.7;
|
|
4272
|
+
function useSidebarCollapsePhase(collapsed, reducedMotion) {
|
|
4273
|
+
const [widthCollapsed, setWidthCollapsed] = useState9(collapsed);
|
|
4274
|
+
const [entriesVisible, setEntriesVisible] = useState9(true);
|
|
4275
|
+
const collapsedTarget = useRef3(collapsed);
|
|
4276
|
+
const isFirstRender = useRef3(true);
|
|
4277
|
+
const widthTimerRef = useRef3(null);
|
|
4278
|
+
const revealTimerRef = useRef3(null);
|
|
4279
|
+
useEffect7(() => {
|
|
4280
|
+
collapsedTarget.current = collapsed;
|
|
4281
|
+
}, [collapsed]);
|
|
4282
|
+
const clearWidthTimer = () => {
|
|
4283
|
+
if (widthTimerRef.current !== null) {
|
|
4284
|
+
clearTimeout(widthTimerRef.current);
|
|
4285
|
+
widthTimerRef.current = null;
|
|
4286
|
+
}
|
|
4287
|
+
};
|
|
4288
|
+
const clearRevealTimer = () => {
|
|
4289
|
+
if (revealTimerRef.current !== null) {
|
|
4290
|
+
clearTimeout(revealTimerRef.current);
|
|
4291
|
+
revealTimerRef.current = null;
|
|
4292
|
+
}
|
|
4293
|
+
};
|
|
4294
|
+
const applyWidthTarget = useCallback4(() => {
|
|
4295
|
+
const willExpand = !collapsedTarget.current;
|
|
4296
|
+
setWidthCollapsed(collapsedTarget.current);
|
|
4297
|
+
clearRevealTimer();
|
|
4298
|
+
if (willExpand && !reducedMotion) {
|
|
4299
|
+
revealTimerRef.current = setTimeout(
|
|
4300
|
+
() => setEntriesVisible(true),
|
|
4301
|
+
STUDIO_SIDEBAR_WIDTH_S * 1e3 * STUDIO_SIDEBAR_EXPAND_REVEAL_FRAC
|
|
4302
|
+
);
|
|
4303
|
+
}
|
|
4304
|
+
}, [reducedMotion]);
|
|
4305
|
+
useEffect7(() => {
|
|
4306
|
+
clearWidthTimer();
|
|
4307
|
+
clearRevealTimer();
|
|
4308
|
+
if (reducedMotion) {
|
|
4309
|
+
setWidthCollapsed(collapsed);
|
|
4310
|
+
setEntriesVisible(true);
|
|
4311
|
+
return;
|
|
4312
|
+
}
|
|
4313
|
+
if (isFirstRender.current) {
|
|
4314
|
+
isFirstRender.current = false;
|
|
4315
|
+
setWidthCollapsed(collapsed);
|
|
4316
|
+
setEntriesVisible(true);
|
|
4317
|
+
return;
|
|
4318
|
+
}
|
|
4319
|
+
setEntriesVisible(false);
|
|
4320
|
+
widthTimerRef.current = setTimeout(
|
|
4321
|
+
applyWidthTarget,
|
|
4322
|
+
STUDIO_SIDEBAR_ENTRIES_OUT_S * 1e3 * WIDTH_OVERLAP_FRAC
|
|
4323
|
+
);
|
|
4324
|
+
return () => {
|
|
4325
|
+
clearWidthTimer();
|
|
4326
|
+
clearRevealTimer();
|
|
4327
|
+
};
|
|
4328
|
+
}, [collapsed, reducedMotion, applyWidthTarget]);
|
|
4329
|
+
const onEntriesBlurOutComplete = useCallback4(() => {
|
|
4330
|
+
applyWidthTarget();
|
|
4331
|
+
}, [applyWidthTarget]);
|
|
4332
|
+
const onPanelWidthComplete = useCallback4(() => {
|
|
4333
|
+
clearRevealTimer();
|
|
4334
|
+
setEntriesVisible(true);
|
|
4335
|
+
}, []);
|
|
4336
|
+
const isCollapsedRail = widthCollapsed;
|
|
4337
|
+
return {
|
|
4338
|
+
widthCollapsed,
|
|
4339
|
+
isCollapsedRail,
|
|
4340
|
+
entriesVisible,
|
|
4341
|
+
onEntriesBlurOutComplete,
|
|
4342
|
+
onPanelWidthComplete
|
|
4343
|
+
};
|
|
4344
|
+
}
|
|
4345
|
+
|
|
4346
|
+
// src/components/studio/sidebar-backdrop.tsx
|
|
4347
|
+
import { AnimatePresence as AnimatePresence2, motion as motion5, useReducedMotion as useReducedMotion2 } from "motion/react";
|
|
4177
4348
|
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
4349
|
+
var StudioSidebarBackdrop = ({
|
|
4350
|
+
open,
|
|
4351
|
+
onClose
|
|
4352
|
+
}) => {
|
|
4353
|
+
const reducedMotion = useReducedMotion2();
|
|
4354
|
+
return /* @__PURE__ */ jsx31(AnimatePresence2, { children: open ? /* @__PURE__ */ jsx31(
|
|
4355
|
+
motion5.button,
|
|
4356
|
+
{
|
|
4357
|
+
type: "button",
|
|
4358
|
+
className: "fixed inset-0 z-40 bg-foreground/30 backdrop-blur-[2px] md:hidden",
|
|
4359
|
+
"aria-label": "Close menu",
|
|
4360
|
+
initial: { opacity: 0 },
|
|
4361
|
+
animate: { opacity: 1 },
|
|
4362
|
+
exit: { opacity: 0 },
|
|
4363
|
+
transition: studioSidebarBackdropTransition(!!reducedMotion),
|
|
4364
|
+
onClick: onClose
|
|
4365
|
+
}
|
|
4366
|
+
) : null });
|
|
4367
|
+
};
|
|
4368
|
+
|
|
4369
|
+
// src/components/studio/sidebar-context.tsx
|
|
4370
|
+
import { createContext as createContext4, useContext as useContext4 } from "react";
|
|
4371
|
+
var StudioSidebarContext = createContext4({
|
|
4372
|
+
collapsed: false,
|
|
4373
|
+
isMobile: false,
|
|
4374
|
+
isCollapsedRail: false,
|
|
4375
|
+
iconOnlyLayout: false
|
|
4376
|
+
});
|
|
4377
|
+
function useStudioSidebarLayout() {
|
|
4378
|
+
return useContext4(StudioSidebarContext);
|
|
4379
|
+
}
|
|
4380
|
+
|
|
4381
|
+
// src/components/studio/sidebar.tsx
|
|
4382
|
+
import {
|
|
4383
|
+
useCallback as useCallback6,
|
|
4384
|
+
useEffect as useEffect9,
|
|
4385
|
+
useMemo as useMemo8,
|
|
4386
|
+
useState as useState11
|
|
4387
|
+
} from "react";
|
|
4388
|
+
import { motion as motion8, useReducedMotion as useReducedMotion5 } from "motion/react";
|
|
4389
|
+
|
|
4390
|
+
// src/components/studio/sidebar-entries.tsx
|
|
4391
|
+
import { motion as motion6, useReducedMotion as useReducedMotion3 } from "motion/react";
|
|
4392
|
+
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
4393
|
+
var StudioSidebarEntries = ({
|
|
4394
|
+
visible,
|
|
4395
|
+
onBlurOutComplete,
|
|
4396
|
+
children,
|
|
4397
|
+
className
|
|
4398
|
+
}) => {
|
|
4399
|
+
const reducedMotion = useReducedMotion3();
|
|
4400
|
+
if (reducedMotion) {
|
|
4401
|
+
return visible ? /* @__PURE__ */ jsx32("div", { className: cn("flex min-h-0 flex-1 flex-col", className), children }) : null;
|
|
4402
|
+
}
|
|
4403
|
+
return /* @__PURE__ */ jsx32(
|
|
4404
|
+
motion6.div,
|
|
4405
|
+
{
|
|
4406
|
+
className: cn("flex min-h-0 flex-1 flex-col", className),
|
|
4407
|
+
initial: false,
|
|
4408
|
+
variants: studioSidebarEntriesContainerVariants,
|
|
4409
|
+
animate: visible ? "visible" : "hidden",
|
|
4410
|
+
transition: studioSidebarEntriesTransition(visible, false),
|
|
4411
|
+
onAnimationComplete: (definition) => {
|
|
4412
|
+
if (definition === "hidden") {
|
|
4413
|
+
onBlurOutComplete();
|
|
4414
|
+
}
|
|
4415
|
+
},
|
|
4416
|
+
style: { pointerEvents: visible ? "auto" : "none" },
|
|
4417
|
+
"aria-hidden": !visible,
|
|
4418
|
+
children
|
|
4419
|
+
}
|
|
4420
|
+
);
|
|
4421
|
+
};
|
|
4422
|
+
|
|
4423
|
+
// src/components/studio/sidebar-footer.tsx
|
|
4424
|
+
import { LogOut } from "lucide-react";
|
|
4425
|
+
|
|
4426
|
+
// src/auth/provider.tsx
|
|
4427
|
+
import {
|
|
4428
|
+
createContext as createContext5,
|
|
4429
|
+
useCallback as useCallback5,
|
|
4430
|
+
useContext as useContext5,
|
|
4431
|
+
useEffect as useEffect8,
|
|
4432
|
+
useState as useState10
|
|
4433
|
+
} from "react";
|
|
4434
|
+
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
4178
4435
|
function isInsideIframe() {
|
|
4179
4436
|
try {
|
|
4180
4437
|
return typeof window !== "undefined" && window.self !== window.top;
|
|
@@ -4182,22 +4439,26 @@ function isInsideIframe() {
|
|
|
4182
4439
|
return true;
|
|
4183
4440
|
}
|
|
4184
4441
|
}
|
|
4185
|
-
var SessionContext =
|
|
4442
|
+
var SessionContext = createContext5(void 0);
|
|
4186
4443
|
var useSession = () => {
|
|
4187
|
-
const context =
|
|
4444
|
+
const context = useContext5(SessionContext);
|
|
4188
4445
|
if (context === void 0) {
|
|
4189
4446
|
throw new Error("useSession must be used within a SessionProvider");
|
|
4190
4447
|
}
|
|
4191
4448
|
return context;
|
|
4192
4449
|
};
|
|
4450
|
+
var useOptionalSession = () => {
|
|
4451
|
+
const context = useContext5(SessionContext);
|
|
4452
|
+
return context ?? null;
|
|
4453
|
+
};
|
|
4193
4454
|
var SessionProvider = ({
|
|
4194
4455
|
children,
|
|
4195
4456
|
enabled = true
|
|
4196
4457
|
}) => {
|
|
4197
|
-
const [user, setUser] =
|
|
4198
|
-
const [loading, setLoading] =
|
|
4199
|
-
const [embedded] =
|
|
4200
|
-
|
|
4458
|
+
const [user, setUser] = useState10(null);
|
|
4459
|
+
const [loading, setLoading] = useState10(enabled);
|
|
4460
|
+
const [embedded] = useState10(isInsideIframe);
|
|
4461
|
+
useEffect8(() => {
|
|
4201
4462
|
if (!enabled) {
|
|
4202
4463
|
setLoading(false);
|
|
4203
4464
|
return;
|
|
@@ -4258,7 +4519,7 @@ var SessionProvider = ({
|
|
|
4258
4519
|
messageCleanup?.();
|
|
4259
4520
|
};
|
|
4260
4521
|
}, [enabled, embedded]);
|
|
4261
|
-
const logout =
|
|
4522
|
+
const logout = useCallback5(() => {
|
|
4262
4523
|
clearTokens();
|
|
4263
4524
|
setUser(null);
|
|
4264
4525
|
const returnTo = encodeURIComponent(
|
|
@@ -4268,7 +4529,7 @@ var SessionProvider = ({
|
|
|
4268
4529
|
() => window.location.href = `/api/auth/login?return_to=${returnTo}`
|
|
4269
4530
|
);
|
|
4270
4531
|
}, []);
|
|
4271
|
-
return /* @__PURE__ */
|
|
4532
|
+
return /* @__PURE__ */ jsx33(
|
|
4272
4533
|
SessionContext.Provider,
|
|
4273
4534
|
{
|
|
4274
4535
|
value: {
|
|
@@ -4283,49 +4544,1185 @@ var SessionProvider = ({
|
|
|
4283
4544
|
);
|
|
4284
4545
|
};
|
|
4285
4546
|
|
|
4286
|
-
// src/
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4547
|
+
// src/components/studio/sidebar-layout.ts
|
|
4548
|
+
function studioSidebarIconOnlyLayout(isMobile, isCollapsedRail) {
|
|
4549
|
+
if (isMobile) return false;
|
|
4550
|
+
return isCollapsedRail;
|
|
4551
|
+
}
|
|
4552
|
+
var studioSidebarCollapsedRailInsetClass = "box-border w-full px-1.5";
|
|
4553
|
+
var studioSidebarCollapsedRailChipRowClass = "flex w-full justify-center";
|
|
4554
|
+
function studioSidebarNavItemClasses(iconOnly, isActive) {
|
|
4555
|
+
if (iconOnly) {
|
|
4556
|
+
return cn(
|
|
4557
|
+
studioSidebarNavItemClass,
|
|
4558
|
+
studioSidebarNavItemLayout(true),
|
|
4559
|
+
isActive ? studioSidebarCollapsedRailItemActiveClass : studioSidebarCollapsedRailItemIdleClass
|
|
4560
|
+
);
|
|
4561
|
+
}
|
|
4562
|
+
return cn(
|
|
4563
|
+
studioSidebarNavItemClass,
|
|
4564
|
+
studioSidebarNavItemLayout(false),
|
|
4565
|
+
isActive ? studioSidebarNavItemActiveClass : studioSidebarNavItemIdleClass
|
|
4566
|
+
);
|
|
4567
|
+
}
|
|
4568
|
+
|
|
4569
|
+
// src/components/studio/sidebar-entry-motion.tsx
|
|
4570
|
+
import { motion as motion7, useReducedMotion as useReducedMotion4 } from "motion/react";
|
|
4571
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
4572
|
+
var StudioSidebarEntryMotion = ({
|
|
4290
4573
|
children,
|
|
4291
|
-
|
|
4292
|
-
enabled = true
|
|
4574
|
+
className
|
|
4293
4575
|
}) => {
|
|
4294
|
-
const
|
|
4295
|
-
if (
|
|
4296
|
-
return children;
|
|
4576
|
+
const reducedMotion = useReducedMotion4();
|
|
4577
|
+
if (reducedMotion) {
|
|
4578
|
+
return /* @__PURE__ */ jsx34("div", { className, children });
|
|
4297
4579
|
}
|
|
4298
|
-
|
|
4299
|
-
|
|
4580
|
+
return /* @__PURE__ */ jsx34(motion7.div, { variants: studioSidebarEntryItemVariants, className: cn(className), children });
|
|
4581
|
+
};
|
|
4582
|
+
|
|
4583
|
+
// src/components/studio/sidebar-tooltip.tsx
|
|
4584
|
+
import { Fragment as Fragment3, jsx as jsx35, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4585
|
+
var StudioSidebarTooltip = ({
|
|
4586
|
+
label,
|
|
4587
|
+
enabled,
|
|
4588
|
+
children
|
|
4589
|
+
}) => {
|
|
4590
|
+
if (!enabled) return /* @__PURE__ */ jsx35(Fragment3, { children });
|
|
4591
|
+
return /* @__PURE__ */ jsxs18(Tooltip, { children: [
|
|
4592
|
+
/* @__PURE__ */ jsx35(TooltipTrigger, { asChild: true, children }),
|
|
4593
|
+
/* @__PURE__ */ jsx35(TooltipContent, { side: "right", className: "text-xs", children: label })
|
|
4594
|
+
] });
|
|
4595
|
+
};
|
|
4596
|
+
|
|
4597
|
+
// src/components/studio/sidebar-footer.tsx
|
|
4598
|
+
import { jsx as jsx36, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
4599
|
+
function userInitials(name, email) {
|
|
4600
|
+
const fromName = name.trim().split(/\s+/).map((part) => part.charAt(0)).join("").slice(0, 2).toUpperCase();
|
|
4601
|
+
if (fromName) return fromName;
|
|
4602
|
+
return email.charAt(0).toUpperCase() || "?";
|
|
4603
|
+
}
|
|
4604
|
+
var StudioSidebarFooter = ({
|
|
4605
|
+
iconOnlyLayout,
|
|
4606
|
+
showTooltips,
|
|
4607
|
+
onSignOut,
|
|
4608
|
+
emptyCaption = null
|
|
4609
|
+
}) => {
|
|
4610
|
+
const session = useOptionalSession();
|
|
4611
|
+
const user = session?.user ?? null;
|
|
4612
|
+
const handleSignOut = () => {
|
|
4613
|
+
session?.logout();
|
|
4614
|
+
onSignOut?.();
|
|
4615
|
+
};
|
|
4616
|
+
return /* @__PURE__ */ jsx36(StudioSidebarEntryMotion, { children: /* @__PURE__ */ jsx36(
|
|
4617
|
+
"footer",
|
|
4618
|
+
{
|
|
4619
|
+
className: cn(
|
|
4620
|
+
"mt-auto w-full shrink-0 py-2.5",
|
|
4621
|
+
iconOnlyLayout ? studioSidebarCollapsedRailInsetClass : "px-2.5"
|
|
4622
|
+
),
|
|
4623
|
+
children: user ? /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-2", children: [
|
|
4624
|
+
iconOnlyLayout ? /* @__PURE__ */ jsx36("div", { className: studioSidebarCollapsedRailChipRowClass, children: /* @__PURE__ */ jsxs19(Avatar, { size: "sm", className: "size-8", children: [
|
|
4625
|
+
user.user_photo_url ? /* @__PURE__ */ jsx36(AvatarImage, { src: user.user_photo_url, alt: user.user_name }) : null,
|
|
4626
|
+
/* @__PURE__ */ jsx36(AvatarFallback, { className: "text-[10px]", children: userInitials(user.user_name, user.user_email) })
|
|
4627
|
+
] }) }) : /* @__PURE__ */ jsxs19("div", { className: "flex min-w-0 items-center gap-2.5", children: [
|
|
4628
|
+
/* @__PURE__ */ jsxs19(Avatar, { size: "sm", children: [
|
|
4629
|
+
user.user_photo_url ? /* @__PURE__ */ jsx36(AvatarImage, { src: user.user_photo_url, alt: user.user_name }) : null,
|
|
4630
|
+
/* @__PURE__ */ jsx36(AvatarFallback, { children: userInitials(user.user_name, user.user_email) })
|
|
4631
|
+
] }),
|
|
4632
|
+
/* @__PURE__ */ jsxs19("div", { className: "min-w-0 flex-1", children: [
|
|
4633
|
+
/* @__PURE__ */ jsx36("p", { className: "truncate text-sm font-medium text-foreground", children: user.user_name }),
|
|
4634
|
+
/* @__PURE__ */ jsx36("p", { className: "truncate text-xs text-muted-foreground", children: user.user_email })
|
|
4635
|
+
] })
|
|
4636
|
+
] }),
|
|
4637
|
+
/* @__PURE__ */ jsx36(
|
|
4638
|
+
"div",
|
|
4639
|
+
{
|
|
4640
|
+
className: iconOnlyLayout ? studioSidebarCollapsedRailChipRowClass : void 0,
|
|
4641
|
+
children: /* @__PURE__ */ jsx36(StudioSidebarTooltip, { label: "Sign out", enabled: showTooltips, children: /* @__PURE__ */ jsxs19(
|
|
4642
|
+
"button",
|
|
4643
|
+
{
|
|
4644
|
+
type: "button",
|
|
4645
|
+
onClick: handleSignOut,
|
|
4646
|
+
className: cn(
|
|
4647
|
+
studioSidebarNavItemClasses(iconOnlyLayout, false),
|
|
4648
|
+
iconOnlyLayout && "inline-flex"
|
|
4649
|
+
),
|
|
4650
|
+
"aria-label": "Sign out",
|
|
4651
|
+
children: [
|
|
4652
|
+
/* @__PURE__ */ jsx36(LogOut, { className: "size-3.5 shrink-0" }),
|
|
4653
|
+
!iconOnlyLayout ? "Sign out" : null
|
|
4654
|
+
]
|
|
4655
|
+
}
|
|
4656
|
+
) })
|
|
4657
|
+
}
|
|
4658
|
+
)
|
|
4659
|
+
] }) : !iconOnlyLayout && emptyCaption ? /* @__PURE__ */ jsx36("p", { className: "px-1 text-xs text-muted-foreground", children: emptyCaption }) : null
|
|
4660
|
+
}
|
|
4661
|
+
) });
|
|
4662
|
+
};
|
|
4663
|
+
|
|
4664
|
+
// src/components/studio/sidebar-header.tsx
|
|
4665
|
+
import { ChevronLeft, ChevronRight, X } from "lucide-react";
|
|
4666
|
+
import { jsx as jsx37, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
4667
|
+
var sidebarHeaderClass = "flex h-12 shrink-0 items-center px-2";
|
|
4668
|
+
var toggleButtonClass = cn(
|
|
4669
|
+
"flex shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors",
|
|
4670
|
+
"hover:bg-muted hover:text-foreground",
|
|
4671
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15"
|
|
4672
|
+
);
|
|
4673
|
+
var SidebarToggleButton = ({ ariaLabel, expanded, onClick, children }) => /* @__PURE__ */ jsx37(
|
|
4674
|
+
"button",
|
|
4675
|
+
{
|
|
4676
|
+
type: "button",
|
|
4677
|
+
onClick,
|
|
4678
|
+
className: cn(toggleButtonClass, "size-7"),
|
|
4679
|
+
"aria-label": ariaLabel,
|
|
4680
|
+
"aria-expanded": expanded,
|
|
4681
|
+
children
|
|
4300
4682
|
}
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4683
|
+
);
|
|
4684
|
+
var CollapsedBrandToggle = ({
|
|
4685
|
+
onExpand,
|
|
4686
|
+
brand
|
|
4687
|
+
}) => /* @__PURE__ */ jsx37("div", { className: studioSidebarCollapsedRailChipRowClass, children: /* @__PURE__ */ jsx37(StudioSidebarTooltip, { label: "Expand sidebar", enabled: true, children: /* @__PURE__ */ jsxs20(
|
|
4688
|
+
"button",
|
|
4689
|
+
{
|
|
4690
|
+
type: "button",
|
|
4691
|
+
onClick: onExpand,
|
|
4692
|
+
"aria-label": "Expand sidebar",
|
|
4693
|
+
"aria-expanded": false,
|
|
4694
|
+
className: cn(
|
|
4695
|
+
toggleButtonClass,
|
|
4696
|
+
"group relative inline-flex size-8 items-center justify-center overflow-hidden rounded-lg"
|
|
4697
|
+
),
|
|
4698
|
+
children: [
|
|
4699
|
+
/* @__PURE__ */ jsx37(
|
|
4700
|
+
"span",
|
|
4701
|
+
{
|
|
4702
|
+
"aria-hidden": true,
|
|
4703
|
+
className: cn(
|
|
4704
|
+
"pointer-events-none flex items-center justify-center",
|
|
4705
|
+
"transition-[opacity,transform] duration-200 ease-out",
|
|
4706
|
+
"group-hover:scale-90 group-hover:opacity-0"
|
|
4707
|
+
),
|
|
4708
|
+
children: brand
|
|
4709
|
+
}
|
|
4710
|
+
),
|
|
4711
|
+
/* @__PURE__ */ jsx37(
|
|
4712
|
+
ChevronRight,
|
|
4713
|
+
{
|
|
4714
|
+
"aria-hidden": true,
|
|
4715
|
+
className: cn(
|
|
4716
|
+
"pointer-events-none absolute inset-0 m-auto size-4",
|
|
4717
|
+
"opacity-0 transition-[opacity,transform] duration-200 ease-out",
|
|
4718
|
+
"group-hover:opacity-100"
|
|
4719
|
+
)
|
|
4720
|
+
}
|
|
4721
|
+
)
|
|
4722
|
+
]
|
|
4723
|
+
}
|
|
4724
|
+
) }) });
|
|
4725
|
+
var StudioSidebarHeader = ({
|
|
4726
|
+
isCollapsedRail,
|
|
4727
|
+
isMobile,
|
|
4728
|
+
mobileOpen,
|
|
4729
|
+
onToggle,
|
|
4730
|
+
brand
|
|
4731
|
+
}) => {
|
|
4732
|
+
if (isMobile) {
|
|
4733
|
+
return /* @__PURE__ */ jsxs20("header", { className: cn(sidebarHeaderClass, "justify-between gap-2 pr-2"), children: [
|
|
4734
|
+
brand,
|
|
4735
|
+
/* @__PURE__ */ jsx37(
|
|
4736
|
+
SidebarToggleButton,
|
|
4737
|
+
{
|
|
4738
|
+
ariaLabel: "Close menu",
|
|
4739
|
+
expanded: mobileOpen,
|
|
4740
|
+
onClick: onToggle,
|
|
4741
|
+
children: /* @__PURE__ */ jsx37(X, { className: "size-3.5" })
|
|
4742
|
+
}
|
|
4743
|
+
)
|
|
4744
|
+
] });
|
|
4745
|
+
}
|
|
4746
|
+
if (isCollapsedRail) {
|
|
4747
|
+
return /* @__PURE__ */ jsx37(
|
|
4748
|
+
"header",
|
|
4749
|
+
{
|
|
4750
|
+
className: cn(
|
|
4751
|
+
"flex h-12 shrink-0 items-center",
|
|
4752
|
+
studioSidebarCollapsedRailInsetClass
|
|
4753
|
+
),
|
|
4754
|
+
children: /* @__PURE__ */ jsx37(CollapsedBrandToggle, { onExpand: onToggle, brand })
|
|
4755
|
+
}
|
|
4304
4756
|
);
|
|
4305
|
-
window.location.href = `/api/auth/login?return_to=${returnTo}`;
|
|
4306
|
-
return null;
|
|
4307
4757
|
}
|
|
4308
|
-
return children
|
|
4758
|
+
return /* @__PURE__ */ jsxs20("header", { className: cn(sidebarHeaderClass, "justify-between gap-1 pr-2"), children: [
|
|
4759
|
+
brand,
|
|
4760
|
+
/* @__PURE__ */ jsx37(
|
|
4761
|
+
SidebarToggleButton,
|
|
4762
|
+
{
|
|
4763
|
+
ariaLabel: "Collapse sidebar",
|
|
4764
|
+
expanded: true,
|
|
4765
|
+
onClick: onToggle,
|
|
4766
|
+
children: /* @__PURE__ */ jsx37(ChevronLeft, { className: "size-4" })
|
|
4767
|
+
}
|
|
4768
|
+
)
|
|
4769
|
+
] });
|
|
4309
4770
|
};
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4771
|
+
|
|
4772
|
+
// src/components/studio/sidebar-workforce.ts
|
|
4773
|
+
function workforceItemId(w) {
|
|
4774
|
+
return w.id ?? w.uid ?? w.name ?? "";
|
|
4775
|
+
}
|
|
4776
|
+
function workforceItemLabel(w) {
|
|
4777
|
+
return w.name ?? workforceItemId(w);
|
|
4778
|
+
}
|
|
4779
|
+
function workforceItemInitial(w) {
|
|
4780
|
+
const label = workforceItemLabel(w);
|
|
4781
|
+
return label.charAt(0).toUpperCase() || "?";
|
|
4782
|
+
}
|
|
4783
|
+
|
|
4784
|
+
// src/components/studio/sidebar-nav.tsx
|
|
4785
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
4786
|
+
var StudioSidebarNav = ({
|
|
4787
|
+
workforces,
|
|
4788
|
+
selectedId,
|
|
4789
|
+
onSelect,
|
|
4790
|
+
iconOnlyLayout,
|
|
4791
|
+
showTooltips
|
|
4792
|
+
}) => {
|
|
4793
|
+
if (workforces.length === 0) return null;
|
|
4794
|
+
return /* @__PURE__ */ jsx38(
|
|
4795
|
+
"nav",
|
|
4796
|
+
{
|
|
4797
|
+
className: cn(
|
|
4798
|
+
"flex min-h-0 flex-1 flex-col overflow-y-auto py-1",
|
|
4799
|
+
iconOnlyLayout ? cn(studioSidebarCollapsedRailInsetClass, "gap-1") : "gap-0.5 px-2"
|
|
4800
|
+
),
|
|
4801
|
+
"aria-label": "Agents",
|
|
4802
|
+
children: workforces.map((w) => {
|
|
4803
|
+
const id = workforceItemId(w);
|
|
4804
|
+
const isActive = id === selectedId;
|
|
4805
|
+
const label = workforceItemLabel(w);
|
|
4806
|
+
return /* @__PURE__ */ jsx38(
|
|
4807
|
+
StudioSidebarEntryMotion,
|
|
4808
|
+
{
|
|
4809
|
+
className: iconOnlyLayout ? studioSidebarCollapsedRailChipRowClass : void 0,
|
|
4810
|
+
children: /* @__PURE__ */ jsx38(StudioSidebarTooltip, { label, enabled: showTooltips, children: /* @__PURE__ */ jsx38(
|
|
4811
|
+
"button",
|
|
4812
|
+
{
|
|
4813
|
+
type: "button",
|
|
4814
|
+
onClick: () => onSelect(id),
|
|
4815
|
+
"aria-pressed": isActive,
|
|
4816
|
+
"aria-label": label,
|
|
4817
|
+
className: cn(
|
|
4818
|
+
studioSidebarNavItemClasses(iconOnlyLayout, isActive),
|
|
4819
|
+
iconOnlyLayout && "inline-flex"
|
|
4820
|
+
),
|
|
4821
|
+
children: iconOnlyLayout ? /* @__PURE__ */ jsx38("span", { className: "text-xs font-semibold leading-none", children: workforceItemInitial(w) }) : /* @__PURE__ */ jsx38("span", { className: "min-w-0 truncate", children: label })
|
|
4822
|
+
}
|
|
4823
|
+
) })
|
|
4824
|
+
},
|
|
4825
|
+
id
|
|
4826
|
+
);
|
|
4827
|
+
})
|
|
4828
|
+
}
|
|
4829
|
+
);
|
|
4830
|
+
};
|
|
4831
|
+
|
|
4832
|
+
// src/components/studio/timbal-mark.tsx
|
|
4833
|
+
import { LiquidMetal } from "@paper-design/shaders-react";
|
|
4834
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
4835
|
+
var DEFAULT_SIZE = 64;
|
|
4836
|
+
var TRANSPARENT_BACK = "#00000000";
|
|
4837
|
+
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=";
|
|
4838
|
+
function TimbalMark({
|
|
4839
|
+
className,
|
|
4840
|
+
size = DEFAULT_SIZE,
|
|
4841
|
+
src = TIMBAL_SYMBOL_DATA_URI
|
|
4842
|
+
}) {
|
|
4843
|
+
return /* @__PURE__ */ jsx39(
|
|
4844
|
+
"div",
|
|
4845
|
+
{
|
|
4846
|
+
className: cn("relative shrink-0 bg-transparent", className),
|
|
4847
|
+
style: { width: size, height: size },
|
|
4848
|
+
role: "img",
|
|
4849
|
+
"aria-label": "Timbal",
|
|
4850
|
+
children: /* @__PURE__ */ jsx39(
|
|
4851
|
+
LiquidMetal,
|
|
4852
|
+
{
|
|
4853
|
+
width: size,
|
|
4854
|
+
height: size,
|
|
4855
|
+
image: src,
|
|
4856
|
+
colorBack: TRANSPARENT_BACK,
|
|
4857
|
+
colorTint: "#ffffff",
|
|
4858
|
+
shape: "none",
|
|
4859
|
+
repetition: 2,
|
|
4860
|
+
softness: 0.1,
|
|
4861
|
+
shiftRed: 0.3,
|
|
4862
|
+
shiftBlue: 0.3,
|
|
4863
|
+
distortion: 0.07,
|
|
4864
|
+
contour: 0.4,
|
|
4865
|
+
angle: 70,
|
|
4866
|
+
speed: 1,
|
|
4867
|
+
scale: 0.6,
|
|
4868
|
+
fit: "contain",
|
|
4869
|
+
className: "size-full bg-transparent",
|
|
4870
|
+
style: { background: "transparent" },
|
|
4871
|
+
webGlContextAttributes: {
|
|
4872
|
+
alpha: true,
|
|
4873
|
+
premultipliedAlpha: false
|
|
4874
|
+
}
|
|
4875
|
+
}
|
|
4876
|
+
)
|
|
4877
|
+
}
|
|
4878
|
+
);
|
|
4879
|
+
}
|
|
4880
|
+
|
|
4881
|
+
// src/components/studio/sidebar.tsx
|
|
4882
|
+
import { jsx as jsx40, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
4883
|
+
var DEFAULT_BREAKPOINT_PX = 768;
|
|
4884
|
+
function readPersistedCollapsed(key) {
|
|
4885
|
+
if (!key || typeof window === "undefined") return false;
|
|
4886
|
+
try {
|
|
4887
|
+
return window.localStorage.getItem(key) === "1";
|
|
4888
|
+
} catch {
|
|
4889
|
+
return false;
|
|
4890
|
+
}
|
|
4891
|
+
}
|
|
4892
|
+
function writePersistedCollapsed(key, collapsed) {
|
|
4893
|
+
if (!key || typeof window === "undefined") return;
|
|
4894
|
+
try {
|
|
4895
|
+
window.localStorage.setItem(key, collapsed ? "1" : "0");
|
|
4896
|
+
} catch {
|
|
4897
|
+
}
|
|
4898
|
+
}
|
|
4899
|
+
var StudioSidebarPanel = ({
|
|
4900
|
+
workforces,
|
|
4901
|
+
selectedId,
|
|
4902
|
+
onSelect,
|
|
4903
|
+
collapsed,
|
|
4904
|
+
onCollapsedChange,
|
|
4905
|
+
isMobile,
|
|
4906
|
+
mobileOpen,
|
|
4907
|
+
onMobileOpenChange,
|
|
4908
|
+
widthCollapsed,
|
|
4909
|
+
entriesVisible,
|
|
4910
|
+
onEntriesBlurOutComplete,
|
|
4911
|
+
onPanelWidthComplete,
|
|
4912
|
+
brand,
|
|
4913
|
+
emptyCaption = null
|
|
4914
|
+
}) => {
|
|
4915
|
+
const reducedMotion = useReducedMotion5();
|
|
4916
|
+
const isCollapsedRail = widthCollapsed && !isMobile;
|
|
4917
|
+
const iconOnlyLayout = studioSidebarIconOnlyLayout(isMobile, isCollapsedRail);
|
|
4918
|
+
const isDrawerOpen = isMobile && mobileOpen;
|
|
4919
|
+
const widthDirection = widthCollapsed ? "collapse" : "expand";
|
|
4920
|
+
const widthTransition = studioSidebarWidthTransition(
|
|
4921
|
+
!!reducedMotion,
|
|
4922
|
+
widthDirection
|
|
4923
|
+
);
|
|
4924
|
+
const handleToggle = () => {
|
|
4925
|
+
if (isMobile) {
|
|
4926
|
+
onMobileOpenChange(false);
|
|
4927
|
+
return;
|
|
4928
|
+
}
|
|
4929
|
+
onCollapsedChange(!collapsed);
|
|
4930
|
+
};
|
|
4931
|
+
const panelWidthPx = isMobile ? SIDEBAR_MOBILE_PX : widthCollapsed ? SIDEBAR_WIDTH_COLLAPSED_PX : SIDEBAR_WIDTH_PX;
|
|
4932
|
+
const brandNode = brand ?? /* @__PURE__ */ jsx40(TimbalMark, { size: 32 });
|
|
4933
|
+
const panel = /* @__PURE__ */ jsxs21(
|
|
4934
|
+
motion8.div,
|
|
4935
|
+
{
|
|
4936
|
+
"data-sidebar-collapsed": isCollapsedRail ? "" : void 0,
|
|
4937
|
+
className: cn(
|
|
4938
|
+
"flex h-full flex-col overflow-hidden",
|
|
4939
|
+
studioSidebarPanelClass,
|
|
4940
|
+
isMobile ? "rounded-none rounded-r-2xl" : "rounded-2xl"
|
|
4941
|
+
),
|
|
4942
|
+
initial: false,
|
|
4943
|
+
animate: { width: panelWidthPx },
|
|
4944
|
+
transition: widthTransition,
|
|
4945
|
+
style: { willChange: entriesVisible ? void 0 : "width" },
|
|
4946
|
+
onAnimationComplete: isMobile || entriesVisible ? void 0 : () => onPanelWidthComplete(),
|
|
4947
|
+
children: [
|
|
4948
|
+
/* @__PURE__ */ jsx40(
|
|
4949
|
+
StudioSidebarHeader,
|
|
4950
|
+
{
|
|
4951
|
+
isCollapsedRail,
|
|
4952
|
+
isMobile,
|
|
4953
|
+
mobileOpen,
|
|
4954
|
+
onToggle: handleToggle,
|
|
4955
|
+
brand: brandNode
|
|
4956
|
+
}
|
|
4957
|
+
),
|
|
4958
|
+
/* @__PURE__ */ jsxs21(
|
|
4959
|
+
StudioSidebarEntries,
|
|
4960
|
+
{
|
|
4961
|
+
visible: entriesVisible,
|
|
4962
|
+
onBlurOutComplete: onEntriesBlurOutComplete,
|
|
4963
|
+
children: [
|
|
4964
|
+
/* @__PURE__ */ jsx40(
|
|
4965
|
+
"div",
|
|
4966
|
+
{
|
|
4967
|
+
id: DOM_IDS.sidebarRuntimeAnchor,
|
|
4968
|
+
className: cn(
|
|
4969
|
+
"min-h-0 shrink-0 empty:hidden",
|
|
4970
|
+
iconOnlyLayout ? "px-1.5 pt-1.5" : "px-2 pt-1.5"
|
|
4971
|
+
)
|
|
4972
|
+
}
|
|
4973
|
+
),
|
|
4974
|
+
/* @__PURE__ */ jsx40(
|
|
4975
|
+
StudioSidebarNav,
|
|
4976
|
+
{
|
|
4977
|
+
workforces,
|
|
4978
|
+
selectedId,
|
|
4979
|
+
onSelect,
|
|
4980
|
+
iconOnlyLayout,
|
|
4981
|
+
showTooltips: isCollapsedRail
|
|
4982
|
+
}
|
|
4983
|
+
),
|
|
4984
|
+
workforces.length === 0 ? /* @__PURE__ */ jsx40("div", { className: "min-h-0 flex-1" }) : null,
|
|
4985
|
+
/* @__PURE__ */ jsx40(
|
|
4986
|
+
StudioSidebarFooter,
|
|
4987
|
+
{
|
|
4988
|
+
iconOnlyLayout,
|
|
4989
|
+
showTooltips: isCollapsedRail,
|
|
4990
|
+
onSignOut: isMobile ? () => onMobileOpenChange(false) : void 0,
|
|
4991
|
+
emptyCaption
|
|
4992
|
+
}
|
|
4993
|
+
)
|
|
4994
|
+
]
|
|
4995
|
+
}
|
|
4996
|
+
)
|
|
4997
|
+
]
|
|
4998
|
+
}
|
|
4999
|
+
);
|
|
5000
|
+
if (isMobile) {
|
|
5001
|
+
return /* @__PURE__ */ jsx40(
|
|
5002
|
+
motion8.aside,
|
|
5003
|
+
{
|
|
5004
|
+
className: "fixed inset-y-0 left-0 z-[60] flex",
|
|
5005
|
+
"aria-label": "Studio navigation",
|
|
5006
|
+
"aria-hidden": !mobileOpen,
|
|
5007
|
+
initial: false,
|
|
5008
|
+
animate: {
|
|
5009
|
+
x: isDrawerOpen ? 0 : -(SIDEBAR_MOBILE_PX + 32)
|
|
5010
|
+
},
|
|
5011
|
+
transition: studioSidebarDrawerTransition(!!reducedMotion),
|
|
5012
|
+
style: { pointerEvents: isDrawerOpen ? "auto" : "none" },
|
|
5013
|
+
children: panel
|
|
5014
|
+
}
|
|
5015
|
+
);
|
|
5016
|
+
}
|
|
5017
|
+
return /* @__PURE__ */ jsx40(
|
|
5018
|
+
"aside",
|
|
5019
|
+
{
|
|
5020
|
+
className: "absolute inset-y-0 left-0 z-[60] flex py-[var(--studio-sidebar-gap)] pl-[var(--studio-sidebar-gap)]",
|
|
5021
|
+
"aria-label": "Studio navigation",
|
|
5022
|
+
children: panel
|
|
5023
|
+
}
|
|
5024
|
+
);
|
|
5025
|
+
};
|
|
5026
|
+
var StudioSidebar = ({
|
|
5027
|
+
workforces: workforcesProp,
|
|
5028
|
+
selectedId: selectedIdProp,
|
|
5029
|
+
onSelect,
|
|
5030
|
+
defaultCollapsed = false,
|
|
5031
|
+
persistKey = STORAGE_KEYS.sidebarCollapsed,
|
|
5032
|
+
mobileBreakpointPx = DEFAULT_BREAKPOINT_PX,
|
|
5033
|
+
brand,
|
|
5034
|
+
emptyCaption,
|
|
5035
|
+
mobileOpen: mobileOpenProp,
|
|
5036
|
+
onMobileOpenChange: onMobileOpenChangeProp
|
|
5037
|
+
}) => {
|
|
5038
|
+
const reducedMotion = useReducedMotion5();
|
|
5039
|
+
const fetched = useWorkforces({ enabled: workforcesProp === void 0 });
|
|
5040
|
+
const workforces = workforcesProp ?? fetched.workforces;
|
|
5041
|
+
const [internalSelected, setInternalSelected] = useState11(
|
|
5042
|
+
selectedIdProp ?? ""
|
|
5043
|
+
);
|
|
5044
|
+
useEffect9(() => {
|
|
5045
|
+
if (selectedIdProp !== void 0) return;
|
|
5046
|
+
if (internalSelected) return;
|
|
5047
|
+
const first = workforces[0]?.id ?? workforces[0]?.uid ?? workforces[0]?.name;
|
|
5048
|
+
if (first) setInternalSelected(first);
|
|
5049
|
+
}, [workforces, selectedIdProp, internalSelected]);
|
|
5050
|
+
const selectedId = selectedIdProp ?? internalSelected ?? workforces[0]?.id ?? workforces[0]?.uid ?? workforces[0]?.name ?? "";
|
|
5051
|
+
const handleSelect = useCallback6(
|
|
5052
|
+
(id) => {
|
|
5053
|
+
if (selectedIdProp === void 0) setInternalSelected(id);
|
|
5054
|
+
onSelect?.(id);
|
|
5055
|
+
},
|
|
5056
|
+
[selectedIdProp, onSelect]
|
|
5057
|
+
);
|
|
5058
|
+
const [collapsed, setCollapsed] = useState11(() => {
|
|
5059
|
+
const persisted = readPersistedCollapsed(persistKey);
|
|
5060
|
+
return persisted || defaultCollapsed;
|
|
5061
|
+
});
|
|
5062
|
+
const handleCollapsedChange = useCallback6(
|
|
5063
|
+
(next) => {
|
|
5064
|
+
setCollapsed(next);
|
|
5065
|
+
writePersistedCollapsed(persistKey, next);
|
|
5066
|
+
},
|
|
5067
|
+
[persistKey]
|
|
5068
|
+
);
|
|
5069
|
+
const [isMobile, setIsMobile] = useState11(() => {
|
|
5070
|
+
if (typeof window === "undefined") return false;
|
|
5071
|
+
return window.innerWidth < mobileBreakpointPx;
|
|
5072
|
+
});
|
|
5073
|
+
useEffect9(() => {
|
|
5074
|
+
if (typeof window === "undefined") return;
|
|
5075
|
+
const onResize = () => setIsMobile(window.innerWidth < mobileBreakpointPx);
|
|
5076
|
+
onResize();
|
|
5077
|
+
window.addEventListener("resize", onResize);
|
|
5078
|
+
return () => window.removeEventListener("resize", onResize);
|
|
5079
|
+
}, [mobileBreakpointPx]);
|
|
5080
|
+
const [internalMobileOpen, setInternalMobileOpen] = useState11(false);
|
|
5081
|
+
const mobileOpen = mobileOpenProp ?? internalMobileOpen;
|
|
5082
|
+
const setMobileOpen = useCallback6(
|
|
5083
|
+
(next) => {
|
|
5084
|
+
if (mobileOpenProp === void 0) setInternalMobileOpen(next);
|
|
5085
|
+
onMobileOpenChangeProp?.(next);
|
|
5086
|
+
},
|
|
5087
|
+
[mobileOpenProp, onMobileOpenChangeProp]
|
|
5088
|
+
);
|
|
5089
|
+
const effectiveCollapsed = isMobile ? false : collapsed;
|
|
5090
|
+
const {
|
|
5091
|
+
widthCollapsed,
|
|
5092
|
+
entriesVisible: phaseEntriesVisible,
|
|
5093
|
+
onEntriesBlurOutComplete,
|
|
5094
|
+
onPanelWidthComplete
|
|
5095
|
+
} = useSidebarCollapsePhase(effectiveCollapsed, !!reducedMotion);
|
|
5096
|
+
const entriesVisible = isMobile || phaseEntriesVisible;
|
|
5097
|
+
const isCollapsedRail = widthCollapsed && !isMobile;
|
|
5098
|
+
const iconOnlyLayout = studioSidebarIconOnlyLayout(isMobile, isCollapsedRail);
|
|
5099
|
+
const contextValue = useMemo8(
|
|
5100
|
+
() => ({
|
|
5101
|
+
collapsed: effectiveCollapsed,
|
|
5102
|
+
isMobile,
|
|
5103
|
+
isCollapsedRail,
|
|
5104
|
+
iconOnlyLayout
|
|
5105
|
+
}),
|
|
5106
|
+
[effectiveCollapsed, isMobile, isCollapsedRail, iconOnlyLayout]
|
|
5107
|
+
);
|
|
5108
|
+
return /* @__PURE__ */ jsx40(StudioSidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx40(
|
|
5109
|
+
StudioSidebarPanel,
|
|
5110
|
+
{
|
|
5111
|
+
workforces,
|
|
5112
|
+
selectedId,
|
|
5113
|
+
onSelect: handleSelect,
|
|
5114
|
+
collapsed: effectiveCollapsed,
|
|
5115
|
+
onCollapsedChange: handleCollapsedChange,
|
|
5116
|
+
isMobile,
|
|
5117
|
+
mobileOpen,
|
|
5118
|
+
onMobileOpenChange: setMobileOpen,
|
|
5119
|
+
widthCollapsed,
|
|
5120
|
+
entriesVisible,
|
|
5121
|
+
onEntriesBlurOutComplete,
|
|
5122
|
+
onPanelWidthComplete,
|
|
5123
|
+
brand,
|
|
5124
|
+
emptyCaption
|
|
5125
|
+
}
|
|
5126
|
+
) });
|
|
5127
|
+
};
|
|
5128
|
+
|
|
5129
|
+
// src/components/studio/sidebar-runtime-portal.tsx
|
|
5130
|
+
import { useCallback as useCallback7, useLayoutEffect, useState as useState12 } from "react";
|
|
5131
|
+
import { createPortal } from "react-dom";
|
|
5132
|
+
import { MessageSquarePlus } from "lucide-react";
|
|
5133
|
+
import { useThread as useThread2 } from "@assistant-ui/react";
|
|
5134
|
+
import { jsx as jsx41, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
5135
|
+
var StudioSidebarRuntimePortal = ({
|
|
5136
|
+
label = "New chat"
|
|
5137
|
+
}) => {
|
|
5138
|
+
const { iconOnlyLayout } = useStudioSidebarLayout();
|
|
5139
|
+
const hasMessages = useThread2((s) => s.messages.length > 0);
|
|
5140
|
+
const { clear } = useTimbalRuntime();
|
|
5141
|
+
const [anchor, setAnchor] = useState12(null);
|
|
5142
|
+
const startNewChat = useCallback7(() => {
|
|
5143
|
+
clear();
|
|
5144
|
+
}, [clear]);
|
|
5145
|
+
useLayoutEffect(() => {
|
|
5146
|
+
setAnchor(document.getElementById(DOM_IDS.sidebarRuntimeAnchor));
|
|
5147
|
+
}, []);
|
|
5148
|
+
if (!anchor || !hasMessages) return null;
|
|
5149
|
+
const button = /* @__PURE__ */ jsxs22(
|
|
5150
|
+
"button",
|
|
5151
|
+
{
|
|
5152
|
+
type: "button",
|
|
5153
|
+
onClick: startNewChat,
|
|
5154
|
+
"aria-label": label,
|
|
5155
|
+
className: studioSidebarNavItemClasses(iconOnlyLayout, false),
|
|
5156
|
+
children: [
|
|
5157
|
+
/* @__PURE__ */ jsx41(MessageSquarePlus, { className: "size-3.5 shrink-0" }),
|
|
5158
|
+
!iconOnlyLayout ? /* @__PURE__ */ jsx41("span", { className: "min-w-0 truncate", children: label }) : null
|
|
5159
|
+
]
|
|
5160
|
+
}
|
|
5161
|
+
);
|
|
5162
|
+
return createPortal(
|
|
5163
|
+
iconOnlyLayout ? /* @__PURE__ */ jsxs22(Tooltip, { children: [
|
|
5164
|
+
/* @__PURE__ */ jsx41(TooltipTrigger, { asChild: true, children: button }),
|
|
5165
|
+
/* @__PURE__ */ jsx41(TooltipContent, { side: "right", className: "text-xs", children: label })
|
|
5166
|
+
] }) : button,
|
|
5167
|
+
anchor
|
|
5168
|
+
);
|
|
5169
|
+
};
|
|
5170
|
+
|
|
5171
|
+
// src/components/studio/welcome.tsx
|
|
5172
|
+
import { motion as motion9 } from "motion/react";
|
|
5173
|
+
import { useThread as useThread3 } from "@assistant-ui/react";
|
|
5174
|
+
import { jsx as jsx42, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
5175
|
+
var luxuryEase2 = [0.16, 1, 0.3, 1];
|
|
5176
|
+
var welcomeStagger2 = {
|
|
5177
|
+
initial: {},
|
|
5178
|
+
animate: {
|
|
5179
|
+
transition: { staggerChildren: 0.16, delayChildren: 0.18 }
|
|
5180
|
+
}
|
|
5181
|
+
};
|
|
5182
|
+
var welcomeItem2 = {
|
|
5183
|
+
initial: { opacity: 0, y: 14 },
|
|
5184
|
+
animate: {
|
|
5185
|
+
opacity: 1,
|
|
5186
|
+
y: 0,
|
|
5187
|
+
transition: { duration: 0.9, ease: luxuryEase2 }
|
|
5188
|
+
}
|
|
5189
|
+
};
|
|
5190
|
+
var welcomeIcon2 = {
|
|
5191
|
+
initial: { opacity: 0, y: 10, scale: 0.96 },
|
|
5192
|
+
animate: {
|
|
5193
|
+
opacity: 1,
|
|
5194
|
+
y: 0,
|
|
5195
|
+
scale: 1,
|
|
5196
|
+
transition: { duration: 1.1, ease: luxuryEase2 }
|
|
5197
|
+
}
|
|
5198
|
+
};
|
|
5199
|
+
var StudioWelcome = ({ config, icon }) => {
|
|
5200
|
+
const isEmpty = useThread3((s) => s.messages.length === 0);
|
|
5201
|
+
if (!isEmpty) return null;
|
|
5202
|
+
const iconNode = icon ?? /* @__PURE__ */ jsx42(
|
|
5203
|
+
TimbalMark,
|
|
5204
|
+
{
|
|
5205
|
+
size: 112,
|
|
5206
|
+
className: "max-md:scale-[0.58] max-md:origin-center"
|
|
5207
|
+
}
|
|
5208
|
+
);
|
|
5209
|
+
return /* @__PURE__ */ jsx42("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: /* @__PURE__ */ jsx42("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ jsxs23(
|
|
5210
|
+
motion9.div,
|
|
5211
|
+
{
|
|
5212
|
+
className: "aui-thread-welcome-message flex flex-col items-center justify-center px-2 text-center sm:px-4",
|
|
5213
|
+
variants: welcomeStagger2,
|
|
5214
|
+
initial: "initial",
|
|
5215
|
+
animate: "animate",
|
|
5216
|
+
children: [
|
|
5217
|
+
/* @__PURE__ */ jsx42(motion9.div, { variants: welcomeIcon2, className: "mb-4 md:mb-5", children: iconNode }),
|
|
5218
|
+
/* @__PURE__ */ jsx42(
|
|
5219
|
+
motion9.h1,
|
|
5220
|
+
{
|
|
5221
|
+
variants: welcomeItem2,
|
|
5222
|
+
className: "aui-thread-welcome-message-inner text-xl font-semibold sm:text-2xl",
|
|
5223
|
+
children: config?.heading ?? "How can I help you today?"
|
|
5224
|
+
}
|
|
5225
|
+
),
|
|
5226
|
+
/* @__PURE__ */ jsx42(
|
|
5227
|
+
motion9.p,
|
|
5228
|
+
{
|
|
5229
|
+
variants: welcomeItem2,
|
|
5230
|
+
className: "aui-thread-welcome-message-inner mt-2 text-muted-foreground",
|
|
5231
|
+
children: config?.subheading ?? "Send a message to start a conversation."
|
|
5232
|
+
}
|
|
5233
|
+
)
|
|
5234
|
+
]
|
|
5235
|
+
}
|
|
5236
|
+
) }) });
|
|
5237
|
+
};
|
|
5238
|
+
|
|
5239
|
+
// src/components/studio/studio-shell.tsx
|
|
5240
|
+
import { Fragment as Fragment4, jsx as jsx43, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
5241
|
+
import { createElement } from "react";
|
|
5242
|
+
var DEFAULT_BREAKPOINT_PX2 = 768;
|
|
5243
|
+
function readPersistedCollapsed2(key) {
|
|
5244
|
+
if (!key || typeof window === "undefined") return false;
|
|
5245
|
+
try {
|
|
5246
|
+
return window.localStorage.getItem(key) === "1";
|
|
5247
|
+
} catch {
|
|
5248
|
+
return false;
|
|
5249
|
+
}
|
|
5250
|
+
}
|
|
5251
|
+
function writePersistedCollapsed2(key, collapsed) {
|
|
5252
|
+
if (!key || typeof window === "undefined") return;
|
|
5253
|
+
try {
|
|
5254
|
+
window.localStorage.setItem(key, collapsed ? "1" : "0");
|
|
5255
|
+
} catch {
|
|
5256
|
+
}
|
|
5257
|
+
}
|
|
5258
|
+
function makeComposerWithPortal(BaseComposer) {
|
|
5259
|
+
const Resolved = BaseComposer ?? Composer;
|
|
5260
|
+
return function StudioComposerWithSidebar(props) {
|
|
5261
|
+
return /* @__PURE__ */ jsxs24(Fragment4, { children: [
|
|
5262
|
+
/* @__PURE__ */ jsx43(StudioSidebarRuntimePortal, {}),
|
|
5263
|
+
/* @__PURE__ */ jsx43(Resolved, { ...props })
|
|
5264
|
+
] });
|
|
5265
|
+
};
|
|
5266
|
+
}
|
|
5267
|
+
var TimbalStudioShell = ({
|
|
5268
|
+
workforceId,
|
|
5269
|
+
workforces: workforcesProp,
|
|
5270
|
+
workforcesFetch,
|
|
5271
|
+
workforcesBaseUrl,
|
|
5272
|
+
brand,
|
|
5273
|
+
headerActions,
|
|
5274
|
+
headerStart,
|
|
5275
|
+
defaultCollapsed = false,
|
|
5276
|
+
persistKey = STORAGE_KEYS.sidebarCollapsed,
|
|
5277
|
+
mobileBreakpointPx = DEFAULT_BREAKPOINT_PX2,
|
|
5278
|
+
sidebarEmptyCaption = null,
|
|
5279
|
+
welcome,
|
|
5280
|
+
components,
|
|
5281
|
+
...chatProps
|
|
5282
|
+
}) => {
|
|
5283
|
+
const reducedMotion = useReducedMotion6();
|
|
5284
|
+
const shouldFetchWorkforces = !workforceId && workforcesProp === void 0;
|
|
5285
|
+
const fetched = useWorkforces({
|
|
5286
|
+
enabled: shouldFetchWorkforces,
|
|
5287
|
+
fetch: workforcesFetch,
|
|
5288
|
+
baseUrl: workforcesBaseUrl
|
|
5289
|
+
});
|
|
5290
|
+
const workforces = workforcesProp ?? fetched.workforces;
|
|
5291
|
+
const [internalSelected, setInternalSelected] = useState13(
|
|
5292
|
+
workforceId ?? ""
|
|
5293
|
+
);
|
|
5294
|
+
useEffect10(() => {
|
|
5295
|
+
if (workforceId) return;
|
|
5296
|
+
if (internalSelected) return;
|
|
5297
|
+
const first = workforces[0]?.id ?? workforces[0]?.uid ?? workforces[0]?.name;
|
|
5298
|
+
if (first) setInternalSelected(first);
|
|
5299
|
+
}, [workforces, workforceId, internalSelected]);
|
|
5300
|
+
const activeWorkforceId = workforceId ?? internalSelected ?? fetched.selectedId ?? "";
|
|
5301
|
+
const [collapsed, setCollapsed] = useState13(() => {
|
|
5302
|
+
const persisted = readPersistedCollapsed2(persistKey);
|
|
5303
|
+
return persisted || defaultCollapsed;
|
|
5304
|
+
});
|
|
5305
|
+
const [isMobile, setIsMobile] = useState13(() => {
|
|
5306
|
+
if (typeof window === "undefined") return false;
|
|
5307
|
+
return window.innerWidth < mobileBreakpointPx;
|
|
5308
|
+
});
|
|
5309
|
+
const [mobileSidebarOpen, setMobileSidebarOpen] = useState13(false);
|
|
5310
|
+
useEffect10(() => {
|
|
5311
|
+
if (typeof window === "undefined") return;
|
|
5312
|
+
const onResize = () => setIsMobile(window.innerWidth < mobileBreakpointPx);
|
|
5313
|
+
onResize();
|
|
5314
|
+
window.addEventListener("resize", onResize);
|
|
5315
|
+
return () => window.removeEventListener("resize", onResize);
|
|
5316
|
+
}, [mobileBreakpointPx]);
|
|
5317
|
+
useEffect10(() => {
|
|
5318
|
+
if (!isMobile) setMobileSidebarOpen(false);
|
|
5319
|
+
}, [isMobile]);
|
|
5320
|
+
useEffect10(() => {
|
|
5321
|
+
if (!mobileSidebarOpen) return;
|
|
5322
|
+
const onKeyDown = (e) => {
|
|
5323
|
+
if (e.key === "Escape") setMobileSidebarOpen(false);
|
|
5324
|
+
};
|
|
5325
|
+
window.addEventListener("keydown", onKeyDown);
|
|
5326
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
5327
|
+
}, [mobileSidebarOpen]);
|
|
5328
|
+
const effectiveCollapsed = isMobile ? false : collapsed;
|
|
5329
|
+
const {
|
|
5330
|
+
widthCollapsed,
|
|
5331
|
+
entriesVisible: phaseEntriesVisible,
|
|
5332
|
+
onEntriesBlurOutComplete,
|
|
5333
|
+
onPanelWidthComplete
|
|
5334
|
+
} = useSidebarCollapsePhase(effectiveCollapsed, !!reducedMotion);
|
|
5335
|
+
const entriesVisible = isMobile || phaseEntriesVisible;
|
|
5336
|
+
const isCollapsedRail = widthCollapsed && !isMobile;
|
|
5337
|
+
const iconOnlyLayout = studioSidebarIconOnlyLayout(isMobile, isCollapsedRail);
|
|
5338
|
+
const layoutDirection = widthCollapsed ? "collapse" : "expand";
|
|
5339
|
+
const layoutTransition = studioSidebarWidthTransition(
|
|
5340
|
+
!!reducedMotion,
|
|
5341
|
+
layoutDirection
|
|
5342
|
+
);
|
|
5343
|
+
const desktopInsetPx = widthCollapsed ? SIDEBAR_INSET_PX_COLLAPSED : SIDEBAR_INSET_PX_EXPANDED;
|
|
5344
|
+
const onCollapsedChange = useCallback8(
|
|
5345
|
+
(next) => {
|
|
5346
|
+
setCollapsed(next);
|
|
5347
|
+
writePersistedCollapsed2(persistKey, next);
|
|
5348
|
+
},
|
|
5349
|
+
[persistKey]
|
|
5350
|
+
);
|
|
5351
|
+
const handleSelectWorkforce = useCallback8(
|
|
5352
|
+
(id) => {
|
|
5353
|
+
if (!workforceId) setInternalSelected(id);
|
|
5354
|
+
if (isMobile) setMobileSidebarOpen(false);
|
|
5355
|
+
},
|
|
5356
|
+
[workforceId, isMobile]
|
|
5357
|
+
);
|
|
5358
|
+
const sidebarContext = useMemo9(
|
|
5359
|
+
() => ({
|
|
5360
|
+
collapsed: effectiveCollapsed,
|
|
5361
|
+
isMobile,
|
|
5362
|
+
isCollapsedRail,
|
|
5363
|
+
iconOnlyLayout
|
|
5364
|
+
}),
|
|
5365
|
+
[effectiveCollapsed, isMobile, isCollapsedRail, iconOnlyLayout]
|
|
5366
|
+
);
|
|
5367
|
+
const resolvedComponents = useMemo9(() => {
|
|
5368
|
+
const next = { Welcome: StudioWelcome, ...components };
|
|
5369
|
+
next.Composer = makeComposerWithPortal(components?.Composer);
|
|
5370
|
+
return next;
|
|
5371
|
+
}, [components]);
|
|
5372
|
+
return /* @__PURE__ */ jsx43(StudioSidebarContext.Provider, { value: sidebarContext, children: /* @__PURE__ */ jsxs24(
|
|
5373
|
+
"div",
|
|
5374
|
+
{
|
|
5375
|
+
className: cn(
|
|
5376
|
+
"relative h-dvh overflow-hidden bg-background",
|
|
5377
|
+
isMobile && mobileSidebarOpen && "max-md:overflow-hidden"
|
|
5378
|
+
),
|
|
5379
|
+
style: studioChromeShellStyle,
|
|
5380
|
+
children: [
|
|
5381
|
+
/* @__PURE__ */ jsx43(
|
|
5382
|
+
"div",
|
|
5383
|
+
{
|
|
5384
|
+
className: "pointer-events-none absolute inset-0 z-0 bg-background",
|
|
5385
|
+
"aria-hidden": true
|
|
5386
|
+
}
|
|
5387
|
+
),
|
|
5388
|
+
/* @__PURE__ */ jsx43(
|
|
5389
|
+
"div",
|
|
5390
|
+
{
|
|
5391
|
+
className: cn(
|
|
5392
|
+
"pointer-events-none absolute inset-0 z-0",
|
|
5393
|
+
studioPlaygroundGradientClass
|
|
5394
|
+
),
|
|
5395
|
+
"aria-hidden": true
|
|
5396
|
+
}
|
|
5397
|
+
),
|
|
5398
|
+
/* @__PURE__ */ jsx43(
|
|
5399
|
+
StudioSidebarBackdrop,
|
|
5400
|
+
{
|
|
5401
|
+
open: isMobile && mobileSidebarOpen,
|
|
5402
|
+
onClose: () => setMobileSidebarOpen(false)
|
|
5403
|
+
}
|
|
5404
|
+
),
|
|
5405
|
+
/* @__PURE__ */ jsx43(
|
|
5406
|
+
StudioSidebarPanel,
|
|
5407
|
+
{
|
|
5408
|
+
workforces,
|
|
5409
|
+
selectedId: activeWorkforceId,
|
|
5410
|
+
onSelect: handleSelectWorkforce,
|
|
5411
|
+
collapsed: effectiveCollapsed,
|
|
5412
|
+
onCollapsedChange,
|
|
5413
|
+
isMobile,
|
|
5414
|
+
mobileOpen: mobileSidebarOpen,
|
|
5415
|
+
onMobileOpenChange: setMobileSidebarOpen,
|
|
5416
|
+
widthCollapsed,
|
|
5417
|
+
entriesVisible,
|
|
5418
|
+
onEntriesBlurOutComplete,
|
|
5419
|
+
onPanelWidthComplete,
|
|
5420
|
+
brand,
|
|
5421
|
+
emptyCaption: sidebarEmptyCaption
|
|
5422
|
+
}
|
|
5423
|
+
),
|
|
5424
|
+
/* @__PURE__ */ jsxs24(
|
|
5425
|
+
motion10.header,
|
|
5426
|
+
{
|
|
5427
|
+
className: cn(
|
|
5428
|
+
"absolute top-0 right-0 z-40 flex items-start justify-between gap-2",
|
|
5429
|
+
"px-3 pt-[var(--studio-topbar-gap)] md:px-4",
|
|
5430
|
+
"left-0"
|
|
5431
|
+
),
|
|
5432
|
+
initial: false,
|
|
5433
|
+
animate: { left: isMobile ? 0 : desktopInsetPx },
|
|
5434
|
+
transition: layoutTransition,
|
|
5435
|
+
children: [
|
|
5436
|
+
/* @__PURE__ */ jsxs24(
|
|
5437
|
+
"div",
|
|
5438
|
+
{
|
|
5439
|
+
className: cn(
|
|
5440
|
+
"flex min-w-0 flex-1 items-center gap-2",
|
|
5441
|
+
studioTopbarPillHeightClass
|
|
5442
|
+
),
|
|
5443
|
+
children: [
|
|
5444
|
+
isMobile && !mobileSidebarOpen ? /* @__PURE__ */ jsx43(
|
|
5445
|
+
TimbalV2Button,
|
|
5446
|
+
{
|
|
5447
|
+
variant: "secondary",
|
|
5448
|
+
size: "sm",
|
|
5449
|
+
isIconOnly: true,
|
|
5450
|
+
className: studioTopbarIconPillClass,
|
|
5451
|
+
onClick: () => setMobileSidebarOpen(true),
|
|
5452
|
+
"aria-label": "Open menu",
|
|
5453
|
+
"aria-expanded": false,
|
|
5454
|
+
children: /* @__PURE__ */ jsx43(Menu, { className: "size-4" })
|
|
5455
|
+
}
|
|
5456
|
+
) : null,
|
|
5457
|
+
headerStart
|
|
5458
|
+
]
|
|
5459
|
+
}
|
|
5460
|
+
),
|
|
5461
|
+
headerActions ? /* @__PURE__ */ jsx43("div", { className: "flex shrink-0 items-center gap-1", children: headerActions }) : null
|
|
5462
|
+
]
|
|
5463
|
+
}
|
|
5464
|
+
),
|
|
5465
|
+
/* @__PURE__ */ jsx43(
|
|
5466
|
+
motion10.main,
|
|
5467
|
+
{
|
|
5468
|
+
className: cn(
|
|
5469
|
+
"relative z-10 flex h-full min-w-0 flex-col",
|
|
5470
|
+
"pt-[var(--studio-inset-top)]",
|
|
5471
|
+
"px-3 md:px-0"
|
|
5472
|
+
),
|
|
5473
|
+
initial: false,
|
|
5474
|
+
animate: { paddingLeft: isMobile ? 12 : desktopInsetPx },
|
|
5475
|
+
transition: layoutTransition,
|
|
5476
|
+
children: activeWorkforceId ? /* @__PURE__ */ createElement(
|
|
5477
|
+
TimbalChat,
|
|
5478
|
+
{
|
|
5479
|
+
...chatProps,
|
|
5480
|
+
workforceId: activeWorkforceId,
|
|
5481
|
+
key: activeWorkforceId,
|
|
5482
|
+
welcome,
|
|
5483
|
+
components: resolvedComponents,
|
|
5484
|
+
className: cn("min-h-0 flex-1 bg-transparent", chatProps.className)
|
|
5485
|
+
}
|
|
5486
|
+
) : null
|
|
5487
|
+
}
|
|
5488
|
+
)
|
|
5489
|
+
]
|
|
5490
|
+
}
|
|
5491
|
+
) });
|
|
5492
|
+
};
|
|
5493
|
+
|
|
5494
|
+
// src/components/studio/mode-toggle.tsx
|
|
5495
|
+
import { useCallback as useCallback9, useEffect as useEffect11, useState as useState14 } from "react";
|
|
5496
|
+
import { Moon, Sun } from "lucide-react";
|
|
5497
|
+
import { jsx as jsx44, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
5498
|
+
var ModeToggle = ({
|
|
5499
|
+
theme,
|
|
5500
|
+
setTheme,
|
|
5501
|
+
className,
|
|
5502
|
+
label = "Toggle theme"
|
|
5503
|
+
}) => {
|
|
5504
|
+
const isControlled = theme !== void 0;
|
|
5505
|
+
const [internalIsDark, setInternalIsDark] = useState14(false);
|
|
5506
|
+
useEffect11(() => {
|
|
5507
|
+
if (isControlled) return;
|
|
5508
|
+
if (typeof document === "undefined") return;
|
|
5509
|
+
setInternalIsDark(document.documentElement.classList.contains("dark"));
|
|
5510
|
+
}, [isControlled]);
|
|
5511
|
+
const isDark = isControlled ? theme === "dark" : internalIsDark;
|
|
5512
|
+
const onClick = useCallback9(() => {
|
|
5513
|
+
const next = isDark ? "light" : "dark";
|
|
5514
|
+
if (setTheme) {
|
|
5515
|
+
setTheme(next);
|
|
5516
|
+
return;
|
|
5517
|
+
}
|
|
5518
|
+
if (typeof document === "undefined") return;
|
|
5519
|
+
document.documentElement.classList.toggle("dark", next === "dark");
|
|
5520
|
+
setInternalIsDark(next === "dark");
|
|
5521
|
+
}, [isDark, setTheme]);
|
|
5522
|
+
return /* @__PURE__ */ jsxs25(
|
|
5523
|
+
TimbalV2Button,
|
|
5524
|
+
{
|
|
5525
|
+
variant: "secondary",
|
|
5526
|
+
size: "sm",
|
|
5527
|
+
isIconOnly: true,
|
|
5528
|
+
onClick,
|
|
5529
|
+
className: cn(
|
|
5530
|
+
studioTopbarPillHeightClass,
|
|
5531
|
+
studioTopbarIconPillClass,
|
|
5532
|
+
"relative",
|
|
5533
|
+
className
|
|
5534
|
+
),
|
|
5535
|
+
"aria-label": label,
|
|
5536
|
+
title: label,
|
|
5537
|
+
children: [
|
|
5538
|
+
/* @__PURE__ */ jsx44(Sun, { className: "size-3.5 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" }),
|
|
5539
|
+
/* @__PURE__ */ jsx44(Moon, { className: "absolute size-3.5 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" }),
|
|
5540
|
+
/* @__PURE__ */ jsx44("span", { className: "sr-only", children: label })
|
|
5541
|
+
]
|
|
5542
|
+
}
|
|
5543
|
+
);
|
|
5544
|
+
};
|
|
5545
|
+
|
|
5546
|
+
// src/artifacts/agent-instructions.ts
|
|
5547
|
+
var ARTIFACT_AGENT_INSTRUCTIONS = `
|
|
5548
|
+
## Rich artifacts (Timbal chat UI)
|
|
5549
|
+
|
|
5550
|
+
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.
|
|
5551
|
+
|
|
5552
|
+
### Delivery channels (either works)
|
|
5553
|
+
|
|
5554
|
+
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.
|
|
5555
|
+
2. **Inline markdown fence** \u2014 embed the same JSON inside a fenced block:
|
|
5556
|
+
|
|
5557
|
+
\`\`\`timbal-artifact
|
|
5558
|
+
{"type":"chart","data":[{"month":"Jan","sales":120}]}
|
|
5559
|
+
\`\`\`
|
|
5560
|
+
|
|
5561
|
+
The alias \`\`\`timbal\`\`\` is also accepted.
|
|
5562
|
+
|
|
5563
|
+
### Built-in artifact types
|
|
5564
|
+
|
|
5565
|
+
| \`type\` | Use for |
|
|
5566
|
+
|---|---|
|
|
5567
|
+
| \`chart\` | Bar, line, area, or pie charts. Fields: \`data\`, optional \`chartType\`, \`xKey\`, \`dataKey\`, \`title\`, \`unit\`. |
|
|
5568
|
+
| \`table\` | Tabular data. Fields: \`rows\`, optional \`columns\`, \`title\`. |
|
|
5569
|
+
| \`question\` | In-thread multiple choice. Fields: \`options: [{ id, label, description? }]\`, optional \`prompt\`, \`multi\`. User replies are sent back as a normal user message. |
|
|
5570
|
+
| \`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). |
|
|
5571
|
+
| \`json\` | Fallback structured view. Fields: \`data\`, optional \`title\`. |
|
|
5572
|
+
| \`ui\` | **Interactive UI** composed from a fixed node palette (hover, click, drag). See below. |
|
|
5573
|
+
|
|
5574
|
+
### When to use \`type: "html"\`
|
|
5575
|
+
|
|
5576
|
+
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\`.
|
|
5577
|
+
|
|
5578
|
+
- Inline \`<style>\`, \`<script>\`, SVG, and canvas are supported.
|
|
5579
|
+
- Default \`sandboxed: true\` runs in an isolated iframe with scripts enabled.
|
|
5580
|
+
- Set \`sandboxed: false\` only for trusted content that needs external CDN scripts/styles or full DOM freedom.
|
|
5581
|
+
- Prefer \`ui\` when controls should send chat messages or host events; prefer \`html\` for self-contained mini-apps and visual demos.
|
|
5582
|
+
|
|
5583
|
+
### When to use \`type: "ui"\`
|
|
5584
|
+
|
|
5585
|
+
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.
|
|
5586
|
+
|
|
5587
|
+
Each \`ui\` artifact has:
|
|
5588
|
+
|
|
5589
|
+
- \`initialState\` \u2014 optional object seeding local state (per widget instance).
|
|
5590
|
+
- \`root\` \u2014 a single node tree (see node kinds below).
|
|
5591
|
+
- optional \`title\` \u2014 card heading.
|
|
5592
|
+
|
|
5593
|
+
**Bindings:** anywhere a primitive is accepted, you may use \`{ "$bind": "dotted.path" }\` to read from \`initialState\` / local state (e.g. \`{ "$bind": "qty" }\`).
|
|
5594
|
+
|
|
5595
|
+
**Actions:** nodes may attach \`onClick\`, \`onChange\`, or \`onDragEnd\` with one action or an array:
|
|
5596
|
+
|
|
5597
|
+
| Action | Shape | Effect |
|
|
5598
|
+
|---|---|---|
|
|
5599
|
+
| User message | \`{ "kind": "message", "text": "..." }\` or \`{ "kind": "message", "text": { "$bind": "path" } }\` | Sends text as the next user message. |
|
|
5600
|
+
| Set state | \`{ "kind": "set", "path": "foo", "value": 1 }\` | Writes local widget state. |
|
|
5601
|
+
| Toggle boolean | \`{ "kind": "toggle", "path": "enabled" }\` | Flips a boolean at \`path\`. |
|
|
5602
|
+
| Host event | \`{ "kind": "emit", "name": "event-name", "payload": { ... } }\` | Bubbles to the host app (\`onArtifactEvent\` on \`<Thread>\`). |
|
|
5603
|
+
|
|
5604
|
+
### \`ui\` node palette (\`root.kind\`)
|
|
5605
|
+
|
|
5606
|
+
| \`kind\` | Purpose | Key fields |
|
|
5607
|
+
|---|---|---|
|
|
5608
|
+
| \`box\` | Layout container | \`children\`, \`direction\` (\`row\`/\`col\`), \`gap\`, \`padding\`, \`align\`, \`justify\`, \`wrap\` |
|
|
5609
|
+
| \`text\` | Body text | \`value\`, optional \`muted\`, \`size\`, \`weight\` |
|
|
5610
|
+
| \`heading\` | Heading | \`value\`, optional \`level\` (1\u20134) |
|
|
5611
|
+
| \`badge\` | Pill label | \`value\`, optional \`tone\` (\`default\`, \`primary\`, \`success\`, \`warn\`, \`danger\`) |
|
|
5612
|
+
| \`button\` | Clickable button | \`label\`, optional \`variant\`, \`size\`, \`disabled\`, \`onClick\` |
|
|
5613
|
+
| \`toggle\` | Boolean switch | \`binding\` (state path), optional \`label\`, \`onChange\` |
|
|
5614
|
+
| \`slider\` | Numeric range | \`binding\`, optional \`min\`, \`max\`, \`step\`, \`label\`, \`showValue\`, \`onChange\` |
|
|
5615
|
+
| \`tooltip\` | Hover tooltip | \`content\`, \`child\` (single node), optional \`side\` |
|
|
5616
|
+
| \`draggable\` | Drag gesture | \`child\`, optional \`axis\` (\`x\`/\`y\`/\`both\`), \`snapBack\`, \`onDragEnd\` |
|
|
5617
|
+
| \`custom\` | Host-registered widget | \`name\`, optional \`props\`, \`children\` \u2014 only if the app registered that name |
|
|
5618
|
+
|
|
5619
|
+
### Example \`ui\` artifact
|
|
5620
|
+
|
|
5621
|
+
\`\`\`json
|
|
5622
|
+
{
|
|
5623
|
+
"type": "ui",
|
|
5624
|
+
"title": "Configure plan",
|
|
5625
|
+
"initialState": { "qty": 1, "premium": false },
|
|
5626
|
+
"root": {
|
|
5627
|
+
"kind": "box",
|
|
5628
|
+
"direction": "col",
|
|
5629
|
+
"gap": 3,
|
|
5630
|
+
"children": [
|
|
5631
|
+
{ "kind": "heading", "value": "Choose quantity", "level": 3 },
|
|
5632
|
+
{
|
|
5633
|
+
"kind": "tooltip",
|
|
5634
|
+
"content": "Drag to adjust quantity",
|
|
5635
|
+
"child": {
|
|
5636
|
+
"kind": "slider",
|
|
5637
|
+
"binding": "qty",
|
|
5638
|
+
"min": 1,
|
|
5639
|
+
"max": 50,
|
|
5640
|
+
"label": "Quantity",
|
|
5641
|
+
"onChange": { "kind": "emit", "name": "qty-changed" }
|
|
5642
|
+
}
|
|
5643
|
+
},
|
|
5644
|
+
{ "kind": "toggle", "binding": "premium", "label": "Premium support" },
|
|
5645
|
+
{
|
|
5646
|
+
"kind": "button",
|
|
5647
|
+
"label": "Confirm",
|
|
5648
|
+
"onClick": { "kind": "message", "text": { "$bind": "qty" } }
|
|
5649
|
+
}
|
|
5650
|
+
]
|
|
5651
|
+
}
|
|
5652
|
+
}
|
|
5653
|
+
\`\`\`
|
|
5654
|
+
|
|
5655
|
+
### Rules
|
|
5656
|
+
|
|
5657
|
+
- Always set \`type\` to a built-in value above unless the app documented a custom type.
|
|
5658
|
+
- Prefer \`ui\` over \`html\` when actions must bubble to the host chat (\`message\`, \`emit\`).
|
|
5659
|
+
- Prefer \`question\` for simple A/B/C choices; use \`ui\` when you need sliders, toggles, drag, or multi-control layouts.
|
|
5660
|
+
- Keep \`data\` arrays reasonably small (charts/tables).
|
|
5661
|
+
|
|
5662
|
+
### After calling an artifact tool (critical)
|
|
5663
|
+
|
|
5664
|
+
When you call a tool that returns an artifact (\`make_chart\`, \`ask_question\`, \`show_table\`, \`show_html\`, \`make_ui_demo\`, etc.):
|
|
5665
|
+
|
|
5666
|
+
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.
|
|
5667
|
+
2. **Do not** emit a matching \`\`\`timbal-artifact\`\`\` block for the same payload \u2014 pick **one** channel (tool result only).
|
|
5668
|
+
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.
|
|
5669
|
+
4. Treat the widget as visible to the user; refer to it as "above" / "the chart" / "the choices" \u2014 never reproduce its contents.
|
|
5670
|
+
`.trim();
|
|
5671
|
+
|
|
5672
|
+
// src/auth/guard.tsx
|
|
5673
|
+
import { Loader2 } from "lucide-react";
|
|
5674
|
+
import { jsx as jsx45 } from "react/jsx-runtime";
|
|
5675
|
+
var AuthGuard = ({
|
|
5676
|
+
children,
|
|
5677
|
+
requireAuth = false,
|
|
5678
|
+
enabled = true
|
|
5679
|
+
}) => {
|
|
5680
|
+
const { isAuthenticated, loading, isEmbedded } = useSession();
|
|
5681
|
+
if (!enabled) {
|
|
5682
|
+
return children;
|
|
5683
|
+
}
|
|
5684
|
+
if (loading) {
|
|
5685
|
+
return /* @__PURE__ */ jsx45("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ jsx45(Loader2, { className: "w-8 h-8 animate-spin" }) });
|
|
5686
|
+
}
|
|
5687
|
+
if (requireAuth && !isAuthenticated && !isEmbedded) {
|
|
5688
|
+
const returnTo = encodeURIComponent(
|
|
5689
|
+
window.location.pathname + window.location.search
|
|
5690
|
+
);
|
|
5691
|
+
window.location.href = `/api/auth/login?return_to=${returnTo}`;
|
|
5692
|
+
return null;
|
|
5693
|
+
}
|
|
5694
|
+
return children;
|
|
5695
|
+
};
|
|
5696
|
+
|
|
5697
|
+
// src/index.ts
|
|
5698
|
+
import {
|
|
5699
|
+
ThreadPrimitive as ThreadPrimitive2,
|
|
5700
|
+
MessagePrimitive as MessagePrimitive3,
|
|
5701
|
+
ComposerPrimitive as ComposerPrimitive4,
|
|
5702
|
+
ActionBarPrimitive as ActionBarPrimitive2,
|
|
5703
|
+
AuiIf as AuiIf3,
|
|
5704
|
+
AssistantRuntimeProvider as AssistantRuntimeProvider2,
|
|
5705
|
+
useThread as useThread4,
|
|
5706
|
+
useThreadRuntime as useThreadRuntime4,
|
|
5707
|
+
useMessageRuntime,
|
|
5708
|
+
useComposerRuntime as useComposerRuntime2
|
|
5709
|
+
} from "@assistant-ui/react";
|
|
5710
|
+
export {
|
|
5711
|
+
ARTIFACT_AGENT_INSTRUCTIONS,
|
|
5712
|
+
ARTIFACT_FENCE_LANGUAGES,
|
|
5713
|
+
ActionBarPrimitive2 as ActionBarPrimitive,
|
|
5714
|
+
ArtifactCard,
|
|
5715
|
+
ArtifactRegistryProvider,
|
|
5716
|
+
ArtifactView,
|
|
5717
|
+
AssistantRuntimeProvider2 as AssistantRuntimeProvider,
|
|
5718
|
+
AuiIf3 as AuiIf,
|
|
5719
|
+
AuthGuard,
|
|
5720
|
+
Avatar,
|
|
4322
5721
|
AvatarFallback,
|
|
4323
5722
|
AvatarImage,
|
|
4324
5723
|
Button,
|
|
4325
5724
|
ChartArtifactView,
|
|
4326
5725
|
Composer,
|
|
4327
|
-
ComposerAddAttachment,
|
|
4328
|
-
ComposerAttachments,
|
|
4329
5726
|
ComposerPrimitive4 as ComposerPrimitive,
|
|
4330
5727
|
DEFAULT_UPLOAD_ACCEPT,
|
|
4331
5728
|
Dialog,
|
|
@@ -4335,44 +5732,27 @@ export {
|
|
|
4335
5732
|
DialogPortal,
|
|
4336
5733
|
DialogTitle,
|
|
4337
5734
|
DialogTrigger,
|
|
4338
|
-
ErrorPrimitive2 as ErrorPrimitive,
|
|
4339
5735
|
HtmlArtifactView,
|
|
4340
5736
|
JsonArtifactView,
|
|
4341
5737
|
MarkdownText,
|
|
4342
|
-
MessagePartPrimitive2 as MessagePartPrimitive,
|
|
4343
5738
|
MessagePrimitive3 as MessagePrimitive,
|
|
5739
|
+
ModeToggle,
|
|
4344
5740
|
QuestionArtifactView,
|
|
4345
|
-
STUDIO_INSET_LEFT,
|
|
4346
|
-
STUDIO_PILL_HEIGHT,
|
|
4347
|
-
STUDIO_SIDEBAR_GAP,
|
|
4348
|
-
STUDIO_SIDEBAR_WIDTH,
|
|
4349
|
-
STUDIO_TOPBAR_GAP,
|
|
4350
|
-
STUDIO_TOPBAR_HEIGHT,
|
|
4351
5741
|
SessionProvider,
|
|
4352
5742
|
Shimmer,
|
|
5743
|
+
StudioSidebar,
|
|
5744
|
+
StudioWelcome,
|
|
4353
5745
|
Suggestions,
|
|
4354
|
-
syntax_highlighter_default as SyntaxHighlighter,
|
|
4355
|
-
TIMBAL_V2_BORDER,
|
|
4356
|
-
TIMBAL_V2_FILL,
|
|
4357
|
-
TIMBAL_V2_LABEL,
|
|
4358
|
-
TIMBAL_V2_PILL_SURFACE,
|
|
4359
|
-
TIMBAL_V2_SECONDARY_CHROME,
|
|
4360
|
-
TIMBAL_V2_SHADOW,
|
|
4361
|
-
TIMBAL_V2_SIZE_HEIGHT,
|
|
4362
|
-
TIMBAL_V2_SIZE_ICON,
|
|
4363
|
-
TIMBAL_V2_SIZE_LABEL_PX,
|
|
4364
5746
|
TableArtifactView,
|
|
4365
5747
|
Thread,
|
|
4366
5748
|
ThreadPrimitive2 as ThreadPrimitive,
|
|
4367
5749
|
TimbalChat,
|
|
4368
5750
|
TimbalChatShell,
|
|
5751
|
+
TimbalMark,
|
|
4369
5752
|
TimbalRuntimeProvider,
|
|
4370
|
-
|
|
5753
|
+
TimbalStudioShell,
|
|
4371
5754
|
ToolArtifactFallback,
|
|
4372
|
-
ToolBodyPresence,
|
|
4373
5755
|
ToolFallback,
|
|
4374
|
-
ToolMotion,
|
|
4375
|
-
ToolPresence,
|
|
4376
5756
|
Tooltip,
|
|
4377
5757
|
TooltipContent,
|
|
4378
5758
|
TooltipIconButton,
|
|
@@ -4382,10 +5762,8 @@ export {
|
|
|
4382
5762
|
UiCustomNodeRegistryProvider,
|
|
4383
5763
|
UiEventProvider,
|
|
4384
5764
|
UiNodeView,
|
|
4385
|
-
UserMessageAttachments,
|
|
4386
5765
|
WorkforceSelector,
|
|
4387
5766
|
authFetch,
|
|
4388
|
-
buttonVariants,
|
|
4389
5767
|
clearTokens,
|
|
4390
5768
|
cn,
|
|
4391
5769
|
createDefaultAttachmentAdapter,
|
|
@@ -4399,7 +5777,6 @@ export {
|
|
|
4399
5777
|
isArtifact,
|
|
4400
5778
|
isArtifactFenceLanguage,
|
|
4401
5779
|
isUiBinding,
|
|
4402
|
-
luxuryEase,
|
|
4403
5780
|
parseArtifactFromToolResult,
|
|
4404
5781
|
parseSSELine2 as parseSSELine,
|
|
4405
5782
|
refreshAccessToken,
|
|
@@ -4409,38 +5786,13 @@ export {
|
|
|
4409
5786
|
setPath,
|
|
4410
5787
|
setRefreshToken,
|
|
4411
5788
|
splitMarkdownByArtifacts,
|
|
4412
|
-
studioArtifactShellClass,
|
|
4413
|
-
studioChromeShellStyle,
|
|
4414
|
-
studioComposeInputShellClass,
|
|
4415
|
-
studioComposerIoWellClass,
|
|
4416
|
-
studioIntegrationBorder,
|
|
4417
|
-
studioIntegrationCardClass,
|
|
4418
|
-
studioIntegrationIconTileClass,
|
|
4419
|
-
studioIntegrationSurfaceSolid,
|
|
4420
|
-
studioListRowButtonClass,
|
|
4421
|
-
studioPillSurfaceClass,
|
|
4422
|
-
studioPlaygroundGradientClass,
|
|
4423
|
-
studioQuestionOptionClass,
|
|
4424
|
-
studioQuestionOptionSelectedClass,
|
|
4425
|
-
studioSecondaryChromeClass,
|
|
4426
|
-
studioTimelineActionClass,
|
|
4427
|
-
studioTimelineBodyPadClass,
|
|
4428
|
-
studioTimelineChevronClass,
|
|
4429
|
-
studioTimelineDetailClass,
|
|
4430
|
-
studioTimelineRowButtonClass,
|
|
4431
|
-
studioTimelineShimmerActionClass,
|
|
4432
|
-
studioTimelineTextClass,
|
|
4433
|
-
studioToolCardShellClass,
|
|
4434
|
-
studioTopbarIconPillClass,
|
|
4435
|
-
studioTopbarPillHeightClass,
|
|
4436
|
-
toolPresenceTransition,
|
|
4437
5789
|
useArtifactRegistry,
|
|
4438
|
-
useAuiState3 as useAuiState,
|
|
4439
5790
|
useComposerRuntime2 as useComposerRuntime,
|
|
4440
5791
|
useMessageRuntime,
|
|
5792
|
+
useOptionalSession,
|
|
4441
5793
|
useResolvedSuggestions,
|
|
4442
5794
|
useSession,
|
|
4443
|
-
|
|
5795
|
+
useThread4 as useThread,
|
|
4444
5796
|
useThreadRuntime4 as useThreadRuntime,
|
|
4445
5797
|
useTimbalRuntime,
|
|
4446
5798
|
useTimbalStream,
|