@the-portland-company/shell 0.97.0 → 0.98.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/CHANGELOG.md +17 -0
- package/dist/app-chrome.cjs +39 -29
- package/dist/app-chrome.cjs.map +1 -1
- package/dist/app-chrome.d.cts +1 -1
- package/dist/app-chrome.d.ts +1 -1
- package/dist/app-chrome.js +4 -4
- package/dist/brand-favicon.cjs.map +1 -1
- package/dist/brand-favicon.js +1 -1
- package/dist/{chunk-WQR42AGC.js → chunk-IVLXZFGV.js} +32 -29
- package/dist/chunk-IVLXZFGV.js.map +1 -0
- package/dist/{chunk-BMR5WAWH.js → chunk-Q5DTPY5N.js} +26 -3
- package/dist/chunk-Q5DTPY5N.js.map +1 -0
- package/dist/{chunk-VAQNZD37.js → chunk-WOOBPM4V.js} +99 -7
- package/dist/chunk-WOOBPM4V.js.map +1 -0
- package/dist/{index-BaUIPQpN.d.cts → index-CUPeC2Ji.d.cts} +46 -2
- package/dist/{index-BEMGfLpI.d.ts → index-DAD6tSfV.d.ts} +46 -2
- package/dist/index.cjs +139 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/native.cjs +153 -31
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +1 -1
- package/dist/native.d.ts +1 -1
- package/dist/native.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-BMR5WAWH.js.map +0 -1
- package/dist/chunk-VAQNZD37.js.map +0 -1
- package/dist/chunk-WQR42AGC.js.map +0 -1
|
@@ -47,6 +47,29 @@ function useBrandAssets() {
|
|
|
47
47
|
}, []);
|
|
48
48
|
return assets;
|
|
49
49
|
}
|
|
50
|
+
function useBrandAsset(kind) {
|
|
51
|
+
const [url, setUrl] = useState(null);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
let done = false;
|
|
54
|
+
const read = () => {
|
|
55
|
+
if (done) return;
|
|
56
|
+
const next = readBrandAsset(kind);
|
|
57
|
+
setUrl((prev) => prev === next ? prev : next);
|
|
58
|
+
};
|
|
59
|
+
const links = Array.from(
|
|
60
|
+
document.querySelectorAll('link[rel="stylesheet"][href*="api/tokens"]')
|
|
61
|
+
);
|
|
62
|
+
links.forEach((l) => l.addEventListener("load", read));
|
|
63
|
+
const timers = RETRY_MS.map((ms) => window.setTimeout(read, ms));
|
|
64
|
+
read();
|
|
65
|
+
return () => {
|
|
66
|
+
done = true;
|
|
67
|
+
links.forEach((l) => l.removeEventListener("load", read));
|
|
68
|
+
timers.forEach((t) => window.clearTimeout(t));
|
|
69
|
+
};
|
|
70
|
+
}, [kind]);
|
|
71
|
+
return url;
|
|
72
|
+
}
|
|
50
73
|
|
|
51
74
|
// src/lib/brandFavicon.ts
|
|
52
75
|
var BRAND_FAVICON_LINK_ID = "politogy-brand-favicon";
|
|
@@ -106,6 +129,6 @@ function BrandFavicon() {
|
|
|
106
129
|
return null;
|
|
107
130
|
}
|
|
108
131
|
|
|
109
|
-
export { BRAND_APPLE_ICON_LINK_ID, BRAND_FAVICON_LINK_ID, BrandFavicon, applyBrandFavicon, useBrandAssets, watchBrandFavicon };
|
|
110
|
-
//# sourceMappingURL=chunk-
|
|
111
|
-
//# sourceMappingURL=chunk-
|
|
132
|
+
export { BRAND_APPLE_ICON_LINK_ID, BRAND_FAVICON_LINK_ID, BrandFavicon, applyBrandFavicon, useBrandAsset, useBrandAssets, watchBrandFavicon };
|
|
133
|
+
//# sourceMappingURL=chunk-Q5DTPY5N.js.map
|
|
134
|
+
//# sourceMappingURL=chunk-Q5DTPY5N.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/brandAssets.ts","../src/lib/brandFavicon.ts"],"names":["RETRY_MS","useEffect"],"mappings":"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","file":"chunk-Q5DTPY5N.js","sourcesContent":["// Brand assets — logo URLs read at RUNTIME from the Brand token sheet.\n//\n// Brand guideline \"Logo standard: use the uploaded Brand assets as-is\": apps\n// (and the shell) never bundle their own copy of a logo; they read the URLs\n// from the Brand `assets` group. `/api/tokens?format=css` emits each set asset\n// as `--asset-<kebab>: url(\"…\")` on `:root`, and every app already loads that\n// sheet at runtime (see ../runtime-tokens.ts), so the rail logo is resolved\n// from the same live sheet as every other chrome value — a Brand upload swaps\n// the logo in every app without a deploy, and there is nothing to fall back to\n// that could drift.\n\n'use client'\n\nimport { useEffect, useState } from 'react'\n\n/** Brand `assets` keys the chrome renders, by their `--asset-<kebab>` name. */\nexport type BrandAssetKind = 'logo-horizontal' | 'logo-square' | 'favicon' | 'apple-icon' | 'verified-icon'\n\n/** `url(\"https://…\")` / `url(https://…)` → the bare https URL, else null. */\nexport function parseCssUrl(value: string | null | undefined): string | null {\n if (!value) return null\n const m = /^url\\(\\s*(['\"]?)(.*?)\\1\\s*\\)$/i.exec(value.trim())\n const url = m?.[2]?.trim()\n return url && /^https:\\/\\//i.test(url) ? url : null\n}\n\n/** One Brand asset URL from the live token sheet, or null while it is unset. */\nexport function readBrandAsset(kind: BrandAssetKind): string | null {\n if (typeof document === 'undefined') return null\n try {\n return parseCssUrl(\n window.getComputedStyle(document.documentElement).getPropertyValue(`--asset-${kind}`),\n )\n } catch {\n return null\n }\n}\n\nexport type BrandAssets = {\n /** `assets.logoHorizontal` — the all-white lockup at the top of the rail. */\n logoHorizontal: string | null\n /** `assets.logoSquare` — the all-white vrm tile on the collapsed rail. */\n logoSquare: string | null\n}\n\nconst EMPTY: BrandAssets = { logoHorizontal: null, logoSquare: null }\n\n// The token sheet is a <link> the app appends at startup, so it may still be\n// in flight on first paint. Re-read when it loads, and a few times after, to\n// cover a link that is inserted after this effect ran.\nconst RETRY_MS = [0, 250, 1000, 3000]\n\n/**\n * The Brand logo URLs, resolved after mount (null on the server and until the\n * runtime token sheet has loaded). Callers reserve the logo's box and draw\n * nothing while a value is null — never a stand-in image.\n */\nexport function useBrandAssets(): BrandAssets {\n const [assets, setAssets] = useState<BrandAssets>(EMPTY)\n useEffect(() => {\n let done = false\n const read = () => {\n if (done) return\n const next = {\n logoHorizontal: readBrandAsset('logo-horizontal'),\n logoSquare: readBrandAsset('logo-square'),\n }\n setAssets((prev) =>\n prev.logoHorizontal === next.logoHorizontal && prev.logoSquare === next.logoSquare\n ? prev\n : next,\n )\n }\n const links = Array.from(\n document.querySelectorAll<HTMLLinkElement>('link[rel=\"stylesheet\"][href*=\"api/tokens\"]'),\n )\n links.forEach((l) => l.addEventListener('load', read))\n const timers = RETRY_MS.map((ms) => window.setTimeout(read, ms))\n read()\n return () => {\n done = true\n links.forEach((l) => l.removeEventListener('load', read))\n timers.forEach((t) => window.clearTimeout(t))\n }\n }, [])\n return assets\n}\n\n/**\n * One Brand asset URL, resolved after mount the same way as the rail logos\n * (null on the server and until the runtime token sheet has loaded). Used by\n * the VRM Verified badge for `assets.verifiedIcon` (`--asset-verified-icon`).\n */\nexport function useBrandAsset(kind: BrandAssetKind): string | null {\n const [url, setUrl] = useState<string | null>(null)\n useEffect(() => {\n let done = false\n const read = () => {\n if (done) return\n const next = readBrandAsset(kind)\n setUrl((prev) => (prev === next ? prev : next))\n }\n const links = Array.from(\n document.querySelectorAll<HTMLLinkElement>('link[rel=\"stylesheet\"][href*=\"api/tokens\"]'),\n )\n links.forEach((l) => l.addEventListener('load', read))\n const timers = RETRY_MS.map((ms) => window.setTimeout(read, ms))\n read()\n return () => {\n done = true\n links.forEach((l) => l.removeEventListener('load', read))\n timers.forEach((t) => window.clearTimeout(t))\n }\n }, [kind])\n return url\n}\n","// Browser-tab icon — Brand `assets.favicon` read at RUNTIME from the Brand\n// token sheet, the same way the rail logo is (./brandAssets).\n//\n// `politogyAppIcons()` (../app-icons) resolves the icon on the SERVER from\n// specs.politogyvrm.com/api/icons/<app>. In production that request comes from\n// a Worker, not a browser, and Cloudflare's bot check answers it with a\n// challenge page, so the metadata comes back with no icon and the tab shows the\n// browser default (or an app's leftover Next.js `favicon.ico` triangle). The\n// token sheet, by contrast, is loaded by the BROWSER in every app, and emits\n// `--asset-favicon` / `--asset-apple-icon` from Brand `assets.*`. Reading those\n// gives every app the Brand's VRM tile with no static file in any repo (Global\n// Rules → App Icons) and no extra request.\n//\n// The link carries a fixed id and is kept the LAST icon link in <head>, so a\n// stale icon from metadata or an old static file never wins over the Brand's.\n\n'use client'\n\nimport { useEffect } from 'react'\n\nimport { readBrandAsset } from './brandAssets'\n\nexport const BRAND_FAVICON_LINK_ID = 'politogy-brand-favicon'\nexport const BRAND_APPLE_ICON_LINK_ID = 'politogy-brand-apple-icon'\n\nfunction upsertLink(id: string, rel: string, href: string): void {\n let link = document.getElementById(id) as HTMLLinkElement | null\n if (!link) {\n link = document.createElement('link')\n link.id = id\n link.rel = rel\n }\n if (link.getAttribute('href') !== href) link.href = href\n // Last icon link in <head> wins. Re-appending an already-last node is a no-op\n // for the browser, so only move it when something was added after it.\n const icons = document.head.querySelectorAll(`link[rel~=\"${rel.split(' ')[0]}\"]`)\n if (icons[icons.length - 1] !== link) document.head.appendChild(link)\n}\n\n/**\n * Point the tab icon (and the iOS home-screen icon) at the Brand's uploaded\n * assets. Returns true once the favicon was set; false while the token sheet\n * has not defined `--asset-favicon` yet. Never draws a stand-in.\n */\nexport function applyBrandFavicon(): boolean {\n if (typeof document === 'undefined') return false\n const favicon = readBrandAsset('favicon')\n if (!favicon) return false\n upsertLink(BRAND_FAVICON_LINK_ID, 'icon', favicon)\n const apple = readBrandAsset('apple-icon')\n if (apple) upsertLink(BRAND_APPLE_ICON_LINK_ID, 'apple-touch-icon', apple)\n return true\n}\n\n// The token sheet is a <link> the app appends at startup, so it may still be in\n// flight on first paint. Re-read when it loads and a few times after.\nconst RETRY_MS = [0, 250, 1000, 3000]\n\n/**\n * Apply the Brand favicon now and keep it applied: on token sheet load, on a\n * few retries, and whenever <head> changes (a client navigation can re-insert\n * metadata icon links after ours). Returns a cleanup function.\n */\nexport function watchBrandFavicon(): () => void {\n if (typeof document === 'undefined') return () => {}\n let done = false\n const apply = () => {\n if (!done) applyBrandFavicon()\n }\n // A token sheet inserted after mount is picked up by the observer below.\n const sheets = new Set<HTMLLinkElement>()\n const listen = () => {\n document\n .querySelectorAll<HTMLLinkElement>('link[rel=\"stylesheet\"][href*=\"api/tokens\"]')\n .forEach((l) => {\n if (sheets.has(l)) return\n sheets.add(l)\n l.addEventListener('load', apply)\n })\n }\n listen()\n const timers = RETRY_MS.map((ms) => window.setTimeout(apply, ms))\n const observer =\n typeof MutationObserver === 'undefined'\n ? null\n : new MutationObserver(() => {\n listen()\n apply()\n })\n observer?.observe(document.head, { childList: true })\n return () => {\n done = true\n sheets.forEach((l) => l.removeEventListener('load', apply))\n timers.forEach((t) => window.clearTimeout(t))\n observer?.disconnect()\n }\n}\n\n/** Renders nothing; sets the Brand favicon after mount. PolitogyAppFrame renders it. */\nexport function BrandFavicon(): null {\n useEffect(() => watchBrandFavicon(), [])\n return null\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readThemeCookie, THEME_STORAGE_KEY, isThemePreference, applyThemePreference, readPendingThemeChoice, writeThemeCookie, clearPendingThemeChoice, markThemeChoicePending } from './chunk-BHRVZPZ7.js';
|
|
2
|
+
import { useBrandAsset } from './chunk-Q5DTPY5N.js';
|
|
2
3
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
4
|
import { createContext, useState, useRef, useCallback, useEffect, useLayoutEffect, useContext, useMemo, useSyncExternalStore } from 'react';
|
|
4
5
|
import { createPortal } from 'react-dom';
|
|
@@ -344,6 +345,90 @@ function RowMenuItem({
|
|
|
344
345
|
}
|
|
345
346
|
);
|
|
346
347
|
}
|
|
348
|
+
var VRM_VERIFIED_TOOLTIP = "Politogy has confirmed this is a real, registered voter.";
|
|
349
|
+
var VRM_TIER_LABELS = {
|
|
350
|
+
verified: "VRM Verified",
|
|
351
|
+
identified: "Identified",
|
|
352
|
+
anonymous: "Anonymous",
|
|
353
|
+
stale: "Stale",
|
|
354
|
+
inactive: "Inactive"
|
|
355
|
+
};
|
|
356
|
+
var TIER_TOOLTIPS = {
|
|
357
|
+
verified: VRM_VERIFIED_TOOLTIP,
|
|
358
|
+
identified: "Identified: we know who this is, but Politogy has not verified them.",
|
|
359
|
+
anonymous: "Anonymous: nothing identifying has been captured yet.",
|
|
360
|
+
stale: "Stale: was VRM Verified, but the proof is more than 12 months old.",
|
|
361
|
+
inactive: "Inactive: the voter file marks this registration inactive or canceled."
|
|
362
|
+
};
|
|
363
|
+
var DOT_FALLBACK = {
|
|
364
|
+
identified: "#a855f7",
|
|
365
|
+
anonymous: "var(--color-graphite, #2b2b2b)",
|
|
366
|
+
stale: "#eab308",
|
|
367
|
+
inactive: "var(--muted, #8a8a8a)"
|
|
368
|
+
};
|
|
369
|
+
function VrmVerifiedBadge({ tier, size, showLabel = true, className, style }) {
|
|
370
|
+
const icon = useBrandAsset("verified-icon");
|
|
371
|
+
const known = tier && tier in VRM_TIER_LABELS ? tier : null;
|
|
372
|
+
const label = known ? VRM_TIER_LABELS[known] : "Not yet computed";
|
|
373
|
+
const title = known ? TIER_TOOLTIPS[known] : "The VRM Verified tier has not been worked out yet.";
|
|
374
|
+
const iconSize = size ?? 16;
|
|
375
|
+
const dotSize = size ?? 8;
|
|
376
|
+
return /* @__PURE__ */ jsxs(
|
|
377
|
+
"span",
|
|
378
|
+
{
|
|
379
|
+
"data-vrm-tier": known ?? "none",
|
|
380
|
+
title,
|
|
381
|
+
"aria-label": showLabel ? void 0 : label,
|
|
382
|
+
role: showLabel ? void 0 : "img",
|
|
383
|
+
className,
|
|
384
|
+
style: {
|
|
385
|
+
display: "inline-flex",
|
|
386
|
+
alignItems: "center",
|
|
387
|
+
gap: 6,
|
|
388
|
+
borderRadius: 9999,
|
|
389
|
+
border: "1px solid var(--line, #e5e5e5)",
|
|
390
|
+
padding: "2px 10px",
|
|
391
|
+
fontSize: 12,
|
|
392
|
+
fontWeight: 600,
|
|
393
|
+
lineHeight: 1.4,
|
|
394
|
+
whiteSpace: "nowrap",
|
|
395
|
+
...style
|
|
396
|
+
},
|
|
397
|
+
children: [
|
|
398
|
+
known === "verified" ? (
|
|
399
|
+
// The box is reserved while the Brand sheet loads; nothing stands in.
|
|
400
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, style: { display: "inline-block", width: iconSize, height: iconSize, flexShrink: 0 }, children: icon ? /* @__PURE__ */ jsx(
|
|
401
|
+
"img",
|
|
402
|
+
{
|
|
403
|
+
src: icon,
|
|
404
|
+
alt: "",
|
|
405
|
+
width: iconSize,
|
|
406
|
+
height: iconSize,
|
|
407
|
+
draggable: false,
|
|
408
|
+
"data-testid": "vrm-verified-icon",
|
|
409
|
+
style: { display: "block", width: iconSize, height: iconSize }
|
|
410
|
+
}
|
|
411
|
+
) : null })
|
|
412
|
+
) : /* @__PURE__ */ jsx(
|
|
413
|
+
"span",
|
|
414
|
+
{
|
|
415
|
+
"aria-hidden": true,
|
|
416
|
+
style: {
|
|
417
|
+
display: "inline-block",
|
|
418
|
+
width: dotSize,
|
|
419
|
+
height: dotSize,
|
|
420
|
+
borderRadius: 9999,
|
|
421
|
+
flexShrink: 0,
|
|
422
|
+
background: known ? `var(--vrm-tier-${known}, ${DOT_FALLBACK[known]})` : "transparent",
|
|
423
|
+
border: known ? void 0 : "1px dashed var(--muted, #8a8a8a)"
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
),
|
|
427
|
+
showLabel ? /* @__PURE__ */ jsx("span", { children: label }) : null
|
|
428
|
+
]
|
|
429
|
+
}
|
|
430
|
+
);
|
|
431
|
+
}
|
|
347
432
|
function FormColumn({ children, className }) {
|
|
348
433
|
return /* @__PURE__ */ jsx("div", { "data-shell-form-column": "", className: clsx2("w-full max-w-[960px]", className), children });
|
|
349
434
|
}
|
|
@@ -609,19 +694,26 @@ function TopBarCountBadge({ count }) {
|
|
|
609
694
|
}
|
|
610
695
|
function TopBarTooltip({
|
|
611
696
|
title,
|
|
612
|
-
description
|
|
697
|
+
description,
|
|
698
|
+
align = "center"
|
|
613
699
|
}) {
|
|
700
|
+
const bodyPosition = align === "end" ? "right-0" : "left-1/2 -translate-x-1/2";
|
|
701
|
+
const arrowPosition = align === "end" ? "" : "left-1/2 -translate-x-1/2";
|
|
702
|
+
const arrowStyle = align === "end" ? { right: "calc(var(--topbar-icon-button-size, 34px) / 2 - 5px)" } : void 0;
|
|
614
703
|
return /* @__PURE__ */ jsxs(
|
|
615
704
|
"span",
|
|
616
705
|
{
|
|
617
706
|
role: "tooltip",
|
|
618
|
-
|
|
707
|
+
"data-tooltip-align": align,
|
|
708
|
+
className: `pointer-events-none absolute ${bodyPosition} top-full z-50 mt-2 hidden w-max max-w-56 flex-col rounded-lg border border-[color:var(--app-btn-tooltip-bg,#2F3136)] bg-[color:var(--app-btn-tooltip-bg,#2F3136)] px-3 py-2 text-left shadow-[var(--shadow-soft)] group-hover/tbtip:flex group-focus-visible/tbtip:flex`,
|
|
619
709
|
children: [
|
|
620
710
|
/* @__PURE__ */ jsx(
|
|
621
711
|
"span",
|
|
622
712
|
{
|
|
623
713
|
"aria-hidden": true,
|
|
624
|
-
|
|
714
|
+
"data-tooltip-arrow": true,
|
|
715
|
+
style: arrowStyle,
|
|
716
|
+
className: `absolute -top-[5px] ${arrowPosition} h-2.5 w-2.5 rotate-45 border-l border-t border-[color:var(--app-btn-tooltip-bg,#2F3136)] bg-[color:var(--app-btn-tooltip-bg,#2F3136)]`
|
|
625
717
|
}
|
|
626
718
|
),
|
|
627
719
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-[color:var(--app-btn-tooltip-fg,#FFFFFF)]", children: title }),
|
|
@@ -2294,7 +2386,7 @@ function useThemePreference() {
|
|
|
2294
2386
|
function TopBarLinkAction({ label, description, href, icon: Icon }) {
|
|
2295
2387
|
return /* @__PURE__ */ jsxs("a", { href, "aria-label": label, className: topBarIconButtonClass(), children: [
|
|
2296
2388
|
/* @__PURE__ */ jsx(Icon, { size: TOPBAR_GLYPH_SIZE, className: "text-current" }),
|
|
2297
|
-
/* @__PURE__ */ jsx(TopBarTooltip, { title: label, description })
|
|
2389
|
+
/* @__PURE__ */ jsx(TopBarTooltip, { title: label, description, align: "end" })
|
|
2298
2390
|
] });
|
|
2299
2391
|
}
|
|
2300
2392
|
function OrganizationSettingsAction({ href }) {
|
|
@@ -2726,6 +2818,6 @@ function BreadcrumbBarView({
|
|
|
2726
2818
|
);
|
|
2727
2819
|
}
|
|
2728
2820
|
|
|
2729
|
-
export { AI_CREDITS_STATE_TITLES, AiCreditsState, BreadcrumbBarView, CORE_APP_ORIGIN, CORE_BILLING_PATH, CREDIT_TYPE_LABELS, CREDIT_TYPE_ORDER, Card, CreditsAction, FormColumn, FuelAction, HeaderTabBar, KNOWN_TAB_GLYPHS, MyProfileAction, NAV_DISPLAY_OPTIONS, NavChromeProvider, NavDisplayAction, NavThemeControl, NotificationsAction, OrganizationSettingsAction, PageHeaderView, RowMenu, RowMenuItem, SPECS_ORIGIN, SpecOverlayAction, SpeculationRulesScript, SupportAction, TOPBAR_GLYPH_SIZE, TopBarCountBadge, TopBarLinkAction, TopBarPanelArrow, TopBarPopover, TopBarTooltip, TopBarWidgetSlot, aiCreditsWalletUrl, buildNavSpeculationRules, buildSpeculationRules, collectSiblingAppUrls, createCommsNotificationsAdapter, creditGaugeRatio, creditStateWord, creditTooltipLine, creditsAriaLabel, creditsIconState, emptyNotificationsFeed, normalizeNotificationsFeed, resolveBrandGlyph, resolveOrgLogoUrl, resolveTabGlyph, rowMenuPosition, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeDedupedFetch, useNavChromeFetcher, useThemePreference, useTopBarIconSlotGlyph, warnDeprecated };
|
|
2730
|
-
//# sourceMappingURL=chunk-
|
|
2731
|
-
//# sourceMappingURL=chunk-
|
|
2821
|
+
export { AI_CREDITS_STATE_TITLES, AiCreditsState, BreadcrumbBarView, CORE_APP_ORIGIN, CORE_BILLING_PATH, CREDIT_TYPE_LABELS, CREDIT_TYPE_ORDER, Card, CreditsAction, FormColumn, FuelAction, HeaderTabBar, KNOWN_TAB_GLYPHS, MyProfileAction, NAV_DISPLAY_OPTIONS, NavChromeProvider, NavDisplayAction, NavThemeControl, NotificationsAction, OrganizationSettingsAction, PageHeaderView, RowMenu, RowMenuItem, SPECS_ORIGIN, SpecOverlayAction, SpeculationRulesScript, SupportAction, TOPBAR_GLYPH_SIZE, TopBarCountBadge, TopBarLinkAction, TopBarPanelArrow, TopBarPopover, TopBarTooltip, TopBarWidgetSlot, VRM_TIER_LABELS, VRM_VERIFIED_TOOLTIP, VrmVerifiedBadge, aiCreditsWalletUrl, buildNavSpeculationRules, buildSpeculationRules, collectSiblingAppUrls, createCommsNotificationsAdapter, creditGaugeRatio, creditStateWord, creditTooltipLine, creditsAriaLabel, creditsIconState, emptyNotificationsFeed, normalizeNotificationsFeed, resolveBrandGlyph, resolveOrgLogoUrl, resolveTabGlyph, rowMenuPosition, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeDedupedFetch, useNavChromeFetcher, useThemePreference, useTopBarIconSlotGlyph, warnDeprecated };
|
|
2822
|
+
//# sourceMappingURL=chunk-WOOBPM4V.js.map
|
|
2823
|
+
//# sourceMappingURL=chunk-WOOBPM4V.js.map
|