@xenide-io/the-old-ui-theme 0.4.4 → 0.4.8

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 (76) hide show
  1. package/dist/{chunk-54ZR4VL5.mjs → chunk-RZXHZWUB.mjs} +44 -17
  2. package/dist/{index-B5NOyoKS.d.mts → index-Od4pIP4F.d.mts} +7 -1
  3. package/dist/{index-B5NOyoKS.d.ts → index-Od4pIP4F.d.ts} +7 -1
  4. package/dist/index.d.mts +2 -2
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +37 -10
  7. package/dist/index.mjs +1 -1
  8. package/dist/suite.d.mts +152 -41
  9. package/dist/suite.d.ts +152 -41
  10. package/dist/suite.js +1366 -671
  11. package/dist/suite.mjs +1304 -610
  12. package/dist/ui.d.mts +1 -1
  13. package/dist/ui.d.ts +1 -1
  14. package/dist/ui.js +37 -10
  15. package/dist/ui.mjs +1 -1
  16. package/package.json +7 -3
  17. package/src/components/ui/Modal.tsx +70 -26
  18. package/src/styles/suite-skin.css +284 -24
  19. package/src/suite/components/ai-panel.test.ts +20 -0
  20. package/src/suite/components/ai-panel.tsx +494 -103
  21. package/src/suite/components/suite-app-layout.tsx +48 -28
  22. package/src/suite/components/suite-layout.tsx +84 -40
  23. package/src/suite/components/suite-mobile-drawer.tsx +35 -22
  24. package/src/suite/components/suite-notification-bell.tsx +9 -3
  25. package/src/suite/components/suite-settings-layout.tsx +82 -0
  26. package/src/suite/components/suite-settings-mobile-nav.tsx +18 -17
  27. package/src/suite/components/suite-skeleton.tsx +3 -3
  28. package/src/suite/components/today-calibrating.tsx +11 -35
  29. package/src/suite/components/today-page-frame.tsx +19 -11
  30. package/src/suite/components/today-ui.tsx +276 -19
  31. package/src/suite/index.ts +41 -25
  32. package/src/suite/lib/apps.ts +32 -2
  33. package/src/suite/lib/use-sidebar-width.ts +114 -0
  34. package/src/components/sections/AccordionShowcase.tsx +0 -45
  35. package/src/components/sections/AlertShowcase.tsx +0 -40
  36. package/src/components/sections/AvatarShowcase.tsx +0 -80
  37. package/src/components/sections/BadgeShowcase.tsx +0 -65
  38. package/src/components/sections/ButtonShowcase.tsx +0 -308
  39. package/src/components/sections/CalendarShowcase.tsx +0 -35
  40. package/src/components/sections/CardShowcase.tsx +0 -159
  41. package/src/components/sections/CodeMockupShowcase.tsx +0 -56
  42. package/src/components/sections/ColorPalette.tsx +0 -117
  43. package/src/components/sections/CommandPaletteShowcase.tsx +0 -48
  44. package/src/components/sections/CountdownShowcase.tsx +0 -43
  45. package/src/components/sections/DiffShowcase.tsx +0 -70
  46. package/src/components/sections/DrawerShowcase.tsx +0 -97
  47. package/src/components/sections/DropdownShowcase.tsx +0 -98
  48. package/src/components/sections/EmptyStateShowcase.tsx +0 -50
  49. package/src/components/sections/FilterChipsShowcase.tsx +0 -98
  50. package/src/components/sections/FormShowcase.tsx +0 -127
  51. package/src/components/sections/HoverCardShowcase.tsx +0 -50
  52. package/src/components/sections/IconShowcase.tsx +0 -121
  53. package/src/components/sections/IndicatorShowcase.tsx +0 -52
  54. package/src/components/sections/KbdShowcase.tsx +0 -57
  55. package/src/components/sections/ModalShowcase.tsx +0 -211
  56. package/src/components/sections/NavigationShowcase.tsx +0 -199
  57. package/src/components/sections/NewComponentsShowcase.tsx +0 -1052
  58. package/src/components/sections/ProductLayoutsShowcase.tsx +0 -78
  59. package/src/components/sections/ProgressShowcase.tsx +0 -82
  60. package/src/components/sections/QuillChartShowcase.tsx +0 -92
  61. package/src/components/sections/QuillDashboardShowcase.tsx +0 -149
  62. package/src/components/sections/SegmentedControlShowcase.tsx +0 -49
  63. package/src/components/sections/SetupThemeShowcase.tsx +0 -262
  64. package/src/components/sections/SidebarShowcase.tsx +0 -152
  65. package/src/components/sections/StackShowcase.tsx +0 -33
  66. package/src/components/sections/StepperShowcase.tsx +0 -37
  67. package/src/components/sections/SuiteShowcase.tsx +0 -669
  68. package/src/components/sections/SwapShowcase.tsx +0 -99
  69. package/src/components/sections/TabShowcase.tsx +0 -84
  70. package/src/components/sections/TableShowcase.tsx +0 -142
  71. package/src/components/sections/TimelineShowcase.tsx +0 -83
  72. package/src/components/sections/ToastShowcase.tsx +0 -108
  73. package/src/components/sections/TooltipShowcase.tsx +0 -38
  74. package/src/components/sections/UtilityShowcase.tsx +0 -81
  75. package/src/styles/excel-themes.css +0 -110
  76. package/src/styles/lemon-primitives.css +0 -550
package/dist/suite.d.mts CHANGED
@@ -1,9 +1,13 @@
1
1
  import * as react from 'react';
2
- import { ReactNode, ComponentType, ButtonHTMLAttributes, CSSProperties, ElementType, PointerEvent } from 'react';
2
+ import { ReactNode, ComponentType, ButtonHTMLAttributes, CSSProperties, PointerEvent, ElementType } from 'react';
3
3
  import { ClassValue } from 'clsx';
4
4
  export { m } from 'motion/react';
5
5
 
6
- /** Full-bleed theme wash + soft clouds; uses ph-* tokens from each app's theme. */
6
+ /**
7
+ * Today page content wrapper with soft atmosphere.
8
+ * Does not own scrolling — `#main-content` is the scrollport so sticky headers work.
9
+ * Glow/clouds are absolute and do not create a nested scrollport.
10
+ */
7
11
  declare function TodayPageFrame({ children }: {
8
12
  children: ReactNode;
9
13
  }): react.JSX.Element;
