@the-portland-company/shell 0.68.1 → 0.69.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.
@@ -2,6 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
3
  import { NavItem, NavBreadcrumb, StandardNavMode, NavLinkComponent, NavChromeFetcher, NavMode, NavUserMenu, NavOrgOption, StandardNavIconKey, NavIcon, NavFooter, NavDisplayMode } from './native.cjs';
4
4
  import './theme-preference.cjs';
5
+ import './FormColumn-DsNP6NVG.cjs';
5
6
 
6
7
  declare function deriveBreadcrumbs(items: NavItem[], pathname: string, opts?: {
7
8
  search?: string;
@@ -103,13 +104,16 @@ type PolitogyAppMode = StandardNavMode;
103
104
  * so widening the surface takes a shell release and a review by whoever owns
104
105
  * the shell.
105
106
  *
106
- * Never add a grant for a visual input. `contentWrapper` qualifies because the
107
- * app either does or does not already emit its own `<main>`; `breadcrumbs`
108
- * qualifies because only the app knows which record a deep link points at.
109
- * "Petitions wants a wider box" would not qualify — that is a look, and looks
110
- * come from tokens.
107
+ * Never add a grant for a visual input. `breadcrumbs` qualifies because only
108
+ * the app knows which record a deep link points at. "Petitions wants a wider
109
+ * box" would not qualify — that is a look, and looks come from tokens.
110
+ *
111
+ * RETIRED (0.69.0): the `contentWrapper` grant. The frame's `<main>` is fluid
112
+ * and apps never emit their own page container (Brand guideline "Content
113
+ * width is fluid"; Reference/UI-Platform → PolitogyAppFrame), so no app may be
114
+ * granted one. Do not re-add it.
111
115
  */
112
- type PolitogyFrameGrant = 'contentWrapper' | 'breadcrumbs' | 'title';
116
+ type PolitogyFrameGrant = 'breadcrumbs' | 'title';
113
117
  /**
114
118
  * The per-app registry — the ONLY place app identity lives. A new app adds a
115
119
  * row here and inherits every chrome behavior; it never re-derives one.
@@ -256,10 +260,10 @@ type PolitogyFrameData = {
256
260
  /** See `PolitogyFrameData.frame` — honored per the app's registry `grants`. */
257
261
  type PolitogyGrantedFrame = {
258
262
  /**
259
- * How the frame wraps page content. `'bare'` for an app that already emits
260
- * its own `<main>` + container, which the default otherwise nests inside
261
- * `mx-auto max-w-7xl` — producing a doubled gutter and, strictly, invalid
262
- * HTML (a `<main>` inside a `<main>`).
263
+ * @deprecated RETIRED in 0.69.0 and ignored: no app holds a `contentWrapper`
264
+ * grant any more. The frame's `<main>` is fluid; remove the app's own page
265
+ * container (`PageContainer`) and stop passing this. Still typed so an app
266
+ * that passes it keeps compiling until it is cleaned up.
263
267
  */
264
268
  contentWrapper?: 'padded' | 'bare';
265
269
  /**
@@ -288,9 +292,17 @@ type PolitogyCoreFrame = {
288
292
  mode?: NavMode;
289
293
  /** Real linked-account switching + core's theme persistence. */
290
294
  userMenu?: NavUserMenu;
291
- /** Mode-specific brand wordmark (core swaps it per operating Mode). */
295
+ /**
296
+ * @deprecated Ignored since 0.69.0. The rail logo is the all-white lockup
297
+ * from Brand `assets.logoHorizontal`, read at runtime, in every Mode —
298
+ * never a mode-specific or bundled wordmark (Left-Navigation §5).
299
+ */
292
300
  brandLogoSrc?: string;
293
- /** Core wraps every page in PageContainer, which emits its own <main>. */
301
+ /**
302
+ * @deprecated Core still wraps its pages in `PageContainer`, which emits its
303
+ * own `<main>`, so `'bare'` is honored for core until those pages are
304
+ * migrated to the frame's fluid `<main>`. Not available to any other app.
305
+ */
294
306
  contentWrapper?: 'padded' | 'bare';
295
307
  };
296
308
  type PolitogyBuildMeta = {
@@ -2,6 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
3
  import { NavItem, NavBreadcrumb, StandardNavMode, NavLinkComponent, NavChromeFetcher, NavMode, NavUserMenu, NavOrgOption, StandardNavIconKey, NavIcon, NavFooter, NavDisplayMode } from './native.js';
4
4
  import './theme-preference.js';
5
+ import './FormColumn-DsNP6NVG.js';
5
6
 
6
7
  declare function deriveBreadcrumbs(items: NavItem[], pathname: string, opts?: {
7
8
  search?: string;
@@ -103,13 +104,16 @@ type PolitogyAppMode = StandardNavMode;
103
104
  * so widening the surface takes a shell release and a review by whoever owns
104
105
  * the shell.
105
106
  *
106
- * Never add a grant for a visual input. `contentWrapper` qualifies because the
107
- * app either does or does not already emit its own `<main>`; `breadcrumbs`
108
- * qualifies because only the app knows which record a deep link points at.
109
- * "Petitions wants a wider box" would not qualify — that is a look, and looks
110
- * come from tokens.
107
+ * Never add a grant for a visual input. `breadcrumbs` qualifies because only
108
+ * the app knows which record a deep link points at. "Petitions wants a wider
109
+ * box" would not qualify — that is a look, and looks come from tokens.
110
+ *
111
+ * RETIRED (0.69.0): the `contentWrapper` grant. The frame's `<main>` is fluid
112
+ * and apps never emit their own page container (Brand guideline "Content
113
+ * width is fluid"; Reference/UI-Platform → PolitogyAppFrame), so no app may be
114
+ * granted one. Do not re-add it.
111
115
  */
112
- type PolitogyFrameGrant = 'contentWrapper' | 'breadcrumbs' | 'title';
116
+ type PolitogyFrameGrant = 'breadcrumbs' | 'title';
113
117
  /**
114
118
  * The per-app registry — the ONLY place app identity lives. A new app adds a
115
119
  * row here and inherits every chrome behavior; it never re-derives one.
@@ -256,10 +260,10 @@ type PolitogyFrameData = {
256
260
  /** See `PolitogyFrameData.frame` — honored per the app's registry `grants`. */
257
261
  type PolitogyGrantedFrame = {
258
262
  /**
259
- * How the frame wraps page content. `'bare'` for an app that already emits
260
- * its own `<main>` + container, which the default otherwise nests inside
261
- * `mx-auto max-w-7xl` — producing a doubled gutter and, strictly, invalid
262
- * HTML (a `<main>` inside a `<main>`).
263
+ * @deprecated RETIRED in 0.69.0 and ignored: no app holds a `contentWrapper`
264
+ * grant any more. The frame's `<main>` is fluid; remove the app's own page
265
+ * container (`PageContainer`) and stop passing this. Still typed so an app
266
+ * that passes it keeps compiling until it is cleaned up.
263
267
  */
264
268
  contentWrapper?: 'padded' | 'bare';
265
269
  /**
@@ -288,9 +292,17 @@ type PolitogyCoreFrame = {
288
292
  mode?: NavMode;
289
293
  /** Real linked-account switching + core's theme persistence. */
290
294
  userMenu?: NavUserMenu;
291
- /** Mode-specific brand wordmark (core swaps it per operating Mode). */
295
+ /**
296
+ * @deprecated Ignored since 0.69.0. The rail logo is the all-white lockup
297
+ * from Brand `assets.logoHorizontal`, read at runtime, in every Mode —
298
+ * never a mode-specific or bundled wordmark (Left-Navigation §5).
299
+ */
292
300
  brandLogoSrc?: string;
293
- /** Core wraps every page in PageContainer, which emits its own <main>. */
301
+ /**
302
+ * @deprecated Core still wraps its pages in `PageContainer`, which emits its
303
+ * own `<main>`, so `'bare'` is honored for core until those pages are
304
+ * migrated to the frame's fluid `<main>`. Not available to any other app.
305
+ */
294
306
  contentWrapper?: 'padded' | 'bare';
295
307
  };
296
308
  type PolitogyBuildMeta = {
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { broadcastLogout, watchLogout } from './chunk-LL6LSJAH.js';
3
- import { clearBetaBannerDismissal, standardPolitogyNav, isNavItemActive, NavAppShell, NavChromeProvider, TopBarWidgetSlot, FuelAction, SpecOverlayAction, NotificationsAction, SupportAction, useChromeMe, useThemePreference, useNavChromeFetcher, useChromeOrgs } from './chunk-2UTIX3LI.js';
3
+ import { clearBetaBannerDismissal, standardPolitogyNav, isNavItemActive, NavAppShell, NavChromeProvider, TopBarWidgetSlot, FuelAction, SpecOverlayAction, NotificationsAction, SupportAction, useChromeMe, useThemePreference, useNavChromeFetcher, useChromeOrgs } from './chunk-WFUWFMCA.js';
4
+ import { warnDeprecated } from './chunk-LPSBSAF3.js';
4
5
  import './chunk-NHBNM5P3.js';
5
6
  import { NAV_DISPLAY_DEFAULT, resolveNavDisplay, isNavDisplayPreference, writeNavDisplayCookie, writeNavDisplayLocal, NAV_DISPLAY_STORAGE_KEY, readNavDisplayCookie } from './chunk-6UHJV2FH.js';
6
7
  import { resolveActiveOrg, isOrgId, writeActiveOrgCookie, ACTIVE_ORG_QUERY_PARAM, readActiveOrgCookie } from './chunk-W2HITMV5.js';
@@ -464,13 +465,54 @@ function LoadingScreen({
464
465
  }
465
466
  );
466
467
  }
468
+ function parseCssUrl(value) {
469
+ if (!value) return null;
470
+ const m = /^url\(\s*(['"]?)(.*?)\1\s*\)$/i.exec(value.trim());
471
+ const url = m?.[2]?.trim();
472
+ return url && /^https:\/\//i.test(url) ? url : null;
473
+ }
474
+ function readBrandAsset(kind) {
475
+ if (typeof document === "undefined") return null;
476
+ try {
477
+ return parseCssUrl(
478
+ window.getComputedStyle(document.documentElement).getPropertyValue(`--asset-${kind}`)
479
+ );
480
+ } catch {
481
+ return null;
482
+ }
483
+ }
484
+ var EMPTY = { logoHorizontal: null, logoSquare: null };
485
+ var RETRY_MS = [0, 250, 1e3, 3e3];
486
+ function useBrandAssets() {
487
+ const [assets, setAssets] = useState(EMPTY);
488
+ useEffect(() => {
489
+ let done = false;
490
+ const read = () => {
491
+ if (done) return;
492
+ const next = {
493
+ logoHorizontal: readBrandAsset("logo-horizontal"),
494
+ logoSquare: readBrandAsset("logo-square")
495
+ };
496
+ setAssets(
497
+ (prev) => prev.logoHorizontal === next.logoHorizontal && prev.logoSquare === next.logoSquare ? prev : next
498
+ );
499
+ };
500
+ const links = Array.from(
501
+ document.querySelectorAll('link[rel="stylesheet"][href*="api/tokens"]')
502
+ );
503
+ links.forEach((l) => l.addEventListener("load", read));
504
+ const timers = RETRY_MS.map((ms) => window.setTimeout(read, ms));
505
+ read();
506
+ return () => {
507
+ done = true;
508
+ links.forEach((l) => l.removeEventListener("load", read));
509
+ timers.forEach((t) => window.clearTimeout(t));
510
+ };
511
+ }, []);
512
+ return assets;
513
+ }
467
514
  var CORE_APP = "vrm";
468
515
  var DEFAULT_SIGN_OUT_URL = "/auth/signout";
469
- var DEFAULT_BRAND_LOGO = "/brand/logos/relationship-mode-logo.png";
470
- var MODE_BRAND_LOGOS = {
471
- petition: "/brand/logos/petition-mode-logo.svg"
472
- };
473
- var modeBrandLogo = (mode) => mode && MODE_BRAND_LOGOS[mode] || DEFAULT_BRAND_LOGO;
474
516
  var POLITOGY_APPS = {
475
517
  vrm: { title: "Politogy VRM", origin: "https://app.politogyvrm.com", storagePrefix: "vrm" },
476
518
  contacts: {
@@ -488,13 +530,12 @@ var POLITOGY_APPS = {
488
530
  origin: "https://petition-mode.politogyvrm.com",
489
531
  storagePrefix: "petitions",
490
532
  mode: "petition",
491
- // Petitions wraps every page in its own PageContainer (which emits its own
492
- // <main>), and its adjudication case is addressed per sheet and per line —
493
- // a trail derived from the nav tree reads "Dashboard › Adjudication" on
494
- // every one of those URLs and cannot name the record you are actually on.
495
- // 'title' for the same reason: its pages have real names ("Batches"),
496
- // where the registry can only say "Petitions".
497
- grants: ["contentWrapper", "breadcrumbs", "title"],
533
+ // Its adjudication case is addressed per sheet and per line — a trail
534
+ // derived from the nav tree reads "Dashboard › Adjudication" on every one
535
+ // of those URLs and cannot name the record you are actually on. 'title'
536
+ // for the same reason: its pages have real names ("Batches"), where the
537
+ // registry can only say "Petitions".
538
+ grants: ["breadcrumbs", "title"],
498
539
  navShape: "flat",
499
540
  beta: false
500
541
  },
@@ -586,6 +627,19 @@ function FrameBody({
586
627
  }) {
587
628
  const meta = POLITOGY_APPS[app];
588
629
  const chrome = useChromeState();
630
+ const brandAssets = useBrandAssets();
631
+ if (data?.frame?.contentWrapper !== void 0) {
632
+ warnDeprecated(
633
+ "frame.contentWrapper",
634
+ "`data.frame.contentWrapper` is retired and ignored: the frame's <main> is fluid. Remove the app's own page container and drop the prop."
635
+ );
636
+ }
637
+ if (data?.core?.brandLogoSrc !== void 0) {
638
+ warnDeprecated(
639
+ "core.brandLogoSrc",
640
+ "`data.core.brandLogoSrc` is ignored: the rail logo is read at runtime from Brand `assets.logoHorizontal`."
641
+ );
642
+ }
589
643
  const bootAppMode = meta.mode;
590
644
  const bootOrgId = chrome?.orgId ?? null;
591
645
  const [bootVisible, setBootVisible] = useState(true);
@@ -724,7 +778,11 @@ function FrameBody({
724
778
  sidebar: {
725
779
  pathname,
726
780
  brand: {
727
- logoSrc: core?.brandLogoSrc ?? modeBrandLogo(appMode),
781
+ logoSrc: brandAssets.logoHorizontal ?? void 0,
782
+ logoSquareSrc: brandAssets.logoSquare ?? void 0,
783
+ // Reserve the logo's box while the token sheet loads; never draw a
784
+ // stand-in.
785
+ logoPending: true,
728
786
  logoAlt: "Politogy",
729
787
  badgeLabel: "P",
730
788
  title: "Politogy"
@@ -756,7 +814,7 @@ function FrameBody({
756
814
  },
757
815
  betaBanner: meta.beta === true ? {} : void 0,
758
816
  modeId: appMode,
759
- contentWrapper: core?.contentWrapper ?? granted("contentWrapper"),
817
+ contentWrapper: core?.contentWrapper,
760
818
  topBar: {
761
819
  // Core's pages publish their own identity; every other app is one
762
820
  // product surface and takes its registry title.