@timbal-ai/timbal-react 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +18 -4
  3. package/dist/app.cjs +3532 -1483
  4. package/dist/app.d.cts +75 -30
  5. package/dist/app.d.ts +75 -30
  6. package/dist/app.esm.js +29 -7
  7. package/dist/{chart-artifact-CMnDys2t.d.ts → chart-artifact-2OTDTRwM.d.ts} +194 -40
  8. package/dist/{chart-artifact-C8-Py6lc.d.cts → chart-artifact-CS3qyGIY.d.cts} +194 -40
  9. package/dist/chat.cjs +264 -107
  10. package/dist/chat.d.cts +2 -2
  11. package/dist/chat.d.ts +2 -2
  12. package/dist/chat.esm.js +4 -3
  13. package/dist/chunk-5ECRZ5O7.esm.js +899 -0
  14. package/dist/{chunk-QU7ET55D.esm.js → chunk-AZL2WANO.esm.js} +320 -177
  15. package/dist/{chunk-OH23AX2V.esm.js → chunk-B4XAC4G7.esm.js} +430 -780
  16. package/dist/chunk-EDEKQYSU.esm.js +10 -0
  17. package/dist/{chunk-GQBYZRD7.esm.js → chunk-IGHBLJV3.esm.js} +38 -27
  18. package/dist/{chunk-OFWC4MIY.esm.js → chunk-JYDJRGDE.esm.js} +5 -3
  19. package/dist/{chunk-VOWNCS3F.esm.js → chunk-SZDYIRMB.esm.js} +1567 -490
  20. package/dist/chunk-TZI3ID3C.esm.js +232 -0
  21. package/dist/{chunk-THBA27QY.esm.js → chunk-WMKPT5BV.esm.js} +242 -123
  22. package/dist/{chunk-VXMM2HX7.esm.js → chunk-ZNYAETFD.esm.js} +1 -1
  23. package/dist/{circular-progress-Ci8L-Hfa.d.cts → circular-progress-CDsJwIPF.d.cts} +19 -77
  24. package/dist/{circular-progress-Ci8L-Hfa.d.ts → circular-progress-CDsJwIPF.d.ts} +19 -77
  25. package/dist/index.cjs +5506 -3626
  26. package/dist/index.d.cts +7 -6
  27. package/dist/index.d.ts +7 -6
  28. package/dist/index.esm.js +45 -33
  29. package/dist/kanban-U5xNe9py.d.cts +212 -0
  30. package/dist/kanban-U5xNe9py.d.ts +212 -0
  31. package/dist/{layout-BTJyU8wd.d.ts → layout-B8r6Jbat.d.ts} +1 -1
  32. package/dist/{layout-C2G-FcER.d.cts → layout-Cu7Ijn04.d.cts} +1 -1
  33. package/dist/site.cjs +358 -0
  34. package/dist/site.d.cts +184 -0
  35. package/dist/site.d.ts +184 -0
  36. package/dist/site.esm.js +322 -0
  37. package/dist/studio.cjs +702 -343
  38. package/dist/studio.d.cts +1 -1
  39. package/dist/studio.d.ts +1 -1
  40. package/dist/studio.esm.js +7 -5
  41. package/dist/styles.css +56 -0
  42. package/dist/{timbal-v2-button-CNfdwGq4.d.cts → timbal-v2-button-B7vPs7gg.d.cts} +2 -2
  43. package/dist/{timbal-v2-button-CNfdwGq4.d.ts → timbal-v2-button-B7vPs7gg.d.ts} +2 -2
  44. package/dist/ui.cjs +1504 -659
  45. package/dist/ui.d.cts +11 -4
  46. package/dist/ui.d.ts +11 -4
  47. package/dist/ui.esm.js +35 -26
  48. package/dist/{welcome-DXqsGTwH.d.ts → welcome-DduQAC4K.d.ts} +4 -0
  49. package/dist/{welcome-BFGRoNfK.d.cts → welcome-NXZlcihe.d.cts} +4 -0
  50. package/package.json +9 -1
  51. package/dist/button-BoyX5pM_.d.cts +0 -18
  52. package/dist/button-BoyX5pM_.d.ts +0 -18
  53. package/dist/chunk-UCGVL7ZY.esm.js +0 -52
@@ -20,7 +20,7 @@ import {
20
20
  } from "./chunk-QIABF4KB.esm.js";
