@the-portland-company/shell 0.76.14 → 0.76.18

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/native.d.ts CHANGED
@@ -1,929 +1,4 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode, ComponentType, CSSProperties } from 'react';
3
- import { ThemePreference as ThemePreference$1 } from './theme-preference.js';
4
-
5
- type FormColumnProps = {
6
- children: ReactNode;
7
- className?: string;
8
- };
9
- /**
10
- * The ONE constrained layout inside the frame's fluid `<main>` (Brand guideline
11
- * "Content width is fluid"): a single left-aligned column, 960px max, for form
12
- * and settings pages — single-record edit forms, Organization Settings tabs,
13
- * My Profile, activation and setup flows. Data surfaces (tables, dashboards,
14
- * maps) never use it; they take the full fluid width.
15
- *
16
- * It adds no gutter of its own — `<main>` already owns the 24px / 16px gutter —
17
- * and it is never centered. There is no width prop on purpose: a per-page
18
- * max-width is exactly what the guideline forbids.
19
- */
20
- declare function FormColumn({ children, className }: FormColumnProps): react_jsx_runtime.JSX.Element;
21
-
22
- /**
23
- * The six canonical top-bar action slots (Reference/Global-Rules v9 → top-bar
24
- * icons). Each slot's GLYPH is unique and comes from the Brand API
25
- * `topbarIcons.items.*` tokens, exposed as `--topbar-icon-<slot>` CSS vars
26
- * whose value is the brand-icon NAME. Every OTHER property — size, gap, color,
27
- * hover, selected — is universal across all six slots.
28
- */
29
- type TopBarIconSlot = 'comms-fuel' | 'apps' | 'notifications' | 'alerts' | 'support' | 'dark-mode';
30
-
31
- type NavIconLike = ComponentType<{
32
- size?: number;
33
- className?: string;
34
- }>;
35
- declare const CORE_APP_ORIGIN = "https://app.politogyvrm.com";
36
- /** Text/Email fuel top-up page (SMS Signal + Email Broadcast). */
37
- declare const CORE_BILLING_PATH = "/organization-settings/subscription-billing/text-email";
38
- /** Specs origin — same env-aware-constant pattern as CORE_APP_ORIGIN. */
39
- declare const SPECS_ORIGIN = "https://specs.politogyvrm.com";
40
- /**
41
- * Resolve an organization logo URL for rendering in ANY app.
42
- *
43
- * `organizations.logo_url` is authored by VRM core and stored as a ROOT-RELATIVE
44
- * core route — `/api/storage/public?bucket=organization-logos&path=<org>/logo.png`
45
- * (the signed-storage proxy). VRM core renders it correctly because that path
46
- * resolves against its own origin; every other app resolves it against its own
47
- * origin (forms.politogyvrm.com/api/storage/public), gets a 404, and shows a
48
- * broken image. The chrome API passes the stored value through verbatim, so the
49
- * resolution belongs here — one definition for every app, core included.
50
- *
51
- * Absolute URLs (http/https/data/blob) pass through untouched.
52
- */
53
- declare function resolveOrgLogoUrl(url: string | null | undefined): string | undefined;
54
- declare function topBarIconButtonClass(tone?: 'default' | 'warning' | 'danger'): string;
55
- declare function TopBarCountBadge({ count }: {
56
- count: number;
57
- }): react_jsx_runtime.JSX.Element | null;
58
- /**
59
- * The shared hover tooltip every top-bar control renders BELOW itself: an
60
- * up-pointing arrow at the icon, a bold title line and a muted description.
61
- * Pure CSS (group-hover) so it works on <a>, <button> and <summary> triggers.
62
- * The trigger must carry `group/tbtip relative` (topBarIconButtonClass does).
63
- */
64
- declare function TopBarTooltip({ title, description, }: {
65
- title: string;
66
- description?: ReactNode;
67
- }): react_jsx_runtime.JSX.Element;
68
- /**
69
- * The up-pointing arrow every top-bar panel renders, anchored under its
70
- * trigger icon (panels are right-aligned, so the arrow sits at the trigger's
71
- * center: 16px in from the panel's right edge). One definition — every menu
72
- * points at its own icon identically.
73
- */
74
- declare function TopBarPanelArrow(): react_jsx_runtime.JSX.Element;
75
- /**
76
- * Wrapper for third-party top-bar widgets that ship their own launcher button
77
- * (e.g. DevNotes). Normalizes the trigger to the universal 32px circular slot
78
- * (chrome.css `.topbar-widget-slot`) and adds the standard tooltip.
79
- */
80
- declare function TopBarWidgetSlot({ title, description, children, }: {
81
- title: string;
82
- description?: string;
83
- children: ReactNode;
84
- }): react_jsx_runtime.JSX.Element;
85
- type ThemePreference = ThemePreference$1;
86
- declare function NavThemeControl({ value, onChange, }: {
87
- value: ThemePreference;
88
- onChange: (next: ThemePreference) => void;
89
- }): react_jsx_runtime.JSX.Element;
90
- type NavChromeFetcher = (path: string, init?: {
91
- method?: string;
92
- headers?: Record<string, string>;
93
- body?: string;
94
- }) => Promise<unknown>;
95
- /** GET me — the authenticated user's chrome identity from the shared API.
96
- * userName prefers the VRM-core profile full name over token claims. */
97
- type ChromeMe = {
98
- user: string | null;
99
- userName: string | null;
100
- avatarUrl: string | null;
101
- themePreference: string | null;
102
- /** Universal navigation-display choice ('menu'|'tabs'|'both'); null when
103
- * unset or when the profile column is absent in this environment. */
104
- navDisplay: string | null;
105
- /** The user's durable active-org preference (full org uuid); null when unset
106
- * or when the profile column is absent. Adopted only when the request
107
- * carries no `?org=`/cookie selector — URL → cookie → profile → default. */
108
- activeOrg?: string | null;
109
- account?: string | null;
110
- accountName?: string | null;
111
- role?: string | null;
112
- /** Contact reply-to, when the profile carries them (optional/tolerant). */
113
- email?: string | null;
114
- phone?: string | null;
115
- };
116
- /**
117
- * A shared read cache scoped to one `<NavChromeProvider>` (one fetcher, one
118
- * page boot). Every consumer of a given (path, orgId) pair within the TTL
119
- * window awaits the SAME promise instead of firing its own request — this is
120
- * what collapsed `/orgs` (2-4x), `/me` (2-3x) and `/notifications` (2-3x) per
121
- * page load, 1-3.5s each, down to one call apiece (nav-latency-report.md
122
- * Table 2). Keying by orgId means switching the active org is itself the
123
- * invalidation: the new org gets a fresh key, never the previous org's cached
124
- * value. A failed request is evicted immediately so the next consumer retries
125
- * rather than replaying the same rejection for the rest of the TTL.
126
- */
127
- declare function createChromeFetchCache(getFetchJson: () => NavChromeFetcher): {
128
- dedupedFetch: (path: string, init: Parameters<NavChromeFetcher>[1] | undefined, opts?: {
129
- orgId?: string | null;
130
- ttlMs?: number;
131
- }) => Promise<unknown>;
132
- invalidate: (path: string) => void;
133
- };
134
- type NavChromeContextValue = {
135
- fetchJson: NavChromeFetcher;
136
- dedupedFetch: ReturnType<typeof createChromeFetchCache>['dedupedFetch'];
137
- invalidateChromeCache: ReturnType<typeof createChromeFetchCache>['invalidate'];
138
- me: ChromeMe | null;
139
- meLoaded: boolean;
140
- };
141
- declare function NavChromeProvider({ fetchJson, children, }: {
142
- fetchJson: NavChromeFetcher;
143
- children: ReactNode;
144
- }): react_jsx_runtime.JSX.Element;
145
- /** The authenticated user's chrome identity (profile name / avatar / theme). */
146
- declare function useChromeMe(): {
147
- me: ChromeMe | null;
148
- loaded: boolean;
149
- };
150
- /** The provider's de-duped chrome read (null outside <NavChromeProvider>). */
151
- declare function useNavChromeDedupedFetch(): NavChromeContextValue['dedupedFetch'] | null;
152
- /** The injected chrome fetcher (null outside <NavChromeProvider>). */
153
- declare function useNavChromeFetcher(): NavChromeFetcher | null;
154
- type FuelChannelStatus = {
155
- remainingUnits: number;
156
- rawBalanceUnits: number;
157
- usedUnits: number;
158
- lowFuel: boolean;
159
- lowFuelThreshold: number;
160
- };
161
- type CommunicationsFuelStatus = {
162
- organizationId: string;
163
- signal: FuelChannelStatus;
164
- broadcast: FuelChannelStatus;
165
- combinedAvailableCredits: number;
166
- };
167
- type ChromeNotificationAlert = {
168
- id: string;
169
- title: string;
170
- description: string;
171
- href: string | null;
172
- kind: string;
173
- };
174
- type ChromeNotificationReply = {
175
- id: string;
176
- contactId: string | null;
177
- name: string;
178
- preview: string;
179
- /** Optional deep-link to the conversation; the new-reply toast opens it. */
180
- href?: string;
181
- /**
182
- * Optional arrival timestamp. Present, it lets the trigger badge count a
183
- * reply as "unseen" only when it is newer than the last time the panel was
184
- * opened; absent (older payloads), replies simply don't survive the first
185
- * open as unseen. Tolerated either way.
186
- */
187
- createdAt?: string;
188
- };
189
- /** A running or finished contact import surfaced in the notifications panel. */
190
- type ChromeNotificationImport = {
191
- id: string;
192
- label: string;
193
- /** 0–100 progress, or null when indeterminate (no bar rendered). */
194
- percent: number | null;
195
- status: 'active' | 'completed';
196
- href: string | null;
197
- };
198
- /** A cluster of quarantined contacts sharing one phone number. */
199
- type ChromeNotificationQuarantine = {
200
- phone: string;
201
- count: number;
202
- /** Upstream may omit it; the row already renders conditionally on it. */
203
- latestAt: string | null;
204
- };
205
- type ChromeNotificationsPayload = {
206
- organizationId: string;
207
- alerts: ChromeNotificationAlert[];
208
- replies: ChromeNotificationReply[];
209
- /** Optional — running/finished imports (tolerant when absent). */
210
- imports?: ChromeNotificationImport[];
211
- /** Optional — clustered quarantined contacts (tolerant when absent). */
212
- quarantined?: ChromeNotificationQuarantine[];
213
- };
214
- type ChromeOrgSummary = {
215
- id: string;
216
- name: string | null;
217
- logoUrl: string | null;
218
- brandColor: string | null;
219
- role: string | null;
220
- /** Un-mapped VRM-core membership role (e.g. "super_admin"). */
221
- rawRole?: string | null;
222
- };
223
- /**
224
- * Fetch the signed-in user's VRM-core organizations through the injected
225
- * fetcher. Exposed as a hook so the org switcher in the sidebar and the
226
- * org-scoped widgets share one request.
227
- */
228
- declare function useChromeOrgs({ enabled }?: {
229
- enabled?: boolean;
230
- }): {
231
- orgs: ChromeOrgSummary[] | null;
232
- loading: boolean;
233
- error: boolean;
234
- };
235
- /**
236
- * A top-bar popover: the shared circular trigger + a right-aligned panel.
237
- * Closes on outside click / Escape. Purely presentational.
238
- *
239
- * EXPORTED so an app with a richer panel than the stock actions can render it
240
- * inside the SHARED chrome — same 32px trigger, same tooltip, same badge, same
241
- * panel surface and arrow — instead of hand-rolling a trigger and drifting.
242
- * This is the enabling step for folding VRM's Fuel breakdown, import-progress,
243
- * alerts and reply-feed panels into the shared cluster one at a time, without
244
- * dropping capability (shell-nav-handoff §4; UI-Platform forbids migrating an
245
- * app to a rendering that loses an element it already ships).
246
- */
247
- declare function TopBarPopover({ label, description, slot, fallbackIcon, badge, tone, onOpen, openToken, onOpenChange, children, panelClassName, }: {
248
- label: string;
249
- description?: string;
250
- slot?: TopBarIconSlot;
251
- fallbackIcon: NavIconLike;
252
- badge?: number;
253
- tone?: 'default' | 'warning' | 'danger';
254
- onOpen?: () => void;
255
- /**
256
- * Imperative "open" signal: whenever this number CHANGES the panel opens
257
- * (and `onOpen` fires). Lets a sibling — e.g. the notifications toast — open
258
- * the panel without owning the popover's state. Undefined disables it.
259
- */
260
- openToken?: number;
261
- /**
262
- * Notified on every open/close. A sibling surface anchored to the same
263
- * trigger (e.g. the notifications toast) must know when the panel is open so
264
- * the two never render on top of each other — Reference/UI-Platform gives
265
- * every top-bar panel ONE surface anchored to its trigger, so a second
266
- * surface at the same anchor always occludes it.
267
- */
268
- onOpenChange?: (open: boolean) => void;
269
- children: ReactNode;
270
- panelClassName?: string;
271
- }): react_jsx_runtime.JSX.Element;
272
- declare function FuelAction({ orgId }: {
273
- orgId: string | null;
274
- }): react_jsx_runtime.JSX.Element;
275
- declare function NotificationsAction({ orgId }: {
276
- orgId: string | null;
277
- }): react_jsx_runtime.JSX.Element;
278
- declare function SupportAction({ orgId, orgs: knownOrgs, }?: {
279
- orgId?: string | null;
280
- orgs?: {
281
- id: string;
282
- name: string | null;
283
- }[];
284
- }): react_jsx_runtime.JSX.Element;
285
- declare function SpecOverlayAction({ orgId, orgName }?: {
286
- orgId?: string | null;
287
- orgName?: string | null;
288
- }): react_jsx_runtime.JSX.Element | null;
289
- type NavDisplayMode = 'menu' | 'tabs' | 'both';
290
- declare function NavDisplayAction({ value, onChange, }: {
291
- value: NavDisplayMode;
292
- onChange: (next: NavDisplayMode) => void;
293
- }): react_jsx_runtime.JSX.Element;
294
- declare function useThemePreference(): {
295
- value: ThemePreference;
296
- setValue: (next: ThemePreference) => void;
297
- };
298
-
299
- /**
300
- * Icon slots used by the standard menus. The shell stays icon-library-agnostic:
301
- * callers map each key to their own icon components (lucide, react-icons, …).
302
- * A missing key simply renders that row without an icon.
303
- */
304
- type StandardNavIconKey = 'home' | 'users' | 'mail' | 'messageSquare' | 'layout' | 'activity' | 'lifeBuoy' | 'grid' | 'list' | 'upload' | 'edit' | 'fileText' | 'send' | 'clock' | 'user' | 'barChart' | 'briefcase' | 'settings' | 'creditCard' | 'dollarSign' | 'share' | 'phone' | 'map' | 'mapPin' | 'target' | 'flag' | 'layoutDashboard' | 'usersRound' | 'mousePointerClick' | 'clipboardList' | 'circleUser' | 'crosshair' | 'landmark' | 'chartNoAxes' | 'doorOpen' | 'signpost';
305
- /** The operating Mode whose nav tree to build. Defaults to `relationship`. */
306
- type StandardNavMode = 'relationship' | 'campaign' | 'petition';
307
- /**
308
- * Per-feature availability for the Campaign tree. Campaign Mode ships its apps
309
- * incrementally: a disabled feature is omitted from the nav entirely (rather
310
- * than rendered as a dead/disabled row), and its flag flips to `true` in a
311
- * later patch release as the app goes live. Dashboard and Voter Contact are
312
- * core-hosted and always present, so they carry no flag.
313
- */
314
- interface CampaignFeatureAvailability {
315
- a2p: boolean;
316
- phonebank: boolean;
317
- canvass: boolean;
318
- signs: boolean;
319
- tribes: boolean;
320
- polling: boolean;
321
- }
322
- /**
323
- * Launch state at this shell version: every Campaign feature is deployed and
324
- * live (a2p / phonebank / canvass / signs .politogyvrm.com all serve the app
325
- * behind SSO as of 2026-07-24), so no row is hidden. The flags remain so a
326
- * future feature can ship dark, and so a caller can hide one per-deployment.
327
- */
328
- declare const CAMPAIGN_FEATURE_AVAILABILITY: CampaignFeatureAvailability;
329
- interface StandardNavOptions {
330
- /**
331
- * @deprecated app.politogyvrm.com (VRM core) is retired (Reference/UI-Platform
332
- * → "Retirement of app.politogyvrm.com"). Every row this tree used to resolve
333
- * against VRM core now points at its V2 host directly, so this is unused.
334
- * Kept only so existing callers don't need to drop the field immediately.
335
- */
336
- coreBaseUrl?: string;
337
- /** Icon component per slot; omitted slots render icon-less rows. */
338
- icons?: Partial<Record<StandardNavIconKey, NavIcon>>;
339
- /**
340
- * App-local override for the "Contacts" item. `children` are used verbatim
341
- * (NOT absolutized) so the owning app nests its own routes; `href` (also
342
- * verbatim) feeds active-detection for the group header. When omitted, the
343
- * item carries VRM core's own contacts sub-pages as absolute links.
344
- * (Relationship tree only.)
345
- */
346
- contactsItem?: {
347
- href?: string;
348
- children?: NavItem[];
349
- /**
350
- * Live contact count shown right-aligned on the Contacts row, already
351
- * formatted for display ("31.9K"). Only the owning app knows it.
352
- * (Specs/Contacts design: `Contacts · 31.9K`.)
353
- */
354
- count?: string | number | null;
355
- };
356
- /**
357
- * Top-level rows to OMIT, by label (case-insensitive), e.g. `['Polls','CTAs']`.
358
- * The Specs/Contacts design rail lists Relationship → Collect → Account with
359
- * exactly Dashboard · Contacts · Email broadcast · SMS/MMS blast / Calls to
360
- * action · Forms · Surveys / My profile · Organization settings; apps that
361
- * still surface Polls / CTAs keep them by default. A section row with no
362
- * remaining items is dropped too.
363
- */
364
- hiddenItems?: string[];
365
- /**
366
- * App-local override for the Petition-mode "Dashboard" entry, same contract
367
- * as `contactsItem`: `href`/`children` used verbatim so the Petitions app
368
- * nests its own routes under the entry. (Petition tree only.)
369
- */
370
- petitionsItem?: {
371
- href?: string;
372
- children?: NavItem[];
373
- };
374
- /**
375
- * The trailing "Support" row. VRM core opens its SupportRequestModal here;
376
- * other apps supply their own handler (`onClick`) or a link (`href`).
377
- * Omitted or `false` → no Support row. Appended to every mode's tree.
378
- */
379
- supportItem?: {
380
- onClick?: () => void;
381
- href?: string;
382
- } | false;
383
- /**
384
- * Which mode's tree to build. Default `relationship`, whose output is
385
- * byte-for-byte what this function produced before modes existed.
386
- */
387
- mode?: StandardNavMode;
388
- /**
389
- * Active organization id (full UUID). EVERY link in EVERY tree carries it as
390
- * `?org=<uuid>` — the same convention the Mode switcher and My Account menu
391
- * use — so the destination app opens on the same org instead of the user's
392
- * default one. Omit it only when the caller genuinely has no active org yet.
393
- */
394
- activeOrgId?: string | null;
395
- /**
396
- * Per-feature Campaign availability overrides, merged over
397
- * `CAMPAIGN_FEATURE_AVAILABILITY`. Only meaningful for the Campaign tree.
398
- */
399
- campaignAvailability?: Partial<CampaignFeatureAvailability>;
400
- }
401
- /**
402
- * Build the standard Politogy VRM menu for the given `mode` (default
403
- * `relationship`), in the exact order and wording the main app renders it. See
404
- * `StandardNavOptions` for the app-specific hooks (`contactsItem`,
405
- * `supportItem`) and the Campaign inputs (`activeOrgId`, `campaignAvailability`).
406
- */
407
- declare function standardPolitogyNav(opts: StandardNavOptions): NavItem[];
408
-
409
- type NavIcon = ComponentType<{
410
- size?: number;
411
- className?: string;
412
- strokeWidth?: number;
413
- }>;
414
- type NavItem = {
415
- /**
416
- * What this row IS. Defaults to `'link'` — every existing `NavItem[]` keeps
417
- * its exact type and rendering.
418
- *
419
- * `'section'` is a non-interactive heading that groups the rows beneath it:
420
- * uppercase, muted, letterspaced, not focusable, no hover. Only `label` is
421
- * read; `href`, `icon`, `onClick` and `children` are ignored.
422
- *
423
- * The legacy chrome supported this and 0.43 dropped it, so apps faked it by
424
- * passing `disabled` rows with no href — which looks approximately right and
425
- * is wrong where it counts: a disabled row announces as an unavailable
426
- * CONTROL to a screen reader, when it is not a control at all. A section is
427
- * its own kind of row (Reference/UI-Platform → Left bar).
428
- *
429
- * Deliberately a widened field rather than a discriminated union: a union
430
- * would make `item.href` a type error for every existing consumer that reads
431
- * it, turning an additive feature into a breaking change.
432
- */
433
- kind?: 'link' | 'section';
434
- /** Route to link to. Optional when `onClick` is supplied (renders a button). */
435
- href?: string;
436
- label: string;
437
- icon?: NavIcon;
438
- /**
439
- * When supplied the row renders as a `<button>` (styled identically to the
440
- * link rows) instead of a routed link — used for actions like "Support".
441
- */
442
- onClick?: () => void;
443
- /**
444
- * Disables the row: non-interactive and dimmed, with `disabledTitle` shown as
445
- * a hover tooltip explaining why. Mirrors `NavTab`'s existing contract so a
446
- * gated row looks the same whether it renders in the sidebar or a tab strip.
447
- * Without this, an app that gates a section (VRM dims Email / SMS until setup
448
- * is complete) had no way to express it and the row rendered fully clickable
449
- * (shell-nav-handoff §3).
450
- */
451
- disabled?: boolean;
452
- /** Tooltip for a disabled row — say why, and how to resolve it. */
453
- disabledTitle?: string;
454
- /**
455
- * Right-aligned count/annotation on the row — e.g. the live contact count
456
- * on "Contacts" (`31.9K`). Pre-formatted by the app; the shell only draws
457
- * it (Specs/Contacts design rail). Omitted/null draws nothing.
458
- */
459
- badge?: string | number | null;
460
- /**
461
- * Nested sub-items. When present, the row becomes an expandable GROUP header.
462
- * Clicking it always toggles the children open/closed and rotates the
463
- * right-aligned chevron; if the item ALSO carries an `onClick`, that runs too,
464
- * so a parent can navigate to its section dashboard while expanding
465
- * (shell-nav-handoff §2). An `href` alone never navigates from a group header. The sidebar runs a single-open accordion (opening one group closes
466
- * the others) and auto-expands whichever group contains the active route —
467
- * mirroring the main VRM app's Chakra sidebar. Children render as smaller nav
468
- * rows on a lighter panel and support both `href` links and `onClick` actions.
469
- */
470
- children?: NavItem[];
471
- };
472
- type NavLinkProps = {
473
- href: string;
474
- className?: string;
475
- 'aria-current'?: 'page' | undefined;
476
- children: ReactNode;
477
- role?: string;
478
- 'aria-selected'?: boolean;
479
- 'aria-label'?: string;
480
- title?: string;
481
- style?: CSSProperties;
482
- };
483
- type NavLinkComponent = ComponentType<NavLinkProps>;
484
- declare function isNavItemActive(pathname: string, href: string): boolean;
485
- /** A multi-mode app (VRM core) renders NavAppShell without a registry modeId;
486
- * its current mode label still decides the rail colour (Left-Navigation §5). */
487
- declare function modeIdFromLabel(label: string | undefined): string | undefined;
488
- /** "Ben Edtl" -> "Ben E." (Left-Navigation §10). One word stays as is. */
489
- declare function shortUserName(name: string): string;
490
- /** Short environment name for the rail's build line ("prod", "staging", "local"). */
491
- declare function shortEnvLabel(label: string): string;
492
- declare function envChipClasses(label: string): string;
493
- type NavBrand = {
494
- /** Where the logo links to. Defaults to "/". */
495
- homeHref?: string;
496
- /**
497
- * Brand logo image src. When supplied this renders as the wordmark logo
498
- * (matching the main app's BrandLogo), and `badgeLabel`/`title`/`subtitle`
499
- * are used only as the no-image fallback.
500
- */
501
- logoSrc?: string;
502
- logoAlt?: string;
503
- /**
504
- * The square mark shown at the top of the COLLAPSED rail (Left-Navigation
505
- * §11.6) — Brand `assets.logoSquare`, the all-white vrm tile. Falls back to
506
- * the badge when omitted.
507
- */
508
- logoSquareSrc?: string;
509
- /**
510
- * The logo URLs are still resolving from the Brand token sheet. The rail
511
- * reserves the logo's box and draws nothing — never the badge fallback,
512
- * which would flash a stand-in on every load.
513
- */
514
- logoPending?: boolean;
515
- /** Short label shown inside the brand badge fallback (e.g. "P"). */
516
- badgeLabel: string;
517
- title: string;
518
- subtitle?: string;
519
- };
520
- type NavOrgOption = {
521
- id: string;
522
- name: string | null;
523
- logoUrl?: string | null;
524
- /** The org's Brand Kit icon mark; falls back to `logoUrl`, then initials. */
525
- iconUrl?: string | null;
526
- brandColor?: string | null;
527
- role?: string | null;
528
- };
529
- type NavOrg = {
530
- name: string | null;
531
- /** Full org id. When present, a copy affordance is shown by the label. */
532
- id?: string | null;
533
- /** Optional org logo for the pill badge; falls back to initials. */
534
- logoUrl?: string | null;
535
- /**
536
- * The org's Brand Kit icon mark, shown on the collapsed rail (32px, on its
537
- * white tile). Falls back to `logoUrl` scaled to fit, then initials.
538
- */
539
- iconUrl?: string | null;
540
- /** Solid pill background (the org's brand color). Defaults to the accent. */
541
- brandColor?: string | null;
542
- /** Org's secondary Brand Kit color; the card's bottom-edge gradient runs
543
- * primary → secondary. Falls back to the Politogy gradient when unset. */
544
- brandColorSecondary?: string | null;
545
- /**
546
- * Organization Settings §7.1–§7.2: when the org has no logo yet, an Account
547
- * Admin sees an "Upload logo" link in the band instead of the org name.
548
- */
549
- canUploadLogo?: boolean;
550
- uploadLogoHref?: string;
551
- onClick?: () => void;
552
- /**
553
- * The user's organizations. When present (even one), the pill renders as a
554
- * dropdown SWITCHER (Reference/UI-Platform "Organization selector": never a
555
- * static label in a multi-org app); selecting one calls `onSwitch(id)`.
556
- */
557
- organizations?: NavOrgOption[];
558
- onSwitch?: (id: string) => void;
559
- /**
560
- * The active org is still resolving from the chrome API. Renders a skeleton
561
- * pill instead of a name. Required because the app's own workspace label is
562
- * NOT the organization: showing it while the real org loads flashes a wrong
563
- * value (Global Rules — async values shimmer, they never render a stand-in).
564
- */
565
- loading?: boolean;
566
- };
567
- type NavModeOption = {
568
- id: string;
569
- label: string;
570
- icon?: NavIcon;
571
- /**
572
- * Left-Navigation §7: a mode the organization does not hold is always
573
- * shown (never hidden), dimmed, and not selectable. Defaults to true.
574
- */
575
- available?: boolean;
576
- /** Tooltip for an unavailable mode, e.g. "Campaign Mode isn't active for
577
- * this organization." Appended with "See upgrade options" for an Account
578
- * Admin on a paid account (never during a trial). */
579
- unavailableTooltip?: string;
580
- };
581
- type NavMode = {
582
- label: string;
583
- icon?: NavIcon;
584
- /**
585
- * Entitled modes for the active organization. With more than one option the
586
- * pill renders as a SELECTOR (dropdown); with zero/one it stays the classic
587
- * disabled single-mode pill. Selecting calls onSelect(id).
588
- */
589
- options?: NavModeOption[];
590
- onSelect?: (id: string) => void;
591
- };
592
- type NavFooterLink = {
593
- label: string;
594
- href: string;
595
- external?: boolean;
596
- };
597
- type NavFooter = {
598
- /**
599
- * Build metadata (env chip / commit / version / date / author). OPTIONAL:
600
- * omit envLabel/version/commit to render a links-only footer — apps show
601
- * the meta block to Super Administrators only (Reference/UI-Platform).
602
- */
603
- envLabel?: string;
604
- version?: string;
605
- commit?: string;
606
- links?: NavFooterLink[];
607
- /** ISO date (or any Date-parseable string) of the deployed commit. */
608
- commitDate?: string;
609
- /** Full name of the commit author (only the first name is shown). */
610
- commitAuthor?: string;
611
- /**
612
- * The signed-in user, drawn as a card (avatar · name · email · chevron)
613
- * ABOVE the links row. Reference/UI-Platform v30 → Left bar: "The user —
614
- * avatar, name, email and the user menu — lives in the left bar footer."
615
- * Clicking it opens the account menu UPWARD. `NavAppShell` fills these from
616
- * `topBar.user` / `topBar.userMenu` / `topBar.onSignOut` automatically, so
617
- * standalone `NavSidebar` consumers pass them only when they want the card.
618
- */
619
- user?: NavUser | null;
620
- userMenu?: NavUserMenu | null;
621
- onSignOut?: () => void;
622
- };
623
- type NavSidebarProps = {
624
- pathname: string;
625
- brand: NavBrand;
626
- nav: {
627
- groupLabel?: string;
628
- items: NavItem[];
629
- isActive?: (pathname: string, href: string) => boolean;
630
- /**
631
- * Render each top-level group's CHILDREN directly at the root of the rail
632
- * — no parent header row, no accordion. For an app whose whole tree nests
633
- * under one entry (Petitions), that parent row is pure anatomy: V1 never
634
- * had it, it duplicates the first child's route, and it costs a level of
635
- * indentation. Sections render as sections; rows render with the 'flat'
636
- * variant (top-level geometry, wash active treatment). Top-level items
637
- * WITHOUT children render unchanged, so a mixed tree degrades sanely.
638
- */
639
- flatten?: boolean;
640
- };
641
- org?: NavOrg | null;
642
- mode?: NavMode | null;
643
- footer?: NavFooter | null;
644
- linkComponent?: NavLinkComponent;
645
- /**
646
- * Small-screen expand state (owned by `NavAppShell`). The rail is never
647
- * hidden (Left-Navigation §11.6): at `md` and up it is the full rail, below
648
- * `md` it collapses to the 64px icon rail. `open` expands the collapsed
649
- * rail to the full rail as a modal drawer with a backdrop, and `onClose`
650
- * wires the backdrop, the close button, and Escape. `md` and up ignores
651
- * both.
652
- */
653
- open?: boolean;
654
- onClose?: () => void;
655
- /**
656
- * Expands the collapsed (below `md`) rail. When set, the square logo tile at
657
- * the top of the collapsed rail becomes the "Expand navigation" control —
658
- * the Left-Navigation Design draws no other toggle and no top-bar hamburger.
659
- */
660
- onOpen?: () => void;
661
- /**
662
- * Closes the expanded rail after a nav-link click without counting as the
663
- * user's Collapse choice. Defaults to `onClose`.
664
- */
665
- onNavigate?: () => void;
666
- };
667
- declare function NavSidebar({ pathname, brand, nav, org, mode, footer, linkComponent, open, onClose, onOpen, onNavigate, }: NavSidebarProps): react_jsx_runtime.JSX.Element;
668
- type NavUser = {
669
- name: string | null;
670
- email?: string | null;
671
- /** Profile PHOTO url — highest-precedence avatar source. */
672
- avatarUrl?: string | null;
673
- /** Memoji url — used when no photo is set; falls back to initials. */
674
- memojiUrl?: string | null;
675
- tier?: string | null;
676
- role?: string | null;
677
- };
678
- type NavTopBarAction = {
679
- key: string;
680
- /**
681
- * Canonical top-bar slot. When set, the glyph is sourced by NAME from the
682
- * Brand API via `--topbar-icon-<slot>`; `icon` becomes the fallback used
683
- * until the runtime Brand stylesheet lands (or when the token is unset).
684
- */
685
- slot?: TopBarIconSlot;
686
- icon: NavIcon;
687
- label: string;
688
- onClick?: () => void;
689
- href?: string;
690
- badge?: number | null;
691
- tone?: 'default' | 'warning' | 'danger';
692
- /** Tooltip body shown under the icon (label is the tooltip title). */
693
- description?: string;
694
- };
695
- type NavLinkedAccount = {
696
- id: string;
697
- name: string | null;
698
- email?: string | null;
699
- avatarUrl?: string | null;
700
- active?: boolean;
701
- };
702
- type NavRoleBadge = {
703
- role: string;
704
- orgName?: string | null;
705
- };
706
- /**
707
- * The My Account menu (avatar dropdown) — mirrors the main VRM app's user
708
- * menu: My Profile / Organization Settings links, a ROLES & ORGANIZATIONS
709
- * section, an ACCOUNTS switcher, an optional theme control, then Sign out.
710
- * Every section renders only when its data is supplied.
711
- */
712
- type NavUserMenu = {
713
- myProfileHref?: string;
714
- organizationSettingsHref?: string;
715
- roles?: NavRoleBadge[];
716
- accounts?: NavLinkedAccount[];
717
- onSwitchAccount?: (id: string) => void;
718
- onRemoveAccount?: (id: string) => void;
719
- addAccountHref?: string;
720
- onAddAccount?: () => void;
721
- /**
722
- * Navigation display (Sub Menu / Tabs Only / Both) — lives in the account
723
- * menu since 0.68.0; the top-bar `NavDisplayAction` popover is retired from
724
- * the standard cluster (design: 4 icon buttons + Help).
725
- */
726
- navDisplay?: {
727
- value: NavDisplayMode;
728
- onChange: (next: NavDisplayMode) => void;
729
- };
730
- /** Theme preference segmented control (Light / System / Dark). */
731
- theme?: {
732
- value: ThemePreference;
733
- onChange: (next: ThemePreference) => void;
734
- };
735
- };
736
- type NavBreadcrumb = {
737
- label: string;
738
- href?: string;
739
- };
740
- type NavTopBarProps = {
741
- /**
742
- * Chrome-owned page title line (`<h1>` above main). Omit when the page body
743
- * owns its own title (registry `pageTitle: false`, e.g. Contacts).
744
- */
745
- title?: string;
746
- subtitle?: string;
747
- /**
748
- * Breadcrumb trail rendered UNDER the page title (Reference/UI-Platform:
749
- * every page and sub-page/tab shows its location). Last crumb = current
750
- * location (non-link); earlier crumbs may carry hrefs.
751
- */
752
- breadcrumbs?: NavBreadcrumb[];
753
- user?: NavUser | null;
754
- userMenu?: NavUserMenu;
755
- onSignOut?: () => void;
756
- /**
757
- * Structured icon-button action cluster (32×32 circular buttons with optional
758
- * count badges), rendered before the `actions` slot. Matches the main app's
759
- * topbar action icons.
760
- */
761
- actionsList?: NavTopBarAction[];
762
- /** App-specific action cluster rendered left of the theme toggle. */
763
- actions?: ReactNode;
764
- /** Theme toggle slot (injected so this package needs no theme dependency). */
765
- themeToggle?: ReactNode;
766
- /**
767
- * Mobile drawer trigger (owned by `NavAppShell`). Supplying it renders a
768
- * hamburger button, hidden at `lg` and up, as the first thing in the header
769
- * — below `lg` the sidebar is otherwise unreachable. Omit to render no
770
- * hamburger at all (e.g. `NavTopBar` used standalone).
771
- */
772
- onOpenNav?: () => void;
773
- /** Whether the drawer `onOpenNav` opens is currently open (drives `aria-expanded`). */
774
- navOpen?: boolean;
775
- /**
776
- * Universal search — Reference/UI-Platform "Top bar → required elements":
777
- * the search field, 320px wide, at the left end of the bar; nothing else
778
- * sits on the left. Omit `onChange`/`onSubmit` for a decorative field (an
779
- * app that has not wired search yet still gets the correct chrome).
780
- */
781
- search?: {
782
- placeholder?: string;
783
- value?: string;
784
- onChange?: (value: string) => void;
785
- onSubmit?: (value: string) => void;
786
- };
787
- /**
788
- * Build notes — a quiet text button that starts the right-hand group
789
- * (Reference/UI-Platform "Top bar → required elements").
790
- */
791
- /**
792
- * Where the My Account trigger lives. `'topbar'` (default for a standalone
793
- * `NavTopBar`) keeps the avatar + name + chevron at the right end of the bar;
794
- * `'sidebar'` / `'none'` hide it here — `NavAppShell` passes `'sidebar'` and
795
- * draws the user card in the left-bar footer instead (UI-Platform v30:
796
- * "There is no My Account badge in the top bar").
797
- */
798
- accountMenu?: 'topbar' | 'sidebar' | 'none';
799
- buildNotes?: {
800
- label?: string;
801
- onOpen?: () => void;
802
- };
803
- };
804
- declare function NavTopBar({ title, subtitle, breadcrumbs, user, userMenu, onSignOut, actionsList, actions, themeToggle, onOpenNav, navOpen, search, buildNotes, accountMenu, }: NavTopBarProps): react_jsx_runtime.JSX.Element;
805
- type NavTab = {
806
- /** Stable identity (used as the React key). */
807
- key: string;
808
- /** The tab's visible text. */
809
- label: string;
810
- /**
811
- * A Lucide icon rendered 6px left of the label (Reference/UI-Platform →
812
- * Tabs, decided 2026-10-06: "Icon + label. Each tab is a Lucide icon."),
813
- * 15px / 1.75 stroke (13px on a small strip), following the label's
814
- * selected / unselected / hover color via `currentColor`. Icon-ONLY tabs
815
- * (no label) are retired — this always pairs with `label`.
816
- */
817
- icon?: NavIcon;
818
- /** Optional count, drawn as a mono pill after the label. */
819
- count?: string | number | null;
820
- /** Route to link to (rendered through `linkComponent`). */
821
- href?: string;
822
- /** Click handler — rendered as a `<button>` when there's no `href`. */
823
- onSelect?: () => void;
824
- /** Whether this tab is the active one (drives the mode-color underline). */
825
- selected?: boolean;
826
- /**
827
- * Non-interactive, dimmed tab (e.g. Surveys' Canvas/Results before a survey
828
- * is chosen). Renders a non-navigating span; `disabledTitle` is the tooltip
829
- * explaining why.
830
- */
831
- disabled?: boolean;
832
- disabledTitle?: string;
833
- };
834
- type NavTabStripProps = {
835
- tabs: NavTab[];
836
- /** Accessible name for the tablist. */
837
- 'aria-label'?: string;
838
- /** Routing primitive for `href` tabs (Next `<Link>`, etc). Defaults to <a>. */
839
- linkComponent?: NavLinkComponent;
840
- /** `'sm'`: 12px text with 8px vertical padding. Default `'md'` (13px / 12px). */
841
- size?: 'md' | 'sm';
842
- /** Extra classes on the tablist container. */
843
- className?: string;
844
- /**
845
- * Optional tab panel rendered directly below the strip, on the page
846
- * surface with no card chrome. Omit to render only the strip and compose
847
- * the page body yourself.
848
- */
849
- children?: ReactNode;
850
- };
851
- /**
852
- * The canonical page tab strip: underlined text tabs on a 1px rule. Render it
853
- * in the page body below the page header; pass the app's `Link` as
854
- * `linkComponent` for `href` tabs.
855
- */
856
- declare function NavTabStrip({ tabs, 'aria-label': ariaLabel, linkComponent, size, className, children, }: NavTabStripProps): react_jsx_runtime.JSX.Element;
857
- /**
858
- * sessionStorage key holding the Beta-banner dismissal. sessionStorage — not
859
- * localStorage — so the dismissal lasts only for the browser session; and it is
860
- * additionally cleared on sign-out (see `clearBetaBannerDismissal`, called from
861
- * the chrome frame) so a fresh LOGIN always re-shows the notice.
862
- */
863
- declare const BETA_BANNER_DISMISS_KEY = "politogy_beta_banner_dismissed";
864
- /**
865
- * Re-arm the Beta banner. The chrome frame calls this on sign-out so the notice
866
- * reappears at the next login rather than staying hidden across the boundary
867
- * (sessionStorage survives an in-tab logout→login round trip on its own).
868
- */
869
- declare function clearBetaBannerDismissal(): void;
870
- type NavBetaBannerProps = {
871
- /** Leading sentence(s) before the link. Defaults to the standard Beta copy. */
872
- text?: string;
873
- /** Bold + underlined link label. Defaults to the standard Terms copy. */
874
- linkLabel?: string;
875
- /** Terms & Conditions URL (opens in a new tab). Defaults to the app T&C page. */
876
- href?: string;
877
- /**
878
- * Show a dismiss (×) button that hides the banner for the rest of the browser
879
- * session. Cleared on sign-out, so it returns at the next login. Default true.
880
- */
881
- dismissible?: boolean;
882
- };
883
- declare function NavBetaBanner({ text, linkLabel, href, dismissible }: NavBetaBannerProps): react_jsx_runtime.JSX.Element | null;
884
- type NavAppShellProps = {
885
- sidebar: NavSidebarProps;
886
- topBar: NavTopBarProps;
887
- /**
888
- * When supplied, a full-width Beta notice strip renders directly below the top
889
- * bar. Presence of the prop enables it; all fields fall back to the standard
890
- * Beta copy + Terms & Conditions link.
891
- */
892
- betaBanner?: NavBetaBannerProps;
893
- /**
894
- * @deprecated The frame's content area is one fluid `<main>` (Brand
895
- * guideline "Content width is fluid"): the 24px gutter (16px below `md`),
896
- * no max-width and no centered container. Apps never emit their own page
897
- * container, so there is nothing left to choose here.
898
- *
899
- * `'bare'` is still honored — it renders `children` with no `<main>` and no
900
- * gutter — only so VRM core, which renders `NavAppShell` directly around
901
- * pages that still carry their own `PageContainer`, does not get a nested
902
- * `<main>` before it migrates. It warns in development and will be removed.
903
- * `'padded'` is now the same as omitting the prop.
904
- */
905
- contentWrapper?: 'padded' | 'bare';
906
- /**
907
- * The operating Mode this frame is scoped to, stamped on the root as
908
- * `data-politogy-mode` so the Brand API's per-Mode chrome tokens can target
909
- * it (Reference/UI-Platform → "Per-mode branding — one accent per Mode").
910
- *
911
- * This is app IDENTITY, not app configuration: `PolitogyAppFrame` passes it
912
- * from the `POLITOGY_APPS` registry, never from a prop an app supplies, so an
913
- * app still cannot choose its own chrome colour.
914
- *
915
- * Omitted (or a Mode that declares no chrome group in the Brand API) => every
916
- * accent falls back to the global one, exactly as before 0.47.
917
- */
918
- modeId?: string;
919
- /**
920
- * Where the user card / account menu renders. `'sidebar'` (default since
921
- * 0.68.0) draws it in the left-bar footer and hides the top-bar trigger
922
- * (Reference/UI-Platform v30); `'topbar'` restores the 0.67 top-right badge.
923
- */
924
- accountMenuPlacement?: 'sidebar' | 'topbar';
925
- children: ReactNode;
926
- };
927
- declare function NavAppShell({ sidebar, topBar, betaBanner, contentWrapper, accountMenuPlacement, modeId, children, }: NavAppShellProps): react_jsx_runtime.JSX.Element;
928
-
929
- export { BETA_BANNER_DISMISS_KEY, CAMPAIGN_FEATURE_AVAILABILITY, CORE_APP_ORIGIN, CORE_BILLING_PATH, type CampaignFeatureAvailability, type ChromeMe, type ChromeNotificationAlert, type ChromeNotificationImport, type ChromeNotificationQuarantine, type ChromeNotificationReply, type ChromeNotificationsPayload, type ChromeOrgSummary, type CommunicationsFuelStatus, FormColumn, FuelAction, type FuelChannelStatus, NavAppShell, type NavAppShellProps, NavBetaBanner, type NavBetaBannerProps, type NavBrand, type NavBreadcrumb, type NavChromeFetcher, NavChromeProvider, NavDisplayAction, type NavDisplayMode, type NavFooter, type NavFooterLink, type NavIcon, type NavItem, type NavLinkComponent, type NavLinkProps, type NavLinkedAccount, type NavMode, type NavModeOption, type NavOrg, type NavOrgOption, type NavRoleBadge, NavSidebar, type NavSidebarProps, type NavTab, NavTabStrip, type NavTabStripProps, NavThemeControl, NavTopBar, type NavTopBarAction, type NavTopBarProps, type NavUser, type NavUserMenu, NotificationsAction, SPECS_ORIGIN, SpecOverlayAction, type StandardNavIconKey, type StandardNavMode, type StandardNavOptions, SupportAction, type ThemePreference, TopBarCountBadge, TopBarPanelArrow, TopBarPopover, TopBarTooltip, TopBarWidgetSlot, clearBetaBannerDismissal, envChipClasses, isNavItemActive, modeIdFromLabel, resolveOrgLogoUrl, shortEnvLabel, shortUserName, standardPolitogyNav, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeDedupedFetch, useNavChromeFetcher, useThemePreference };
1
+ import 'react/jsx-runtime';
2
+ import 'react';
3
+ export { B as BETA_BANNER_DISMISS_KEY, q as CAMPAIGN_FEATURE_AVAILABILITY, r as CORE_APP_ORIGIN, s as CORE_BILLING_PATH, t as CampaignFeatureAvailability, u as ChromeMe, v as ChromeNotificationAlert, w as ChromeNotificationImport, x as ChromeNotificationQuarantine, y as ChromeNotificationReply, z as ChromeNotificationsPayload, A as ChromeOrgSummary, D as CommunicationsFuelStatus, F as FormColumn, E as FuelAction, G as FuelChannelStatus, H as NavAppShell, I as NavAppShellProps, J as NavBetaBanner, K as NavBetaBannerProps, L as NavBrand, g as NavBreadcrumb, j as NavChromeFetcher, M as NavChromeProvider, O as NavDisplayAction, p as NavDisplayMode, o as NavFooter, P as NavFooterLink, f as NavIcon, N as NavItem, i as NavLinkComponent, Q as NavLinkProps, R as NavLinkedAccount, k as NavMode, T as NavModeOption, U as NavOrg, m as NavOrgOption, V as NavRoleBadge, W as NavSidebar, X as NavSidebarProps, Y as NavTab, Z as NavTabStrip, _ as NavTabStripProps, $ as NavThemeControl, a0 as NavTopBar, a1 as NavTopBarAction, a2 as NavTopBarProps, a3 as NavUser, l as NavUserMenu, a4 as NotificationsAction, a5 as SPECS_ORIGIN, a6 as SpecOverlayAction, S as StandardNavIconKey, h as StandardNavMode, a7 as StandardNavOptions, a8 as SupportAction, a9 as ThemePreference, aa as TopBarCountBadge, ab as TopBarPanelArrow, ac as TopBarPopover, ad as TopBarTooltip, ae as TopBarWidgetSlot, af as clearBetaBannerDismissal, ag as envChipClasses, ah as isNavItemActive, ai as modeIdFromLabel, aj as resolveOrgLogoUrl, ak as shortEnvLabel, al as shortUserName, am as standardPolitogyNav, an as topBarIconButtonClass, ao as useChromeMe, ap as useChromeOrgs, aq as useNavChromeDedupedFetch, ar as useNavChromeFetcher, as as useThemePreference } from './index-DJ3qBzfQ.js';
4
+ import './theme-preference.js';