@the-portland-company/shell 0.32.2 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/native.d.cts CHANGED
@@ -1,12 +1,23 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, ComponentType, CSSProperties } from 'react';
3
- import { T as TopBarIconSlot } from './topbarIconSlot-FunwEKO9.cjs';
4
3
  import { ThemePreference as ThemePreference$1 } from './theme-preference.cjs';
5
4
 
5
+ /**
6
+ * The six canonical top-bar action slots (Reference/Global-Rules v9 → top-bar
7
+ * icons). Each slot's GLYPH is unique and comes from the Brand API
8
+ * `topbarIcons.items.*` tokens, exposed as `--topbar-icon-<slot>` CSS vars
9
+ * whose value is the brand-icon NAME. Every OTHER property — size, gap, color,
10
+ * hover, selected — is universal across all six slots.
11
+ */
12
+ type TopBarIconSlot = 'comms-fuel' | 'apps' | 'notifications' | 'alerts' | 'support' | 'dark-mode';
13
+
6
14
  type NavIconLike = ComponentType<{
7
15
  size?: number;
8
16
  className?: string;
9
17
  }>;
18
+ declare const CORE_APP_ORIGIN = "https://app.politogyvrm.com";
19
+ /** Text/Email fuel top-up page (SMS Signal + Email Broadcast). */
20
+ declare const CORE_BILLING_PATH = "/organization-settings/subscription-billing/text-email";
10
21
  declare function topBarIconButtonClass(tone?: 'default' | 'warning' | 'danger'): string;
11
22
  /** The shared count badge — one definition, used by every slot. */