21
21
  import {
22
22
  WorkforceSelector
23
- } from "./chunk-OFWC4MIY.esm.js";
23
+ } from "./chunk-JYDJRGDE.esm.js";
24
24
  import {
25
25
  Composer,
26
26
  TimbalChat,
@@ -43,10 +43,18 @@ import {
43
43
  studioTopbarIconPillClass,
44
44
  studioTopbarPillHeightClass,
45
45
  useTimbalRuntime
46
- } from "./chunk-GQBYZRD7.esm.js";
46
+ } from "./chunk-IGHBLJV3.esm.js";
47
+ import {
48
+ DropdownMenu,
49
+ DropdownMenuContent,
50
+ DropdownMenuItem,
51
+ DropdownMenuLabel,
52
+ DropdownMenuSeparator,
53
+ DropdownMenuTrigger
54
+ } from "./chunk-TZI3ID3C.esm.js";
47
55
  import {
48
56
  PillSegmentedTabs
49
- } from "./chunk-VXMM2HX7.esm.js";
57
+ } from "./chunk-ZNYAETFD.esm.js";
50
58
  import {
51
59
  Avatar,
52
60
  AvatarFallback,
@@ -54,9 +62,11 @@ import {
54
62
  TimbalV2Button,
55
63
  Tooltip,
56
64
  TooltipContent,
57
- TooltipTrigger,
65
+ TooltipTrigger
66
+ } from "./chunk-AZL2WANO.esm.js";
67
+ import {
58
68
  cn
59
- } from "./chunk-QU7ET55D.esm.js";
69
+ } from "./chunk-EDEKQYSU.esm.js";
60
70
 
61
71
  // src/hooks/use-workforces.ts
62
72
  import { useEffect, useMemo, useRef, useState } from "react";
