@the-portland-company/shell 0.97.1 → 0.99.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 +18 -0
- 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-XPTC47TY.js → chunk-PQQLCUNO.js} +255 -3
- package/dist/chunk-PQQLCUNO.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-5IRZD6GF.js → chunk-YMCWLO2L.js} +3 -3
- package/dist/{chunk-5IRZD6GF.js.map → chunk-YMCWLO2L.js.map} +1 -1
- package/dist/{index-SHcw15A4.d.cts → index-DhrhpBVm.d.cts} +49 -1
- package/dist/{index-smsLP_tM.d.ts → index-Di9AyVsU.d.ts} +49 -1
- package/dist/index.cjs +301 -20
- 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 +313 -30
- 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-XPTC47TY.js.map +0 -1
package/dist/app-chrome.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { S as StandardNavIconKey,
|
|
3
|
+
import { S as StandardNavIconKey, z as NavIcon, N as NavItem, D as NavBreadcrumb, E as StandardNavMode, G as NavLinkComponent, I as NavChromeFetcher, J as NavMode, L as NavUserMenu, M as NavOrgOption, i as NotificationsAdapter, O as NavFooterLink, Q as NavFooter, U as NavDisplayMode } from './index-DhrhpBVm.cjs';
|
|
4
4
|
import './theme-preference.cjs';
|
|
5
5
|
import './brand-favicon.cjs';
|
|
6
6
|
|
package/dist/app-chrome.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { S as StandardNavIconKey,
|
|
3
|
+
import { S as StandardNavIconKey, z as NavIcon, N as NavItem, D as NavBreadcrumb, E as StandardNavMode, G as NavLinkComponent, I as NavChromeFetcher, J as NavMode, L as NavUserMenu, M as NavOrgOption, i as NotificationsAdapter, O as NavFooterLink, Q as NavFooter, U as NavDisplayMode } from './index-Di9AyVsU.js';
|
|
4
4
|
import './theme-preference.js';
|
|
5
5
|
import './brand-favicon.js';
|
|
6
6
|
|
package/dist/app-chrome.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { broadcastLogout, watchLogout } from './chunk-LL6LSJAH.js';
|
|
3
3
|
import { writeUrlState } from './chunk-GVQKZI5X.js';
|
|
4
|
-
import { clearBetaBannerDismissal, standardPolitogyNav, standardNavIcons, isNavItemActive, NavAppShell } from './chunk-
|
|
5
|
-
export { standardNavIcons } from './chunk-
|
|
4
|
+
import { clearBetaBannerDismissal, standardPolitogyNav, standardNavIcons, isNavItemActive, NavAppShell } from './chunk-YMCWLO2L.js';
|
|
5
|
+
export { standardNavIcons } from './chunk-YMCWLO2L.js';
|
|
6
6
|
import { orgIdTail, ORG_ID_QUERY_PARAM, settingsBaseUrl, authBaseUrl, readOrgSelectorFromUrl, matchOrgSelector, syncOrgIdInUrl, isOrgId, switchActiveOrg, ACTIVE_ORG_QUERY_PARAM, writeActiveOrgCookie, resolveActiveOrg, readActiveOrgCookie } from './chunk-5LO5W7W5.js';
|
|
7
|
-
import { warnDeprecated, NavChromeProvider, FuelAction, NotificationsAction, OrganizationSettingsAction, MyProfileAction, useChromeMe, useNavChromeDedupedFetch, useChromeOrgs, useNavChromeFetcher } from './chunk-
|
|
7
|
+
import { warnDeprecated, NavChromeProvider, FuelAction, NotificationsAction, OrganizationSettingsAction, MyProfileAction, useChromeMe, useNavChromeDedupedFetch, useChromeOrgs, useNavChromeFetcher } from './chunk-PQQLCUNO.js';
|
|
8
8
|
import './chunk-BHRVZPZ7.js';
|
|
9
9
|
import { NAV_DISPLAY_DEFAULT, resolveNavDisplay, writeNavDisplayLocal, writeNavDisplayCookie, isNavDisplayPreference, NAV_DISPLAY_STORAGE_KEY, readNavDisplayCookie } from './chunk-7YVJ7HQG.js';
|
|
10
|
-
import { useBrandAssets, BrandFavicon } from './chunk-
|
|
10
|
+
import { useBrandAssets, BrandFavicon } from './chunk-Q5DTPY5N.js';
|
|
11
11
|
import { createContext, useMemo, useRef, useEffect, useState, useCallback, useContext } from 'react';
|
|
12
12
|
import { createDevNotesClient, DevNotesProvider, DevNotesTaskListModal, DevNotesOverlay } from '@the-portland-company/devnotes';
|
|
13
13
|
import { LuContactRound, LuMegaphone, LuFilePenLine } from 'react-icons/lu';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/brandAssets.ts","../src/lib/brandFavicon.ts"],"names":["useEffect"],"mappings":"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","file":"brand-favicon.cjs","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'\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","// 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
|
+
{"version":3,"sources":["../src/lib/brandAssets.ts","../src/lib/brandFavicon.ts"],"names":["useEffect"],"mappings":"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","file":"brand-favicon.cjs","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"]}
|
package/dist/brand-favicon.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
export { BRAND_APPLE_ICON_LINK_ID, BRAND_FAVICON_LINK_ID, BrandFavicon, applyBrandFavicon, watchBrandFavicon } from './chunk-
|
|
2
|
+
export { BRAND_APPLE_ICON_LINK_ID, BRAND_FAVICON_LINK_ID, BrandFavicon, applyBrandFavicon, watchBrandFavicon } from './chunk-Q5DTPY5N.js';
|
|
3
3
|
//# sourceMappingURL=brand-favicon.js.map
|
|
4
4
|
//# sourceMappingURL=brand-favicon.js.map
|
|
@@ -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,257 @@ 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
|
+
verified: "#00A651",
|
|
365
|
+
identified: "#a855f7",
|
|
366
|
+
anonymous: "var(--color-graphite, #2b2b2b)",
|
|
367
|
+
stale: "#eab308",
|
|
368
|
+
inactive: "var(--muted, #8a8a8a)"
|
|
369
|
+
};
|
|
370
|
+
function VrmVerifiedBadge({ tier, variant = "pill", size, showLabel = true, className, style }) {
|
|
371
|
+
const known = tier && tier in VRM_TIER_LABELS ? tier : null;
|
|
372
|
+
if (variant === "icon") {
|
|
373
|
+
return known === "verified" ? /* @__PURE__ */ jsx(VerifiedIcon, { size: size ?? 16, className, style }) : null;
|
|
374
|
+
}
|
|
375
|
+
const label = known ? VRM_TIER_LABELS[known] : "Not yet computed";
|
|
376
|
+
const title = known ? TIER_TOOLTIPS[known] : "The VRM Verified tier has not been worked out yet.";
|
|
377
|
+
const dotSize = size ?? 8;
|
|
378
|
+
return /* @__PURE__ */ jsxs(
|
|
379
|
+
"span",
|
|
380
|
+
{
|
|
381
|
+
"data-vrm-tier": known ?? "none",
|
|
382
|
+
title,
|
|
383
|
+
"aria-label": showLabel ? void 0 : label,
|
|
384
|
+
role: showLabel ? void 0 : "img",
|
|
385
|
+
className,
|
|
386
|
+
style: {
|
|
387
|
+
display: "inline-flex",
|
|
388
|
+
alignItems: "center",
|
|
389
|
+
gap: 6,
|
|
390
|
+
borderRadius: 9999,
|
|
391
|
+
border: "1px solid var(--line, #e5e5e5)",
|
|
392
|
+
padding: "2px 10px",
|
|
393
|
+
fontSize: 12,
|
|
394
|
+
fontWeight: 600,
|
|
395
|
+
lineHeight: 1.4,
|
|
396
|
+
whiteSpace: "nowrap",
|
|
397
|
+
...style
|
|
398
|
+
},
|
|
399
|
+
children: [
|
|
400
|
+
/* @__PURE__ */ jsx(
|
|
401
|
+
"span",
|
|
402
|
+
{
|
|
403
|
+
"aria-hidden": true,
|
|
404
|
+
"data-vrm-dot": true,
|
|
405
|
+
style: {
|
|
406
|
+
display: "inline-block",
|
|
407
|
+
width: dotSize,
|
|
408
|
+
height: dotSize,
|
|
409
|
+
borderRadius: 9999,
|
|
410
|
+
flexShrink: 0,
|
|
411
|
+
background: known ? `var(--vrm-tier-${known}, ${DOT_FALLBACK[known]})` : "transparent",
|
|
412
|
+
border: known ? void 0 : "1px dashed var(--muted, #8a8a8a)"
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
),
|
|
416
|
+
showLabel ? /* @__PURE__ */ jsx("span", { children: label }) : null
|
|
417
|
+
]
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
function VerifiedIcon({ size, className, style }) {
|
|
422
|
+
const icon = useBrandAsset("verified-icon");
|
|
423
|
+
return (
|
|
424
|
+
// The box is reserved while the Brand sheet loads; nothing stands in.
|
|
425
|
+
/* @__PURE__ */ jsx(
|
|
426
|
+
"span",
|
|
427
|
+
{
|
|
428
|
+
"data-vrm-tier": "verified",
|
|
429
|
+
"data-vrm-variant": "icon",
|
|
430
|
+
role: "img",
|
|
431
|
+
"aria-label": VRM_TIER_LABELS.verified,
|
|
432
|
+
title: VRM_VERIFIED_TOOLTIP,
|
|
433
|
+
className,
|
|
434
|
+
style: { display: "inline-block", width: size, height: size, flexShrink: 0, verticalAlign: "middle", ...style },
|
|
435
|
+
children: icon ? /* @__PURE__ */ jsx(
|
|
436
|
+
"img",
|
|
437
|
+
{
|
|
438
|
+
src: icon,
|
|
439
|
+
alt: "",
|
|
440
|
+
width: size,
|
|
441
|
+
height: size,
|
|
442
|
+
draggable: false,
|
|
443
|
+
"data-testid": "vrm-verified-icon",
|
|
444
|
+
style: { display: "block", width: size, height: size }
|
|
445
|
+
}
|
|
446
|
+
) : null
|
|
447
|
+
}
|
|
448
|
+
)
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
var CONTACTS_ORIGIN = "https://contacts.politogyvrm.com";
|
|
452
|
+
function withOrg(path, orgId) {
|
|
453
|
+
return orgId ? `${path}?org=${encodeURIComponent(orgId)}` : path;
|
|
454
|
+
}
|
|
455
|
+
function contactEmbedUrl(contactId, orgId, origin = CONTACTS_ORIGIN) {
|
|
456
|
+
return withOrg(`${origin}/contacts/embed/${encodeURIComponent(contactId)}`, orgId);
|
|
457
|
+
}
|
|
458
|
+
function contactPageUrl(contactId, orgId, origin = CONTACTS_ORIGIN) {
|
|
459
|
+
return withOrg(`${origin}/contacts/${encodeURIComponent(contactId)}`, orgId);
|
|
460
|
+
}
|
|
461
|
+
function prefersReducedMotion() {
|
|
462
|
+
try {
|
|
463
|
+
return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
464
|
+
} catch {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
var iconButton = {
|
|
469
|
+
display: "inline-flex",
|
|
470
|
+
alignItems: "center",
|
|
471
|
+
justifyContent: "center",
|
|
472
|
+
borderRadius: 9999,
|
|
473
|
+
border: "1px solid var(--line, #d7dadf)",
|
|
474
|
+
padding: 6,
|
|
475
|
+
background: "transparent",
|
|
476
|
+
color: "var(--muted, #5c6b80)",
|
|
477
|
+
cursor: "pointer"
|
|
478
|
+
};
|
|
479
|
+
function ContactSlideIn({ contactId, orgId, onClose, contactsOrigin = CONTACTS_ORIGIN }) {
|
|
480
|
+
const [shown, setShown] = useState(false);
|
|
481
|
+
useEffect(() => {
|
|
482
|
+
if (!contactId) {
|
|
483
|
+
setShown(false);
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (prefersReducedMotion()) {
|
|
487
|
+
setShown(true);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
const id = requestAnimationFrame(() => setShown(true));
|
|
491
|
+
return () => cancelAnimationFrame(id);
|
|
492
|
+
}, [contactId]);
|
|
493
|
+
useEffect(() => {
|
|
494
|
+
if (!contactId) return;
|
|
495
|
+
const onKey = (event) => {
|
|
496
|
+
if (event.key === "Escape") onClose();
|
|
497
|
+
};
|
|
498
|
+
document.addEventListener("keydown", onKey);
|
|
499
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
500
|
+
}, [contactId, onClose]);
|
|
501
|
+
if (!contactId) return null;
|
|
502
|
+
return /* @__PURE__ */ jsx(
|
|
503
|
+
"div",
|
|
504
|
+
{
|
|
505
|
+
"data-testid": "contact-slide-in-overlay",
|
|
506
|
+
onClick: onClose,
|
|
507
|
+
style: { position: "fixed", inset: 0, zIndex: 60, background: "rgba(0, 0, 0, 0.4)" },
|
|
508
|
+
children: /* @__PURE__ */ jsxs(
|
|
509
|
+
"aside",
|
|
510
|
+
{
|
|
511
|
+
role: "dialog",
|
|
512
|
+
"aria-modal": "true",
|
|
513
|
+
"aria-label": "Contact card",
|
|
514
|
+
"data-testid": "contact-slide-in",
|
|
515
|
+
onClick: (event) => event.stopPropagation(),
|
|
516
|
+
style: {
|
|
517
|
+
position: "absolute",
|
|
518
|
+
top: 0,
|
|
519
|
+
right: 0,
|
|
520
|
+
bottom: 0,
|
|
521
|
+
width: "100%",
|
|
522
|
+
maxWidth: 672,
|
|
523
|
+
display: "flex",
|
|
524
|
+
flexDirection: "column",
|
|
525
|
+
background: "var(--panel, #ffffff)",
|
|
526
|
+
color: "var(--foreground, #2f3136)",
|
|
527
|
+
borderLeft: "1px solid var(--line, #d7dadf)",
|
|
528
|
+
boxShadow: "var(--shadow-soft, 0 10px 28px rgba(27, 28, 32, 0.14))",
|
|
529
|
+
transform: shown ? "translateX(0)" : "translateX(100%)",
|
|
530
|
+
transition: "transform 220ms cubic-bezier(0.16, 1, 0.3, 1)"
|
|
531
|
+
},
|
|
532
|
+
children: [
|
|
533
|
+
/* @__PURE__ */ jsxs(
|
|
534
|
+
"div",
|
|
535
|
+
{
|
|
536
|
+
style: {
|
|
537
|
+
display: "flex",
|
|
538
|
+
alignItems: "center",
|
|
539
|
+
justifyContent: "space-between",
|
|
540
|
+
gap: 12,
|
|
541
|
+
borderBottom: "1px solid var(--line, #d7dadf)",
|
|
542
|
+
padding: "12px 24px"
|
|
543
|
+
},
|
|
544
|
+
children: [
|
|
545
|
+
/* @__PURE__ */ jsx(
|
|
546
|
+
"p",
|
|
547
|
+
{
|
|
548
|
+
style: {
|
|
549
|
+
margin: 0,
|
|
550
|
+
fontSize: 12,
|
|
551
|
+
fontWeight: 600,
|
|
552
|
+
letterSpacing: "0.18em",
|
|
553
|
+
textTransform: "uppercase",
|
|
554
|
+
color: "var(--muted, #5c6b80)"
|
|
555
|
+
},
|
|
556
|
+
children: "Contact Card"
|
|
557
|
+
}
|
|
558
|
+
),
|
|
559
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
|
|
560
|
+
/* @__PURE__ */ jsx(
|
|
561
|
+
"a",
|
|
562
|
+
{
|
|
563
|
+
href: contactPageUrl(contactId, orgId, contactsOrigin),
|
|
564
|
+
target: "_top",
|
|
565
|
+
style: { fontSize: 13, fontWeight: 600, color: "var(--color-race-blue-500, #007bff)", textDecoration: "none" },
|
|
566
|
+
children: "Open in Contacts"
|
|
567
|
+
}
|
|
568
|
+
),
|
|
569
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-label": "Close contact card", title: "Close", onClick: onClose, style: iconButton, children: /* @__PURE__ */ jsxs("svg", { "aria-hidden": true, width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
570
|
+
/* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
|
|
571
|
+
/* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
|
|
572
|
+
] }) })
|
|
573
|
+
] })
|
|
574
|
+
]
|
|
575
|
+
}
|
|
576
|
+
),
|
|
577
|
+
/* @__PURE__ */ jsx(
|
|
578
|
+
"iframe",
|
|
579
|
+
{
|
|
580
|
+
title: "Contact card",
|
|
581
|
+
src: contactEmbedUrl(contactId, orgId, contactsOrigin),
|
|
582
|
+
"data-testid": "contact-slide-in-frame",
|
|
583
|
+
style: { flex: 1, minHeight: 0, width: "100%", border: 0, background: "var(--panel, #ffffff)" }
|
|
584
|
+
},
|
|
585
|
+
contactId
|
|
586
|
+
)
|
|
587
|
+
]
|
|
588
|
+
}
|
|
589
|
+
)
|
|
590
|
+
}
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
function useContactSlideIn() {
|
|
594
|
+
const [contactId, setContactId] = useState(null);
|
|
595
|
+
const open = useCallback((id) => setContactId(id), []);
|
|
596
|
+
const close = useCallback(() => setContactId(null), []);
|
|
597
|
+
return { contactId, open, close };
|
|
598
|
+
}
|
|
347
599
|
function FormColumn({ children, className }) {
|
|
348
600
|
return /* @__PURE__ */ jsx("div", { "data-shell-form-column": "", className: clsx2("w-full max-w-[960px]", className), children });
|
|
349
601
|
}
|
|
@@ -2733,6 +2985,6 @@ function BreadcrumbBarView({
|
|
|
2733
2985
|
);
|
|
2734
2986
|
}
|
|
2735
2987
|
|
|
2736
|
-
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 };
|
|
2737
|
-
//# sourceMappingURL=chunk-
|
|
2738
|
-
//# sourceMappingURL=chunk-
|
|
2988
|
+
export { AI_CREDITS_STATE_TITLES, AiCreditsState, BreadcrumbBarView, CONTACTS_ORIGIN, CORE_APP_ORIGIN, CORE_BILLING_PATH, CREDIT_TYPE_LABELS, CREDIT_TYPE_ORDER, Card, ContactSlideIn, 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, contactEmbedUrl, contactPageUrl, createCommsNotificationsAdapter, creditGaugeRatio, creditStateWord, creditTooltipLine, creditsAriaLabel, creditsIconState, emptyNotificationsFeed, normalizeNotificationsFeed, resolveBrandGlyph, resolveOrgLogoUrl, resolveTabGlyph, rowMenuPosition, topBarIconButtonClass, useChromeMe, useChromeOrgs, useContactSlideIn, useNavChromeDedupedFetch, useNavChromeFetcher, useThemePreference, useTopBarIconSlotGlyph, warnDeprecated };
|
|
2989
|
+
//# sourceMappingURL=chunk-PQQLCUNO.js.map
|
|
2990
|
+
//# sourceMappingURL=chunk-PQQLCUNO.js.map
|