@the-portland-company/shell 0.82.0 → 0.84.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.
@@ -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, f as NavIcon, N as NavItem, g as NavBreadcrumb, h as StandardNavMode, i as NavLinkComponent, j as NavChromeFetcher, k as NavMode, l as NavUserMenu, m as NavOrgOption, b as NotificationsAdapter, o as NavFooterLink, p as NavFooter, q as NavDisplayMode } from './index-C3PFq1hl.cjs';
3
+ import { S as StandardNavIconKey, f as NavIcon, N as NavItem, g as NavBreadcrumb, h as StandardNavMode, i as NavLinkComponent, j as NavChromeFetcher, k as NavMode, l as NavUserMenu, m as NavOrgOption, b as NotificationsAdapter, o as NavFooterLink, p as NavFooter, q as NavDisplayMode } from './index--q40spnY.cjs';
4
4
  import './theme-preference.cjs';
5
5
 
6
6
  /**
@@ -401,6 +401,21 @@ type ChromeState = {
401
401
  navDisplay: NavDisplayMode;
402
402
  setNavDisplay: (m: NavDisplayMode) => void;
403
403
  };
404
+ /**
405
+ * Where an organization switch goes (Specs/Left-Navigation §6, §11.2, decided
406
+ * 2026-10-15 by Ben): the new organization's Relationship Dashboard, from every
407
+ * app, Mode and page, behind the Loading Screen. The Relationship Dashboard is
408
+ * the one page every organization has, so nothing the user was looking at is
409
+ * carried into an organization that may not have it. (Measured before this: a
410
+ * switch from Campaign Mode to an organization without it kept the Campaign
411
+ * rail, then showed an access error that needed a sign-out.)
412
+ *
413
+ * An object so tests can replace `navigate` (jsdom cannot navigate).
414
+ */
415
+ declare const orgSwitchLanding: {
416
+ href(orgId: string): string | null;
417
+ navigate(href: string): void;
418
+ };
404
419
  declare function useChromeState(): ChromeState | null;