@@ -394,9 +404,9 @@ function TimbalMark({
394
404
  // src/studio/sidebar/sidebar.tsx
395
405
  import {
396
406
  useCallback as useCallback3,
397
- useEffect as useEffect4,
407
+ useEffect as useEffect5,
398
408
  useMemo as useMemo2,
399
- useState as useState4
409
+ useState as useState5
400
410
  } from "react";
401
411
  import { motion as motion4, useReducedMotion as useReducedMotion4 } from "motion/react";
402
412
 
@@ -523,7 +533,8 @@ var StudioSidebarEntries = ({
523
533
  };
524
534
 
525
535
  // src/studio/sidebar/sidebar-footer.tsx
526
- import { LogOut } from "lucide-react";
536
+ import { useState as useState4, useEffect as useEffect4 } from "react";
537
+ import { LogOut, Sun, Moon } from "lucide-react";
527
538
 
528
539
  // src/studio/sidebar/sidebar-layout.ts
529
540
  function studioSidebarIconOnlyLayout(isMobile, isCollapsedRail) {
@@ -576,7 +587,7 @@ var StudioSidebarTooltip = ({
576
587
  };
577
588
 
578
589
  // src/studio/sidebar/sidebar-footer.tsx
579
- import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
590
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
580
591
  function userInitials(name, email) {
581
592
  const fromName = name.trim().split(/\s+/).map((part) => part.charAt(0)).join("").slice(0, 2).toUpperCase();
582
593
  if (fromName) return fromName;
@@ -590,10 +601,75 @@ var StudioSidebarFooter = ({
590
601
  }) => {
591
602
  const session = useOptionalSession();
592
603
  const user = session?.user ?? null;
604
+ const [isDark, setIsDark] = useState4(false);
605
+ useEffect4(() => {
606
+ if (typeof window === "undefined" || typeof document === "undefined") return;
607
+ const stored = window.localStorage.getItem(STORAGE_KEYS.theme);
608
+ if (stored) {
609
+ setIsDark(stored === "dark");
610
+ } else {
611
+ setIsDark(document.documentElement.classList.contains("dark"));
612
+ }
613
+ const observer = new MutationObserver(() => {
614
+ setIsDark(document.documentElement.classList.contains("dark"));
615
+ });
616
+ observer.observe(document.documentElement, {
617
+ attributes: true,
618
+ attributeFilter: ["class"]
619
+ });
620
+ return () => observer.disconnect();
621
+ }, []);
622
+ const handleToggleTheme = () => {
623
+ const nextIsDark = !isDark;
624
+ setIsDark(nextIsDark);
625
+ if (typeof document !== "undefined") {
626
+ document.documentElement.classList.toggle("dark", nextIsDark);
627
+ }
628
+ if (typeof window !== "undefined") {
629
+ try {
630
+ window.localStorage.setItem(STORAGE_KEYS.theme, nextIsDark ? "dark" : "light");
631
+ } catch {
632
+ }
633
+ }
634
+ };
593
635
  const handleSignOut = () => {
594
636
  session?.logout();
595
637
  onSignOut?.();
596
638
  };
639
+ const dropdownContent = user ? /* @__PURE__ */ jsxs3(
640
+ DropdownMenuContent,
641
+ {
642
+ side: iconOnlyLayout ? "right" : "top",
643
+ align: iconOnlyLayout ? "end" : "start",
644
+ className: "w-56 z-[70]",
645
+ children: [
646
+ /* @__PURE__ */ jsx8(DropdownMenuLabel, { className: "font-normal", children: /* @__PURE__ */ jsxs3("div", { className: "flex flex-col space-y-1", children: [
647
+ /* @__PURE__ */ jsx8("p", { className: "truncate text-sm font-medium leading-none text-foreground", children: user.user_name }),
648
+ /* @__PURE__ */ jsx8("p", { className: "truncate text-xs leading-none text-muted-foreground", children: user.user_email })
649
+ ] }) }),
650
+ /* @__PURE__ */ jsx8(DropdownMenuSeparator, {}),
651
+ /* @__PURE__ */ jsx8(DropdownMenuItem, { onClick: handleToggleTheme, className: "cursor-pointer", children: isDark ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
652
+ /* @__PURE__ */ jsx8(Sun, { className: "mr-2 size-3.5 shrink-0 text-muted-foreground" }),
653
+ /* @__PURE__ */ jsx8("span", { children: "Light mode" })
654
+ ] }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
655
+ /* @__PURE__ */ jsx8(Moon, { className: "mr-2 size-3.5 shrink-0 text-muted-foreground" }),
656
+ /* @__PURE__ */ jsx8("span", { children: "Dark mode" })
657
+ ] }) }),
658
+ /* @__PURE__ */ jsx8(DropdownMenuSeparator, {}),
659
+ /* @__PURE__ */ jsxs3(
660
+ DropdownMenuItem,
661
+ {
662
+ onClick: handleSignOut,
663
+ className: "cursor-pointer text-destructive focus:text-destructive focus:bg-destructive/10",
664
+ children: [
665
+ /* @__PURE__ */ jsx8(LogOut, { className: "mr-2 size-3.5 shrink-0" }),
666
+ /* @__PURE__ */ jsx8("span", { children: "Sign out" })
667
+ ]
668
+ }
669
+ )
670
+ ]
671
+ }
672
+ ) : null;
597
673
  return /* @__PURE__ */ jsx8(StudioSidebarEntryMotion, { children: /* @__PURE__ */ jsx8(
598
674
  "footer",
599
675
  {
@@ -601,42 +677,36 @@ var StudioSidebarFooter = ({
601
677
  "mt-auto w-full shrink-0 py-2.5",
602
678
  iconOnlyLayout ? studioSidebarCollapsedRailInsetClass : "px-2.5"
603
679
  ),
604
- children: user ? /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-2", children: [
605
- iconOnlyLayout ? /* @__PURE__ */ jsx8("div", { className: studioSidebarCollapsedRailChipRowClass, children: /* @__PURE__ */ jsxs3(Avatar, { size: "sm", className: "size-8", children: [
606
- user.user_photo_url ? /* @__PURE__ */ jsx8(AvatarImage, { src: user.user_photo_url, alt: user.user_name }) : null,
607
- /* @__PURE__ */ jsx8(AvatarFallback, { className: "text-[10px]", children: userInitials(user.user_name, user.user_email) })
608
- ] }) }) : /* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 items-center gap-2.5", children: [
609
- /* @__PURE__ */ jsxs3(Avatar, { size: "sm", children: [
610
- user.user_photo_url ? /* @__PURE__ */ jsx8(AvatarImage, { src: user.user_photo_url, alt: user.user_name }) : null,
611
- /* @__PURE__ */ jsx8(AvatarFallback, { children: userInitials(user.user_name, user.user_email) })
612
- ] }),
613
- /* @__PURE__ */ jsxs3("div", { className: "min-w-0 flex-1", children: [
614
- /* @__PURE__ */ jsx8("p", { className: "truncate text-sm font-medium text-foreground", children: user.user_name }),
615
- /* @__PURE__ */ jsx8("p", { className: "truncate text-xs text-muted-foreground", children: user.user_email })
616
- ] })
617
- ] }),
618
- /* @__PURE__ */ jsx8(
619
- "div",
680
+ children: user ? /* @__PURE__ */ jsxs3(DropdownMenu, { children: [
681
+ /* @__PURE__ */ jsx8("div", { className: cn(iconOnlyLayout && studioSidebarCollapsedRailChipRowClass), children: /* @__PURE__ */ jsx8(StudioSidebarTooltip, { label: iconOnlyLayout ? user.user_name : "User menu", enabled: showTooltips, children: /* @__PURE__ */ jsx8(DropdownMenuTrigger, { asChild: true, children: iconOnlyLayout ? /* @__PURE__ */ jsx8(
682
+ "button",
620
683
  {
621
- className: iconOnlyLayout ? studioSidebarCollapsedRailChipRowClass : void 0,
622
- children: /* @__PURE__ */ jsx8(StudioSidebarTooltip, { label: "Sign out", enabled: showTooltips, children: /* @__PURE__ */ jsxs3(
623
- "button",
624
- {
625
- type: "button",
626
- onClick: handleSignOut,
627
- className: cn(
628
- studioSidebarNavItemClasses(iconOnlyLayout, false),
629
- iconOnlyLayout && "inline-flex"
630
- ),
631
- "aria-label": "Sign out",
632
- children: [
633
- /* @__PURE__ */ jsx8(LogOut, { className: "size-3.5 shrink-0" }),
634
- !iconOnlyLayout ? "Sign out" : null
635
- ]
636
- }
637
- ) })
684
+ type: "button",
685
+ className: "rounded-full outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 transition-colors hover:bg-accent/50 p-0.5",
686
+ "aria-label": "User menu",
687
+ children: /* @__PURE__ */ jsxs3(Avatar, { size: "sm", className: "size-8", children: [
688
+ user.user_photo_url ? /* @__PURE__ */ jsx8(AvatarImage, { src: user.user_photo_url, alt: user.user_name }) : null,
689
+ /* @__PURE__ */ jsx8(AvatarFallback, { className: "text-[10px]", children: userInitials(user.user_name, user.user_email) })
690
+ ] })
638
691
  }
639
- )
692
+ ) : /* @__PURE__ */ jsxs3(
693
+ "button",
694
+ {
695
+ type: "button",
696
+ className: "flex w-full min-w-0 items-center gap-2.5 rounded-lg p-2 hover:bg-accent/50 outline-none focus-visible:ring-2 focus-visible:ring-ring transition-colors text-left",
697
+ children: [
698
+ /* @__PURE__ */ jsxs3(Avatar, { size: "sm", className: "shrink-0", children: [
699
+ user.user_photo_url ? /* @__PURE__ */ jsx8(AvatarImage, { src: user.user_photo_url, alt: user.user_name }) : null,
700
+ /* @__PURE__ */ jsx8(AvatarFallback, { children: userInitials(user.user_name, user.user_email) })
701
+ ] }),
702
+ /* @__PURE__ */ jsxs3("div", { className: "min-w-0 flex-1", children: [
703
+ /* @__PURE__ */ jsx8("p", { className: "truncate text-sm font-medium text-foreground", children: user.user_name }),
704
+ /* @__PURE__ */ jsx8("p", { className: "truncate text-xs text-muted-foreground", children: user.user_email })
705
+ ] })
706
+ ]
707
+ }
708
+ ) }) }) }),
709
+ dropdownContent
640
710
  ] }) : !iconOnlyLayout && emptyCaption ? /* @__PURE__ */ jsx8("p", { className: "px-1 text-xs text-muted-foreground", children: emptyCaption }) : null
641
711
  }
642
712
  ) });
