@xenide-io/the-old-ui-theme 0.3.2 → 0.4.3
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/dist/chunk-54ZR4VL5.mjs +4641 -0
- package/dist/chunk-G53YLHVE.mjs +1023 -0
- package/dist/{index-BgG8Homu.d.mts → index-B5NOyoKS.d.mts} +100 -100
- package/dist/{index-BgG8Homu.d.ts → index-B5NOyoKS.d.ts} +100 -100
- package/dist/index.d.mts +9 -145
- package/dist/index.d.ts +9 -145
- package/dist/index.js +653 -1111
- package/dist/index.mjs +86 -342
- package/dist/suite.d.mts +760 -0
- package/dist/suite.d.ts +760 -0
- package/dist/suite.js +2800 -0
- package/dist/suite.mjs +2441 -0
- package/dist/ui.d.mts +1 -2
- package/dist/ui.d.ts +1 -2
- package/dist/ui.js +14 -10
- package/dist/ui.mjs +13 -11
- package/package.json +43 -24
- package/src/components/icons/icons.tsx +0 -2
- package/src/components/icons/index.ts +0 -3
- package/src/components/sections/IconShowcase.tsx +1 -110
- package/src/components/sections/NewComponentsShowcase.tsx +4 -4
- package/src/components/sections/SidebarShowcase.tsx +3 -3
- package/src/components/sections/SuiteShowcase.tsx +669 -0
- package/src/components/ui/ComponentDocs.tsx +2 -2
- package/src/components/ui/ContextMenu.tsx +1 -1
- package/src/components/ui/Menubar.tsx +1 -1
- package/src/components/ui/Sidebar.tsx +10 -8
- package/src/styles/suite-skin.css +255 -0
- package/src/suite/components/ai-panel.tsx +202 -0
- package/src/suite/components/app-switcher.tsx +196 -0
- package/src/suite/components/command-palette-host.tsx +62 -0
- package/src/suite/components/deferred-chrome.tsx +12 -0
- package/src/suite/components/suite-app-layout.tsx +69 -0
- package/src/suite/components/suite-bottom-nav.tsx +113 -0
- package/src/suite/components/suite-layout.tsx +285 -0
- package/src/suite/components/suite-mobile-drawer.tsx +150 -0
- package/src/suite/components/suite-mobile-header.tsx +71 -0
- package/src/suite/components/suite-notification-bell.tsx +227 -0
- package/src/suite/components/suite-settings-mobile-nav.tsx +83 -0
- package/src/suite/components/suite-sidebar.tsx +198 -0
- package/src/suite/components/suite-skeleton.tsx +191 -0
- package/src/suite/components/suite-user-menu.tsx +109 -0
- package/src/suite/components/theme-provider.tsx +174 -0
- package/src/suite/components/today-calibrating.tsx +95 -0
- package/src/suite/components/today-page-frame.tsx +28 -0
- package/src/suite/components/today-ui.tsx +370 -0
- package/src/suite/icons/app-accents.ts +75 -0
- package/src/suite/icons/glyph-parts.tsx +67 -0
- package/src/suite/icons/glyphs.ts +203 -0
- package/src/suite/icons/index.ts +12 -0
- package/src/suite/icons/suite-app-icon.tsx +68 -0
- package/src/suite/icons/suite-icon.tsx +93 -0
- package/src/suite/index.ts +108 -0
- package/src/suite/lib/apps.ts +75 -0
- package/src/suite/lib/cn.ts +6 -0
- package/src/suite/lib/injected.ts +54 -0
- package/src/suite/lib/motion.tsx +48 -0
- package/src/suite/lib/use-idle-mount.ts +25 -0
- package/dist/chunk-5HSOBJ4F.mjs +0 -5968
- package/src/components/icons/lemon-brand-icons.tsx +0 -16
- package/src/components/icons/lemon-category-icons.tsx +0 -72
- package/src/components/icons/lemon-icons.tsx +0 -57
package/dist/suite.d.mts
ADDED
|
@@ -0,0 +1,760 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, ComponentType, ButtonHTMLAttributes, CSSProperties, ElementType, PointerEvent } from 'react';
|
|
3
|
+
import { ClassValue } from 'clsx';
|
|
4
|
+
export { m } from 'motion/react';
|
|
5
|
+
|
|
6
|
+
/** Full-bleed theme wash + soft clouds; uses ph-* tokens from each app's theme. */
|
|
7
|
+
declare function TodayPageFrame({ children }: {
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}): react.JSX.Element;
|
|
10
|
+
|
|
11
|
+
type LucideIcon = react.ComponentType<react.SVGProps<SVGSVGElement>>;
|
|
12
|
+
type SuiteAppSlug$1 = 'shellstack' | 'tides' | 'turtletime' | 'kraken';
|
|
13
|
+
declare function sourceToSuiteApp(source: string): SuiteAppSlug$1;
|
|
14
|
+
declare function suiteAppLabel(source: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Small line icon for list rows — the app's suite glyph with its brand
|
|
17
|
+
* accent on a muted base. Not the branded app tile (see SuiteAppIcon).
|
|
18
|
+
*/
|
|
19
|
+
declare function SourceAppGlyph({ source, className, }: {
|
|
20
|
+
source: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
}): react.JSX.Element;
|
|
23
|
+
declare function SuiteAppStrip({ className, icons, }: {
|
|
24
|
+
className?: string;
|
|
25
|
+
icons?: Partial<Record<SuiteAppSlug$1, ReactNode>>;
|
|
26
|
+
}): react.JSX.Element;
|
|
27
|
+
declare function AnimatedSun({ className }: {
|
|
28
|
+
className?: string;
|
|
29
|
+
}): react.JSX.Element;
|
|
30
|
+
declare function AnimatedMoon({ className }: {
|
|
31
|
+
className?: string;
|
|
32
|
+
}): react.JSX.Element;
|
|
33
|
+
/** Sun through the day, moon from 18:00 to 06:00. */
|
|
34
|
+
declare function TodayTimeIcon({ className }: {
|
|
35
|
+
className?: string;
|
|
36
|
+
}): react.JSX.Element;
|
|
37
|
+
declare function TodayTopBar({ refreshing, loading, onRefresh, appIcon, appName, }: {
|
|
38
|
+
refreshing?: boolean;
|
|
39
|
+
loading?: boolean;
|
|
40
|
+
onRefresh: () => void;
|
|
41
|
+
appIcon?: ReactNode;
|
|
42
|
+
appName?: string;
|
|
43
|
+
}): react.JSX.Element;
|
|
44
|
+
declare function getTodayGreeting(user?: {
|
|
45
|
+
first_name?: string;
|
|
46
|
+
name?: string;
|
|
47
|
+
email?: string;
|
|
48
|
+
}, stats?: {
|
|
49
|
+
taskCount?: number;
|
|
50
|
+
overdueCount?: number;
|
|
51
|
+
hours?: number;
|
|
52
|
+
}): string;
|
|
53
|
+
declare function TodayHero({ message, }: {
|
|
54
|
+
message?: ReactNode;
|
|
55
|
+
}): react.JSX.Element;
|
|
56
|
+
declare function TodaySection({ icon: Icon, iconClassName, title, description, action, testId, children, }: {
|
|
57
|
+
icon: LucideIcon;
|
|
58
|
+
iconClassName?: string;
|
|
59
|
+
title: string;
|
|
60
|
+
description?: string;
|
|
61
|
+
action?: ReactNode;
|
|
62
|
+
testId?: string;
|
|
63
|
+
children: ReactNode;
|
|
64
|
+
}): react.JSX.Element;
|
|
65
|
+
declare function TodayPanel({ children, className, }: {
|
|
66
|
+
children: ReactNode;
|
|
67
|
+
className?: string;
|
|
68
|
+
}): react.JSX.Element;
|
|
69
|
+
declare function TodayEmptyState({ title, description, }: {
|
|
70
|
+
title: string;
|
|
71
|
+
description?: string;
|
|
72
|
+
}): react.JSX.Element;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Structural types for theme primitives each app injects from
|
|
76
|
+
* `@xenide-io/the-old-ui-theme/ui` (the shared package must not depend on it).
|
|
77
|
+
* The real components satisfy these shapes, so apps can pass them directly.
|
|
78
|
+
*/
|
|
79
|
+
interface SuiteDropdownMenuProps {
|
|
80
|
+
trigger: ReactNode;
|
|
81
|
+
children: ReactNode;
|
|
82
|
+
'aria-label': string;
|
|
83
|
+
align?: 'start' | 'center' | 'end';
|
|
84
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
85
|
+
sideOffset?: number;
|
|
86
|
+
className?: string;
|
|
87
|
+
panelClassName?: string;
|
|
88
|
+
open?: boolean;
|
|
89
|
+
onOpenChange?: (open: boolean) => void;
|
|
90
|
+
}
|
|
91
|
+
type SuiteDropdownMenuComponent = ComponentType<SuiteDropdownMenuProps>;
|
|
92
|
+
type SuiteDropdownItemComponent = ComponentType<ButtonHTMLAttributes<HTMLButtonElement>>;
|
|
93
|
+
interface SuiteCommandItem {
|
|
94
|
+
id: string;
|
|
95
|
+
label: string;
|
|
96
|
+
shortcut?: string;
|
|
97
|
+
icon?: ReactNode;
|
|
98
|
+
onSelect: () => void;
|
|
99
|
+
}
|
|
100
|
+
type SuiteCommandPaletteComponent = ComponentType<{
|
|
101
|
+
items: SuiteCommandItem[];
|
|
102
|
+
isOpen: boolean;
|
|
103
|
+
onClose: () => void;
|
|
104
|
+
placeholder?: string;
|
|
105
|
+
className?: string;
|
|
106
|
+
}>;
|
|
107
|
+
/** App-branded spinner (each app has its own AppSpinner design). */
|
|
108
|
+
type SuiteSpinnerComponent = ComponentType<{
|
|
109
|
+
size?: 'sm' | 'md' | 'lg';
|
|
110
|
+
className?: string;
|
|
111
|
+
label?: string;
|
|
112
|
+
}>;
|
|
113
|
+
|
|
114
|
+
declare function appSwitcherTriggerClass(open: boolean, collapsed?: boolean): string;
|
|
115
|
+
declare function appSwitcherMarkClass(): string;
|
|
116
|
+
/** No sticky Radix highlight while waiting for cross-app redirect. */
|
|
117
|
+
declare function appSwitcherMenuItemClass(): string;
|
|
118
|
+
declare function AppSwitcherMark({ children, collapsed, }: {
|
|
119
|
+
children: ReactNode;
|
|
120
|
+
collapsed?: boolean;
|
|
121
|
+
}): react.JSX.Element;
|
|
122
|
+
declare function AppSwitcherChevron({ open, collapsed, }: {
|
|
123
|
+
open: boolean;
|
|
124
|
+
collapsed?: boolean;
|
|
125
|
+
}): react.JSX.Element;
|
|
126
|
+
interface SuiteAppEntry {
|
|
127
|
+
slug: string;
|
|
128
|
+
name: string;
|
|
129
|
+
description: string;
|
|
130
|
+
icon: string;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Suite app switcher dropdown. Apps inject their brand mark/title, the
|
|
134
|
+
* visible app list, the cross-app navigation handler, and the theme
|
|
135
|
+
* dropdown primitives.
|
|
136
|
+
*/
|
|
137
|
+
declare function AppSwitcher({ apps, currentApp, onSelect, mark, title, collapsed, dropdownMenu: DropdownMenu, dropdownItem: DropdownItem, }: {
|
|
138
|
+
apps: SuiteAppEntry[];
|
|
139
|
+
currentApp: string;
|
|
140
|
+
onSelect: (app: SuiteAppEntry) => void;
|
|
141
|
+
mark: ReactNode;
|
|
142
|
+
title: ReactNode;
|
|
143
|
+
collapsed?: boolean;
|
|
144
|
+
dropdownMenu: SuiteDropdownMenuComponent;
|
|
145
|
+
dropdownItem: SuiteDropdownItemComponent;
|
|
146
|
+
}): react.JSX.Element;
|
|
147
|
+
|
|
148
|
+
/** Cross-app (suite) notification from `/api/notifications/` — shared across ShellStack apps. */
|
|
149
|
+
interface SuiteNotification {
|
|
150
|
+
id: string;
|
|
151
|
+
title: string;
|
|
152
|
+
body: string;
|
|
153
|
+
href: string;
|
|
154
|
+
kind: string;
|
|
155
|
+
source_app: string;
|
|
156
|
+
read_at: string | null;
|
|
157
|
+
created_at: string;
|
|
158
|
+
workspace: string | null;
|
|
159
|
+
organisation: string | null;
|
|
160
|
+
}
|
|
161
|
+
interface SuiteNotificationsResponse {
|
|
162
|
+
notifications: SuiteNotification[];
|
|
163
|
+
unread_count: number;
|
|
164
|
+
}
|
|
165
|
+
declare function SuiteNotificationBell({ fetchNotifications, markRead, markAllRead, dropdownMenu: DropdownMenu, cacheKey, }: {
|
|
166
|
+
fetchNotifications: () => Promise<SuiteNotificationsResponse>;
|
|
167
|
+
markRead: (id: string) => Promise<unknown>;
|
|
168
|
+
markAllRead: () => Promise<unknown>;
|
|
169
|
+
dropdownMenu: SuiteDropdownMenuComponent;
|
|
170
|
+
/** sessionStorage key for stale-while-revalidate; `null` disables caching. */
|
|
171
|
+
cacheKey?: string | null;
|
|
172
|
+
}): react.JSX.Element;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Cmd/Ctrl+K command palette host. Apps build the item list and inject the
|
|
176
|
+
* theme CommandPalette primitive.
|
|
177
|
+
*/
|
|
178
|
+
declare function CommandPaletteHost({ items, isAuthenticated, placeholder, commandPalette: CommandPalette, }: {
|
|
179
|
+
items: SuiteCommandItem[];
|
|
180
|
+
isAuthenticated?: boolean;
|
|
181
|
+
placeholder?: string;
|
|
182
|
+
commandPalette: SuiteCommandPaletteComponent;
|
|
183
|
+
}): react.JSX.Element | null;
|
|
184
|
+
|
|
185
|
+
/** Command K — mount after idle so first paint stays light. */
|
|
186
|
+
declare function DeferredChrome({ children }: {
|
|
187
|
+
children: ReactNode;
|
|
188
|
+
}): react.JSX.Element | null;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Suite mobile navigation drawer. Backdrop fade + panel slide, Escape to
|
|
192
|
+
* close, body scroll-lock and focus hand-off while open. Nav content stays
|
|
193
|
+
* app-side via `children`.
|
|
194
|
+
*/
|
|
195
|
+
declare function SuiteMobileDrawer({ open, onClose, children, side, showCloseButton, closeLabel, backdropLabel, dialogLabel, durationMs, dataTest, panelDataTest, panelClassName, }: {
|
|
196
|
+
open: boolean;
|
|
197
|
+
onClose: () => void;
|
|
198
|
+
children: ReactNode;
|
|
199
|
+
/** Edge the panel slides in from. */
|
|
200
|
+
side?: 'left' | 'right';
|
|
201
|
+
/** Standard close row (h-14, trailing X button) above the content. */
|
|
202
|
+
showCloseButton?: boolean;
|
|
203
|
+
closeLabel?: string;
|
|
204
|
+
backdropLabel?: string;
|
|
205
|
+
/** Accessible name for the dialog panel. */
|
|
206
|
+
dialogLabel?: string;
|
|
207
|
+
/** Slide/fade duration; also the close-transition unmount delay. */
|
|
208
|
+
durationMs?: number;
|
|
209
|
+
dataTest?: string;
|
|
210
|
+
panelDataTest?: string;
|
|
211
|
+
/** Panel surface overrides (e.g. `bg-ph-canvas`). */
|
|
212
|
+
panelClassName?: string;
|
|
213
|
+
}): react.JSX.Element | null;
|
|
214
|
+
|
|
215
|
+
type SuiteMenuIcon = ComponentType<{
|
|
216
|
+
className?: string;
|
|
217
|
+
'aria-hidden'?: boolean | 'true' | 'false';
|
|
218
|
+
}>;
|
|
219
|
+
/**
|
|
220
|
+
* Suite mobile app bar — the standardized top of every app on phone/tablet.
|
|
221
|
+
* Fixed slot order across the suite: [menu] [brand/context] … [actions].
|
|
222
|
+
* Translucent + blurred (suite-skin.css `.suite-app-bar`), safe-area aware,
|
|
223
|
+
* 44px minimum touch targets. Desktop chrome (rail/top bar) stays app-side.
|
|
224
|
+
*/
|
|
225
|
+
declare function SuiteMobileHeader({ onMenuClick, menuIcon: MenuIcon, title, actions, menuLabel, menuDataTest, dataTest, className, }: {
|
|
226
|
+
/** Optional — omit to drop the hamburger (bottom-nav apps don't need one). */
|
|
227
|
+
onMenuClick?: () => void;
|
|
228
|
+
/** Leading button glyph — defaults to Menu; browse-style drawers can swap it. */
|
|
229
|
+
menuIcon?: SuiteMenuIcon;
|
|
230
|
+
/** Brand/context slot — app mark + title or app switcher. */
|
|
231
|
+
title?: ReactNode;
|
|
232
|
+
/** Right-hand slot — search, bell, avatar (keep this order). */
|
|
233
|
+
actions?: ReactNode;
|
|
234
|
+
menuLabel?: string;
|
|
235
|
+
menuDataTest?: string;
|
|
236
|
+
dataTest?: string;
|
|
237
|
+
className?: string;
|
|
238
|
+
}): react.JSX.Element;
|
|
239
|
+
|
|
240
|
+
interface SuiteUserMenuProps {
|
|
241
|
+
name?: string | null;
|
|
242
|
+
email?: string | null;
|
|
243
|
+
image?: string | null;
|
|
244
|
+
/** Destination for the "Profile settings" item. */
|
|
245
|
+
settingsHref: string;
|
|
246
|
+
onSignOut: () => void;
|
|
247
|
+
/** Fallback letter(s) when there is no avatar image. */
|
|
248
|
+
fallbackInitials?: string;
|
|
249
|
+
dataTest?: string;
|
|
250
|
+
className?: string;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Suite account context menu — one tap on the avatar opens a small menu
|
|
254
|
+
* with profile settings and sign out. Used in the mobile app bar of every
|
|
255
|
+
* app so account actions behave identically across the suite (no dedicated
|
|
256
|
+
* logout icon cluttering the mobile chrome).
|
|
257
|
+
*/
|
|
258
|
+
declare function SuiteUserMenu({ name, email, image, settingsHref, onSignOut, fallbackInitials, dataTest, className, }: SuiteUserMenuProps): react.JSX.Element;
|
|
259
|
+
|
|
260
|
+
/** Any icon component that accepts sizing/stroke props (Lucide, theme icons). */
|
|
261
|
+
type SuiteNavIcon = ComponentType<{
|
|
262
|
+
className?: string;
|
|
263
|
+
strokeWidth?: number | string;
|
|
264
|
+
'aria-hidden'?: boolean | 'true' | 'false';
|
|
265
|
+
}>;
|
|
266
|
+
/**
|
|
267
|
+
* Suite bottom navigation — the mobile/tablet primary nav, identical in
|
|
268
|
+
* every app. Hick's Law: 5 items maximum (dev warning beyond that).
|
|
269
|
+
* Visuals come from suite-skin.css (`suite-bottom-nav`, `__pill`) so the
|
|
270
|
+
* translucent blur, safe-area padding, and press physics stay in sync
|
|
271
|
+
* across the suite; per-item content stays app-side via `items`.
|
|
272
|
+
*/
|
|
273
|
+
interface SuiteBottomNavItem {
|
|
274
|
+
href: string;
|
|
275
|
+
label: string;
|
|
276
|
+
icon: SuiteNavIcon;
|
|
277
|
+
active?: boolean;
|
|
278
|
+
dataTest?: string;
|
|
279
|
+
}
|
|
280
|
+
declare function SuiteBottomNav({ items, ariaLabel, dataTest, className, }: {
|
|
281
|
+
items: readonly SuiteBottomNavItem[];
|
|
282
|
+
ariaLabel?: string;
|
|
283
|
+
dataTest?: string;
|
|
284
|
+
className?: string;
|
|
285
|
+
}): react.JSX.Element;
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* The single source of truth for the ShellStack app family — used by the
|
|
289
|
+
* app switcher, mobile bottom nav, launchpad, and cross-app navigation.
|
|
290
|
+
* Slugs double as accent keys (see icons/app-accents.ts) and data-test
|
|
291
|
+
* suffixes (`switch-app-${slug}`, `suite-nav-${slug}`).
|
|
292
|
+
*/
|
|
293
|
+
type SuiteAppSlug = 'shellstack' | 'tides' | 'turtletime' | 'kraken';
|
|
294
|
+
interface SuiteAppDefinition {
|
|
295
|
+
slug: SuiteAppSlug;
|
|
296
|
+
name: string;
|
|
297
|
+
description: string;
|
|
298
|
+
/** Public asset path — every app hosts all four icons. */
|
|
299
|
+
icon: string;
|
|
300
|
+
/** Landing route used after cross-app SSO redirect. */
|
|
301
|
+
landing: string;
|
|
302
|
+
/** Env var carrying the app's base URL (dev fallback included). */
|
|
303
|
+
baseUrlEnv: string;
|
|
304
|
+
baseUrlFallback: string;
|
|
305
|
+
}
|
|
306
|
+
/** Display order — launchpad first, then by daily workflow. */
|
|
307
|
+
declare const SUITE_APPS: readonly SuiteAppDefinition[];
|
|
308
|
+
declare const SUITE_APP_MAP: Readonly<Record<SuiteAppSlug, SuiteAppDefinition>>;
|
|
309
|
+
/** Resolve an app's base URL: env var first, dev fallback second. */
|
|
310
|
+
declare function suiteAppBaseUrl(slug: SuiteAppSlug): string;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* 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)
|
|
317
|
+
*/
|
|
318
|
+
declare function TodayCalibrating({ onRetry, retrying, className, spinner: Spinner, variant, retrySpinnerClassName, }: {
|
|
319
|
+
onRetry?: () => void;
|
|
320
|
+
retrying?: boolean;
|
|
321
|
+
className?: string;
|
|
322
|
+
spinner: SuiteSpinnerComponent;
|
|
323
|
+
variant?: 'ring' | 'pulse';
|
|
324
|
+
retrySpinnerClassName?: string;
|
|
325
|
+
}): react.JSX.Element;
|
|
326
|
+
|
|
327
|
+
type SuiteTheme = 'system' | 'light' | 'dark';
|
|
328
|
+
type SuiteResolvedTheme = 'light' | 'dark';
|
|
329
|
+
interface SuiteThemeConfig {
|
|
330
|
+
/** localStorage key holding the stored preference. */
|
|
331
|
+
storageKey: string;
|
|
332
|
+
/** `data-theme` attribute value for the light theme. */
|
|
333
|
+
lightThemeId: string;
|
|
334
|
+
/** `data-theme` attribute value for the dark theme. */
|
|
335
|
+
darkThemeId: string;
|
|
336
|
+
/**
|
|
337
|
+
* Resolved theme to assume when `matchMedia` is unavailable
|
|
338
|
+
* (server render / pre-hydration).
|
|
339
|
+
*/
|
|
340
|
+
fallbackTheme: SuiteResolvedTheme;
|
|
341
|
+
/**
|
|
342
|
+
* Optional `<meta id="theme-color-meta">` colours, synced whenever the
|
|
343
|
+
* theme is (re)applied after mount. Omit both to leave the meta tag
|
|
344
|
+
* untouched.
|
|
345
|
+
*/
|
|
346
|
+
themeColorLight?: string;
|
|
347
|
+
themeColorDark?: string;
|
|
348
|
+
}
|
|
349
|
+
interface SuiteThemeContextValue {
|
|
350
|
+
theme: SuiteTheme;
|
|
351
|
+
resolvedTheme: SuiteResolvedTheme;
|
|
352
|
+
setTheme: (theme: SuiteTheme) => void;
|
|
353
|
+
toggleTheme: () => void;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Theme provider shared by suite apps. Each app's root layout runs a small
|
|
357
|
+
* boot script that applies `data-theme` before hydration; this provider
|
|
358
|
+
* adopts that DOM state on mount and owns every post-hydration change (user
|
|
359
|
+
* picks a theme, or the OS preference flips while set to `system`).
|
|
360
|
+
*
|
|
361
|
+
* Apps wrap this with their own `ThemeProvider`/`useTheme` module that pins
|
|
362
|
+
* the storage key, theme ids and meta colours.
|
|
363
|
+
*/
|
|
364
|
+
declare function SuiteThemeProvider({ config, children, }: {
|
|
365
|
+
config: SuiteThemeConfig;
|
|
366
|
+
children: ReactNode;
|
|
367
|
+
}): react.JSX.Element;
|
|
368
|
+
declare function useSuiteTheme(): SuiteThemeContextValue;
|
|
369
|
+
|
|
370
|
+
interface SuiteAiPreset {
|
|
371
|
+
label: string;
|
|
372
|
+
prompt: string;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Thin ShellStack AI slide-over shared by suite apps.
|
|
376
|
+
*
|
|
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.
|
|
381
|
+
*/
|
|
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<{
|
|
387
|
+
configured: boolean;
|
|
388
|
+
}>;
|
|
389
|
+
complete: (params: {
|
|
390
|
+
prompt: string;
|
|
391
|
+
}) => Promise<{
|
|
392
|
+
text: string;
|
|
393
|
+
}>;
|
|
394
|
+
brandIcon: ComponentType<{
|
|
395
|
+
className?: string;
|
|
396
|
+
}>;
|
|
397
|
+
spinner: ComponentType<{
|
|
398
|
+
className?: string;
|
|
399
|
+
}>;
|
|
400
|
+
}): react.JSX.Element;
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Suite icon glyph definitions — pure path data, no React.
|
|
404
|
+
*
|
|
405
|
+
* Shared geometric grammar (lucide-compatible):
|
|
406
|
+
* - 24×24 viewBox
|
|
407
|
+
* - 2px strokes, round caps/joins (set by the renderer)
|
|
408
|
+
* - `fill="none" stroke="currentColor"` unless `filled: true`
|
|
409
|
+
*
|
|
410
|
+
* Elements flagged `accent: true` are rendered inside a group coloured by
|
|
411
|
+
* `var(--suite-icon-accent, currentColor)` — `<SuiteIcon accent="…">` sets the
|
|
412
|
+
* variable from `app-accents.ts`; without an accent they inherit the text
|
|
413
|
+
* colour like any lucide icon.
|
|
414
|
+
*/
|
|
415
|
+
type SuiteGlyphElement = {
|
|
416
|
+
kind: 'path';
|
|
417
|
+
d: string;
|
|
418
|
+
accent?: boolean;
|
|
419
|
+
filled?: boolean;
|
|
420
|
+
} | {
|
|
421
|
+
kind: 'circle';
|
|
422
|
+
cx: number;
|
|
423
|
+
cy: number;
|
|
424
|
+
r: number;
|
|
425
|
+
accent?: boolean;
|
|
426
|
+
filled?: boolean;
|
|
427
|
+
} | {
|
|
428
|
+
kind: 'rect';
|
|
429
|
+
x: number;
|
|
430
|
+
y: number;
|
|
431
|
+
width: number;
|
|
432
|
+
height: number;
|
|
433
|
+
rx?: number;
|
|
434
|
+
accent?: boolean;
|
|
435
|
+
filled?: boolean;
|
|
436
|
+
};
|
|
437
|
+
interface SuiteGlyph {
|
|
438
|
+
/** One-line description of what the mark depicts (used in docs/sheets). */
|
|
439
|
+
description: string;
|
|
440
|
+
elements: SuiteGlyphElement[];
|
|
441
|
+
/**
|
|
442
|
+
* The accent group carries a subtle CSS animation (today-sun rays only).
|
|
443
|
+
* Renderers must honour prefers-reduced-motion; see suite-icon.tsx.
|
|
444
|
+
*/
|
|
445
|
+
animatedAccent?: boolean;
|
|
446
|
+
}
|
|
447
|
+
type SuiteIconName = 'timer-shell' | 'kanban-wave' | 'squid-doc' | 'stack-hex' | 'crew-bot' | 'workspace' | 'organisation' | 'integration-plug' | 'suite-grid' | 'bell-wave' | 'today-sun';
|
|
448
|
+
declare const SUITE_GLYPHS: Record<SuiteIconName, SuiteGlyph>;
|
|
449
|
+
declare const SUITE_ICON_NAMES: SuiteIconName[];
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Per-app brand colours for the suite icon system — the single place hexes
|
|
453
|
+
* live. `accent` tints a glyph's accent layer; `tile`/`onTile`/
|
|
454
|
+
* `onTileAccent` drive `<SuiteAppIcon>` (the programmatic favicon-style
|
|
455
|
+
* tile + glyph mark).
|
|
456
|
+
*/
|
|
457
|
+
type SuiteAccentSlug = 'turtletime' | 'tides' | 'kraken' | 'shellstack' | 'crew';
|
|
458
|
+
interface SuiteAppAccent {
|
|
459
|
+
/** Display name (default aria label for app marks). */
|
|
460
|
+
label: string;
|
|
461
|
+
/** Brand accent — tints glyph accent layers via `--suite-icon-accent`. */
|
|
462
|
+
accent: string;
|
|
463
|
+
/** App tile background. */
|
|
464
|
+
tile: string;
|
|
465
|
+
/** Base glyph colour on the tile. */
|
|
466
|
+
onTile: string;
|
|
467
|
+
/** Accent-layer glyph colour on the tile. */
|
|
468
|
+
onTileAccent: string;
|
|
469
|
+
}
|
|
470
|
+
declare const APP_ACCENTS: Record<SuiteAccentSlug, SuiteAppAccent>;
|
|
471
|
+
/** Which glyph represents each app. */
|
|
472
|
+
declare const APP_GLYPHS: Record<SuiteAccentSlug, SuiteIconName>;
|
|
473
|
+
|
|
474
|
+
interface SuiteIconProps {
|
|
475
|
+
name: SuiteIconName;
|
|
476
|
+
/** px size; a Tailwind sizing class on `className` also works. */
|
|
477
|
+
size?: number | string;
|
|
478
|
+
/** App slug — tints the glyph's accent layer with the app's brand hex. */
|
|
479
|
+
accent?: SuiteAccentSlug;
|
|
480
|
+
strokeWidth?: number;
|
|
481
|
+
/** Only today-sun animates; set false to freeze it. Reduced-motion safe. */
|
|
482
|
+
animated?: boolean;
|
|
483
|
+
/** Accessible label. Without it the icon is `aria-hidden` (decorative). */
|
|
484
|
+
label?: string;
|
|
485
|
+
className?: string;
|
|
486
|
+
style?: CSSProperties;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Suite icon — hand-drawn glyphs on the lucide grammar (24×24, 2px strokes,
|
|
490
|
+
* round caps/joins). Strokes inherit `currentColor`, so ph-* text tokens just
|
|
491
|
+
* work; `accent` adds a per-app brand tint to the glyph's accent layer.
|
|
492
|
+
*/
|
|
493
|
+
declare function SuiteIcon({ name, size, accent, strokeWidth, animated, label, className, style, }: SuiteIconProps): react.JSX.Element;
|
|
494
|
+
|
|
495
|
+
declare const SIZE_PRESETS: {
|
|
496
|
+
readonly sm: 28;
|
|
497
|
+
readonly md: 36;
|
|
498
|
+
readonly lg: 44;
|
|
499
|
+
};
|
|
500
|
+
interface SuiteAppIconProps {
|
|
501
|
+
app: SuiteAccentSlug;
|
|
502
|
+
/** px size, or a preset (sm 28 / md 36 / lg 44). */
|
|
503
|
+
size?: number | keyof typeof SIZE_PRESETS;
|
|
504
|
+
/** Accessible label; defaults to decorative (`aria-hidden`). */
|
|
505
|
+
label?: string;
|
|
506
|
+
className?: string;
|
|
507
|
+
style?: CSSProperties;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* An app's simplified mark — brand tile + its suite glyph, drawn
|
|
511
|
+
* programmatically at any size (no cross-app <img> favicon lookups).
|
|
512
|
+
* Colours come from app-accents.ts.
|
|
513
|
+
*/
|
|
514
|
+
declare function SuiteAppIcon({ app, size, label, className, style, }: SuiteAppIconProps): react.JSX.Element;
|
|
515
|
+
|
|
516
|
+
/** Mount non-critical chrome after the browser is idle (or a short timeout). */
|
|
517
|
+
declare function useIdleMount(timeoutMs?: number): boolean;
|
|
518
|
+
|
|
519
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Suite motion foundation.
|
|
523
|
+
*
|
|
524
|
+
* `LazyMotion` + `domAnimation` keeps the animation runtime (~15 kB) out of
|
|
525
|
+
* the initial bundle — features load with the first animated component.
|
|
526
|
+
* `strict` guarantees only the tree-shakeable `m` component is used inside
|
|
527
|
+
* the provider (never the heavier `motion` component).
|
|
528
|
+
*
|
|
529
|
+
* Usage:
|
|
530
|
+
* <SuiteMotionProvider>
|
|
531
|
+
* <m.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} />
|
|
532
|
+
* </SuiteMotionProvider>
|
|
533
|
+
*
|
|
534
|
+
* Prefer CSS transitions for micro-interactions (hover/press/colour) and
|
|
535
|
+
* reach for `m` only when you need springs, gestures, or layout animation.
|
|
536
|
+
*/
|
|
537
|
+
declare function SuiteMotionProvider({ children }: {
|
|
538
|
+
children: ReactNode;
|
|
539
|
+
}): react.JSX.Element;
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Spring presets — the JS counterparts of the `ease-spring-*` timing
|
|
543
|
+
* functions defined in each app's tailwind config. Use these for entrances,
|
|
544
|
+
* sheets, drawers, and press feedback so JS and CSS motion feel identical.
|
|
545
|
+
* All respect `prefers-reduced-motion` when paired with
|
|
546
|
+
* `MotionConfig reducedMotion="user"` or CSS `motion-reduce:` variants.
|
|
547
|
+
*/
|
|
548
|
+
declare const SUITE_SPRINGS: {
|
|
549
|
+
/** Snappy panel/sheet entrances — small overshoot. */
|
|
550
|
+
readonly fast: {
|
|
551
|
+
readonly type: "spring";
|
|
552
|
+
readonly stiffness: 400;
|
|
553
|
+
readonly damping: 32;
|
|
554
|
+
readonly mass: 0.8;
|
|
555
|
+
};
|
|
556
|
+
/** Gentle scrims, fades, list staggers. */
|
|
557
|
+
readonly subtle: {
|
|
558
|
+
readonly type: "spring";
|
|
559
|
+
readonly stiffness: 260;
|
|
560
|
+
readonly damping: 26;
|
|
561
|
+
readonly mass: 1;
|
|
562
|
+
};
|
|
563
|
+
/** Press/tap feedback — quick settle, no wobble. */
|
|
564
|
+
readonly press: {
|
|
565
|
+
readonly type: "spring";
|
|
566
|
+
readonly stiffness: 600;
|
|
567
|
+
readonly damping: 35;
|
|
568
|
+
readonly mass: 0.5;
|
|
569
|
+
};
|
|
570
|
+
};
|
|
571
|
+
type SuiteSpringName = keyof typeof SUITE_SPRINGS;
|
|
572
|
+
|
|
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;
|
|
580
|
+
interface SuiteBreadcrumbsProps {
|
|
581
|
+
items: {
|
|
582
|
+
label: ReactNode;
|
|
583
|
+
href?: string;
|
|
584
|
+
}[];
|
|
585
|
+
className?: string;
|
|
586
|
+
}
|
|
587
|
+
/** Minimal slash-separated breadcrumb line. */
|
|
588
|
+
declare function SuiteBreadcrumbs({ items, className }: SuiteBreadcrumbsProps): react.JSX.Element;
|
|
589
|
+
declare function SuitePage({ children, width, inset, className, as: Component, dataTest, id, role, 'aria-live': ariaLive, }: {
|
|
590
|
+
children: ReactNode;
|
|
591
|
+
width?: SuitePageWidth;
|
|
592
|
+
inset?: boolean;
|
|
593
|
+
className?: string;
|
|
594
|
+
as?: ElementType;
|
|
595
|
+
dataTest?: string;
|
|
596
|
+
id?: string;
|
|
597
|
+
role?: string;
|
|
598
|
+
'aria-live'?: React.AriaAttributes['aria-live'];
|
|
599
|
+
}): react.JSX.Element;
|
|
600
|
+
declare function SuitePageHeader({ title, description, eyebrow, actions, className, titleClassName, dataTest,
|
|
601
|
+
/** Optional icon rendered before the title. */
|
|
602
|
+
icon,
|
|
603
|
+
/** Use the animated sun/moon icon from the Today page. */
|
|
604
|
+
todayIcon, todayIconClassName,
|
|
605
|
+
/** Small badge/pill next to the title (e.g. "Beta", org name). */
|
|
606
|
+
badge,
|
|
607
|
+
/** Breadcrumb line rendered above the title. */
|
|
608
|
+
breadcrumb, }: {
|
|
609
|
+
title: ReactNode;
|
|
610
|
+
description?: ReactNode;
|
|
611
|
+
eyebrow?: ReactNode;
|
|
612
|
+
actions?: ReactNode;
|
|
613
|
+
className?: string;
|
|
614
|
+
titleClassName?: string;
|
|
615
|
+
dataTest?: string;
|
|
616
|
+
icon?: ReactNode;
|
|
617
|
+
todayIcon?: boolean;
|
|
618
|
+
todayIconClassName?: string;
|
|
619
|
+
badge?: ReactNode;
|
|
620
|
+
breadcrumb?: ReactNode;
|
|
621
|
+
}): react.JSX.Element;
|
|
622
|
+
declare function SuiteToolbar({ children, className, label, dataTest, }: {
|
|
623
|
+
children: ReactNode;
|
|
624
|
+
className?: string;
|
|
625
|
+
label?: string;
|
|
626
|
+
dataTest?: string;
|
|
627
|
+
}): react.JSX.Element;
|
|
628
|
+
declare function SuiteTabList({ children, className, label, dataTest, }: {
|
|
629
|
+
children: ReactNode;
|
|
630
|
+
className?: string;
|
|
631
|
+
label: string;
|
|
632
|
+
dataTest?: string;
|
|
633
|
+
}): react.JSX.Element;
|
|
634
|
+
declare function SuiteSectionHeader({ title, description, action, className, }: {
|
|
635
|
+
title: ReactNode;
|
|
636
|
+
description?: ReactNode;
|
|
637
|
+
action?: ReactNode;
|
|
638
|
+
className?: string;
|
|
639
|
+
}): react.JSX.Element;
|
|
640
|
+
|
|
641
|
+
interface SuiteSkeletonProps {
|
|
642
|
+
className?: string;
|
|
643
|
+
lines?: number;
|
|
644
|
+
circle?: boolean;
|
|
645
|
+
width?: string;
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Shared skeleton using the-old-ui-theme `ph-skeleton` shimmer class.
|
|
649
|
+
* The shimmer animation is defined in the theme, so this component is
|
|
650
|
+
* framework-agnostic and works in any app that imports the theme.
|
|
651
|
+
*/
|
|
652
|
+
declare function SuiteSkeleton({ className, lines, circle, width, }: SuiteSkeletonProps): react.JSX.Element;
|
|
653
|
+
declare function SuiteSkeletonCard({ className, rows, header, }: {
|
|
654
|
+
className?: string;
|
|
655
|
+
rows?: number;
|
|
656
|
+
header?: boolean;
|
|
657
|
+
}): react.JSX.Element;
|
|
658
|
+
declare function SuiteSkeletonList({ className, items, }: {
|
|
659
|
+
className?: string;
|
|
660
|
+
items?: number;
|
|
661
|
+
}): react.JSX.Element;
|
|
662
|
+
interface SuiteEmptyStateProps {
|
|
663
|
+
icon?: ReactNode;
|
|
664
|
+
title: string;
|
|
665
|
+
description?: ReactNode;
|
|
666
|
+
action?: ReactNode;
|
|
667
|
+
className?: string;
|
|
668
|
+
size?: 'sm' | 'md';
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Branded empty state with a soft gradient orb and clear action affordance.
|
|
672
|
+
* Uses the app icon when available so empty states feel native to each app.
|
|
673
|
+
*/
|
|
674
|
+
declare function SuiteEmptyState({ icon, title, description, action, className, size, }: SuiteEmptyStateProps): react.JSX.Element;
|
|
675
|
+
|
|
676
|
+
interface SuiteSettingsNavItem {
|
|
677
|
+
label: string;
|
|
678
|
+
href: string;
|
|
679
|
+
icon: ComponentType<{
|
|
680
|
+
className?: string;
|
|
681
|
+
'aria-hidden'?: boolean;
|
|
682
|
+
}> | ReactNode;
|
|
683
|
+
testId?: string;
|
|
684
|
+
}
|
|
685
|
+
interface SuiteSettingsMobileNavProps {
|
|
686
|
+
items: SuiteSettingsNavItem[];
|
|
687
|
+
activeHref: string;
|
|
688
|
+
onSelect: (href: string) => void;
|
|
689
|
+
dataTest?: string;
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Horizontal scrollable settings nav for mobile.
|
|
693
|
+
* Replaces a native <select> with icon+label pills that are easier to scan,
|
|
694
|
+
* meet 44px touch targets, and preserve visual hierarchy (Law of UX: Hick's Law,
|
|
695
|
+
* Recognition over Recall).
|
|
696
|
+
*/
|
|
697
|
+
declare function SuiteSettingsMobileNav({ items, activeHref, onSelect, dataTest, }: SuiteSettingsMobileNavProps): react.JSX.Element;
|
|
698
|
+
|
|
699
|
+
type CollapsedNode = ReactNode | ((collapsed: boolean) => ReactNode);
|
|
700
|
+
interface SuiteSidebarNavItem {
|
|
701
|
+
href: string;
|
|
702
|
+
label: string;
|
|
703
|
+
icon: SuiteNavIcon;
|
|
704
|
+
active?: boolean;
|
|
705
|
+
onClick?: () => void;
|
|
706
|
+
badge?: ReactNode;
|
|
707
|
+
/** Optional colour class for the nav icon. */
|
|
708
|
+
iconClassName?: string;
|
|
709
|
+
}
|
|
710
|
+
interface SuiteSidebarProps {
|
|
711
|
+
/** Optional custom app switcher node, or a function of collapsed state. */
|
|
712
|
+
appSwitcher?: CollapsedNode;
|
|
713
|
+
/** Workspace/org/project switcher rendered below the app switcher. */
|
|
714
|
+
contextSwitcher: CollapsedNode;
|
|
715
|
+
navItems: SuiteSidebarNavItem[];
|
|
716
|
+
/** Optional secondary nav / tree rendered below primary nav. */
|
|
717
|
+
secondaryNav?: ReactNode;
|
|
718
|
+
userMenu: CollapsedNode;
|
|
719
|
+
notificationBell?: CollapsedNode;
|
|
720
|
+
/** Optional extra footer content placed next to the user menu. */
|
|
721
|
+
footerExtras?: CollapsedNode;
|
|
722
|
+
collapsed?: boolean;
|
|
723
|
+
className?: string;
|
|
724
|
+
/** Use the richer surface background instead of canvas. */
|
|
725
|
+
surface?: boolean;
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Standardised ShellStack sidebar. Matches the original TurtleTime layout
|
|
729
|
+
* so the chrome feels familiar across all apps:
|
|
730
|
+
* - app switcher + notification bell in a compact header
|
|
731
|
+
* - workspace switcher at the top of the nav body
|
|
732
|
+
* - primary nav items styled like the original NavLink
|
|
733
|
+
* - avatar + optional logout in the footer
|
|
734
|
+
*/
|
|
735
|
+
declare function SuiteSidebar({ appSwitcher, contextSwitcher, navItems, secondaryNav, userMenu, notificationBell, footerExtras, collapsed, className, surface, }: SuiteSidebarProps): react.JSX.Element;
|
|
736
|
+
|
|
737
|
+
interface SuiteAppLayoutProps {
|
|
738
|
+
sidebar: ReactNode;
|
|
739
|
+
children: ReactNode;
|
|
740
|
+
mobileHeader?: ReactNode;
|
|
741
|
+
bottomNav?: ReactNode;
|
|
742
|
+
/** Desktop sidebar width in px. */
|
|
743
|
+
sidebarWidth?: number;
|
|
744
|
+
/** True when the sidebar is collapsed to the icon rail. */
|
|
745
|
+
collapsed?: boolean;
|
|
746
|
+
/** Drag this to resize the sidebar. */
|
|
747
|
+
onStartResize?: (e: PointerEvent<HTMLDivElement>) => void;
|
|
748
|
+
/** Double-click to reset sidebar width. */
|
|
749
|
+
onResetWidth?: () => void;
|
|
750
|
+
className?: string;
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
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.
|
|
757
|
+
*/
|
|
758
|
+
declare function SuiteAppLayout({ sidebar, children, mobileHeader, bottomNav, sidebarWidth, collapsed, onStartResize, onResetWidth, className, }: SuiteAppLayoutProps): react.JSX.Element;
|
|
759
|
+
|
|
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 };
|