12
23
  declare function TopBarCountBadge({ count }: {
@@ -59,6 +70,9 @@ type ChromeMe = {
59
70
  account?: string | null;
60
71
  accountName?: string | null;
61
72
  role?: string | null;
73
+ /** Contact reply-to, when the profile carries them (optional/tolerant). */
74
+ email?: string | null;
75
+ phone?: string | null;
62
76
  };
63
77
  declare function NavChromeProvider({ fetchJson, children, }: {
64
78
  fetchJson: NavChromeFetcher;
@@ -96,11 +110,39 @@ type ChromeNotificationReply = {
96
110
  contactId: string | null;
97
111
  name: string;
98
112
  preview: string;
113
+ /** Optional deep-link to the conversation; the new-reply toast opens it. */
114
+ href?: string;
115
+ /**
116
+ * Optional arrival timestamp. Present, it lets the trigger badge count a
117
+ * reply as "unseen" only when it is newer than the last time the panel was
118
+ * opened; absent (older payloads), replies simply don't survive the first
119
+ * open as unseen. Tolerated either way.
120
+ */
121
+ createdAt?: string;
122
+ };
123
+ /** A running or finished contact import surfaced in the notifications panel. */
124
+ type ChromeNotificationImport = {
125
+ id: string;
126
+ label: string;
127
+ /** 0–100 progress, or null when indeterminate (no bar rendered). */
128
+ percent: number | null;
129
+ status: 'active' | 'completed';
130
+ href: string | null;
131
+ };
132
+ /** A cluster of quarantined contacts sharing one phone number. */
133
+ type ChromeNotificationQuarantine = {
134
+ phone: string;
135
+ count: number;
136
+ latestAt: string;
99
137
  };
100
138
  type ChromeNotificationsPayload = {
101
139
  organizationId: string;
102
140
  alerts: ChromeNotificationAlert[];
103
141
  replies: ChromeNotificationReply[];
142
+ /** Optional — running/finished imports (tolerant when absent). */
143
+ imports?: ChromeNotificationImport[];
144
+ /** Optional — clustered quarantined contacts (tolerant when absent). */
145
+ quarantined?: ChromeNotificationQuarantine[];
104
146
  };
105
147
  type ChromeOrgSummary = {
106
148
  id: string;
@@ -133,7 +175,7 @@ declare function useChromeOrgs(): {
133
175
  * dropping capability (shell-nav-handoff §4; UI-Platform forbids migrating an
134
176
  * app to a rendering that loses an element it already ships).
135
177
  */
136
- declare function TopBarPopover({ label, description, slot, fallbackIcon, badge, tone, onOpen, children, panelClassName, }: {
178
+ declare function TopBarPopover({ label, description, slot, fallbackIcon, badge, tone, onOpen, openToken, children, panelClassName, }: {
137
179
  label: string;
138
180
  description?: string;
139
181
  slot?: TopBarIconSlot;
@@ -141,6 +183,12 @@ declare function TopBarPopover({ label, description, slot, fallbackIcon, badge,
141
183
  badge?: number;
142
184
  tone?: 'default' | 'warning' | 'danger';
143
185
  onOpen?: () => void;
186
+ /**
187
+ * Imperative "open" signal: whenever this number CHANGES the panel opens
188
+ * (and `onOpen` fires). Lets a sibling — e.g. the notifications toast — open
189
+ * the panel without owning the popover's state. Undefined disables it.
190
+ */
191
+ openToken?: number;
144
192
  children: ReactNode;
145
193
  panelClassName?: string;
146
194
  }): react_jsx_runtime.JSX.Element;
@@ -150,7 +198,9 @@ declare function FuelAction({ orgId }: {
150
198
  declare function NotificationsAction({ orgId }: {
151
199
  orgId: string | null;
152
200
  }): react_jsx_runtime.JSX.Element;
153
- declare function SupportAction(): react_jsx_runtime.JSX.Element;
201
+ declare function SupportAction({ orgId }?: {
202
+ orgId?: string | null;
203
+ }): react_jsx_runtime.JSX.Element;
154
204
  type NavDisplayMode = 'menu' | 'tabs' | 'both';
155
205
  declare function NavDisplayAction({ value, onChange, }: {
156
206
  value: NavDisplayMode;
@@ -187,7 +237,8 @@ interface CampaignFeatureAvailability {
187
237
  /**
188
238
  * Launch state at this shell version: Polling Engine (polls app) and Tribes
189
239
  * (Contacts app) are live; A2P, Phone Banking, Field Canvassing and Sign
190
- * Mapping shipped to production 2026-07-24 — all Campaign features are ON.
240
+ * Mapping are not yet deployed and stay hidden until their patch release flips
241
+ * the flag.
191
242
  */
192
243
  declare const CAMPAIGN_FEATURE_AVAILABILITY: CampaignFeatureAvailability;
193
244
  interface StandardNavOptions {
@@ -560,4 +611,4 @@ type NavAppShellProps = {
560
611
  };
561
612
  declare function NavAppShell({ sidebar, topBar, betaBanner, contentWrapper, children, }: NavAppShellProps): react_jsx_runtime.JSX.Element;
562
613
 
563
- export { CAMPAIGN_FEATURE_AVAILABILITY, type CampaignFeatureAvailability, type ChromeMe, type ChromeNotificationAlert, type ChromeNotificationReply, type ChromeNotificationsPayload, type ChromeOrgSummary, type CommunicationsFuelStatus, 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, type StandardNavIconKey, type StandardNavMode, type StandardNavOptions, SupportAction, type ThemePreference, TopBarCountBadge, TopBarPanelArrow, TopBarPopover, TopBarTooltip, TopBarWidgetSlot, envChipClasses, isNavItemActive, standardPolitogyNav, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeFetcher, useThemePreference };
614
+ export { 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, 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, type StandardNavIconKey, type StandardNavMode, type StandardNavOptions, SupportAction, type ThemePreference, TopBarCountBadge, TopBarPanelArrow, TopBarPopover, TopBarTooltip, TopBarWidgetSlot, envChipClasses, isNavItemActive, standardPolitogyNav, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeFetcher, useThemePreference };
package/dist/native.d.ts CHANGED
@@ -1,12 +1,23 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, ComponentType, CSSProperties } from 'react';
3
- import { T as TopBarIconSlot } from './topbarIconSlot-FunwEKO9.js';
4
3
  import { ThemePreference as ThemePreference$1 } from './theme-preference.js';
5
4
 
5
+ /**
6
+ * The six canonical top-bar action slots (Reference/Global-Rules v9 → top-bar
7
+ * icons). Each slot's GLYPH is unique and comes from the Brand API
8
+ * `topbarIcons.items.*` tokens, exposed as `--topbar-icon-<slot>` CSS vars
9
+ * whose value is the brand-icon NAME. Every OTHER property — size, gap, color,
10
+ * hover, selected — is universal across all six slots.
11
+ */
12
+ type TopBarIconSlot = 'comms-fuel' | 'apps' | 'notifications' | 'alerts' | 'support' | 'dark-mode';
13
+
6
14
  type NavIconLike = ComponentType<{
7
15
  size?: number;
8
16
  className?: string;
9
17
  }>;
18
+ declare const CORE_APP_ORIGIN = "https://app.politogyvrm.com";
19
+ /** Text/Email fuel top-up page (SMS Signal + Email Broadcast). */
20
+ declare const CORE_BILLING_PATH = "/organization-settings/subscription-billing/text-email";
10
21
  declare function topBarIconButtonClass(tone?: 'default' | 'warning' | 'danger'): string;
11
22
  /** The shared count badge — one definition, used by every slot. */
12
23
  declare function TopBarCountBadge({ count }: {
@@ -59,6 +70,9 @@ type ChromeMe = {
59
70
  account?: string | null;
60
71
  accountName?: string | null;
61
72
  role?: string | null;
73
+ /** Contact reply-to, when the profile carries them (optional/tolerant). */
74
+ email?: string | null;
75
+ phone?: string | null;
62
76
  };
63
77
  declare function NavChromeProvider({ fetchJson, children, }: {
64
78
  fetchJson: NavChromeFetcher;
@@ -96,11 +110,39 @@ type ChromeNotificationReply = {
96
110
  contactId: string | null;
97
111
  name: string;
98
112
  preview: string;
113
+ /** Optional deep-link to the conversation; the new-reply toast opens it. */
114
+ href?: string;
115
+ /**
116
+ * Optional arrival timestamp. Present, it lets the trigger badge count a
117
+ * reply as "unseen" only when it is newer than the last time the panel was
118
+ * opened; absent (older payloads), replies simply don't survive the first
119
+ * open as unseen. Tolerated either way.
120
+ */
121
+ createdAt?: string;
122
+ };
123
+ /** A running or finished contact import surfaced in the notifications panel. */
124
+ type ChromeNotificationImport = {
125
+ id: string;
126
+ label: string;
127
+ /** 0–100 progress, or null when indeterminate (no bar rendered). */
128
+ percent: number | null;
129
+ status: 'active' | 'completed';
130
+ href: string | null;
131
+ };
132
+ /** A cluster of quarantined contacts sharing one phone number. */
133
+ type ChromeNotificationQuarantine = {
134
+ phone: string;
135
+ count: number;
136
+ latestAt: string;
99
137
  };
100
138
  type ChromeNotificationsPayload = {
101
139
  organizationId: string;
102
140
  alerts: ChromeNotificationAlert[];
103
141
  replies: ChromeNotificationReply[];
142
+ /** Optional — running/finished imports (tolerant when absent). */
143
+ imports?: ChromeNotificationImport[];
144
+ /** Optional — clustered quarantined contacts (tolerant when absent). */
145
+ quarantined?: ChromeNotificationQuarantine[];
104
146
  };
105
147
  type ChromeOrgSummary = {
106
148
  id: string;
@@ -133,7 +175,7 @@ declare function useChromeOrgs(): {
133
175
  * dropping capability (shell-nav-handoff §4; UI-Platform forbids migrating an
134
176
  * app to a rendering that loses an element it already ships).
135
177
  */
136
- declare function TopBarPopover({ label, description, slot, fallbackIcon, badge, tone, onOpen, children, panelClassName, }: {
178
+ declare function TopBarPopover({ label, description, slot, fallbackIcon, badge, tone, onOpen, openToken, children, panelClassName, }: {
137
179
  label: string;
138
180
  description?: string;
139
181
  slot?: TopBarIconSlot;
@@ -141,6 +183,12 @@ declare function TopBarPopover({ label, description, slot, fallbackIcon, badge,
141
183
  badge?: number;
142
184
  tone?: 'default' | 'warning' | 'danger';
143
185
  onOpen?: () => void;
186
+ /**
187
+ * Imperative "open" signal: whenever this number CHANGES the panel opens
188
+ * (and `onOpen` fires). Lets a sibling — e.g. the notifications toast — open
189
+ * the panel without owning the popover's state. Undefined disables it.
190
+ */
191
+ openToken?: number;
144
192
  children: ReactNode;
145
193
  panelClassName?: string;
146
194
  }): react_jsx_runtime.JSX.Element;
@@ -150,7 +198,9 @@ declare function FuelAction({ orgId }: {
150
198
  declare function NotificationsAction({ orgId }: {
151
199
  orgId: string | null;
152
200
  }): react_jsx_runtime.JSX.Element;
153
- declare function SupportAction(): react_jsx_runtime.JSX.Element;
201
+ declare function SupportAction({ orgId }?: {
202
+ orgId?: string | null;
203
+ }): react_jsx_runtime.JSX.Element;
154
204
  type NavDisplayMode = 'menu' | 'tabs' | 'both';
155
205
  declare function NavDisplayAction({ value, onChange, }: {
156
206
  value: NavDisplayMode;
@@ -187,7 +237,8 @@ interface CampaignFeatureAvailability {
187
237
  /**
188
238
  * Launch state at this shell version: Polling Engine (polls app) and Tribes
189
239
  * (Contacts app) are live; A2P, Phone Banking, Field Canvassing and Sign
190
- * Mapping shipped to production 2026-07-24 — all Campaign features are ON.
240
+ * Mapping are not yet deployed and stay hidden until their patch release flips
241
+ * the flag.
191
242
  */
192
243
  declare const CAMPAIGN_FEATURE_AVAILABILITY: CampaignFeatureAvailability;
193
244
  interface StandardNavOptions {
@@ -560,4 +611,4 @@ type NavAppShellProps = {
560
611
  };
561
612
  declare function NavAppShell({ sidebar, topBar, betaBanner, contentWrapper, children, }: NavAppShellProps): react_jsx_runtime.JSX.Element;
562
613
 
563
- export { CAMPAIGN_FEATURE_AVAILABILITY, type CampaignFeatureAvailability, type ChromeMe, type ChromeNotificationAlert, type ChromeNotificationReply, type ChromeNotificationsPayload, type ChromeOrgSummary, type CommunicationsFuelStatus, 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, type StandardNavIconKey, type StandardNavMode, type StandardNavOptions, SupportAction, type ThemePreference, TopBarCountBadge, TopBarPanelArrow, TopBarPopover, TopBarTooltip, TopBarWidgetSlot, envChipClasses, isNavItemActive, standardPolitogyNav, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeFetcher, useThemePreference };
614
+ export { 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, 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, type StandardNavIconKey, type StandardNavMode, type StandardNavOptions, SupportAction, type ThemePreference, TopBarCountBadge, TopBarPanelArrow, TopBarPopover, TopBarTooltip, TopBarWidgetSlot, envChipClasses, isNavItemActive, standardPolitogyNav, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeFetcher, useThemePreference };
package/dist/native.js CHANGED
@@ -1,6 +1,5 @@
1
1
  "use client";
2
- export { CAMPAIGN_FEATURE_AVAILABILITY, FuelAction, NavAppShell, NavBetaBanner, NavChromeProvider, NavDisplayAction, NavSidebar, NavTabStrip, NavThemeControl, NavTopBar, NotificationsAction, SupportAction, TopBarCountBadge, TopBarPanelArrow, TopBarPopover, TopBarTooltip, TopBarWidgetSlot, envChipClasses, isNavItemActive, standardPolitogyNav, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeFetcher, useThemePreference } from './chunk-PWBYDQCO.js';
3
- import './chunk-NV6WHTEZ.js';
2
+ export { CAMPAIGN_FEATURE_AVAILABILITY, CORE_APP_ORIGIN, CORE_BILLING_PATH, FuelAction, NavAppShell, NavBetaBanner, NavChromeProvider, NavDisplayAction, NavSidebar, NavTabStrip, NavThemeControl, NavTopBar, NotificationsAction, SupportAction, TopBarCountBadge, TopBarPanelArrow, TopBarPopover, TopBarTooltip, TopBarWidgetSlot, envChipClasses, isNavItemActive, standardPolitogyNav, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeFetcher, useThemePreference } from './chunk-CVBEBCID.js';
4
3
  import './chunk-LL7RCJQN.js';
5
4
  //# sourceMappingURL=native.js.map
6
5
  //# sourceMappingURL=native.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@the-portland-company/shell",
3
- "version": "0.32.2",
3
+ "version": "0.34.0",
4
4
  "description": "Shared chrome (header, sidebar, footer, theme, auth) for politogy apps. Drop into any Vite SPA to inherit the politogy look and signed-in user.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -1,54 +0,0 @@
1
- import { FiUser, FiSettings, FiMessageSquare, FiMail, FiInfo, FiSun, FiMoon, FiHelpCircle, FiLifeBuoy, FiAlertCircle, FiAlertTriangle, FiBell, FiGrid, FiZap, FiBatteryCharging, FiBattery } from 'react-icons/fi';
2
- import { useState, useEffect } from 'react';
3
-
4
- // src/lib/brandGlyphs.tsx
5
- var GLYPHS = {
6
- // Communications Fuel reads as a LEVEL, so its glyph is a battery. `bolt`/
7
- // `zap` stay mapped for older Brand values.
8
- "battery-charging": FiBatteryCharging,
9
- battery: FiBattery,
10
- fuel: FiBatteryCharging,
11
- bolt: FiZap,
12
- zap: FiZap,
13
- grid: FiGrid,
14
- apps: FiGrid,
15
- bell: FiBell,
16
- notification: FiBell,
17
- "alert-triangle": FiAlertTriangle,
18
- alert: FiAlertTriangle,
19
- "alert-circle": FiAlertCircle,
20
- "life-buoy": FiLifeBuoy,
21
- "life-ring": FiLifeBuoy,
22
- support: FiLifeBuoy,
23
- "help-circle": FiHelpCircle,
24
- moon: FiMoon,
25
- sun: FiSun,
26
- info: FiInfo,
27
- mail: FiMail,
28
- "message-square": FiMessageSquare,
29
- settings: FiSettings,
30
- user: FiUser
31
- };
32
- function resolveBrandGlyph(name) {
33
- if (!name) return null;
34
- return GLYPHS[name.trim().toLowerCase()] ?? null;
35
- }
36
- function useTopBarIconSlotGlyph(slot) {
37
- const [name, setName] = useState(null);
38
- useEffect(() => {
39
- if (typeof window === "undefined") return;
40
- const read = () => {
41
- const raw = window.getComputedStyle(document.documentElement).getPropertyValue(`--topbar-icon-${slot}`).trim().replace(/^['"]|['"]$/g, "");
42
- setName(raw.length > 0 ? raw : null);
43
- };
44
- read();
45
- const observer = new MutationObserver(read);
46
- observer.observe(document.head, { childList: true, subtree: true });
47
- return () => observer.disconnect();
48
- }, [slot]);
49
- return name;
50
- }
51
-
52
- export { resolveBrandGlyph, useTopBarIconSlotGlyph };
53
- //# sourceMappingURL=chunk-NV6WHTEZ.js.map
54
- //# sourceMappingURL=chunk-NV6WHTEZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/brandGlyphs.tsx","../src/lib/topbarIconSlot.ts"],"names":[],"mappings":";;;;AAkCA,IAAM,MAAA,GAAyC;AAAA;AAAA;AAAA,EAG7C,kBAAA,EAAoB,iBAAA;AAAA,EACpB,OAAA,EAAS,SAAA;AAAA,EACT,IAAA,EAAM,iBAAA;AAAA,EACN,IAAA,EAAM,KAAA;AAAA,EACN,GAAA,EAAK,KAAA;AAAA,EACL,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM,MAAA;AAAA,EACN,YAAA,EAAc,MAAA;AAAA,EACd,gBAAA,EAAkB,eAAA;AAAA,EAClB,KAAA,EAAO,eAAA;AAAA,EACP,cAAA,EAAgB,aAAA;AAAA,EAChB,WAAA,EAAa,UAAA;AAAA,EACb,WAAA,EAAa,UAAA;AAAA,EACb,OAAA,EAAS,UAAA;AAAA,EACT,aAAA,EAAe,YAAA;AAAA,EACf,IAAA,EAAM,MAAA;AAAA,EACN,GAAA,EAAK,KAAA;AAAA,EACL,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM,MAAA;AAAA,EACN,gBAAA,EAAkB,eAAA;AAAA,EAClB,QAAA,EAAU,UAAA;AAAA,EACV,IAAA,EAAM;AACR,CAAA;AAOO,SAAS,kBAAkB,IAAA,EAAwD;AACxF,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,OAAO,OAAO,IAAA,CAAK,IAAA,EAAK,CAAE,WAAA,EAAa,CAAA,IAAK,IAAA;AAC9C;ACzCO,SAAS,uBAAuB,IAAA,EAAqC;AAC1E,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAwB,IAAI,CAAA;AAEpD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAEnC,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,MAAM,GAAA,GAAM,MAAA,CACT,gBAAA,CAAiB,QAAA,CAAS,eAAe,CAAA,CACzC,gBAAA,CAAiB,CAAA,cAAA,EAAiB,IAAI,EAAE,CAAA,CACxC,IAAA,EAAK,CAEL,OAAA,CAAQ,gBAAgB,EAAE,CAAA;AAC7B,MAAA,OAAA,CAAQ,GAAA,CAAI,MAAA,GAAS,CAAA,GAAI,GAAA,GAAM,IAAI,CAAA;AAAA,IACrC,CAAA;AAEA,IAAA,IAAA,EAAK;AAEL,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,IAAI,CAAA;AAC1C,IAAA,QAAA,CAAS,OAAA,CAAQ,SAAS,IAAA,EAAM,EAAE,WAAW,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AAClE,IAAA,OAAO,MAAM,SAAS,UAAA,EAAW;AAAA,EACnC,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,OAAO,IAAA;AACT","file":"chunk-NV6WHTEZ.js","sourcesContent":["import type { ComponentType } from 'react'\nimport {\n FiAlertCircle,\n FiBattery,\n FiBatteryCharging,\n FiAlertTriangle,\n FiBell,\n FiGrid,\n FiHelpCircle,\n FiInfo,\n FiLifeBuoy,\n FiMail,\n FiMessageSquare,\n FiMoon,\n FiSettings,\n FiSun,\n FiUser,\n FiZap,\n} from 'react-icons/fi'\n\nexport type GlyphComponent = ComponentType<{ size?: number | string; className?: string }>\n\n/**\n * Brand-glyph registry: maps the icon NAME the Brand API emits (e.g.\n * `--topbar-icon-comms-fuel: bolt`) to a component.\n *\n * These names are Feather/Lucide icon names, NOT asset filenames — there is no\n * `/brand/icons/<name>.svg` for them in any app, and treating them as URLs\n * renders a broken image. Resolving them against the icon library the shell\n * already depends on keeps every app consistent with zero vendored assets.\n *\n * Aliases are included where Brand and Feather disagree on a name (`bolt` vs\n * `zap`, `life-buoy` vs `life-ring`).\n */\nconst GLYPHS: Record<string, GlyphComponent> = {\n // Communications Fuel reads as a LEVEL, so its glyph is a battery. `bolt`/\n // `zap` stay mapped for older Brand values.\n 'battery-charging': FiBatteryCharging,\n battery: FiBattery,\n fuel: FiBatteryCharging,\n bolt: FiZap,\n zap: FiZap,\n grid: FiGrid,\n apps: FiGrid,\n bell: FiBell,\n notification: FiBell,\n 'alert-triangle': FiAlertTriangle,\n alert: FiAlertTriangle,\n 'alert-circle': FiAlertCircle,\n 'life-buoy': FiLifeBuoy,\n 'life-ring': FiLifeBuoy,\n support: FiLifeBuoy,\n 'help-circle': FiHelpCircle,\n moon: FiMoon,\n sun: FiSun,\n info: FiInfo,\n mail: FiMail,\n 'message-square': FiMessageSquare,\n settings: FiSettings,\n user: FiUser,\n}\n\n/**\n * Resolve a Brand glyph name to a component. Returns null for an unknown name\n * so the caller renders its own fallback — an unrecognized token must never\n * produce a broken or empty icon.\n */\nexport function resolveBrandGlyph(name: string | null | undefined): GlyphComponent | null {\n if (!name) return null\n return GLYPHS[name.trim().toLowerCase()] ?? null\n}\n\n/** Names the registry knows — exported for tests and tooling. */\nexport const KNOWN_BRAND_GLYPHS = Object.keys(GLYPHS)\n","import { useEffect, useState } from 'react'\n\n/**\n * The six canonical top-bar action slots (Reference/Global-Rules v9 → top-bar\n * icons). Each slot's GLYPH is unique and comes from the Brand API\n * `topbarIcons.items.*` tokens, exposed as `--topbar-icon-<slot>` CSS vars\n * whose value is the brand-icon NAME. Every OTHER property — size, gap, color,\n * hover, selected — is universal across all six slots.\n */\nexport type TopBarIconSlot =\n | 'comms-fuel'\n | 'apps'\n | 'notifications'\n | 'alerts'\n | 'support'\n | 'dark-mode'\n\n/**\n * Reads the glyph NAME for a slot from its `--topbar-icon-<slot>` CSS var.\n *\n * Runs in an effect because the Brand stylesheet is appended to <head> at\n * runtime (Global Rules forbids baking it into the build), so the var is not\n * resolvable during SSR or the first synchronous render. The MutationObserver\n * re-reads once the stylesheet lands so the glyph upgrades from the caller's\n * fallback without a reload.\n *\n * Returns null when the slot has no Brand glyph — callers render their own\n * fallback icon in that case.\n */\nexport function useTopBarIconSlotGlyph(slot: TopBarIconSlot): string | null {\n const [name, setName] = useState<string | null>(null)\n\n useEffect(() => {\n if (typeof window === 'undefined') return\n\n const read = () => {\n const raw = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(`--topbar-icon-${slot}`)\n .trim()\n // Brand may emit the name quoted (e.g. \"bell\"); strip the quotes.\n .replace(/^['\"]|['\"]$/g, '')\n setName(raw.length > 0 ? raw : null)\n }\n\n read()\n\n const observer = new MutationObserver(read)\n observer.observe(document.head, { childList: true, subtree: true })\n return () => observer.disconnect()\n }, [slot])\n\n return name\n}\n\n/** Path to a brand-icon SVG in the consuming app's public dir. */\nexport function brandIconSrc(name: string, basePath = '/brand/icons/') {\n return `${basePath}${name}.svg`\n}\n"]}