@@ -662,53 +732,70 @@ var SidebarToggleButton = ({ ariaLabel, expanded, onClick, children }) => /* @__
662
732
  children
663
733
  }
664
734
  );
665
- var CollapsedBrandToggle = ({
666
- onExpand,
667
- brand
668
- }) => /* @__PURE__ */ jsx9("div", { className: studioSidebarCollapsedRailChipRowClass, children: /* @__PURE__ */ jsx9(StudioSidebarTooltip, { label: "Expand sidebar", enabled: true, children: /* @__PURE__ */ jsxs4(
669
- "button",
670
- {
671
- type: "button",
672
- onClick: onExpand,
673
- "aria-label": "Expand sidebar",
674
- "aria-expanded": false,
675
- className: cn(
676
- toggleButtonClass,
677
- "group relative inline-flex size-8 items-center justify-center overflow-hidden rounded-lg"
678
- ),
679
- children: [
680
- /* @__PURE__ */ jsx9(
681
- "span",
682
- {
683
- "aria-hidden": true,
684
- className: cn(
685
- "pointer-events-none flex items-center justify-center",
686
- "transition-[opacity,transform] duration-200 ease-out",
687
- "group-hover:scale-90 group-hover:opacity-0"
688
- ),
689
- children: brand
690
- }
691
- ),
692
- /* @__PURE__ */ jsx9(
693
- ChevronRight,
694
- {
695
- "aria-hidden": true,
696
- className: cn(
697
- "pointer-events-none absolute inset-0 m-auto size-4",
698
- "opacity-0 transition-[opacity,transform] duration-200 ease-out",
699
- "group-hover:opacity-100"
700
- )
701
- }
702
- )
703
- ]
735
+ var CollapsedBrandToggle = ({ onExpand, logo, fallbackToChevron }) => {
736
+ if (fallbackToChevron || !logo) {
737
+ return /* @__PURE__ */ jsx9("div", { className: studioSidebarCollapsedRailChipRowClass, children: /* @__PURE__ */ jsx9(StudioSidebarTooltip, { label: "Expand sidebar", enabled: true, children: /* @__PURE__ */ jsx9(
738
+ "button",
739
+ {
740
+ type: "button",
741
+ onClick: onExpand,
742
+ "aria-label": "Expand sidebar",
743
+ "aria-expanded": false,
744
+ className: cn(
745
+ toggleButtonClass,
746
+ "group relative inline-flex size-8 items-center justify-center overflow-hidden rounded-lg"
747
+ ),
748
+ children: /* @__PURE__ */ jsx9(ChevronRight, { "aria-hidden": true, className: "size-4" })
749
+ }
750
+ ) }) });
704
751
  }
705
- ) }) });
752
+ return /* @__PURE__ */ jsx9("div", { className: studioSidebarCollapsedRailChipRowClass, children: /* @__PURE__ */ jsx9(StudioSidebarTooltip, { label: "Expand sidebar", enabled: true, children: /* @__PURE__ */ jsxs4(
753
+ "button",
754
+ {
755
+ type: "button",
756
+ onClick: onExpand,
757
+ "aria-label": "Expand sidebar",
758
+ "aria-expanded": false,
759
+ className: cn(
760
+ toggleButtonClass,
761
+ "group relative inline-flex size-8 items-center justify-center overflow-hidden rounded-lg"
762
+ ),
763
+ children: [
764
+ /* @__PURE__ */ jsx9(
765
+ "span",
766
+ {
767
+ "aria-hidden": true,
768
+ className: cn(
769
+ "pointer-events-none flex items-center justify-center",
770
+ "transition-[opacity,transform] duration-200 ease-out",
771
+ "group-hover:scale-90 group-hover:opacity-0"
772
+ ),
773
+ children: logo
774
+ }
775
+ ),
776
+ /* @__PURE__ */ jsx9(
777
+ ChevronRight,
778
+ {
779
+ "aria-hidden": true,
780
+ className: cn(
781
+ "pointer-events-none absolute inset-0 m-auto size-4",
782
+ "opacity-0 transition-[opacity,transform] duration-200 ease-out",
783
+ "group-hover:opacity-100"
784
+ )
785
+ }
786
+ )
787
+ ]
788
+ }
789
+ ) }) });
790
+ };
706
791
  var StudioSidebarHeader = ({
707
792
  isCollapsedRail,
708
793
  isMobile,
709
794
  mobileOpen,
710
795
  onToggle,
711
- brand
796
+ brand,
797
+ logo,
798
+ fallbackToChevron
712
799
  }) => {
713
800
  if (isMobile) {
714
801
  return /* @__PURE__ */ jsxs4("header", { className: cn(sidebarHeaderClass, "justify-between gap-2 pr-2"), children: [
@@ -732,7 +819,14 @@ var StudioSidebarHeader = ({
732
819
  "flex h-12 shrink-0 items-center",
733
820
  studioSidebarCollapsedRailInsetClass
734
821
  ),
735
- children: /* @__PURE__ */ jsx9(CollapsedBrandToggle, { onExpand: onToggle, brand })
822
+ children: /* @__PURE__ */ jsx9(
823
+ CollapsedBrandToggle,
824
+ {
825
+ onExpand: onToggle,
826
+ logo,
827
+ fallbackToChevron
828
+ }
829
+ )
736
830
  }
737
831
  );
738
832
  }
@@ -857,6 +951,7 @@ var StudioSidebarPanel = ({
857
951
  onEntriesBlurOutComplete,
858
952
  onPanelWidthComplete,
859
953
  brand,
954
+ logo,
860
955
  emptyCaption = null
861
956
  }) => {
862
957
  const reducedMotion = useReducedMotion4();
@@ -876,7 +971,10 @@ var StudioSidebarPanel = ({
876
971
  onCollapsedChange(!collapsed);
877
972
  };
878
973
  const panelWidthPx = isMobile ? SIDEBAR_MOBILE_PX : widthCollapsed ? SIDEBAR_WIDTH_COLLAPSED_PX : SIDEBAR_WIDTH_PX;
974
+ const isCustomBrand = brand !== void 0;
975
+ const fallbackToChevron = isCustomBrand && !logo;
879
976
  const brandNode = brand ?? /* @__PURE__ */ jsx11(TimbalMark, { size: 32 });
977
+ const logoNode = logo ?? (isCustomBrand ? null : brandNode);
880
978
  const panel = /* @__PURE__ */ jsxs5(
881
979
  motion4.div,
882
980
  {
@@ -899,7 +997,9 @@ var StudioSidebarPanel = ({
899
997
  isMobile,
900
998
  mobileOpen,
901
999
  onToggle: handleToggle,
902
- brand: brandNode
1000
+ brand: brandNode,
1001
+ logo: logoNode,
1002
+ fallbackToChevron
903
1003
  }
904
1004
  ),
905
1005
  /* @__PURE__ */ jsxs5(
@@ -978,6 +1078,7 @@ var StudioSidebar = ({
978
1078
  persistKey = STORAGE_KEYS.sidebarCollapsed,
979
1079
  mobileBreakpointPx = DEFAULT_BREAKPOINT_PX,
980
1080
  brand,
1081
+ logo,
981
1082
  emptyCaption,
982
1083
  mobileOpen: mobileOpenProp,
983
1084
  onMobileOpenChange: onMobileOpenChangeProp,
@@ -986,24 +1087,17 @@ var StudioSidebar = ({
986
1087
  const reducedMotion = useReducedMotion4();
987
1088
  const fetched = useWorkforces({ enabled: workforcesProp === void 0 });
988
1089
  const workforces = workforcesProp ?? fetched.workforces;
989
- const [internalSelected, setInternalSelected] = useState4(
1090
+ const [internalSelected, setInternalSelected] = useState5(
990
1091
  selectedIdProp ?? ""
991
1092
  );
992
- useEffect4(() => {
1093
+ useEffect5(() => {
993
1094
  if (selectedIdProp !== void 0) return;
994
1095
  if (internalSelected) return;
995
1096
  const first = workforces[0]?.id ?? workforces[0]?.uid ?? workforces[0]?.name;
996
1097
  if (first) setInternalSelected(first);
997
1098
  }, [workforces, selectedIdProp, internalSelected]);
998
1099
  const selectedId = selectedIdProp ?? internalSelected ?? workforces[0]?.id ?? workforces[0]?.uid ?? workforces[0]?.name ?? "";
999
- const handleSelect = useCallback3(
1000
- (id) => {
1001
- if (selectedIdProp === void 0) setInternalSelected(id);
1002
- onSelect?.(id);
1003
- },
1004
- [selectedIdProp, onSelect]
1005
- );
1006
- const [collapsed, setCollapsed] = useState4(() => {
1100
+ const [collapsed, setCollapsed] = useState5(() => {
1007
1101
  const persisted = readPersistedCollapsed(persistKey);
1008
1102
  return persisted || defaultCollapsed;
1009
1103
  });
@@ -1014,18 +1108,18 @@ var StudioSidebar = ({
1014
1108
  },
1015
1109
  [persistKey]
1016
1110
  );
1017
- const [isMobile, setIsMobile] = useState4(() => {
1111
+ const [isMobile, setIsMobile] = useState5(() => {
1018
1112
  if (typeof window === "undefined") return false;
1019
1113
  return window.innerWidth < mobileBreakpointPx;
1020
1114
  });
1021
- useEffect4(() => {
1115
+ useEffect5(() => {
1022
1116
  if (typeof window === "undefined") return;
1023
1117
  const onResize = () => setIsMobile(window.innerWidth < mobileBreakpointPx);
1024
1118
  onResize();
1025
1119
  window.addEventListener("resize", onResize);
1026
1120
  return () => window.removeEventListener("resize", onResize);
1027
1121
  }, [mobileBreakpointPx]);
1028
- const [internalMobileOpen, setInternalMobileOpen] = useState4(false);
1122
+ const [internalMobileOpen, setInternalMobileOpen] = useState5(false);
1029
1123
  const mobileOpen = mobileOpenProp ?? internalMobileOpen;
1030
1124
  const setMobileOpen = useCallback3(
1031
1125
  (next) => {
@@ -1034,6 +1128,25 @@ var StudioSidebar = ({
1034
1128
  },
1035
1129
  [mobileOpenProp, onMobileOpenChangeProp]
1036
1130
  );
1131
+ const handleSelect = useCallback3(
1132
+ (id) => {
1133
+ if (selectedIdProp === void 0) setInternalSelected(id);
1134
+ onSelect?.(id);
1135
+ if (isMobile) setMobileOpen(false);
1136
+ },
1137
+ [selectedIdProp, onSelect, isMobile, setMobileOpen]
1138
+ );
1139
+ useEffect5(() => {
1140
+ if (!isMobile && mobileOpen) setMobileOpen(false);
1141
+ }, [isMobile, mobileOpen, setMobileOpen]);
1142
+ useEffect5(() => {
1143
+ if (!isMobile || !mobileOpen) return;
1144
+ const onKeyDown = (e) => {
1145
+ if (e.key === "Escape") setMobileOpen(false);
1146
+ };
1147
+ window.addEventListener("keydown", onKeyDown);
1148
+ return () => window.removeEventListener("keydown", onKeyDown);
1149
+ }, [isMobile, mobileOpen, setMobileOpen]);
1037
1150
  const effectiveCollapsed = isMobile ? false : collapsed;
1038
1151
  const {
1039
1152
  widthCollapsed,
@@ -1049,9 +1162,10 @@ var StudioSidebar = ({
1049
1162
  collapsed: effectiveCollapsed,
1050
1163
  isMobile,
1051
1164
  isCollapsedRail,
1052
- iconOnlyLayout
1165
+ iconOnlyLayout,
1166
+ closeMobile: () => setMobileOpen(false)
1053
1167
  }),
1054
- [effectiveCollapsed, isMobile, isCollapsedRail, iconOnlyLayout]
1168
+ [effectiveCollapsed, isMobile, isCollapsedRail, iconOnlyLayout, setMobileOpen]
1055
1169
  );
1056
1170
  return /* @__PURE__ */ jsxs5(StudioSidebarContext.Provider, { value: contextValue, children: [
1057
1171
  /* @__PURE__ */ jsx11(StudioSidebarShellInsetBridge, { onInsetChange }),
@@ -1071,6 +1185,7 @@ var StudioSidebar = ({
1071
1185
  onEntriesBlurOutComplete,
1072
1186
  onPanelWidthComplete,
1073
1187
  brand,
1188
+ logo,
1074
1189
  emptyCaption
1075
1190
  }
1076
1191
  )
@@ -1147,15 +1262,15 @@ var StudioWelcome = ({ config, icon }) => {
1147
1262
  // src/studio/shell/studio-shell.tsx
1148
1263
  import {
1149
1264
  useCallback as useCallback5,
1150
- useEffect as useEffect5,
1265
+ useEffect as useEffect6,
1151
1266
  useMemo as useMemo3,
1152
- useState as useState6
1267
+ useState as useState7
1153
1268
  } from "react";
1154
1269
  import { Menu } from "lucide-react";
1155
1270
  import { motion as motion6, useReducedMotion as useReducedMotion5 } from "motion/react";
1156
1271
 
1157
1272
  // src/studio/sidebar/sidebar-runtime-portal.tsx
1158
- import { useCallback as useCallback4, useLayoutEffect as useLayoutEffect2, useState as useState5 } from "react";
1273
+ import { useCallback as useCallback4, useLayoutEffect as useLayoutEffect2, useState as useState6 } from "react";
1159
1274
  import { createPortal } from "react-dom";
1160
1275
  import { MessageSquarePlus } from "lucide-react";
1161
1276
  import { useThread as useThread2 } from "@assistant-ui/react";
@@ -1163,13 +1278,14 @@ import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
1163
1278
  var StudioSidebarRuntimePortal = ({
1164
1279
  label = "New chat"
1165
1280
  }) => {
1166
- const { iconOnlyLayout } = useStudioSidebarLayout();
1281
+ const { iconOnlyLayout, isMobile, closeMobile } = useStudioSidebarLayout();
1167
1282
  const hasMessages = useThread2((s) => s.messages.length > 0);
1168
1283
  const { clear } = useTimbalRuntime();
1169
- const [anchor, setAnchor] = useState5(null);
1284
+ const [anchor, setAnchor] = useState6(null);
1170
1285
  const startNewChat = useCallback4(() => {
1171
1286
  clear();
1172
- }, [clear]);
1287
+ if (isMobile) closeMobile?.();
1288
+ }, [clear, isMobile, closeMobile]);
1173
1289
  useLayoutEffect2(() => {
1174
1290
  setAnchor(document.getElementById(DOM_IDS.sidebarRuntimeAnchor));
1175
1291
  }, []);
@@ -1197,7 +1313,7 @@ var StudioSidebarRuntimePortal = ({
1197
1313
  };
1198
1314
 
1199
1315
  // src/studio/shell/studio-shell.tsx
1200
- import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
1316
+ import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
1201
1317
  import { createElement } from "react";
1202
1318
  var DEFAULT_BREAKPOINT_PX2 = 768;
1203
1319
  function readPersistedCollapsed2(key) {
@@ -1218,7 +1334,7 @@ function writePersistedCollapsed2(key, collapsed) {
1218
1334
  function makeComposerWithPortal(BaseComposer) {
1219
1335
  const Resolved = BaseComposer ?? Composer;
1220
1336
  return function StudioComposerWithSidebar(props) {
1221
- return /* @__PURE__ */ jsxs8(Fragment2, { children: [
1337
+ return /* @__PURE__ */ jsxs8(Fragment3, { children: [
1222
1338
  /* @__PURE__ */ jsx14(StudioSidebarRuntimePortal, {}),
1223
1339
  /* @__PURE__ */ jsx14(Resolved, { ...props })
1224
1340
  ] });
@@ -1230,6 +1346,7 @@ var TimbalStudioShell = ({
1230
1346
  workforcesFetch,
1231
1347
  workforcesBaseUrl,
1232
1348
  brand,
1349
+ logo,
1233
1350
  headerActions,
1234
1351
  headerStart,
1235
1352
  defaultCollapsed = false,
@@ -1248,36 +1365,36 @@ var TimbalStudioShell = ({
1248
1365
  baseUrl: workforcesBaseUrl
1249
1366
  });
1250
1367
  const workforces = workforcesProp ?? fetched.workforces;
1251
- const [internalSelected, setInternalSelected] = useState6(
1368
+ const [internalSelected, setInternalSelected] = useState7(
1252
1369
  workforceId ?? ""
1253
1370
  );
1254
- useEffect5(() => {
1371
+ useEffect6(() => {
1255
1372
  if (workforceId) return;
1256
1373
  if (internalSelected) return;
1257
1374
  const first = workforces[0]?.id ?? workforces[0]?.uid ?? workforces[0]?.name;
1258
1375
  if (first) setInternalSelected(first);
1259
1376
  }, [workforces, workforceId, internalSelected]);
1260
1377
  const activeWorkforceId = workforceId ?? internalSelected ?? fetched.selectedId ?? "";
1261
- const [collapsed, setCollapsed] = useState6(() => {
1378
+ const [collapsed, setCollapsed] = useState7(() => {
1262
1379
  const persisted = readPersistedCollapsed2(persistKey);
1263
1380
  return persisted || defaultCollapsed;
1264
1381
  });
1265
- const [isMobile, setIsMobile] = useState6(() => {
1382
+ const [isMobile, setIsMobile] = useState7(() => {
1266
1383
  if (typeof window === "undefined") return false;
1267
1384
  return window.innerWidth < mobileBreakpointPx;
1268
1385
  });
1269
- const [mobileSidebarOpen, setMobileSidebarOpen] = useState6(false);
1270
- useEffect5(() => {
1386
+ const [mobileSidebarOpen, setMobileSidebarOpen] = useState7(false);
1387
+ useEffect6(() => {
1271
1388
  if (typeof window === "undefined") return;
1272
1389
  const onResize = () => setIsMobile(window.innerWidth < mobileBreakpointPx);
1273
1390
  onResize();
1274
1391
  window.addEventListener("resize", onResize);
1275
1392
  return () => window.removeEventListener("resize", onResize);
1276
1393
  }, [mobileBreakpointPx]);
1277
- useEffect5(() => {
1394
+ useEffect6(() => {
1278
1395
  if (!isMobile) setMobileSidebarOpen(false);
1279
1396
  }, [isMobile]);
1280
- useEffect5(() => {
1397
+ useEffect6(() => {
1281
1398
  if (!mobileSidebarOpen) return;
1282
1399
  const onKeyDown = (e) => {
1283
1400
  if (e.key === "Escape") setMobileSidebarOpen(false);
@@ -1320,7 +1437,8 @@ var TimbalStudioShell = ({
1320
1437
  collapsed: effectiveCollapsed,
1321
1438
  isMobile,
1322
1439
  isCollapsedRail,
1323
- iconOnlyLayout
1440
+ iconOnlyLayout,
1441
+ closeMobile: () => setMobileSidebarOpen(false)
1324
1442
  }),
1325
1443
  [effectiveCollapsed, isMobile, isCollapsedRail, iconOnlyLayout]
1326
1444
  );
@@ -1378,6 +1496,7 @@ var TimbalStudioShell = ({
1378
1496
  onEntriesBlurOutComplete,
1379
1497
  onPanelWidthComplete,
1380
1498
  brand,
1499
+ logo,
1381
1500
  emptyCaption: sidebarEmptyCaption
1382
1501
  }
1383
1502
  ),
@@ -1452,8 +1571,8 @@ var TimbalStudioShell = ({
1452
1571
  };
1453
1572
 
1454
1573
  // src/studio/sidebar/mode-toggle.tsx
1455
- import { useCallback as useCallback6, useLayoutEffect as useLayoutEffect3, useState as useState7 } from "react";
1456
- import { Moon, Sun } from "lucide-react";
1574
+ import { useCallback as useCallback6, useLayoutEffect as useLayoutEffect3, useState as useState8 } from "react";
1575
+ import { Moon as Moon2, Sun as Sun2 } from "lucide-react";
1457
1576
  import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
1458
1577
  function readStoredTheme() {
1459
1578
  if (typeof window === "undefined") return null;
@@ -1482,7 +1601,7 @@ var ModeToggle = ({
1482
1601
  label = "Toggle theme"
1483
1602
  }) => {
1484
1603
  const isControlled = theme !== void 0;
1485
- const [internalIsDark, setInternalIsDark] = useState7(false);
1604
+ const [internalIsDark, setInternalIsDark] = useState8(false);
1486
1605
  useLayoutEffect3(() => {
1487
1606
  if (isControlled) return;
1488
1607
  const stored = readStoredTheme();
@@ -1522,8 +1641,8 @@ var ModeToggle = ({
1522
1641
  "aria-label": label,
1523
1642
  title: label,
1524
1643
  children: [
1525
- /* @__PURE__ */ jsx15(Sun, { className: "size-3.5 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" }),
1526
- /* @__PURE__ */ jsx15(Moon, { className: "absolute size-3.5 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" }),
1644
+ /* @__PURE__ */ jsx15(Sun2, { className: "size-3.5 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" }),
1645
+ /* @__PURE__ */ jsx15(Moon2, { className: "absolute size-3.5 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" }),
1527
1646
  /* @__PURE__ */ jsx15("span", { className: "sr-only", children: label })
1528
1647
  ]
1529
1648
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  cn
3
- } from "./chunk-QU7ET55D.esm.js";
3
+ } from "./chunk-EDEKQYSU.esm.js";
4
4
 
5
5
  // src/ui/pill-segmented-tabs.tsx
6
6
  import {