@@ -50,8 +54,56 @@ declare function getTodayGreeting(user?: {
50
54
  overdueCount?: number;
51
55
  hours?: number;
52
56
  }): string;
53
- declare function TodayHero({ message, }: {
57
+ declare function TodayHero({ message, brief, briefMeta, }: {
54
58
  message?: ReactNode;
59
+ /** AI / local focus brief under the greeting. */
60
+ brief?: ReactNode;
61
+ briefMeta?: ReactNode;
62
+ }): react.JSX.Element;
63
+ type TodayPrimaryAccent = 'tides' | 'turtletime' | 'kraken' | 'shellstack' | 'neutral';
64
+ /**
65
+ * Compact primary CTA for Today — one action per app.
66
+ * Colours live in suite-skin (.today-primary-action); no idle animation.
67
+ */
68
+ declare function TodayPrimaryAction({ label, description, icon, accent, onClick, href, loading, active, className, dataTest, }: {
69
+ label: string;
70
+ description?: string;
71
+ icon?: ReactNode;
72
+ accent?: TodayPrimaryAccent;
73
+ onClick?: () => void;
74
+ href?: string;
75
+ loading?: boolean;
76
+ /** e.g. timer already running */
77
+ active?: boolean;
78
+ className?: string;
79
+ dataTest?: string;
80
+ }): react.JSX.Element;
81
+ declare function TodayEmptyAction({ title, description, actionLabel, href, onClick, dataTest, }: {
82
+ title: string;
83
+ description?: string;
84
+ actionLabel?: string;
85
+ href?: string;
86
+ onClick?: () => void;
87
+ dataTest?: string;
88
+ }): react.JSX.Element;
89
+ /** Desktop Today shell: main column + sticky Ask AI / brief aside. */
90
+ declare function TodayLayout({ primary, main, aside, className, }: {
91
+ primary?: ReactNode;
92
+ main: ReactNode;
93
+ aside?: ReactNode;
94
+ className?: string;
95
+ }): react.JSX.Element;
96
+ /**
97
+ * Today Ask AI CTA — opens the suite assistant (not Kraken Deep Research).
98
+ * Prefer onClick → openSuiteAskAi(); href is a fallback only.
99
+ */
100
+ declare function TodayAskAiCard({ title, description, cta, className, onClick, href, }: {
101
+ title?: string;
102
+ description?: string;
103
+ cta?: string;
104
+ className?: string;
105
+ onClick?: () => void;
106
+ href?: string;
55
107
  }): react.JSX.Element;
56
108
  declare function TodaySection({ icon: Icon, iconClassName, title, description, action, testId, children, }: {
57
109
  icon: LucideIcon;
@@ -192,14 +244,16 @@ declare function DeferredChrome({ children }: {
192
244
  * close, body scroll-lock and focus hand-off while open. Nav content stays
193
245
  * app-side via `children`.
194
246
  */
195
- declare function SuiteMobileDrawer({ open, onClose, children, side, showCloseButton, closeLabel, backdropLabel, dialogLabel, durationMs, dataTest, panelDataTest, panelClassName, }: {
247
+ declare function SuiteMobileDrawer({ open, onClose, children, side, showCloseButton, title, closeLabel, backdropLabel, dialogLabel, durationMs, dataTest, panelDataTest, panelClassName, }: {
196
248
  open: boolean;
197
249
  onClose: () => void;
198
250
  children: ReactNode;
199
251
  /** Edge the panel slides in from. */
200
- side?: 'left' | 'right';
252
+ side?: "left" | "right";
201
253
  /** Standard close row (h-14, trailing X button) above the content. */
202
254
  showCloseButton?: boolean;
255
+ /** Optional label in the standard close row. */
256
+ title?: ReactNode;
203
257
  closeLabel?: string;
204
258
  backdropLabel?: string;
205
259
  /** Accessible name for the dialog panel. */
@@ -237,6 +291,25 @@ declare function SuiteMobileHeader({ onMenuClick, menuIcon: MenuIcon, title, act
237
291
  className?: string;
238
292
  }): react.JSX.Element;
239
293
 
294
+ interface SuiteSettingsLayoutProps {
295
+ children: ReactNode;
296
+ sidebar: ReactNode;
297
+ mobileNav?: ReactNode;
298
+ loading?: ReactNode;
299
+ title?: ReactNode;
300
+ description?: ReactNode;
301
+ header?: ReactNode;
302
+ dataTest?: string;
303
+ headerDataTest?: string;
304
+ className?: string;
305
+ contentClassName?: string;
306
+ }
307
+ /**
308
+ * Canonical settings geometry for every suite app.
309
+ * Apps own nav data and content; the suite owns spacing, scrolling and breakpoints.
310
+ */
311
+ declare function SuiteSettingsLayout({ children, sidebar, mobileNav, loading, title, description, header, dataTest, headerDataTest, className, contentClassName, }: SuiteSettingsLayoutProps): react.JSX.Element;
312
+
240
313
  interface SuiteUserMenuProps {
241
314
  name?: string | null;
242
315
  email?: string | null;
@@ -308,18 +381,24 @@ declare const SUITE_APPS: readonly SuiteAppDefinition[];
308
381
  declare const SUITE_APP_MAP: Readonly<Record<SuiteAppSlug, SuiteAppDefinition>>;
309
382
  /** Resolve an app's base URL: env var first, dev fallback second. */
310
383
  declare function suiteAppBaseUrl(slug: SuiteAppSlug): string;
384
+ /**
385
+ * Suite notification links are often stored as `/dashboard/...` relative to the
386
+ * *source* app. Resolving them with the current product origin opens the wrong
387
+ * app — prefix with that app's base URL instead.
388
+ */
389
+ declare function resolveSuiteNotificationHref(href: string | null | undefined, sourceApp: string | null | undefined): string;
311
390
 
312
391
  /**
313
392
  * Today-page loading/empty calibrating state. Apps inject their branded
314
- * AppSpinner; `variant` picks the ornamentation style:
315
- * - `ring` large spinner ring + ping behind the sun (TurtleTime/ShellStack)
316
- * - `pulse` — pulsing sun only (Tides/Kraken)
393
+ * AppSpinner. Kept deliberately quiet single soft fade + one spinner,
394
+ * no ping/pulse stacks that compete with OAuth/launch handoffs.
317
395
  */
318
- declare function TodayCalibrating({ onRetry, retrying, className, spinner: Spinner, variant, retrySpinnerClassName, }: {
396
+ declare function TodayCalibrating({ onRetry, retrying, className, spinner: Spinner, variant: _variant, retrySpinnerClassName, }: {
319
397
  onRetry?: () => void;
320
398
  retrying?: boolean;
321
399
  className?: string;
322
400
  spinner: SuiteSpinnerComponent;
401
+ /** @deprecated Kept for call-site compat; ornamentation is always calm. */
323
402
  variant?: 'ring' | 'pulse';
324
403
  retrySpinnerClassName?: string;
325
404
  }): react.JSX.Element;
@@ -367,36 +446,50 @@ declare function SuiteThemeProvider({ config, children, }: {
367
446
  }): react.JSX.Element;
368
447
  declare function useSuiteTheme(): SuiteThemeContextValue;
369
448
 
449
+ declare const SUITE_OPEN_ASK_AI_EVENT = "shellstack:open-ask-ai";
450
+ type SuiteAskAiOpenDetail = {
451
+ prompt?: string;
452
+ };
453
+ /** Open the suite Ask AI panel from anywhere (Today card, command palette, …). */
454
+ declare function openSuiteAskAi(detail?: SuiteAskAiOpenDetail): void;
370
455
  interface SuiteAiPreset {
371
456
  label: string;
372
457
  prompt: string;
373
458
  }
459
+ interface SuiteAiChatMessage {
460
+ role: 'user' | 'assistant';
461
+ content: string;
462
+ created_at?: string;
463
+ }
374
464
  /**
375
- * Thin ShellStack AI slide-over shared by suite apps.
465
+ * Suite-wide Ask AI slide-over Notion-style continuous chat.
376
466
  *
377
- * One-shot completions via the shared `/api/ai/complete` endpoint. Apps
378
- * inject their API helpers, preset prompts, brand icon and spinner. Renders
379
- * its own floating launcher so it can be mounted once in the authenticated
380
- * app shell.
467
+ * One thread per workspace (persisted via injected fetch/send/clear helpers).
468
+ * Not Kraken Deep Research. Apps mount this once in the authenticated shell.
381
469
  */
382
- declare function SuiteAiPanel({ presets, emptyState, fetchStatus, complete, brandIcon: BrandIcon, spinner: Spinner, }: {
383
- presets: SuiteAiPreset[];
384
- /** Idle-state hint copy shown before the first request. */
385
- emptyState: ReactNode;
386
- fetchStatus: () => Promise<{
470
+ declare function SuiteAiPanel({ presets, emptyState, title, fetchChat, sendMessage, clearChat, brandIcon: BrandIcon, spinner: Spinner, hideLauncher, }: {
471
+ presets?: SuiteAiPreset[];
472
+ emptyState?: ReactNode;
473
+ title?: string;
474
+ fetchChat: () => Promise<{
475
+ messages: SuiteAiChatMessage[];
387
476
  configured: boolean;
388
477
  }>;
389
- complete: (params: {
478
+ sendMessage: (params: {
390
479
  prompt: string;
391
480
  }) => Promise<{
392
- text: string;
481
+ messages: SuiteAiChatMessage[];
482
+ reply: string;
393
483
  }>;
394
- brandIcon: ComponentType<{
484
+ clearChat: () => Promise<void>;
485
+ brandIcon?: ComponentType<{
395
486
  className?: string;
396
487
  }>;
397
488
  spinner: ComponentType<{
398
489
  className?: string;
399
490
  }>;
491
+ /** When true, only Today / events open the panel (no floating button). */
492
+ hideLauncher?: boolean;
400
493
  }): react.JSX.Element;
401
494
 
402
495
  /**
@@ -516,6 +609,23 @@ declare function SuiteAppIcon({ app, size, label, className, style, }: SuiteAppI
516
609
  /** Mount non-critical chrome after the browser is idle (or a short timeout). */
517
610
  declare function useIdleMount(timeoutMs?: number): boolean;
518
611
 
612
+ declare const SIDEBAR_RAIL_WIDTH = 56;
613
+ declare const SIDEBAR_COLLAPSE_THRESHOLD = 80;
614
+ declare const SIDEBAR_MIN_EXPANDED_WIDTH = 180;
615
+ declare const SIDEBAR_MAX_WIDTH = 320;
616
+ declare const SIDEBAR_DEFAULT_WIDTH = 320;
617
+ /**
618
+ * Shared suite sidebar resizing: drag below the threshold to collapse,
619
+ * drag the rail edge out to expand, and double-click to reset.
620
+ */
621
+ declare function useSidebarWidth(storageKey: string): {
622
+ width: number;
623
+ collapsed: boolean;
624
+ setCollapsed: (value: boolean) => void;
625
+ resetWidth: () => void;
626
+ startResize: (event: PointerEvent<HTMLDivElement>) => void;
627
+ };
628
+
519
629
  declare function cn(...inputs: ClassValue[]): string;
520
630
 
521
631
  /**
@@ -570,13 +680,8 @@ declare const SUITE_SPRINGS: {
570
680
  };
571
681
  type SuiteSpringName = keyof typeof SUITE_SPRINGS;
572
682
 
573
- declare const WIDTHS: {
574
- readonly full: "max-w-none";
575
- readonly wide: "max-w-7xl";
576
- readonly content: "max-w-6xl";
577
- readonly narrow: "max-w-4xl";
578
- };
579
- type SuitePageWidth = keyof typeof WIDTHS;
683
+ /** Width tokens — applied as data-width; CSS in suite-skin.css owns max-width. */
684
+ type SuitePageWidth = 'full' | 'wide' | 'content' | 'narrow' | 'reading';
580
685
  interface SuiteBreadcrumbsProps {
581
686
  items: {
582
687
  label: ReactNode;
@@ -605,7 +710,9 @@ todayIcon, todayIconClassName,
605
710
  /** Small badge/pill next to the title (e.g. "Beta", org name). */
606
711
  badge,
607
712
  /** Breadcrumb line rendered above the title. */
608
- breadcrumb, }: {
713
+ breadcrumb,
714
+ /** Stick to the top of the scrollport (desktop page titles). */
715
+ sticky, }: {
609
716
  title: ReactNode;
610
717
  description?: ReactNode;
611
718
  eyebrow?: ReactNode;
@@ -618,6 +725,7 @@ breadcrumb, }: {
618
725
  todayIconClassName?: string;
619
726
  badge?: ReactNode;
620
727
  breadcrumb?: ReactNode;
728
+ sticky?: boolean;
621
729
  }): react.JSX.Element;
622
730
  declare function SuiteToolbar({ children, className, label, dataTest, }: {
623
731
  children: ReactNode;
@@ -676,10 +784,7 @@ declare function SuiteEmptyState({ icon, title, description, action, className,
676
784
  interface SuiteSettingsNavItem {
677
785
  label: string;
678
786
  href: string;
679
- icon: ComponentType<{
680
- className?: string;
681
- 'aria-hidden'?: boolean;
682
- }> | ReactNode;
787
+ icon: ElementType | ReactNode;
683
788
  testId?: string;
684
789
  }
685
790
  interface SuiteSettingsMobileNavProps {
@@ -687,6 +792,8 @@ interface SuiteSettingsMobileNavProps {
687
792
  activeHref: string;
688
793
  onSelect: (href: string) => void;
689
794
  dataTest?: string;
795
+ ariaLabel?: string;
796
+ className?: string;
690
797
  }
691
798
  /**
692
799
  * Horizontal scrollable settings nav for mobile.
@@ -694,7 +801,7 @@ interface SuiteSettingsMobileNavProps {
694
801
  * meet 44px touch targets, and preserve visual hierarchy (Law of UX: Hick's Law,
695
802
  * Recognition over Recall).
696
803
  */
697
- declare function SuiteSettingsMobileNav({ items, activeHref, onSelect, dataTest, }: SuiteSettingsMobileNavProps): react.JSX.Element;
804
+ declare function SuiteSettingsMobileNav({ items, activeHref, onSelect, dataTest, ariaLabel, className, }: SuiteSettingsMobileNavProps): react.JSX.Element;
698
805
 
699
806
  type CollapsedNode = ReactNode | ((collapsed: boolean) => ReactNode);
700
807
  interface SuiteSidebarNavItem {
@@ -743,6 +850,11 @@ interface SuiteAppLayoutProps {
743
850
  sidebarWidth?: number;
744
851
  /** True when the sidebar is collapsed to the icon rail. */
745
852
  collapsed?: boolean;
853
+ /**
854
+ * When true, `#main-content` does not scroll — the page owns an internal
855
+ * scrollport (e.g. Deep Research: fixed header + composer, chat scrolls).
856
+ */
857
+ lockMainScroll?: boolean;
746
858
  /** Drag this to resize the sidebar. */
747
859
  onStartResize?: (e: PointerEvent<HTMLDivElement>) => void;
748
860
  /** Double-click to reset sidebar width. */
@@ -750,11 +862,10 @@ interface SuiteAppLayoutProps {
750
862
  className?: string;
751
863
  }
752
864
  /**
753
- * Responsive ShellStack app shell. Desktop: resizable fixed sidebar +
754
- * scrollable content with an optional drag handle. Mobile/tablet: mobile
755
- * header + content + bottom nav. This is the single layout primitive every
756
- * app should use.
865
+ * Responsive ShellStack app shell. One content tree (no duplicate children),
866
+ * one `#main-content` landmark. Desktop: fixed sidebar + scrollable main.
867
+ * Mobile: header + main + bottom nav.
757
868
  */
758
- declare function SuiteAppLayout({ sidebar, children, mobileHeader, bottomNav, sidebarWidth, collapsed, onStartResize, onResetWidth, className, }: SuiteAppLayoutProps): react.JSX.Element;
869
+ declare function SuiteAppLayout({ sidebar, children, mobileHeader, bottomNav, sidebarWidth, collapsed, lockMainScroll, onStartResize, onResetWidth, className, }: SuiteAppLayoutProps): react.JSX.Element;
759
870
 
760
- export { APP_ACCENTS, APP_GLYPHS, AnimatedMoon, AnimatedSun, AppSwitcher, AppSwitcherChevron, AppSwitcherMark, CommandPaletteHost, DeferredChrome, SUITE_APPS, SUITE_APP_MAP, SUITE_GLYPHS, SUITE_ICON_NAMES, SUITE_SPRINGS, SourceAppGlyph, type SuiteAccentSlug, SuiteAiPanel, type SuiteAiPreset, type SuiteAppAccent, type SuiteAppDefinition, type SuiteAppEntry, SuiteAppIcon, type SuiteAppIconProps, SuiteAppLayout, type SuiteAppLayoutProps, type SuiteAppSlug, SuiteAppStrip, SuiteBottomNav, type SuiteBottomNavItem, SuiteBreadcrumbs, type SuiteBreadcrumbsProps, type SuiteCommandItem, type SuiteCommandPaletteComponent, type SuiteDropdownItemComponent, type SuiteDropdownMenuComponent, type SuiteDropdownMenuProps, SuiteEmptyState, type SuiteGlyph, type SuiteGlyphElement, SuiteIcon, type SuiteIconName, type SuiteIconProps, SuiteMobileDrawer, SuiteMobileHeader, SuiteMotionProvider, type SuiteNotification, SuiteNotificationBell, type SuiteNotificationsResponse, SuitePage, SuitePageHeader, type SuitePageWidth, type SuiteResolvedTheme, SuiteSectionHeader, SuiteSettingsMobileNav, type SuiteSettingsNavItem, SuiteSidebar, type SuiteSidebarNavItem, SuiteSkeleton, SuiteSkeletonCard, SuiteSkeletonList, type SuiteSpinnerComponent, type SuiteSpringName, SuiteTabList, type SuiteTheme, type SuiteThemeConfig, type SuiteThemeContextValue, SuiteThemeProvider, SuiteToolbar, SuiteUserMenu, type SuiteUserMenuProps, TodayCalibrating, TodayEmptyState, TodayHero, TodayPageFrame, TodayPanel, TodaySection, TodayTimeIcon, TodayTopBar, appSwitcherMarkClass, appSwitcherMenuItemClass, appSwitcherTriggerClass, cn, getTodayGreeting, sourceToSuiteApp, suiteAppBaseUrl, suiteAppLabel, useIdleMount, useSuiteTheme };
871
+ export { APP_ACCENTS, APP_GLYPHS, AnimatedMoon, AnimatedSun, AppSwitcher, AppSwitcherChevron, AppSwitcherMark, CommandPaletteHost, DeferredChrome, SIDEBAR_COLLAPSE_THRESHOLD, SIDEBAR_DEFAULT_WIDTH, SIDEBAR_MAX_WIDTH, SIDEBAR_MIN_EXPANDED_WIDTH, SIDEBAR_RAIL_WIDTH, SUITE_APPS, SUITE_APP_MAP, SUITE_GLYPHS, SUITE_ICON_NAMES, SUITE_OPEN_ASK_AI_EVENT, SUITE_SPRINGS, SourceAppGlyph, type SuiteAccentSlug, type SuiteAiChatMessage, SuiteAiPanel, type SuiteAiPreset, type SuiteAppAccent, type SuiteAppDefinition, type SuiteAppEntry, SuiteAppIcon, type SuiteAppIconProps, SuiteAppLayout, type SuiteAppLayoutProps, type SuiteAppSlug, SuiteAppStrip, type SuiteAskAiOpenDetail, SuiteBottomNav, type SuiteBottomNavItem, SuiteBreadcrumbs, type SuiteBreadcrumbsProps, type SuiteCommandItem, type SuiteCommandPaletteComponent, type SuiteDropdownItemComponent, type SuiteDropdownMenuComponent, type SuiteDropdownMenuProps, SuiteEmptyState, type SuiteGlyph, type SuiteGlyphElement, SuiteIcon, type SuiteIconName, type SuiteIconProps, SuiteMobileDrawer, SuiteMobileHeader, SuiteMotionProvider, type SuiteNotification, SuiteNotificationBell, type SuiteNotificationsResponse, SuitePage, SuitePageHeader, type SuitePageWidth, type SuiteResolvedTheme, SuiteSectionHeader, SuiteSettingsLayout, type SuiteSettingsLayoutProps, SuiteSettingsMobileNav, type SuiteSettingsNavItem, SuiteSidebar, type SuiteSidebarNavItem, SuiteSkeleton, SuiteSkeletonCard, SuiteSkeletonList, type SuiteSpinnerComponent, type SuiteSpringName, SuiteTabList, type SuiteTheme, type SuiteThemeConfig, type SuiteThemeContextValue, SuiteThemeProvider, SuiteToolbar, SuiteUserMenu, type SuiteUserMenuProps, TodayAskAiCard, TodayCalibrating, TodayEmptyAction, TodayEmptyState, TodayHero, TodayLayout, TodayPageFrame, TodayPanel, type TodayPrimaryAccent, TodayPrimaryAction, TodaySection, TodayTimeIcon, TodayTopBar, appSwitcherMarkClass, appSwitcherMenuItemClass, appSwitcherTriggerClass, cn, getTodayGreeting, openSuiteAskAi, resolveSuiteNotificationHref, sourceToSuiteApp, suiteAppBaseUrl, suiteAppLabel, useIdleMount, useSidebarWidth, useSuiteTheme };
package/dist/suite.d.ts CHANGED
@@ -1,9 +1,13 @@
1
1
  import * as react from 'react';
2
- import { ReactNode, ComponentType, ButtonHTMLAttributes, CSSProperties, ElementType, PointerEvent } from 'react';
2
+ import { ReactNode, ComponentType, ButtonHTMLAttributes, CSSProperties, PointerEvent, ElementType } from 'react';
3
3
  import { ClassValue } from 'clsx';
4
4
  export { m } from 'motion/react';
5
5
 
6
- /** Full-bleed theme wash + soft clouds; uses ph-* tokens from each app's theme. */
6
+ /**
7
+ * Today page content wrapper with soft atmosphere.
8
+ * Does not own scrolling — `#main-content` is the scrollport so sticky headers work.
9
+ * Glow/clouds are absolute and do not create a nested scrollport.
10
+ */
7
11
  declare function TodayPageFrame({ children }: {
8
12
  children: ReactNode;
9
13
  }): react.JSX.Element;
@@ -50,8 +54,56 @@ declare function getTodayGreeting(user?: {
50
54
  overdueCount?: number;
51
55
  hours?: number;
52
56
  }): string;
53
- declare function TodayHero({ message, }: {
57
+ declare function TodayHero({ message, brief, briefMeta, }: {
54
58
  message?: ReactNode;
59
+ /** AI / local focus brief under the greeting. */
60
+ brief?: ReactNode;
61
+ briefMeta?: ReactNode;
62
+ }): react.JSX.Element;
63
+ type TodayPrimaryAccent = 'tides' | 'turtletime' | 'kraken' | 'shellstack' | 'neutral';
64
+ /**
65
+ * Compact primary CTA for Today — one action per app.
66
+ * Colours live in suite-skin (.today-primary-action); no idle animation.
67
+ */
68
+ declare function TodayPrimaryAction({ label, description, icon, accent, onClick, href, loading, active, className, dataTest, }: {
69
+ label: string;
70
+ description?: string;
71
+ icon?: ReactNode;
72
+ accent?: TodayPrimaryAccent;
73
+ onClick?: () => void;
74
+ href?: string;
75
+ loading?: boolean;
76
+ /** e.g. timer already running */
77
+ active?: boolean;
78
+ className?: string;
79
+ dataTest?: string;
80
+ }): react.JSX.Element;
81
+ declare function TodayEmptyAction({ title, description, actionLabel, href, onClick, dataTest, }: {
82
+ title: string;
83
+ description?: string;
84
+ actionLabel?: string;
85
+ href?: string;
86
+ onClick?: () => void;
87
+ dataTest?: string;
88
+ }): react.JSX.Element;
89
+ /** Desktop Today shell: main column + sticky Ask AI / brief aside. */
90
+ declare function TodayLayout({ primary, main, aside, className, }: {
91
+ primary?: ReactNode;
92
+ main: ReactNode;
93
+ aside?: ReactNode;
94
+ className?: string;
95
+ }): react.JSX.Element;
96
+ /**
97
+ * Today Ask AI CTA — opens the suite assistant (not Kraken Deep Research).
98
+ * Prefer onClick → openSuiteAskAi(); href is a fallback only.
99
+ */
100
+ declare function TodayAskAiCard({ title, description, cta, className, onClick, href, }: {
101
+ title?: string;
102
+ description?: string;
103
+ cta?: string;
104
+ className?: string;
105
+ onClick?: () => void;
106
+ href?: string;
55
107
  }): react.JSX.Element;
56
108
  declare function TodaySection({ icon: Icon, iconClassName, title, description, action, testId, children, }: {
57
109
  icon: LucideIcon;
@@ -192,14 +244,16 @@ declare function DeferredChrome({ children }: {
192
244
  * close, body scroll-lock and focus hand-off while open. Nav content stays
193
245
  * app-side via `children`.
194
246
  */
195
- declare function SuiteMobileDrawer({ open, onClose, children, side, showCloseButton, closeLabel, backdropLabel, dialogLabel, durationMs, dataTest, panelDataTest, panelClassName, }: {
247
+ declare function SuiteMobileDrawer({ open, onClose, children, side, showCloseButton, title, closeLabel, backdropLabel, dialogLabel, durationMs, dataTest, panelDataTest, panelClassName, }: {
196
248
  open: boolean;
197
249
  onClose: () => void;
198
250
  children: ReactNode;
199
251
  /** Edge the panel slides in from. */
200
- side?: 'left' | 'right';
252
+ side?: "left" | "right";
201
253
  /** Standard close row (h-14, trailing X button) above the content. */
202
254
  showCloseButton?: boolean;
255
+ /** Optional label in the standard close row. */
256
+ title?: ReactNode;
203
257
  closeLabel?: string;
204
258
  backdropLabel?: string;
205
259
  /** Accessible name for the dialog panel. */
@@ -237,6 +291,25 @@ declare function SuiteMobileHeader({ onMenuClick, menuIcon: MenuIcon, title, act
237
291
  className?: string;
238
292
  }): react.JSX.Element;
239
293
 
294
+ interface SuiteSettingsLayoutProps {
295
+ children: ReactNode;
296
+ sidebar: ReactNode;
297
+ mobileNav?: ReactNode;
298
+ loading?: ReactNode;
299
+ title?: ReactNode;
300
+ description?: ReactNode;
301
+ header?: ReactNode;
302
+ dataTest?: string;
303
+ headerDataTest?: string;
304
+ className?: string;
305
+ contentClassName?: string;
306
+ }
307
+ /**
308
+ * Canonical settings geometry for every suite app.
309
+ * Apps own nav data and content; the suite owns spacing, scrolling and breakpoints.
310
+ */
311
+ declare function SuiteSettingsLayout({ children, sidebar, mobileNav, loading, title, description, header, dataTest, headerDataTest, className, contentClassName, }: SuiteSettingsLayoutProps): react.JSX.Element;
312
+
240
313
  interface SuiteUserMenuProps {
241
314
  name?: string | null;
242
315
  email?: string | null;
@@ -308,18 +381,24 @@ declare const SUITE_APPS: readonly SuiteAppDefinition[];
308
381
  declare const SUITE_APP_MAP: Readonly<Record<SuiteAppSlug, SuiteAppDefinition>>;
309
382
  /** Resolve an app's base URL: env var first, dev fallback second. */
310
383
  declare function suiteAppBaseUrl(slug: SuiteAppSlug): string;
384
+ /**
385
+ * Suite notification links are often stored as `/dashboard/...` relative to the
386
+ * *source* app. Resolving them with the current product origin opens the wrong
387
+ * app — prefix with that app's base URL instead.
388
+ */
389
+ declare function resolveSuiteNotificationHref(href: string | null | undefined, sourceApp: string | null | undefined): string;
311
390
 
312
391
  /**
313
392
  * Today-page loading/empty calibrating state. Apps inject their branded
314
- * AppSpinner; `variant` picks the ornamentation style:
315
- * - `ring` large spinner ring + ping behind the sun (TurtleTime/ShellStack)
316
- * - `pulse` — pulsing sun only (Tides/Kraken)
393
+ * AppSpinner. Kept deliberately quiet single soft fade + one spinner,
394
+ * no ping/pulse stacks that compete with OAuth/launch handoffs.
317
395
  */
318
- declare function TodayCalibrating({ onRetry, retrying, className, spinner: Spinner, variant, retrySpinnerClassName, }: {
396
+ declare function TodayCalibrating({ onRetry, retrying, className, spinner: Spinner, variant: _variant, retrySpinnerClassName, }: {
319
397
  onRetry?: () => void;
320
398
  retrying?: boolean;
321
399
  className?: string;
322
400
  spinner: SuiteSpinnerComponent;
401
+ /** @deprecated Kept for call-site compat; ornamentation is always calm. */
323
402
  variant?: 'ring' | 'pulse';
324
403
  retrySpinnerClassName?: string;
325
404
  }): react.JSX.Element;
@@ -367,36 +446,50 @@ declare function SuiteThemeProvider({ config, children, }: {
367
446
  }): react.JSX.Element;
368
447
  declare function useSuiteTheme(): SuiteThemeContextValue;
369
448
 
449
+ declare const SUITE_OPEN_ASK_AI_EVENT = "shellstack:open-ask-ai";
450
+ type SuiteAskAiOpenDetail = {
451
+ prompt?: string;
452
+ };
453
+ /** Open the suite Ask AI panel from anywhere (Today card, command palette, …). */
454
+ declare function openSuiteAskAi(detail?: SuiteAskAiOpenDetail): void;
370
455
  interface SuiteAiPreset {
371
456
  label: string;
372
457
  prompt: string;
373
458
  }
459
+ interface SuiteAiChatMessage {
460
+ role: 'user' | 'assistant';
461
+ content: string;
462
+ created_at?: string;
463
+ }
374
464
  /**
375
- * Thin ShellStack AI slide-over shared by suite apps.
465
+ * Suite-wide Ask AI slide-over Notion-style continuous chat.
376
466
  *
377
- * One-shot completions via the shared `/api/ai/complete` endpoint. Apps
378
- * inject their API helpers, preset prompts, brand icon and spinner. Renders
379
- * its own floating launcher so it can be mounted once in the authenticated
380
- * app shell.
467
+ * One thread per workspace (persisted via injected fetch/send/clear helpers).
468
+ * Not Kraken Deep Research. Apps mount this once in the authenticated shell.
381
469
  */
382
- declare function SuiteAiPanel({ presets, emptyState, fetchStatus, complete, brandIcon: BrandIcon, spinner: Spinner, }: {
383
- presets: SuiteAiPreset[];
384
- /** Idle-state hint copy shown before the first request. */
385
- emptyState: ReactNode;
386
- fetchStatus: () => Promise<{
470
+ declare function SuiteAiPanel({ presets, emptyState, title, fetchChat, sendMessage, clearChat, brandIcon: BrandIcon, spinner: Spinner, hideLauncher, }: {
471
+ presets?: SuiteAiPreset[];
472
+ emptyState?: ReactNode;
473
+ title?: string;
474
+ fetchChat: () => Promise<{
475
+ messages: SuiteAiChatMessage[];
387
476
  configured: boolean;
388
477
  }>;
389
- complete: (params: {
478
+ sendMessage: (params: {
390
479
  prompt: string;
391
480
  }) => Promise<{
392
- text: string;
481
+ messages: SuiteAiChatMessage[];
482
+ reply: string;
393
483
  }>;
394
- brandIcon: ComponentType<{
484
+ clearChat: () => Promise<void>;
485
+ brandIcon?: ComponentType<{
395
486
  className?: string;
396
487
  }>;
397
488
  spinner: ComponentType<{
398
489
  className?: string;
399
490
  }>;
491
+ /** When true, only Today / events open the panel (no floating button). */
492
+ hideLauncher?: boolean;
400
493
  }): react.JSX.Element;
401
494
 
402
495
  /**
@@ -516,6 +609,23 @@ declare function SuiteAppIcon({ app, size, label, className, style, }: SuiteAppI
516
609
  /** Mount non-critical chrome after the browser is idle (or a short timeout). */
517
610
  declare function useIdleMount(timeoutMs?: number): boolean;
518
611
 
612
+ declare const SIDEBAR_RAIL_WIDTH = 56;
613
+ declare const SIDEBAR_COLLAPSE_THRESHOLD = 80;
614
+ declare const SIDEBAR_MIN_EXPANDED_WIDTH = 180;
615
+ declare const SIDEBAR_MAX_WIDTH = 320;
616
+ declare const SIDEBAR_DEFAULT_WIDTH = 320;
617
+ /**
618
+ * Shared suite sidebar resizing: drag below the threshold to collapse,
619
+ * drag the rail edge out to expand, and double-click to reset.
620
+ */
621
+ declare function useSidebarWidth(storageKey: string): {
622
+ width: number;
623
+ collapsed: boolean;
624
+ setCollapsed: (value: boolean) => void;
625
+ resetWidth: () => void;
626
+ startResize: (event: PointerEvent<HTMLDivElement>) => void;
627
+ };
628
+
519
629
  declare function cn(...inputs: ClassValue[]): string;
520
630
 
521
631
  /**
@@ -570,13 +680,8 @@ declare const SUITE_SPRINGS: {
570
680
  };
571
681
  type SuiteSpringName = keyof typeof SUITE_SPRINGS;
572
682
 
573
- declare const WIDTHS: {
574
- readonly full: "max-w-none";
575
- readonly wide: "max-w-7xl";
576
- readonly content: "max-w-6xl";
577
- readonly narrow: "max-w-4xl";
578
- };
579
- type SuitePageWidth = keyof typeof WIDTHS;
683
+ /** Width tokens — applied as data-width; CSS in suite-skin.css owns max-width. */
684
+ type SuitePageWidth = 'full' | 'wide' | 'content' | 'narrow' | 'reading';
580
685
  interface SuiteBreadcrumbsProps {
581
686
  items: {
582
687
  label: ReactNode;
@@ -605,7 +710,9 @@ todayIcon, todayIconClassName,
605
710
  /** Small badge/pill next to the title (e.g. "Beta", org name). */
606
711
  badge,
607
712
  /** Breadcrumb line rendered above the title. */
608
- breadcrumb, }: {
713
+ breadcrumb,
714
+ /** Stick to the top of the scrollport (desktop page titles). */
715
+ sticky, }: {
609
716
  title: ReactNode;
610
717
  description?: ReactNode;
611
718
  eyebrow?: ReactNode;
@@ -618,6 +725,7 @@ breadcrumb, }: {
618
725
  todayIconClassName?: string;
619
726
  badge?: ReactNode;
620
727
  breadcrumb?: ReactNode;
728
+ sticky?: boolean;
621
729
  }): react.JSX.Element;
622
730
  declare function SuiteToolbar({ children, className, label, dataTest, }: {
623
731
  children: ReactNode;
@@ -676,10 +784,7 @@ declare function SuiteEmptyState({ icon, title, description, action, className,
676
784
  interface SuiteSettingsNavItem {
677
785
  label: string;
678
786
  href: string;
679
- icon: ComponentType<{
680
- className?: string;
681
- 'aria-hidden'?: boolean;
682
- }> | ReactNode;
787
+ icon: ElementType | ReactNode;
683
788
  testId?: string;
684
789
  }
685
790
  interface SuiteSettingsMobileNavProps {
@@ -687,6 +792,8 @@ interface SuiteSettingsMobileNavProps {
687
792
  activeHref: string;
688
793
  onSelect: (href: string) => void;
689
794
  dataTest?: string;
795
+ ariaLabel?: string;
796
+ className?: string;
690
797
  }
691
798
  /**
692
799
  * Horizontal scrollable settings nav for mobile.
@@ -694,7 +801,7 @@ interface SuiteSettingsMobileNavProps {
694
801
  * meet 44px touch targets, and preserve visual hierarchy (Law of UX: Hick's Law,
695
802
  * Recognition over Recall).
696
803
  */
697
- declare function SuiteSettingsMobileNav({ items, activeHref, onSelect, dataTest, }: SuiteSettingsMobileNavProps): react.JSX.Element;
804
+ declare function SuiteSettingsMobileNav({ items, activeHref, onSelect, dataTest, ariaLabel, className, }: SuiteSettingsMobileNavProps): react.JSX.Element;
698
805
 
699
806
  type CollapsedNode = ReactNode | ((collapsed: boolean) => ReactNode);
700
807
  interface SuiteSidebarNavItem {
@@ -743,6 +850,11 @@ interface SuiteAppLayoutProps {
743
850
  sidebarWidth?: number;
744
851
  /** True when the sidebar is collapsed to the icon rail. */
745
852
  collapsed?: boolean;
853
+ /**
854
+ * When true, `#main-content` does not scroll — the page owns an internal
855
+ * scrollport (e.g. Deep Research: fixed header + composer, chat scrolls).
856
+ */
857
+ lockMainScroll?: boolean;
746
858
  /** Drag this to resize the sidebar. */
747
859
  onStartResize?: (e: PointerEvent<HTMLDivElement>) => void;
748
860
  /** Double-click to reset sidebar width. */
@@ -750,11 +862,10 @@ interface SuiteAppLayoutProps {
750
862
  className?: string;
751
863
  }
752
864
  /**
753
- * Responsive ShellStack app shell. Desktop: resizable fixed sidebar +
754
- * scrollable content with an optional drag handle. Mobile/tablet: mobile
755
- * header + content + bottom nav. This is the single layout primitive every
756
- * app should use.
865
+ * Responsive ShellStack app shell. One content tree (no duplicate children),
866
+ * one `#main-content` landmark. Desktop: fixed sidebar + scrollable main.
867
+ * Mobile: header + main + bottom nav.
757
868
  */
758
- declare function SuiteAppLayout({ sidebar, children, mobileHeader, bottomNav, sidebarWidth, collapsed, onStartResize, onResetWidth, className, }: SuiteAppLayoutProps): react.JSX.Element;
869
+ declare function SuiteAppLayout({ sidebar, children, mobileHeader, bottomNav, sidebarWidth, collapsed, lockMainScroll, onStartResize, onResetWidth, className, }: SuiteAppLayoutProps): react.JSX.Element;
759
870
 
760
- export { APP_ACCENTS, APP_GLYPHS, AnimatedMoon, AnimatedSun, AppSwitcher, AppSwitcherChevron, AppSwitcherMark, CommandPaletteHost, DeferredChrome, SUITE_APPS, SUITE_APP_MAP, SUITE_GLYPHS, SUITE_ICON_NAMES, SUITE_SPRINGS, SourceAppGlyph, type SuiteAccentSlug, SuiteAiPanel, type SuiteAiPreset, type SuiteAppAccent, type SuiteAppDefinition, type SuiteAppEntry, SuiteAppIcon, type SuiteAppIconProps, SuiteAppLayout, type SuiteAppLayoutProps, type SuiteAppSlug, SuiteAppStrip, SuiteBottomNav, type SuiteBottomNavItem, SuiteBreadcrumbs, type SuiteBreadcrumbsProps, type SuiteCommandItem, type SuiteCommandPaletteComponent, type SuiteDropdownItemComponent, type SuiteDropdownMenuComponent, type SuiteDropdownMenuProps, SuiteEmptyState, type SuiteGlyph, type SuiteGlyphElement, SuiteIcon, type SuiteIconName, type SuiteIconProps, SuiteMobileDrawer, SuiteMobileHeader, SuiteMotionProvider, type SuiteNotification, SuiteNotificationBell, type SuiteNotificationsResponse, SuitePage, SuitePageHeader, type SuitePageWidth, type SuiteResolvedTheme, SuiteSectionHeader, SuiteSettingsMobileNav, type SuiteSettingsNavItem, SuiteSidebar, type SuiteSidebarNavItem, SuiteSkeleton, SuiteSkeletonCard, SuiteSkeletonList, type SuiteSpinnerComponent, type SuiteSpringName, SuiteTabList, type SuiteTheme, type SuiteThemeConfig, type SuiteThemeContextValue, SuiteThemeProvider, SuiteToolbar, SuiteUserMenu, type SuiteUserMenuProps, TodayCalibrating, TodayEmptyState, TodayHero, TodayPageFrame, TodayPanel, TodaySection, TodayTimeIcon, TodayTopBar, appSwitcherMarkClass, appSwitcherMenuItemClass, appSwitcherTriggerClass, cn, getTodayGreeting, sourceToSuiteApp, suiteAppBaseUrl, suiteAppLabel, useIdleMount, useSuiteTheme };
871
+ export { APP_ACCENTS, APP_GLYPHS, AnimatedMoon, AnimatedSun, AppSwitcher, AppSwitcherChevron, AppSwitcherMark, CommandPaletteHost, DeferredChrome, SIDEBAR_COLLAPSE_THRESHOLD, SIDEBAR_DEFAULT_WIDTH, SIDEBAR_MAX_WIDTH, SIDEBAR_MIN_EXPANDED_WIDTH, SIDEBAR_RAIL_WIDTH, SUITE_APPS, SUITE_APP_MAP, SUITE_GLYPHS, SUITE_ICON_NAMES, SUITE_OPEN_ASK_AI_EVENT, SUITE_SPRINGS, SourceAppGlyph, type SuiteAccentSlug, type SuiteAiChatMessage, SuiteAiPanel, type SuiteAiPreset, type SuiteAppAccent, type SuiteAppDefinition, type SuiteAppEntry, SuiteAppIcon, type SuiteAppIconProps, SuiteAppLayout, type SuiteAppLayoutProps, type SuiteAppSlug, SuiteAppStrip, type SuiteAskAiOpenDetail, SuiteBottomNav, type SuiteBottomNavItem, SuiteBreadcrumbs, type SuiteBreadcrumbsProps, type SuiteCommandItem, type SuiteCommandPaletteComponent, type SuiteDropdownItemComponent, type SuiteDropdownMenuComponent, type SuiteDropdownMenuProps, SuiteEmptyState, type SuiteGlyph, type SuiteGlyphElement, SuiteIcon, type SuiteIconName, type SuiteIconProps, SuiteMobileDrawer, SuiteMobileHeader, SuiteMotionProvider, type SuiteNotification, SuiteNotificationBell, type SuiteNotificationsResponse, SuitePage, SuitePageHeader, type SuitePageWidth, type SuiteResolvedTheme, SuiteSectionHeader, SuiteSettingsLayout, type SuiteSettingsLayoutProps, SuiteSettingsMobileNav, type SuiteSettingsNavItem, SuiteSidebar, type SuiteSidebarNavItem, SuiteSkeleton, SuiteSkeletonCard, SuiteSkeletonList, type SuiteSpinnerComponent, type SuiteSpringName, SuiteTabList, type SuiteTheme, type SuiteThemeConfig, type SuiteThemeContextValue, SuiteThemeProvider, SuiteToolbar, SuiteUserMenu, type SuiteUserMenuProps, TodayAskAiCard, TodayCalibrating, TodayEmptyAction, TodayEmptyState, TodayHero, TodayLayout, TodayPageFrame, TodayPanel, type TodayPrimaryAccent, TodayPrimaryAction, TodaySection, TodayTimeIcon, TodayTopBar, appSwitcherMarkClass, appSwitcherMenuItemClass, appSwitcherTriggerClass, cn, getTodayGreeting, openSuiteAskAi, resolveSuiteNotificationHref, sourceToSuiteApp, suiteAppBaseUrl, suiteAppLabel, useIdleMount, useSidebarWidth, useSuiteTheme };