405
420
  type ControlledOrgState = {
406
421
  orgId: string | null;
@@ -580,4 +595,4 @@ type UseChromeModeArg = ModeId | {
580
595
  */
581
596
  declare function useChromeMode(arg?: UseChromeModeArg): NavMode;
582
597
 
583
- export { type BootPhase, type BootProgress, type BootStageId, type ChromeDevNotesConfig, type ChromeIdentity, ChromeTopBarActions, type ControlledOrgState, LoadingScreen, MODE_SEARCH_PLACEHOLDER, POLITOGY_APPS, PolitogyAppChrome, PolitogyAppFrame, type PolitogyAppKey, type PolitogyAppMode, type PolitogyAppSession, type PolitogyBuildMeta, type PolitogyFrameData, type PolitogyFrameGrant, type PolitogyGrantedFrame, type ResolvedIdentity, type TokenOrgState, deriveBreadcrumbs, footerLinks, looksLikeEmail, modeLandingHref, resolveIdentity, standardNavIcons, useChromeFooter, useChromeIdentity, useChromeMode, useChromeState, useChromeUserMenu, useIsSuperAdmin };
598
+ export { type BootPhase, type BootProgress, type BootStageId, type ChromeDevNotesConfig, type ChromeIdentity, ChromeTopBarActions, type ControlledOrgState, LoadingScreen, MODE_SEARCH_PLACEHOLDER, POLITOGY_APPS, PolitogyAppChrome, PolitogyAppFrame, type PolitogyAppKey, type PolitogyAppMode, type PolitogyAppSession, type PolitogyBuildMeta, type PolitogyFrameData, type PolitogyFrameGrant, type PolitogyGrantedFrame, type ResolvedIdentity, type TokenOrgState, deriveBreadcrumbs, footerLinks, looksLikeEmail, modeLandingHref, orgSwitchLanding, resolveIdentity, standardNavIcons, useChromeFooter, useChromeIdentity, useChromeMode, useChromeState, useChromeUserMenu, useIsSuperAdmin };
@@ -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, f as NavIcon, N as NavItem, g as NavBreadcrumb, h as StandardNavMode, i as NavLinkComponent, j as NavChromeFetcher, k as NavMode, l as NavUserMenu, m as NavOrgOption, b as NotificationsAdapter, o as NavFooterLink, p as NavFooter, q as NavDisplayMode } from './index-CwTnsR9R.js';
3
+ import { S as StandardNavIconKey, f as NavIcon, N as NavItem, g as NavBreadcrumb, h as StandardNavMode, i as NavLinkComponent, j as NavChromeFetcher, k as NavMode, l as NavUserMenu, m as NavOrgOption, b as NotificationsAdapter, o as NavFooterLink, p as NavFooter, q as NavDisplayMode } from './index-C4ob05Pc.js';
4
4
  import './theme-preference.js';
5
5
 
6
6
  /**
@@ -401,6 +401,21 @@ type ChromeState = {
401
401
  navDisplay: NavDisplayMode;
402
402
  setNavDisplay: (m: NavDisplayMode) => void;
403
403
  };
404
+ /**
405
+ * Where an organization switch goes (Specs/Left-Navigation §6, §11.2, decided
406
+ * 2026-10-15 by Ben): the new organization's Relationship Dashboard, from every
407
+ * app, Mode and page, behind the Loading Screen. The Relationship Dashboard is
408
+ * the one page every organization has, so nothing the user was looking at is
409
+ * carried into an organization that may not have it. (Measured before this: a
410
+ * switch from Campaign Mode to an organization without it kept the Campaign
411
+ * rail, then showed an access error that needed a sign-out.)
412
+ *
413
+ * An object so tests can replace `navigate` (jsdom cannot navigate).
414
+ */
415
+ declare const orgSwitchLanding: {
416
+ href(orgId: string): string | null;
417
+ navigate(href: string): void;
418
+ };
404
419
  declare function useChromeState(): ChromeState | null;
405
420
  type ControlledOrgState = {
406
421
  orgId: string | null;
@@ -580,4 +595,4 @@ type UseChromeModeArg = ModeId | {
580
595
  */
581
596
  declare function useChromeMode(arg?: UseChromeModeArg): NavMode;
582
597
 
583
- export { type BootPhase, type BootProgress, type BootStageId, type ChromeDevNotesConfig, type ChromeIdentity, ChromeTopBarActions, type ControlledOrgState, LoadingScreen, MODE_SEARCH_PLACEHOLDER, POLITOGY_APPS, PolitogyAppChrome, PolitogyAppFrame, type PolitogyAppKey, type PolitogyAppMode, type PolitogyAppSession, type PolitogyBuildMeta, type PolitogyFrameData, type PolitogyFrameGrant, type PolitogyGrantedFrame, type ResolvedIdentity, type TokenOrgState, deriveBreadcrumbs, footerLinks, looksLikeEmail, modeLandingHref, resolveIdentity, standardNavIcons, useChromeFooter, useChromeIdentity, useChromeMode, useChromeState, useChromeUserMenu, useIsSuperAdmin };
598
+ export { type BootPhase, type BootProgress, type BootStageId, type ChromeDevNotesConfig, type ChromeIdentity, ChromeTopBarActions, type ControlledOrgState, LoadingScreen, MODE_SEARCH_PLACEHOLDER, POLITOGY_APPS, PolitogyAppChrome, PolitogyAppFrame, type PolitogyAppKey, type PolitogyAppMode, type PolitogyAppSession, type PolitogyBuildMeta, type PolitogyFrameData, type PolitogyFrameGrant, type PolitogyGrantedFrame, type ResolvedIdentity, type TokenOrgState, deriveBreadcrumbs, footerLinks, looksLikeEmail, modeLandingHref, orgSwitchLanding, resolveIdentity, standardNavIcons, useChromeFooter, useChromeIdentity, useChromeMode, useChromeState, useChromeUserMenu, useIsSuperAdmin };
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { broadcastLogout, watchLogout } from './chunk-LL6LSJAH.js';
3
- import { clearBetaBannerDismissal, standardPolitogyNav, standardNavIcons, isNavItemActive, NavAppShell } from './chunk-VWY6IIAR.js';
4
- export { standardNavIcons } from './chunk-VWY6IIAR.js';
5
- import { warnDeprecated, NavChromeProvider, TopBarWidgetSlot, FuelAction, SpecOverlayAction, NotificationsAction, SupportAction, useChromeMe, useNavChromeDedupedFetch, useChromeOrgs, useNavChromeFetcher } from './chunk-L73FZKGE.js';
3
+ import { clearBetaBannerDismissal, standardPolitogyNav, standardNavIcons, isNavItemActive, NavAppShell } from './chunk-QS3Z4N73.js';
4
+ export { standardNavIcons } from './chunk-QS3Z4N73.js';
5
+ import { warnDeprecated, NavChromeProvider, TopBarWidgetSlot, FuelAction, SpecOverlayAction, NotificationsAction, SupportAction, useChromeMe, useNavChromeDedupedFetch, useChromeOrgs, useNavChromeFetcher } from './chunk-PRZP2SB6.js';
6
6
  import './chunk-BHRVZPZ7.js';
7
7
  import { NAV_DISPLAY_DEFAULT, resolveNavDisplay, writeNavDisplayLocal, writeNavDisplayCookie, isNavDisplayPreference, NAV_DISPLAY_STORAGE_KEY, readNavDisplayCookie } from './chunk-7YVJ7HQG.js';
8
8
  import { authBaseUrl, orgIdTail, settingsBaseUrl, ORG_ID_QUERY_PARAM, readOrgSelectorFromUrl, matchOrgSelector, syncOrgIdInUrl, isOrgId, switchActiveOrg, ACTIVE_ORG_QUERY_PARAM, writeActiveOrgCookie, resolveActiveOrg, readActiveOrgCookie } from './chunk-5LO5W7W5.js';
@@ -803,7 +803,7 @@ function FrameBody({
803
803
  {
804
804
  visible: bootVisible,
805
805
  bootProgress,
806
- syntheticReady: appReady ?? chromeResolved,
806
+ syntheticReady: (appReady ?? chromeResolved) && !chrome?.orgPending,
807
807
  onExitComplete: () => setBootVisible(false)
808
808
  },
809
809
  bootGeneration
@@ -893,6 +893,18 @@ function FrameBody({
893
893
  }
894
894
  var ORG_STORAGE_KEY = "vrm.activeOrg";
895
895
  var MODE_STORAGE_KEY = "vrm.activeMode";
896
+ var orgSwitchLanding = {
897
+ href(orgId) {
898
+ return modeLandingHref("relationship", {
899
+ orgId,
900
+ hostname: typeof window === "undefined" ? null : window.location.hostname
901
+ });
902
+ },
903
+ navigate(href) {
904
+ window.location.assign(href);
905
+ }
906
+ };
907
+ var ORG_SWITCH_REEXCHANGE_BUDGET_MS = 4e3;
896
908
  var ChromeStateContext = createContext(null);
897
909
  function useChromeState() {
898
910
  return useContext(ChromeStateContext);
@@ -908,6 +920,7 @@ function TokenChromeStateProvider({
908
920
  const [pendingOrg, setPendingOrg] = useState(null);
909
921
  const tokenOrgRef = useRef(tokenOrg);
910
922
  tokenOrgRef.current = tokenOrg;
923
+ const leavingRef = useRef(false);
911
924
  useEffect(() => {
912
925
  setNavDisplayState(resolveNavDisplay());
913
926
  }, []);
@@ -948,6 +961,7 @@ function TokenChromeStateProvider({
948
961
  }, [overrideOrg, tokenOrg.orgId]);
949
962
  useEffect(() => {
950
963
  if (!pendingOrg || tokenOrg.orgId !== pendingOrg) return;
964
+ if (leavingRef.current) return;
951
965
  setPendingOrg(null);
952
966
  try {
953
967
  const next = syncOrgIdInUrl(window.location.href, pendingOrg);
@@ -970,8 +984,16 @@ function TokenChromeStateProvider({
970
984
  window.history.replaceState(window.history.state, "", url.toString());
971
985
  } catch {
972
986
  }
973
- await tokenOrgRef.current.onReexchange(claims.orgId, { perTab: false });
987
+ leavingRef.current = true;
988
+ await Promise.race([
989
+ Promise.resolve(tokenOrgRef.current.onReexchange(claims.orgId, { perTab: false })).catch(() => {
990
+ }),
991
+ new Promise((resolve) => setTimeout(resolve, ORG_SWITCH_REEXCHANGE_BUDGET_MS))
992
+ ]);
993
+ const href = orgSwitchLanding.href(claims.orgId);
994
+ if (href) orgSwitchLanding.navigate(href);
974
995
  } catch (err) {
996
+ leavingRef.current = false;
975
997
  setPendingOrg(null);
976
998
  tokenOrgRef.current.onSwitchError?.(err);
977
999
  }
@@ -1036,10 +1058,13 @@ function ChromeStateProvider({
1036
1058
  const navReconciled = useRef(false);
1037
1059
  const orgReconciled = useRef(false);
1038
1060
  const hadBootSelector = useRef(false);
1061
+ const bootUrlTail = useRef(null);
1039
1062
  useEffect(() => {
1040
1063
  try {
1064
+ const urlSelector = readOrgSelectorFromUrl(window.location.search);
1065
+ if (urlSelector && !isOrgId(urlSelector)) bootUrlTail.current = urlSelector;
1041
1066
  const selector = resolveActiveOrg();
1042
- if (selector) hadBootSelector.current = true;
1067
+ if (selector || urlSelector) hadBootSelector.current = true;
1043
1068
  const storedOrg = selector ?? localStorage.getItem(ORG_STORAGE_KEY);
1044
1069
  if (storedOrg) setOrgIdState(storedOrg);
1045
1070
  } catch {
@@ -1076,7 +1101,9 @@ function ChromeStateProvider({
1076
1101
  }, []);
1077
1102
  useEffect(() => {
1078
1103
  if (!orgs || orgs.length === 0) return;
1079
- setOrgIdState((prev) => prev && orgs.some((o) => o.id === prev) ? prev : orgs[0].id);
1104
+ const fromUrl = matchOrgSelector(bootUrlTail.current, orgs)?.id ?? null;
1105
+ bootUrlTail.current = null;
1106
+ setOrgIdState((prev) => fromUrl ?? (prev && orgs.some((o) => o.id === prev) ? prev : orgs[0].id));
1080
1107
  }, [orgs]);
1081
1108
  const activeOrgRef = useRef(null);
1082
1109
  const memberOrgsRef = useRef([]);
@@ -1134,6 +1161,10 @@ function ChromeStateProvider({
1134
1161
  } catch {
1135
1162
  }
1136
1163
  writeActiveOrgCookie(id);
1164
+ if (isOrgId(id)) {
1165
+ const href = orgSwitchLanding.href(id);
1166
+ if (href) orgSwitchLanding.navigate(href);
1167
+ }
1137
1168
  }, []);
1138
1169
  const setNavDisplay = useCallback(
1139
1170
  (m) => {
@@ -1200,8 +1231,10 @@ function ChromeStateProvider({
1200
1231
  }
1201
1232
  try {
1202
1233
  const url = new URL(window.location.href);
1203
- if (url.searchParams.get(ACTIVE_ORG_QUERY_PARAM) !== activeOrgId) {
1204
- url.searchParams.set(ACTIVE_ORG_QUERY_PARAM, activeOrgId);
1234
+ const tail = orgIdTail(activeOrgId);
1235
+ if (url.searchParams.has(ACTIVE_ORG_QUERY_PARAM) || url.searchParams.get(ORG_ID_QUERY_PARAM) !== tail) {
1236
+ url.searchParams.delete(ACTIVE_ORG_QUERY_PARAM);
1237
+ url.searchParams.set(ORG_ID_QUERY_PARAM, tail);
1205
1238
  window.history.replaceState(window.history.state, "", url.toString());
1206
1239
  }
1207
1240
  } catch {
@@ -1553,6 +1586,6 @@ function useChromeMode(arg = {}) {
1553
1586
  };
1554
1587
  }
1555
1588
 
1556
- export { ChromeTopBarActions, LoadingScreen, MODE_SEARCH_PLACEHOLDER, POLITOGY_APPS, PolitogyAppChrome, PolitogyAppFrame, deriveBreadcrumbs, footerLinks, looksLikeEmail, modeLandingHref, resolveIdentity, useChromeFooter, useChromeIdentity, useChromeMode, useChromeState, useChromeUserMenu, useIsSuperAdmin };
1589
+ export { ChromeTopBarActions, LoadingScreen, MODE_SEARCH_PLACEHOLDER, POLITOGY_APPS, PolitogyAppChrome, PolitogyAppFrame, deriveBreadcrumbs, footerLinks, looksLikeEmail, modeLandingHref, orgSwitchLanding, resolveIdentity, useChromeFooter, useChromeIdentity, useChromeMode, useChromeState, useChromeUserMenu, useIsSuperAdmin };
1557
1590
  //# sourceMappingURL=app-chrome.js.map
1558
1591
  //# sourceMappingURL=app-chrome.js.map