@cboxdk/cbox-ui 0.9.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
- import { ReactNode, ComponentProps, ComponentType } from 'react';
3
+ import { ReactNode, ComponentType, AnchorHTMLAttributes, ComponentProps } from 'react';
4
4
  import { C as CboxThemeMode, a as CboxKnownApp } from './catalog-BroZWvws.js';
5
5
  export { b as CboxAppCatalogState, c as CboxCatalogApp, d as authorizeHref, p as parseAppCatalog, r as readKnownAppCatalog, e as rememberAppCatalog, s as secureIconUrl, f as signInTarget } from './catalog-BroZWvws.js';
6
6
  import { LucideIcon } from 'lucide-react';
@@ -208,176 +208,489 @@ declare function useCboxId(): CboxIdContextValue;
208
208
  */
209
209
  declare function useCboxIdOptional(): CboxIdContextValue | null;
210
210
 
211
- type Props$7 = ComponentProps<'main'> & {
211
+ type CboxTranslationValues = Record<string, string | number>;
212
+ type CboxTranslator = (message: string, values?: CboxTranslationValues) => string;
213
+ declare function interpolate(message: string, values?: CboxTranslationValues): string;
214
+ /** Optional and additive: without a provider existing consumers retain English. */
215
+ declare function CboxLocalizationProvider({ locale, translate, formatDate, children }: {
216
+ locale: string;
217
+ translate: CboxTranslator;
218
+ formatDate?: (value: string) => string;
212
219
  children: ReactNode;
220
+ }): react_jsx_runtime.JSX.Element;
221
+ declare function useCboxLocalization(): {
222
+ locale: string;
223
+ t: CboxTranslator;
224
+ formatDate: (value: string) => string;
213
225
  };
226
+
214
227
  /**
215
- * Scrolling main column inside an <AppShell>. Wears the soft blue-
216
- * tinted gradient canvas so every Cbox app sits on the same
217
- * background.
228
+ * Help's state lives outside React (§7.1): open or closed, what it shows, the search, the scroll
229
+ * position and the support updates survive an Inertia visit and even a remount of the shell,
230
+ * like a browser side panel. The conversation itself lives in the `<cbox-support>` element, which
231
+ * survives as long as the shell sits in the host's persistent layout.
218
232
  */
219
- declare function AppContent({ children, className, ...props }: Props$7): react_jsx_runtime.JSX.Element;
233
+ type HelpArticle = {
234
+ id: string;
235
+ title: string;
236
+ excerpt?: string;
237
+ body?: string;
238
+ url?: string;
239
+ source?: string;
240
+ };
241
+ type SupportUpdate = {
242
+ id: string;
243
+ kind: 'ticket' | 'chat';
244
+ title: string;
245
+ excerpt?: string;
246
+ at?: string;
247
+ unread: boolean;
248
+ url?: string;
249
+ };
250
+ type HelpStatus = 'idle' | 'loading' | 'ready' | 'unavailable';
251
+ type HelpState = {
252
+ open: boolean;
253
+ /** The article shown instead of the home view, or null. */
254
+ article: HelpArticle | null;
255
+ query: string;
256
+ scrollTop: number;
257
+ updates: SupportUpdate[];
258
+ updatesStatus: HelpStatus;
259
+ /** A question waiting for the chat to be ready ("Ask Cbox: …" from the palette). */
260
+ pendingQuestion: string | null;
261
+ /** Whether `open` was taken from the person's saved preference yet. */
262
+ seeded: boolean;
263
+ /**
264
+ * `open` came from the saved preference, not from the person on this page. Help left open
265
+ * shows docked from 1280px; below that it waits until the person opens it, so a phone or a
266
+ * narrow window never lands under the full-screen overlay.
267
+ */
268
+ restored: boolean;
269
+ /** Which list the support updates came from (URL and organization), so a switch reloads them. */
270
+ updatesKey: string | null;
271
+ };
272
+ type HelpStore = {
273
+ get(): HelpState;
274
+ set(patch: Partial<HelpState> | ((state: HelpState) => Partial<HelpState>)): void;
275
+ subscribe(listener: () => void): () => void;
276
+ };
277
+ declare function createHelpStore(initial?: Partial<HelpState>): HelpStore;
278
+
279
+ type ShellIcon = ComponentType<{
280
+ size?: number;
281
+ strokeWidth?: number;
282
+ className?: string;
283
+ 'aria-hidden'?: boolean;
284
+ }>;
285
+ /** Lucide names an app can use for areas, pages and actions without shipping its own map. */
286
+ declare const SHELL_ICONS: Readonly<Record<string, ShellIcon>>;
220
287
 
221
288
  /**
222
- * Top-level chrome. Hosts the desktop sidebar (left) and the
223
- * scrollable content column (right) side-by-side. Fits the full
224
- * viewport height; only the content column scrolls.
289
+ * The `shell` Inertia prop: the one data contract every Cbox app shares (spec §11.1).
225
290
  *
226
- * Pair with <AppContent> inside. Per-app sidebars compose alongside
227
- * — cbox-ui doesn't ship one because the nav items are app-specific.
291
+ * The server (laravel-console-kit) produces it; `<CboxShell>` renders it. It carries only the
292
+ * current selection and URLs. Lists, the app catalog, help and search load in the browser after
293
+ * the page has painted, so building this prop never calls another service (local first, §11.2a).
228
294
  */
229
- declare function AppShell({ children }: {
230
- children: ReactNode;
231
- }): react_jsx_runtime.JSX.Element;
232
-
233
- type CboxNavItem = {
295
+ /** The product key (URL standard §1). Unknown keys are allowed so a new app needs no release here. */
296
+ type AppKey = 'id' | 'billing' | 'telemetry' | 'work' | 'brain' | 'infra' | 'engage' | 'assistant' | 'sites' | 'stache' | 'status' | 'tax' | 'signals' | 'domains' | (string & {});
297
+ /**
298
+ * A labelled link. `href` is the same URL under the name laravel-console-kit 0.2 sends; the
299
+ * shell reads `url` first, then `href`.
300
+ */
301
+ type Link = {
234
302
  label: string;
303
+ url: string;
304
+ href?: string;
305
+ };
306
+ /**
307
+ * One page inside an area. `icon` is a Lucide icon name (`"git-branch"`), resolved by the shell.
308
+ * `href` is the same URL under the name laravel-console-kit 0.2 sends; the shell reads `url`
309
+ * first, then `href`.
310
+ */
311
+ type NavPage = {
312
+ key: string;
313
+ label: string;
314
+ url: string;
315
+ href?: string;
316
+ icon?: string;
235
317
  /**
236
- * Absolute path the host's router can navigate to. Apps that
237
- * scope nav by org slug should compose the path themselves
238
- * (`/org/${slug}/endpoints`) before passing it in — cbox-ui
239
- * stays unaware of routing conventions.
318
+ * The page is not part of the organization's plan: it shows with a lock and an accessible
319
+ * "(locked)", and `url` leads to the upgrade prompt.
240
320
  */
241
- href: string;
242
- icon: ComponentType<{
243
- className?: string;
244
- strokeWidth?: number;
245
- }>;
246
- /** Highlight the row for child routes too (`/endpoints/123`
247
- * matches the `Endpoints` row when this is true). */
248
- matchPrefix?: boolean;
321
+ locked?: boolean;
322
+ /** A badge, such as open drafts. Not shown when 0 or absent. */
323
+ count?: number;
324
+ /**
325
+ * A heading inside the area's subnav (Settings → "Organization", "Project"). Pages of one
326
+ * group show together under it, in the order each group first appears.
327
+ */
328
+ group?: string;
249
329
  };
250
- type CboxNavSection = {
330
+ /** One area in the rail. The subnav shows its pages when it has more than one. */
331
+ type NavArea = {
332
+ key: string;
251
333
  label: string;
252
- items: CboxNavItem[];
334
+ url: string;
335
+ href?: string;
336
+ icon?: string;
337
+ pages?: NavPage[];
253
338
  };
339
+ type ContextTone = 'production' | 'sandbox' | 'neutral';
254
340
  /**
255
- * Generic Link contract — apps inject their own (Inertia's `Link`,
256
- * Wouter, React Router, plain `<a>`). cbox-ui doesn't depend on
257
- * any router so the same chrome works everywhere.
341
+ * One selectable item of a level: the current one in the prop, and every row a level's
342
+ * `listUrl` returns. Environments are app-defined (§5.1a): `tone`, `label` and `testData` are
343
+ * all optional and the shell never sorts the items.
258
344
  */
259
- type LinkComponent = ComponentType<{
260
- href: string;
261
- prefetch?: boolean;
262
- children: ReactNode;
263
- className?: string;
264
- title?: string;
265
- 'aria-label'?: string;
266
- /** Set on the link of the page the person is on. */
267
- 'aria-current'?: 'page';
268
- }>;
269
- type CboxAppSidebarProps = {
270
- /** App key for the brand submark (and aria labels). */
271
- appKey: string;
272
- /** Optional override for the submark — defaults to `appKey`. */
273
- brandSubmark?: string | null;
274
- /** Where brand assets live. Default `/brand`. */
275
- assetBase?: string;
276
- /** Where the brand row links to (typically the app's home). */
277
- brandHref?: string;
278
- /** Nav sections — top to bottom. */
279
- sections: CboxNavSection[];
280
- /** Active path — used to highlight the current row. */
281
- currentPath: string;
282
- /** Apps inject their router's Link primitive. */
283
- LinkComponent: LinkComponent;
284
- /** Persisted "is the desktop sidebar collapsed?" state. */
285
- collapsed?: boolean;
286
- className?: string;
345
+ type ContextItem = {
346
+ id: string;
347
+ name: string;
348
+ /** Chip text. Defaults to the first letters of the name. */
349
+ initials?: string;
350
+ /** The coloured square: production green, sandbox amber, neutral grey. */
351
+ tone?: ContextTone;
352
+ /** Short app-defined label beside the name ("default", "test data"). */
353
+ label?: string;
354
+ /** The sandbox strip shows while the current item has test data. */
355
+ testData?: boolean;
287
356
  };
288
- /**
289
- * Standard Cbox sidebar. Every app wears this — the only variable
290
- * bits are `sections` (per-app nav) and `appKey` (drives the brand
291
- * submark).
292
- *
293
- * Hidden below `lg` — apps render a separate mobile drawer that
294
- * shares the same `sections` config.
295
- *
296
- * No app should ship its own sidebar component. The chrome is the
297
- * shape; nav items are the data.
298
- */
299
- declare function CboxAppSidebar({ appKey, brandSubmark, assetBase, brandHref, sections, currentPath, LinkComponent, collapsed, className, }: CboxAppSidebarProps): react_jsx_runtime.JSX.Element;
300
-
301
- type CboxAppShellProps = {
302
- /** App key — drives the brand submark + aria labels. */
303
- appKey: string;
304
- /** Override the submark text (defaults to appKey). */
305
- brandSubmark?: string | null;
306
- /** Asset base for brand pngs. Default `/brand`. */
307
- assetBase?: string;
308
- /** Brand row href (typically the app's home). */
309
- brandHref?: string;
310
- /** Sidebar nav config. */
311
- sections: CboxNavSection[];
312
- /** Active path — used by both sidebar (highlight) and topbar
313
- * (sidebar-collapse toggle aria state). */
314
- currentPath: string;
315
- /** Apps inject their router's Link primitive. */
316
- LinkComponent: LinkComponent;
317
- /** Persisted "sidebar collapsed?" state — owned by the host
318
- * (the cookie hook lives there). */
319
- sidebarCollapsed?: boolean;
320
- /** Click handler for the topbar collapse toggle. Hide the
321
- * toggle entirely by omitting this prop. */
322
- onToggleSidebar?: () => void;
357
+ type ContextLevel = {
358
+ /** `organization`, `project`, `environment`, or the app's own key (`site`, `space`). */
359
+ key: 'organization' | 'project' | 'environment' | (string & {});
360
+ /** Singular, as the app names it: "Organization", "Site", "Space", "Environment". */
361
+ label: string;
362
+ /** Plural for headings ("Organizations"). Defaults to `label` + "s". */
363
+ labelPlural?: string;
364
+ current: ContextItem;
323
365
  /**
324
- * Topbar centre slot — typically the org switcher / context
325
- * bar. Apps that aren't org-scoped (notifications, account
326
- * pages) leave this off.
366
+ * Lazy JSON list, fetched when a menu opens: `GET listUrl?q=&parent=&cursor=&limit=` answering
367
+ * `{ data: ContextItem[], has_more: boolean, next_cursor: string | null }`.
327
368
  */
328
- topbarCentre?: ReactNode;
369
+ listUrl: string;
370
+ /** `POST createUrl { name, parent? }` answering `{ id, detailsUrl }`. Absent: no "New …". */
371
+ createUrl?: string;
372
+ /** "View all". */
373
+ allUrl: string;
329
374
  /**
330
- * Handler to open the in-app command palette / search UI.
331
- * Always rendered — when omitted the trigger is a no-op so the
332
- * chrome stays visually identical across all apps regardless of
333
- * whether a palette has been wired up yet.
375
+ * Settings page of one item, as a URL template on the wire: `{id}` is replaced with the
376
+ * item's id (`/orgs/{id}/settings`). Absent: no gear.
334
377
  */
335
- onSearchOpen?: () => void;
378
+ settingsUrl?: string;
379
+ };
380
+ type PaletteAction = {
381
+ id: string;
382
+ label: string;
383
+ url: string;
384
+ /** `post` for actions that change something. Default `get`. */
385
+ method?: 'get' | 'post';
386
+ icon?: string;
387
+ /** Extra words the palette matches on. */
388
+ keywords?: string[];
389
+ };
390
+ type ShellHelp = {
391
+ /** False: Help still renders, and says it is not available here. */
392
+ enabled: boolean;
393
+ /** The page's help topic key (§7.2.3). */
394
+ topic?: string;
395
+ /** Same-origin route the Assistant SDK's `<cbox-support>` element fetches its session from. */
396
+ sessionUrl?: string;
397
+ /** Where the SDK script is served. Default `/ai-assistant/support.js` (laravel-assistant-client). */
398
+ scriptUrl?: string;
399
+ /** The support portal. Absent or offline: the link is hidden. */
400
+ portalUrl?: string;
401
+ /** `GET` support updates; `POST {updatesUrl}/{id}/read` marks one read. */
402
+ updatesUrl?: string;
403
+ /** `GET ?q=&topic=` docs, help centre and knowledge base search. */
404
+ searchUrl?: string;
405
+ /** Articles for a topic, as a template: `{topic}` is replaced. */
406
+ articlesUrl?: string;
407
+ };
408
+ type ShellNotifications = {
409
+ enabled: false;
410
+ } | {
411
+ enabled: true;
412
+ unread: number;
413
+ url: string;
414
+ };
415
+ type ShellBanner = {
416
+ kind: 'sandbox' | 'impersonation' | 'notice';
417
+ text: string;
418
+ action?: Link;
419
+ };
420
+ type ShellTheme = 'system' | 'light' | 'dark';
421
+ type ShellPreferences = {
422
+ theme: ShellTheme;
423
+ locale: string;
424
+ railPinned: boolean;
425
+ helpOpen: boolean;
426
+ /** The subnav collapsed to its strip (⌘.). */
427
+ subnavCollapsed?: boolean;
428
+ /** Regional format (a BCP 47 locale for dates and numbers), from Cbox ID's preferences. */
429
+ regionalFormat?: string;
430
+ /** IANA time zone, from Cbox ID's preferences. */
431
+ timeZone?: string;
432
+ };
433
+ type ShellOption = {
434
+ code: string;
435
+ label: string;
436
+ };
437
+ /**
438
+ * What the account menu (§10) links to. A row whose URL is absent is not shown (laravel-console-kit
439
+ * leaves out what the app has no route for).
440
+ */
441
+ type ShellAccount = {
442
+ /** Profile and security, in Cbox ID. */
443
+ profileUrl?: string;
444
+ switchAccountUrl?: string;
445
+ signOutUrl?: string;
446
+ /** Default `post`. */
447
+ signOutMethod?: 'get' | 'post';
448
+ /** Languages the app is translated into. */
449
+ languages?: ShellOption[];
450
+ /** Regional formats offered. Defaults to a short list. */
451
+ formats?: ShellOption[];
452
+ /** Line under the name in the account menu. Default "Signed in with Cbox ID". */
453
+ signedInWith?: string;
454
+ };
455
+ type Shell = {
456
+ app: {
457
+ key: AppKey;
458
+ name: string;
459
+ homeUrl: string;
460
+ };
461
+ person: {
462
+ id: string;
463
+ name: string;
464
+ initials: string;
465
+ avatarUrl?: string;
466
+ email?: string;
467
+ };
468
+ /** The page title and route, for "On this page" and the chat's page intent. */
469
+ page?: {
470
+ title: string;
471
+ route?: string;
472
+ };
473
+ nav: {
474
+ areas: NavArea[];
475
+ activeArea: string;
476
+ activePage?: string;
477
+ };
478
+ context: {
479
+ /** 1–3, in order. The first is the organization. */
480
+ levels: ContextLevel[];
481
+ /** `POST` target; the server resolves same-page or list fallback (§5.6). */
482
+ switchUrl: string;
483
+ };
484
+ palette: {
485
+ /** `GET ?q=` → `{ data: [{ id, title, subtitle?, url }] }`, in the current context. */
486
+ searchUrl?: string;
487
+ /** `GET ?q=` → level 2/3 combinations across organizations (§6.1.4). */
488
+ gotoUrl?: string;
489
+ actions: PaletteAction[];
490
+ /** The palette search field's placeholder, e.g. "Search customers, invoices… or pages". Default "Search or ask…". */
491
+ placeholder?: string;
492
+ };
493
+ help: ShellHelp;
494
+ notifications: ShellNotifications;
495
+ apps: {
496
+ /** The host's catalog endpoint (laravel-id-client `CboxId::appCatalogRoutes()`). */
497
+ catalogUrl: string;
498
+ /** "All products ↗". Default https://cbox.dk. */
499
+ productsUrl?: string;
500
+ };
501
+ /** The account menu's links. Absent (laravel-console-kit 0.2.2): the menu has only the preferences. */
502
+ account?: ShellAccount;
503
+ banner?: ShellBanner;
504
+ preferences: ShellPreferences;
505
+ };
506
+ /** How the shell moves the person. An Inertia host passes `router.visit`. */
507
+ type ShellNavigate = (url: string, options?: {
508
+ method?: 'get' | 'post';
509
+ data?: Record<string, unknown>;
510
+ newTab?: boolean;
511
+ }) => void;
512
+ /** Where the shell reports a preference the person changed, for the host to persist. */
513
+ type ShellPreferenceChange = <K extends keyof ShellPreferences>(key: K, value: ShellPreferences[K]) => void;
514
+
515
+ /** A client-side link (Inertia's `Link`). Receives `href`, `className`, `children` and ARIA props. */
516
+ type ShellLinkComponent = ComponentType<AnchorHTMLAttributes<HTMLAnchorElement> & {
517
+ href: string;
518
+ children?: ReactNode;
519
+ }>;
520
+ /** Which overlay is open. Only one at a time, so two menus never stack. */
521
+ type ShellOverlay = 'org' | 'context' | 'apps' | 'account' | 'palette' | 'nav-sheet' | 'context-sheet' | null;
522
+ type ShellApi = {
523
+ shell: Shell;
524
+ t: CboxTranslator;
525
+ navigate: ShellNavigate;
526
+ Link: ShellLinkComponent;
527
+ icons: Readonly<Record<string, ShellIcon>>;
528
+ preferences: ShellPreferences;
529
+ setPreference: ShellPreferenceChange;
530
+ overlay: ShellOverlay;
531
+ setOverlay: (overlay: ShellOverlay) => void;
532
+ help: HelpStore;
533
+ /** Open or close Help. */
534
+ toggleHelp: (open?: boolean) => void;
535
+ /** Open Help on an article. */
536
+ openArticle: (article: HelpArticle) => void;
537
+ /** Open Help and send a question to the chat with the page as context. */
538
+ ask: (question: string) => void;
539
+ /** Switch context: `chosen` maps level keys to ids. */
540
+ switchTo: (chosen: Record<string, string>) => void;
541
+ };
542
+ /** Help for a page's own `?` button, or `null` outside the shell. */
543
+ declare function useShellHelp(): Pick<ShellApi, 'toggleHelp' | 'openArticle' | 'ask'> | null;
544
+
545
+ type CboxShellProps = {
546
+ /** The shared `shell` prop. */
547
+ shell: Shell;
548
+ /** The page. */
549
+ children: ReactNode;
550
+ /** How to move the person. Inertia: `(url, o) => router.visit(url, { method: o?.method, data: o?.data })`, plus `window.open` for `newTab`. Default: page loads and form posts. */
551
+ navigate?: ShellNavigate;
552
+ /** Client-side link for nav and settings links (Inertia's `Link`). Default `<a>`. */
553
+ LinkComponent?: ShellLinkComponent;
554
+ /** Extra icons by name, on top of the built-in Lucide set. */
555
+ icons?: Readonly<Record<string, ShellIcon>>;
336
556
  /**
337
- * Override the right cluster on the topbar. Default:
338
- * `[<SearchTrigger>?] <AppLauncher /> <NotificationsBell /> <UserMenu />`.
339
- * Override only when an app needs a completely different mix.
557
+ * Called when the person changes a preference, for the host to persist (a cookie read before
558
+ * first paint, and Cbox ID's preferences for theme, language, format and time zone). Without
559
+ * it the shell writes a `cbox_shell_<key>` cookie.
340
560
  */
341
- topbarRightCluster?: ReactNode;
342
- children: ReactNode;
561
+ onPreferenceChange?: ShellPreferenceChange;
562
+ /** Help's state store. Default: one per page, so it outlives the shell's own remounts. */
563
+ helpStore?: HelpStore;
564
+ /** Where the Cbox wordmark is served. Default `/brand`. */
565
+ brandAssetBase?: string;
566
+ /** `id` of the `<main>` landmark, which the shell's "Skip to content" link targets. Default `main-content`. */
567
+ mainId?: string;
343
568
  };
344
569
  /**
345
- * Top-level Cbox application shell. Composes sidebar + topbar +
346
- * content into the single chrome shape every Cbox app wears.
570
+ * Apply a theme choice to the document the way the tokens read it: `.dark` and `data-theme` on
571
+ * the root, with `system` following the device. The saved choice stays `system`; the device's
572
+ * scheme is never written back (cbox-design, shared preferences).
573
+ */
574
+ declare function applyTheme(theme: ShellTheme): void;
575
+ /**
576
+ * The inline script a host puts in `<head>` so the theme is right before the first paint
577
+ * (§12.1). `theme` is the person's saved choice from the `shell` prop.
578
+ */
579
+ declare function themeBootScript(theme: ShellTheme): string;
580
+ /**
581
+ * The one shell for every Cbox app (spec 2026-11-10 shell v1): rail with the account at the
582
+ * bottom, subnav, header with the context selectors, Search, Help, the bell when the app has a
583
+ * source, Switch app; the ⌘K palette; the Help column; and the phone layout.
347
584
  *
348
- * Apps reduce to ~30 lines of layout: define nav, render
349
- * `<CboxAppShell>{children}</CboxAppShell>`. No app should
350
- * compose `<AppShell>`/`<AppContent>`/sidebar/topbar manually —
351
- * drift is the whole reason this component exists.
585
+ * Render it in the host's persistent layout (Inertia `Page.layout`), so the rail, Help and the
586
+ * chat survive page visits; only `shell` and `children` change.
352
587
  */
353
- declare function CboxAppShell({ appKey, brandSubmark, assetBase, brandHref, sections, currentPath, LinkComponent, sidebarCollapsed, onToggleSidebar, topbarCentre, onSearchOpen, topbarRightCluster, children, }: CboxAppShellProps): react_jsx_runtime.JSX.Element;
588
+ declare function CboxShell({ shell, children, navigate, LinkComponent, icons, onPreferenceChange, helpStore, brandAssetBase, mainId }: CboxShellProps): react_jsx_runtime.JSX.Element;
354
589
 
355
- type CboxMobileNavDrawerProps = {
356
- open: boolean;
357
- onClose: () => void;
358
- appKey: string;
359
- brandSubmark?: string | null;
360
- assetBase?: string;
361
- brandHref?: string;
362
- sections: CboxNavSection[];
363
- currentPath: string;
364
- LinkComponent: LinkComponent;
590
+ /** The page intent the chat is given (§7.2.4): route, title and context. */
591
+ type PageIntent = {
592
+ route?: string;
593
+ title?: string;
594
+ context: string;
595
+ url?: string;
596
+ };
597
+ declare function contextTrail(shell: Shell): string;
598
+ declare function pageIntent(shell: Shell): PageIntent;
599
+
600
+ /** One app in the grid (§9). */
601
+ type ShellApp = {
602
+ key: string;
603
+ name: string;
604
+ /** One line: "Identity and sign-in". */
605
+ purpose: string | null;
606
+ /** Fixed per-app hue (0–360); the tile is drawn in it, in light and dark. */
607
+ hue: number;
608
+ iconUrl: string | null;
609
+ iconDarkUrl: string | null;
610
+ /** Where the tile goes: the app, or its admission page when the organization lacks it. */
611
+ url: string;
612
+ /** The organization has this app. False: "More from Cbox", dimmed. */
613
+ inOrganization: boolean;
614
+ };
615
+ /** Each app's fixed hue when the catalog sends none. */
616
+ declare const APP_HUES: Readonly<Record<string, number>>;
617
+ /** A stable hue for an unknown key, so its tile keeps its colour between pages. */
618
+ declare function hueFor(key: string, given?: unknown): number;
619
+ type ShellCatalogState = {
620
+ status: 'loading';
621
+ } | {
622
+ status: 'ready';
623
+ apps: ShellApp[];
624
+ } | {
625
+ status: 'signin_required';
626
+ href: string | null;
627
+ } | {
628
+ status: 'unavailable';
365
629
  };
366
630
  /**
367
- * Mobile-only slide-in sidebar. Hidden on `lg` and up — there the
368
- * desktop `CboxAppSidebar` is always visible. Shares the same
369
- * `sections` shape as the desktop sidebar so apps don't have to
370
- * maintain two nav configs.
371
- *
372
- * State (open/close) lives in `CboxAppShell` so it can wire the
373
- * hamburger button + auto-close on `currentPath` change. The drawer
374
- * itself just renders; it doesn't track anything.
631
+ * The catalog answer, with the shell's additions (§9.3): `in_organization` (default true),
632
+ * `admission_url` for apps the organization does not have, `purpose` (falls back to
633
+ * `description`) and `hue`. Only http(s) links are kept.
634
+ */
635
+ declare function parseShellCatalog(ok: boolean, body: unknown, here?: {
636
+ origin: string;
637
+ pathname: string;
638
+ search: string;
639
+ }): ShellCatalogState;
640
+
641
+ /**
642
+ * The shell's few network shapes and the pure rules around them: list pages, inline create,
643
+ * the switch payload and settings links. Everything here is same-origin and JSON.
644
+ */
645
+ type ListPage = {
646
+ items: ContextItem[];
647
+ hasMore: boolean;
648
+ nextCursor: string | null;
649
+ };
650
+ /** First letters of the first two words, for a chip. */
651
+ declare function initialsOf(name: string): string;
652
+ /**
653
+ * A list answer. The URL standard's envelope (`{ object: 'list', data, has_more, next_cursor }`)
654
+ * and a bare array are both accepted; rows without an id and a name are dropped.
655
+ */
656
+ declare function parseListPage(body: unknown): ListPage;
657
+ /** `url` with query parameters added; empty values are left out. Works for relative URLs. */
658
+ declare function withQuery(url: string, params: Record<string, string | undefined | null>): string;
659
+ /** The settings link of one item, from the level's URL template. Null when the level has none. */
660
+ declare function settingsHref(level: Pick<ContextLevel, 'settingsUrl'>, id: string): string | null;
661
+ /**
662
+ * Which environment a project click lands on (§5.4): the one with the current environment's
663
+ * name when the project has it, else its first. Undefined when the project has none.
664
+ */
665
+ declare function environmentFor(environments: readonly ContextItem[], currentName: string | undefined): ContextItem | undefined;
666
+ /**
667
+ * The switch payload (§5.6): every level above the chosen one keeps its current id, the chosen
668
+ * levels get theirs, and levels below are left to the server (it lands on the last used one).
669
+ * `return_to` is where the person is, so the server can stay on the same page.
670
+ */
671
+ declare function switchPayload(levels: readonly ContextLevel[], chosen: Record<string, string>, returnTo: string): Record<string, string>;
672
+
673
+ type Props$2 = ComponentProps<'main'> & {
674
+ children: ReactNode;
675
+ };
676
+ /**
677
+ * Scrolling main column inside an <AppShell>. Wears the soft blue-
678
+ * tinted gradient canvas so every Cbox app sits on the same
679
+ * background.
680
+ */
681
+ declare function AppContent({ children, className, ...props }: Props$2): react_jsx_runtime.JSX.Element;
682
+
683
+ /**
684
+ * Top-level chrome. Hosts the desktop sidebar (left) and the
685
+ * scrollable content column (right) side-by-side. Fits the full
686
+ * viewport height; only the content column scrolls.
375
687
  *
376
- * Closes on: Escape, scrim click, navigation (parent unsets `open`
377
- * when `currentPath` changes). Locks body scroll while open so the
378
- * page underneath doesn't scroll on touch.
688
+ * Pair with <AppContent> inside. Per-app sidebars compose alongside
689
+ * — cbox-ui doesn't ship one because the nav items are app-specific.
379
690
  */
380
- declare function CboxMobileNavDrawer({ open, onClose, appKey, brandSubmark, assetBase, brandHref, sections, currentPath, LinkComponent, }: CboxMobileNavDrawerProps): react_jsx_runtime.JSX.Element;
691
+ declare function AppShell({ children }: {
692
+ children: ReactNode;
693
+ }): react_jsx_runtime.JSX.Element;
381
694
 
382
695
  type CboxBrandProps = {
383
696
  /**
@@ -416,96 +729,6 @@ type CboxBrandProps = {
416
729
  */
417
730
  declare function CboxBrand({ appKey, submark, assetBase, tone, collapsed, className, }: CboxBrandProps): react_jsx_runtime.JSX.Element;
418
731
 
419
- type CboxOrgContextBarProps = {
420
- /**
421
- * Apps inject their router's Link primitive — used for the
422
- * crumb's brand-side anchor. The dropdown's onSelect calls
423
- * `onNavigate(href)` so apps can either `router.visit(href)`
424
- * (Inertia) or `<Link>`-style navigate.
425
- */
426
- LinkComponent: LinkComponent;
427
- /**
428
- * Called when the user picks a different org from the dropdown.
429
- * Receives an absolute path with the slug substituted in. Apps
430
- * trigger their router.
431
- *
432
- * Path-rewrite rule (Cbox suite convention):
433
- * /org/<old-slug>/foo/bar → /org/<new-slug>/foo/bar
434
- * /something-else → /org/<new-slug>
435
- *
436
- * Apps that aren't org-scoped (notifications) typically don't
437
- * render this component at all — but if they do, switching
438
- * lands on the new org's `/org/<slug>` root and lets the host
439
- * sort the rest out.
440
- */
441
- onNavigate: (href: string) => void;
442
- };
443
- /**
444
- * Standard Cbox topbar org switcher. One crumb, one dropdown,
445
- * URL-driven (no POST, no session pin). Mirrors id's pattern 1:1
446
- * so the chrome reads identically across the suite — that's the
447
- * whole reason it's here, not in each app.
448
- *
449
- * Apps render this in the `topbarCentre` slot of `CboxAppShell`.
450
- * Hides itself when there's no current org (eg pre-auth, or
451
- * non-org-scoped surfaces).
452
- */
453
- declare function CboxOrgContextBar({ LinkComponent, onNavigate, }: CboxOrgContextBarProps): react_jsx_runtime.JSX.Element | null;
454
-
455
- type Props$6 = {
456
- /**
457
- * App branding rendered on the left — typically a small logo +
458
- * the app name. Rendered inside a fixed-height bar so keep it
459
- * visually compact (24-32px tall content).
460
- */
461
- brand: ReactNode;
462
- /** Anything between brand and the right cluster — search, breadcrumbs, etc. */
463
- centre?: ReactNode;
464
- /**
465
- * Override slots if an app needs a different control mix in the
466
- * right cluster. Default: AppLauncher → NotificationsBell → UserMenu.
467
- */
468
- rightCluster?: ReactNode;
469
- /**
470
- * Whether to show the org switcher next to the brand. Hide on
471
- * non-org-scoped surfaces (eg id account-settings).
472
- */
473
- showOrgSwitcher?: boolean;
474
- className?: string;
475
- };
476
- /**
477
- * Standard Cbox top bar. Same shell across every app — keeps cross-app
478
- * navigation (launcher, account, notifications) muscle-memory-stable.
479
- */
480
- declare function TopBar({ brand, centre, rightCluster, showOrgSwitcher, className, }: Props$6): react_jsx_runtime.JSX.Element;
481
-
482
- type AppLauncherProps = {
483
- className?: string;
484
- /**
485
- * Called when the user clicks an app they're not entitled to. Use
486
- * this to open an upgrade flow / Stripe checkout / Intercom message.
487
- * If unset, locked tiles fall through to a static "Add to plan"
488
- * affordance — the click is a no-op so we never silently ship the
489
- * user to a broken paywall.
490
- */
491
- onLockedAppClick?: (app: CboxAppLink) => void;
492
- };
493
- /**
494
- * Cross-app launcher — the 9-dot button in the top bar.
495
- *
496
- * Renders the Cbox suite as a vertical list with status per app:
497
- * - entitled apps → full-colour tile, click navigates with ?org=<slug>
498
- * - locked apps → greyed out + lock badge, opens upgrade flow if the
499
- * host app provides one (otherwise inert click)
500
- * - coming-soon → greyed out + "soon" badge, never clickable
501
- * - the current app → highlighted ring on its monogram tile
502
- *
503
- * Row layout (vs. the old 3-col grid) gives us room for descriptions
504
- * and status badges, which makes the entitlement signal readable at a
505
- * glance instead of needing a tooltip.
506
- */
507
- declare function AppLauncher({ className, onLockedAppClick }: AppLauncherProps): react_jsx_runtime.JSX.Element | null;
508
-
509
732
  type CboxAppCatalogProps = {
510
733
  /**
511
734
  * Same-origin URL the host serves the person's app catalog from (a proxy of Cbox ID's
@@ -568,126 +791,6 @@ type CboxServiceMarkProps = {
568
791
  /** An app's own mark (its rail or brand icon), read from the catalog this browser last kept. */
569
792
  declare function CboxServiceMark({ appKey, className, fallback }: CboxServiceMarkProps): react_jsx_runtime.JSX.Element;
570
793
 
571
- type AppSwitcherProps = {
572
- className?: string;
573
- /**
574
- * Called when the user clicks an app they're not entitled to. Use
575
- * this to open an upgrade flow / Stripe checkout / Intercom message.
576
- * If unset, locked rows fall through to a static "Add to plan"
577
- * affordance — the click is a no-op so we never silently ship the
578
- * user to a broken paywall.
579
- */
580
- onLockedAppClick?: (app: CboxAppLink) => void;
581
- };
582
- /**
583
- * Left-cluster app picker — the dropdown button that sits beside OrgSwitcher.
584
- *
585
- * Shows the current app's monogram + name as the trigger so both context
586
- * dimensions (which app, which org) are immediately visible in the left
587
- * cluster without needing to open anything.
588
- *
589
- * The dropdown preserves the full AppLauncher row richness: monogram tile
590
- * with per-app accent, name, description, and entitlement badges. Entitled
591
- * apps are grouped first; locked / coming-soon land in an "Available" section.
592
- *
593
- * Includes typeahead — auto-focus on open, filters name/description/key as
594
- * the user types, arrow-key navigation, Enter to activate, Escape to close.
595
- *
596
- * Soft-reads via useCboxIdOptional — renders null when no provider is
597
- * mounted above (admin shells, pre-auth pages).
598
- */
599
- declare function AppSwitcher({ className, onLockedAppClick }: AppSwitcherProps): react_jsx_runtime.JSX.Element | null;
600
-
601
- /**
602
- * Bell with unread-count badge + popover preview. Click opens a
603
- * dropdown with the last 5 items inline (no navigation), each with
604
- * an inline mark-read action and an optional deep-link to the page
605
- * that originated the notification. "See all" at the bottom links
606
- * to the central notifications service inbox — the only navigation
607
- * away from the host app.
608
- *
609
- * Pattern matches Linear / GitHub / Stripe: glance + mark-read
610
- * without leaving context; cross-app jump only when the user
611
- * explicitly wants the full list.
612
- *
613
- * Renders nothing if the context is missing or notifications
614
- * aren't configured (eg pre-auth pages).
615
- */
616
- declare function NotificationsBell({ className }: {
617
- className?: string;
618
- }): react_jsx_runtime.JSX.Element | null;
619
-
620
- type Props$5 = {
621
- /**
622
- * Optional renderer override for the trigger so apps can match
623
- * their topbar style (filled button vs ghost vs icon-only).
624
- */
625
- Trigger?: ComponentType<{
626
- organization: CboxOrganization | null;
627
- onClick: () => void;
628
- open: boolean;
629
- }>;
630
- className?: string;
631
- };
632
- /**
633
- * Dropdown that surfaces the user's orgs and dispatches the picked
634
- * one through `onSwitchOrganization`. Reads everything else from
635
- * CboxIdProvider so the same component works in id, cortex, atlas —
636
- * no per-app data wiring.
637
- *
638
- * Includes typeahead — auto-focus on open, filters by name as the
639
- * user types, arrow-key navigation, Enter to switch, Escape to close.
640
- */
641
- declare function OrgSwitcher({ Trigger, className }: Props$5): react_jsx_runtime.JSX.Element;
642
-
643
- type Props$4 = {
644
- /** Click handler — typically dispatches the app's command-palette
645
- * open shortcut. Apps that don't have a palette yet pass a no-op
646
- * so the chrome stays visually consistent across the suite. */
647
- onOpen?: () => void;
648
- className?: string;
649
- label?: string;
650
- };
651
- /**
652
- * Topbar Search trigger — a visual-only command-palette button.
653
- *
654
- * Hosted in cbox-ui because every Cbox app's chrome must show the
655
- * same search affordance in the same spot, with the same width and
656
- * the same shortcut hint. Drift across apps means users see layout
657
- * shifts when tabbing between id / webhooks / cortex; that's a UX
658
- * tax we don't want to charge them.
659
- *
660
- * The actual palette stays per-app (commands differ); this primitive
661
- * just renders the trigger and dispatches `onOpen`.
662
- */
663
- declare function SearchTrigger({ onOpen, className, label }: Props$4): react_jsx_runtime.JSX.Element;
664
-
665
- type Props$3 = {
666
- /**
667
- * App-specific menu items rendered above the standard
668
- * "Manage account" / "Sign out" set. Use sparingly — the goal
669
- * is consistency across apps.
670
- */
671
- extras?: ReactNode;
672
- placement?: 'bottom-end' | 'top-start';
673
- className?: string;
674
- /**
675
- * The router's link for the account and organization rows, when they are pages of this
676
- * app (an Inertia `Link` keeps the visit client-side). Default: a plain anchor, which is
677
- * right when the rows deep-link into Cbox ID on another origin.
678
- */
679
- LinkComponent?: LinkComponent;
680
- };
681
- /**
682
- * User-menu dropdown. Always exposes:
683
- * - Manage account ↗ (deep-link into id)
684
- * - Team & billing ↗ (deep-link into id, current org scope)
685
- * - Sign out
686
- *
687
- * The arrows signal cross-app navigation — id is canonical.
688
- */
689
- declare function UserMenu({ extras, className, placement, LinkComponent: Link }: Props$3): react_jsx_runtime.JSX.Element;
690
-
691
794
  /**
692
795
  * Combobox — the canonical select replacement for the Cbox suite.
693
796
  *
@@ -758,7 +861,7 @@ type ComboboxAvatar = {
758
861
  accent?: string;
759
862
  src?: string;
760
863
  };
761
- type LinkComp$1 = ComponentType<{
864
+ type LinkComp = ComponentType<{
762
865
  href: string;
763
866
  prefetch?: boolean;
764
867
  className?: string;
@@ -794,7 +897,7 @@ type CommonProps = {
794
897
  * Framework Link adapter for navigation-mode items + footer link.
795
898
  * If unset, navigation falls back to plain `<a>`.
796
899
  */
797
- LinkComponent?: LinkComp$1;
900
+ LinkComponent?: LinkComp;
798
901
  /** ID for the trigger button (associate with a <Label htmlFor>). */
799
902
  id?: string;
800
903
  /** className for the outer wrapper. */
@@ -818,111 +921,6 @@ type NavModeProps = CommonProps & {
818
921
  type ComboboxProps = ValueModeProps | NavModeProps;
819
922
  declare function Combobox(props: ComboboxProps): react_jsx_runtime.JSX.Element;
820
923
 
821
- /**
822
- * ContextBar — the topbar breadcrumb-style context selector. One
823
- * crumb per level of context (org / project / environment / branch /
824
- * deployment). Each crumb renders as a chip (avatar + label +
825
- * chevron) and opens a dropdown with the items at that level plus
826
- * an optional "+ New X" footer.
827
- *
828
- * The pattern is the cloud-platform default — Vercel, Render, Forge,
829
- * GitHub, Stripe, Cortex all use it. Topbar carries identity and
830
- * context; sidebar carries navigation. The two never overlap.
831
- *
832
- * URL-driven by default — clicking a dropdown item navigates via the
833
- * supplied `LinkComponent`. Apps that need a non-navigational select
834
- * (post a form, mutate session state) pass `onSelect` instead.
835
- *
836
- * Separator between crumbs is a muted slash — same as Forge / Cortex.
837
- */
838
- type ContextAvatar = {
839
- /** 1–2 character monogram. Defaults to first letter of the label. */
840
- initials?: string;
841
- /**
842
- * Hex / CSS colour applied as the avatar's bg. Falls back to the
843
- * neutral chip when missing. Per-item override of the default.
844
- */
845
- accent?: string;
846
- /** Optional avatar image URL — overrides initials when set. */
847
- src?: string;
848
- };
849
- type ContextItem = {
850
- /** Stable identity for the item (slug, id). */
851
- id: string;
852
- /** Primary display label. */
853
- label: string;
854
- /** Optional secondary line — slug, role, env name. Mono-tracked. */
855
- secondary?: string;
856
- /** Avatar specification. Same shape as the crumb's own avatar. */
857
- avatar?: ContextAvatar;
858
- /** Navigation target — clicking the item navigates here. */
859
- href?: string;
860
- /** Mark the item as the active selection (gets a check on the right). */
861
- current?: boolean;
862
- /**
863
- * Optional href to a settings page for this item. When set, a
864
- * cogwheel button appears on the right of the row on hover/focus
865
- * — clicking it navigates straight to settings without going
866
- * through the item's normal selection. Cortex-style shortcut.
867
- */
868
- settingsHref?: string;
869
- /**
870
- * Aria-label for the optional settings cogwheel. Defaults to
871
- * `Settings for <label>`. Override when the label alone isn't
872
- * enough context (eg multiple items with the same name).
873
- */
874
- settingsAriaLabel?: string;
875
- };
876
- type ContextCrumb = {
877
- /** Stable identity for the crumb (used as React key). */
878
- id: string;
879
- /** The chip's visible label — typically the active item's name. */
880
- label: string;
881
- /** The chip's avatar — typically the active item's avatar. */
882
- avatar?: ContextAvatar;
883
- /** Items shown in the dropdown. Empty array = chip with no menu. */
884
- items: ContextItem[];
885
- /**
886
- * Optional footer link below the items — typically "+ New X" or
887
- * "Manage Y". Renders with a + icon and an accent text colour.
888
- */
889
- footerLink?: {
890
- label: string;
891
- href: string;
892
- };
893
- /**
894
- * Override per-item navigation. When set, item clicks call this
895
- * with the item's id instead of navigating to `item.href`. Useful
896
- * for posting a form (eg an org switcher that POSTs to a server-side
897
- * endpoint).
898
- */
899
- onSelect?: (itemId: string) => void;
900
- /** Optional aria-label for the chip's button (defaults to "Switch <label>"). */
901
- ariaLabel?: string;
902
- };
903
- type LinkComp = ComponentType<{
904
- href: string;
905
- prefetch?: boolean;
906
- className?: string;
907
- children: ReactNode;
908
- }>;
909
- type Props$2 = {
910
- crumbs: ContextCrumb[];
911
- /**
912
- * The framework's link component. Inertia consumers pass the
913
- * Inertia Link; TanStack Router consumers pass their typed Link.
914
- * Plain `<a>` is the fallback.
915
- */
916
- LinkComponent?: LinkComp;
917
- className?: string;
918
- };
919
- declare function ContextBar({ crumbs, LinkComponent, className, }: Props$2): react_jsx_runtime.JSX.Element | null;
920
- declare function ContextAvatarChip({ avatar, fallbackLabel, size, }: {
921
- avatar: ContextAvatar;
922
- fallbackLabel: string;
923
- size?: 'sm' | 'md';
924
- }): react_jsx_runtime.JSX.Element;
925
-
926
924
  /**
927
925
  * Generic panel container — soft border, card surface, subtle shadow.
928
926
  * The default building block for every section on a page.
@@ -990,6 +988,13 @@ type Props$1 = {
990
988
  eyebrow?: ReactNode;
991
989
  description?: ReactNode;
992
990
  actions?: ReactNode;
991
+ /**
992
+ * Show the `?` beside the title that toggles the shell's Help column (spec §7.1). The page's
993
+ * help topic travels in `shell.help.topic`, set on the server per route (console-kit's
994
+ * `helpTopic`), so Help knows the topic on the first paint and for pages without a header.
995
+ * Ignored outside `CboxShell`.
996
+ */
997
+ help?: boolean;
993
998
  className?: string;
994
999
  };
995
1000
  /**
@@ -998,7 +1003,7 @@ type Props$1 = {
998
1003
  * Cortex-style — no italics, no brackets — so it carries across many
999
1004
  * sibling apps cleanly.
1000
1005
  */
1001
- declare function PageHeader({ title, eyebrow, description, actions, className, }: Props$1): react_jsx_runtime.JSX.Element;
1006
+ declare function PageHeader({ title, eyebrow, description, actions, help, className, }: Props$1): react_jsx_runtime.JSX.Element;
1002
1007
 
1003
1008
  /**
1004
1009
  * Width policy for `<PageShell>` — the single horizontal-rhythm
@@ -1224,25 +1229,17 @@ declare function StatusPill({ children, tone, className, dot, }: StatusPillProps
1224
1229
  * land.
1225
1230
  *
1226
1231
  * The criterion for accepting a new surface: "would it be useful
1227
- * in *every* Cbox app?" Inbox yes. Search yes. Help yes. "Webhook
1232
+ * in *every* Cbox app?" Inbox yes. "Webhook
1228
1233
  * delivery details" no — that's a route inside webhooks, not a
1229
1234
  * cross-app overlay.
1230
1235
  */
1231
1236
 
1232
- type SurfaceId = 'inbox' | 'search' | 'activity' | 'help';
1237
+ /** Search and Help are the shell's palette and Help column now; `inbox` stays for apps that use it. */
1238
+ type SurfaceId = 'inbox';
1233
1239
  type SurfaceArgs = {
1234
1240
  inbox: {
1235
1241
  focusUnread?: boolean;
1236
1242
  };
1237
- search: {
1238
- initialQuery?: string;
1239
- };
1240
- activity: {
1241
- scope?: 'user' | 'org';
1242
- };
1243
- help: {
1244
- topic?: string;
1245
- };
1246
1243
  };
1247
1244
  /**
1248
1245
  * Auth + transport plumbing the host injects. cbox-ui's surface
@@ -1258,7 +1255,6 @@ type Transport = {
1258
1255
  */
1259
1256
  urls: Partial<{
1260
1257
  notifications: string;
1261
- search: string;
1262
1258
  audit: string;
1263
1259
  realtime: string;
1264
1260
  }>;
@@ -1279,10 +1275,6 @@ type Transport = {
1279
1275
  csrfToken?: () => string;
1280
1276
  };
1281
1277
  type SurfaceConfig = Partial<{
1282
- search: {
1283
- placeholder?: string;
1284
- scopes?: string[];
1285
- };
1286
1278
  inbox: {};
1287
1279
  }>;
1288
1280
  /**
@@ -1338,7 +1330,7 @@ type CboxSurfacesProps = {
1338
1330
 
1339
1331
  /**
1340
1332
  * Mount the cbox-ui surface runtime once per app, alongside the
1341
- * page tree. The host's chrome (bell, search trigger) reads
1333
+ * page tree. The host's chrome (the bell) reads
1342
1334
  * `useCboxSurfaces()` to open surfaces; cbox-ui renders the
1343
1335
  * active one as a modal/drawer over the page.
1344
1336
  *
@@ -1355,7 +1347,7 @@ declare function CboxSurfaces({ transport, surfaces, config, children, }: CboxSu
1355
1347
  declare function useCboxSurfaces(): SurfaceController;
1356
1348
  /**
1357
1349
  * Optional variant — returns `null` when no `<CboxSurfaces>` host is
1358
- * mounted. Chrome controls (bell, search trigger) use this to
1350
+ * mounted. Chrome controls (the bell) use this to
1359
1351
  * degrade gracefully to cross-app navigation when the host hasn't
1360
1352
  * opted into the surface runtime yet.
1361
1353
  */
@@ -1461,67 +1453,6 @@ declare function parseUrlSearch<S extends UrlSchema>(search: string, schema: S):
1461
1453
  */
1462
1454
  declare function buildUrlSearch<S extends UrlSchema>(state: InferUrlState<S>, schema: S): string;
1463
1455
 
1464
- type CboxTranslationValues = Record<string, string | number>;
1465
- type CboxTranslator = (message: string, values?: CboxTranslationValues) => string;
1466
- declare function interpolate(message: string, values?: CboxTranslationValues): string;
1467
- /** Optional and additive: without a provider existing consumers retain English. */
1468
- declare function CboxLocalizationProvider({ locale, translate, formatDate, children }: {
1469
- locale: string;
1470
- translate: CboxTranslator;
1471
- formatDate?: (value: string) => string;
1472
- children: ReactNode;
1473
- }): react_jsx_runtime.JSX.Element;
1474
- declare function useCboxLocalization(): {
1475
- locale: string;
1476
- t: CboxTranslator;
1477
- formatDate: (value: string) => string;
1478
- };
1479
-
1480
- type CboxNavArea = CboxNavItem & {
1481
- items?: CboxNavItem[];
1482
- };
1483
- type CboxWorkspaceShellProps = {
1484
- appKey: string;
1485
- brandSubmark: string;
1486
- areas: CboxNavArea[];
1487
- currentPath: string;
1488
- LinkComponent: LinkComponent;
1489
- context: ReactNode;
1490
- tools: ReactNode;
1491
- account: ReactNode;
1492
- children: ReactNode;
1493
- /** Where the brand row links. Default `/`. */
1494
- brandHref?: string;
1495
- /** `id` of the `<main>` landmark, so a host's skip link can target it. Default `main-content`. */
1496
- mainId?: string;
1497
- /**
1498
- * Rail pinned open. Pass `pinned` + `onPinnedChange` to control it (the host persists the
1499
- * preference, in a cookie or Cbox ID), or `defaultPinned` to seed the shell's own state.
1500
- */
1501
- pinned?: boolean;
1502
- defaultPinned?: boolean;
1503
- onPinnedChange?: (pinned: boolean) => void;
1504
- /** Contextual subnav collapsed to its strip. Controlled and uncontrolled as `pinned`. */
1505
- collapsed?: boolean;
1506
- defaultCollapsed?: boolean;
1507
- onCollapsedChange?: (collapsed: boolean) => void;
1508
- };
1509
- /**
1510
- * How well `href` matches `path`: the href's length when the path is the href or beneath it,
1511
- * -1 otherwise. `/` matches only itself, so a home item never claims every page.
1512
- */
1513
- declare function navMatchLength(path: string, href: string): number;
1514
- /** The item whose href is the most specific match for `path`, or undefined. */
1515
- declare function activeNavItem<T extends CboxNavItem>(path: string, items: readonly T[]): T | undefined;
1516
- /**
1517
- * The area `path` is in: the one holding the most specific match among its own href and its
1518
- * items' hrefs. A first-match would put every page beneath an area at `/` (an overview, a
1519
- * dashboard) under that area and never show another area's subnav.
1520
- */
1521
- declare function activeNavArea<T extends CboxNavArea>(path: string, areas: readonly T[]): T | undefined;
1522
- /** Two-tier workspace navigation. Route ownership and preference persistence stay with the host. */
1523
- declare function CboxWorkspaceShell({ appKey, brandSubmark, areas, currentPath, LinkComponent: Link, context, tools, account, children, brandHref, mainId, pinned: pinnedProp, defaultPinned, onPinnedChange, collapsed: collapsedProp, defaultCollapsed, onCollapsedChange }: CboxWorkspaceShellProps): react_jsx_runtime.JSX.Element;
1524
-
1525
1456
  /** The chart tokens in order, for series that set their own colour. */
1526
1457
  declare const CHART_PALETTE: string[];
1527
1458
  /** A row's shape over the window, small: a line with a faint area, zero at the bottom. Decorative. */
@@ -1532,4 +1463,4 @@ declare function Sparkline({ values, color, width, height }: {
1532
1463
  height?: number;
1533
1464
  }): react_jsx_runtime.JSX.Element | null;
1534
1465
 
1535
- export { AppContent, AppLauncher, AppShell, AppSwitcher, CHART_PALETTE, CboxAppCatalog, type CboxAppCatalogProps, CboxAppIcon, type CboxAppIconProps, type CboxAppKey, type CboxAppLink, CboxAppShell, type CboxAppShellProps, CboxAppSidebar, type CboxAppSidebarProps, CboxBrand, type CboxBrandProps, type CboxIdContextValue, CboxIdProvider, CboxKnownApp, CboxLocalizationProvider, CboxMobileNavDrawer, type CboxMobileNavDrawerProps, type CboxNavArea, type CboxNavItem, type CboxNavSection, type CboxNotificationPreviewItem, type CboxNotificationsState, CboxOrgContextBar, type CboxOrgContextBarProps, type CboxOrganization, CboxServiceMark, type CboxServiceMarkProps, CboxSurfaces, type CboxSurfacesProps, type CboxTranslationValues, type CboxTranslator, type CboxUser, CboxWorkspaceShell, type CboxWorkspaceShellProps, Combobox, type ComboboxAvatar, type ComboboxGroup, type ComboboxOption, type ComboboxProps, type ContextAvatar, ContextAvatarChip, ContextBar, type ContextCrumb, type ContextItem, DataPanel, EmptyState, Heading, type InboxState, type InferUrlState, KeyValue, KeyValueList, type LinkComponent, NotificationsBell, OrgSwitcher, PageHeader, PageShell, type PageTabSpec, PageTabs, type PageTabsProps, type PageWidth, PanelBody, type RealtimeState, type RealtimeStatus, RowLink, type RowLinkProps, SearchTrigger, SectionHeader, Sparkline, StatTile, StatusPill, type SurfaceArgs, type SurfaceConfig, type SurfaceController, type SurfaceId, TopBar, type Transport, type UrlField, type UrlSchema, UserMenu, activeNavArea, activeNavItem, buildUrlSearch, cn, defineUrlSchema, interpolate, navMatchLength, parseUrlSearch, urlBoolean, urlEnum, urlNumber, urlString, urlStringArray, useCboxId, useCboxIdOptional, useCboxLocalization, useCboxSurfaces, useCboxSurfacesOptional, useKnownAppCatalog };
1466
+ export { APP_HUES, AppContent, type AppKey, AppShell, CHART_PALETTE, CboxAppCatalog, type CboxAppCatalogProps, CboxAppIcon, type CboxAppIconProps, type CboxAppKey, type CboxAppLink, CboxBrand, type CboxBrandProps, type CboxIdContextValue, CboxIdProvider, CboxKnownApp, CboxLocalizationProvider, type CboxNotificationPreviewItem, type CboxNotificationsState, type CboxOrganization, CboxServiceMark, type CboxServiceMarkProps, CboxShell, type CboxShellProps, CboxSurfaces, type CboxSurfacesProps, type CboxTranslationValues, type CboxTranslator, type CboxUser, Combobox, type ComboboxAvatar, type ComboboxGroup, type ComboboxOption, type ComboboxProps, type ContextItem, type ContextLevel, type ContextTone, DataPanel, EmptyState, Heading, type HelpArticle, type HelpState, type HelpStore, type InboxState, type InferUrlState, KeyValue, KeyValueList, type ListPage, type NavArea, type NavPage, PageHeader, type PageIntent, PageShell, type PageTabSpec, PageTabs, type PageTabsProps, type PageWidth, type PaletteAction, PanelBody, type RealtimeState, type RealtimeStatus, RowLink, type RowLinkProps, SHELL_ICONS, SectionHeader, type Shell, type ShellAccount, type Link as ShellActionLink, type ShellApp, type ShellBanner, type ShellCatalogState, type ShellHelp, type ShellIcon, type ShellLinkComponent, type ShellNavigate, type ShellNotifications, type ShellOption, type ShellPreferenceChange, type ShellPreferences, type ShellTheme, Sparkline, StatTile, StatusPill, type SupportUpdate, type SurfaceArgs, type SurfaceConfig, type SurfaceController, type SurfaceId, type Transport, type UrlField, type UrlSchema, applyTheme, buildUrlSearch, cn, contextTrail, createHelpStore, defineUrlSchema, environmentFor, hueFor, initialsOf, interpolate, pageIntent, parseListPage, parseShellCatalog, parseUrlSearch, settingsHref, switchPayload, themeBootScript, urlBoolean, urlEnum, urlNumber, urlString, urlStringArray, useCboxId, useCboxIdOptional, useCboxLocalization, useCboxSurfaces, useCboxSurfacesOptional, useKnownAppCatalog, useShellHelp, withQuery };