@the-portland-company/shell 0.25.0 → 0.27.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 +43 -0
- package/dist/app-chrome.cjs +40 -6
- package/dist/app-chrome.cjs.map +1 -1
- package/dist/app-chrome.d.cts +28 -3
- package/dist/app-chrome.d.ts +28 -3
- package/dist/app-chrome.js +18 -4
- package/dist/app-chrome.js.map +1 -1
- package/dist/{chunk-QCA2PGKA.js → chunk-I3DWBWY6.js} +25 -5
- package/dist/chunk-I3DWBWY6.js.map +1 -0
- package/dist/native.cjs +23 -3
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +31 -5
- package/dist/native.d.ts +31 -5
- package/dist/native.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-QCA2PGKA.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,46 @@
|
|
|
1
|
+
## 0.27.0 — 2026-07-23
|
|
2
|
+
|
|
3
|
+
VRM native-chrome parity (shell-nav-handoff §1–§3). All three were verified in
|
|
4
|
+
this package's source before changing anything, and all three are additive —
|
|
5
|
+
forms / surveys / polls / contacts behavior is unchanged.
|
|
6
|
+
|
|
7
|
+
### Added — `NavAppShell contentWrapper`
|
|
8
|
+
|
|
9
|
+
`'padded'` (default) keeps the existing `<main class="px-6 py-7">` + `mx-auto
|
|
10
|
+
max-w-7xl`. `'bare'` renders children directly. VRM wraps every page in the
|
|
11
|
+
shell's own `PageContainer` — which emits its OWN `<main>` and max-width — so
|
|
12
|
+
the default gave it a **nested `<main>`** (invalid HTML) and a doubled gutter on
|
|
13
|
+
Org Settings, Email Broadcast and SMS/MMS Blast.
|
|
14
|
+
|
|
15
|
+
### Added — nav group headers can navigate as well as expand
|
|
16
|
+
|
|
17
|
+
A group header always toggles; when the item also carries an `onClick`, that now
|
|
18
|
+
runs too, so a parent row can open its section dashboard AND expand in one
|
|
19
|
+
click. Existing apps pass no parent `onClick`, so nothing changes for them.
|
|
20
|
+
|
|
21
|
+
### Added — `NavItem.disabled` + `NavItem.disabledTitle`
|
|
22
|
+
|
|
23
|
+
Mirrors `NavTab`'s existing contract: a gated row renders as a non-interactive,
|
|
24
|
+
dimmed `aria-disabled` span with its reason as a tooltip. VRM gates Email / SMS
|
|
25
|
+
until setup is complete and previously had no way to express that, so gated rows
|
|
26
|
+
rendered fully clickable.
|
|
27
|
+
|
|
28
|
+
## 0.26.0 — 2026-07-23
|
|
29
|
+
|
|
30
|
+
### Added — `PolitogyAppFrame` data plumbing (so Contacts can adopt it)
|
|
31
|
+
|
|
32
|
+
`PolitogyFrameData` (the optional `data` prop) carries the things that differ by
|
|
33
|
+
**where an app's data comes from**, never by how its chrome looks:
|
|
34
|
+
|
|
35
|
+
- `fetchJson` / `devNotes` — for apps that authenticate client-side instead of
|
|
36
|
+
through a same-origin `/api/chrome/*` proxy (Contacts).
|
|
37
|
+
- `org` — controlled active-org state for apps that own switching.
|
|
38
|
+
- `contactsItem` — app-owned children for a standard nav entry the app owns.
|
|
39
|
+
- `fallbackAvatarUrl` — avatar fallback (stored memoji / default) when the
|
|
40
|
+
profile has no uploaded photo.
|
|
41
|
+
|
|
42
|
+
Adding a *visual* option here would re-open the drift this component closes.
|
|
43
|
+
|
|
1
44
|
## 0.25.0 — 2026-07-23
|
|
2
45
|
|
|
3
46
|
### Added — `PolitogyAppFrame`: one component owns the whole app frame
|
package/dist/app-chrome.cjs
CHANGED
|
@@ -1313,6 +1313,17 @@ function NavRow({
|
|
|
1313
1313
|
item.label
|
|
1314
1314
|
] })
|
|
1315
1315
|
] });
|
|
1316
|
+
if (item.disabled) {
|
|
1317
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1318
|
+
"span",
|
|
1319
|
+
{
|
|
1320
|
+
"aria-disabled": "true",
|
|
1321
|
+
title: item.disabledTitle,
|
|
1322
|
+
className: `${wrapperClasses} cursor-not-allowed opacity-50`,
|
|
1323
|
+
children: inner
|
|
1324
|
+
}
|
|
1325
|
+
);
|
|
1326
|
+
}
|
|
1316
1327
|
if (item.onClick && !item.href) {
|
|
1317
1328
|
return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: item.onClick, className: `w-full text-left ${wrapperClasses}`, children: inner });
|
|
1318
1329
|
}
|
|
@@ -1346,7 +1357,10 @@ function NavGroup({
|
|
|
1346
1357
|
"button",
|
|
1347
1358
|
{
|
|
1348
1359
|
type: "button",
|
|
1349
|
-
onClick:
|
|
1360
|
+
onClick: () => {
|
|
1361
|
+
onToggle();
|
|
1362
|
+
item.onClick?.();
|
|
1363
|
+
},
|
|
1350
1364
|
"aria-expanded": open,
|
|
1351
1365
|
className: headerClasses,
|
|
1352
1366
|
children: [
|
|
@@ -1866,14 +1880,20 @@ function useCloseNavDetailsOnOutsideClick() {
|
|
|
1866
1880
|
};
|
|
1867
1881
|
}, []);
|
|
1868
1882
|
}
|
|
1869
|
-
function NavAppShell({
|
|
1883
|
+
function NavAppShell({
|
|
1884
|
+
sidebar,
|
|
1885
|
+
topBar,
|
|
1886
|
+
betaBanner,
|
|
1887
|
+
contentWrapper = "padded",
|
|
1888
|
+
children
|
|
1889
|
+
}) {
|
|
1870
1890
|
useCloseNavDetailsOnOutsideClick();
|
|
1871
1891
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]", children: [
|
|
1872
1892
|
/* @__PURE__ */ jsxRuntime.jsx(NavSidebar, { ...sidebar }),
|
|
1873
1893
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lg:pl-[240px]", children: [
|
|
1874
1894
|
/* @__PURE__ */ jsxRuntime.jsx(NavTopBar, { ...topBar }),
|
|
1875
1895
|
betaBanner ? /* @__PURE__ */ jsxRuntime.jsx(NavBetaBanner, { ...betaBanner }) : null,
|
|
1876
|
-
/* @__PURE__ */ jsxRuntime.jsx("main", { className: "px-6 py-7", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto max-w-7xl", children }) })
|
|
1896
|
+
contentWrapper === "bare" ? children : /* @__PURE__ */ jsxRuntime.jsx("main", { className: "px-6 py-7", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto max-w-7xl", children }) })
|
|
1877
1897
|
] })
|
|
1878
1898
|
] });
|
|
1879
1899
|
}
|
|
@@ -1963,6 +1983,7 @@ function PolitogyAppFrame({
|
|
|
1963
1983
|
session,
|
|
1964
1984
|
onSignOut,
|
|
1965
1985
|
buildMeta,
|
|
1986
|
+
data,
|
|
1966
1987
|
children
|
|
1967
1988
|
}) {
|
|
1968
1989
|
const meta = POLITOGY_APPS[app];
|
|
@@ -1970,6 +1991,9 @@ function PolitogyAppFrame({
|
|
|
1970
1991
|
PolitogyAppChrome,
|
|
1971
1992
|
{
|
|
1972
1993
|
storagePrefix: meta.storagePrefix,
|
|
1994
|
+
fetchJson: data?.fetchJson,
|
|
1995
|
+
devNotes: data?.devNotes,
|
|
1996
|
+
org: data?.org,
|
|
1973
1997
|
identity: {
|
|
1974
1998
|
userId: session.userId,
|
|
1975
1999
|
userName: session.userName ?? null,
|
|
@@ -1986,6 +2010,7 @@ function PolitogyAppFrame({
|
|
|
1986
2010
|
session,
|
|
1987
2011
|
onSignOut,
|
|
1988
2012
|
buildMeta,
|
|
2013
|
+
data,
|
|
1989
2014
|
children
|
|
1990
2015
|
}
|
|
1991
2016
|
)
|
|
@@ -2000,6 +2025,7 @@ function FrameBody({
|
|
|
2000
2025
|
session,
|
|
2001
2026
|
onSignOut,
|
|
2002
2027
|
buildMeta,
|
|
2028
|
+
data,
|
|
2003
2029
|
children
|
|
2004
2030
|
}) {
|
|
2005
2031
|
const meta = POLITOGY_APPS[app];
|
|
@@ -2016,8 +2042,14 @@ function FrameBody({
|
|
|
2016
2042
|
const activeCoreOrg = coreOrgs.find((o) => o.id === chrome?.orgId) ?? null;
|
|
2017
2043
|
const navDisplay = chrome?.navDisplay ?? "both";
|
|
2018
2044
|
const navItems = react.useMemo(
|
|
2019
|
-
() => standardPolitogyNav({
|
|
2020
|
-
|
|
2045
|
+
() => standardPolitogyNav({
|
|
2046
|
+
coreBaseUrl: POLITOGY_APPS.vrm.origin,
|
|
2047
|
+
icons: standardNavIcons,
|
|
2048
|
+
// An app that OWNS a standard nav entry (Contacts) nests its own routes
|
|
2049
|
+
// under it. This is routing data, not chrome configuration.
|
|
2050
|
+
contactsItem: data?.contactsItem
|
|
2051
|
+
}),
|
|
2052
|
+
[data?.contactsItem]
|
|
2021
2053
|
);
|
|
2022
2054
|
const breadcrumbs = react.useMemo(
|
|
2023
2055
|
() => deriveBreadcrumbs(navItems, pathname, { search, origin: meta.origin }),
|
|
@@ -2056,7 +2088,9 @@ function FrameBody({
|
|
|
2056
2088
|
user: {
|
|
2057
2089
|
name: identity.userName,
|
|
2058
2090
|
email: identity.email,
|
|
2059
|
-
|
|
2091
|
+
// The chrome API's avatar wins; the app may supply a fallback chain
|
|
2092
|
+
// (e.g. a stored memoji) for users with no uploaded photo.
|
|
2093
|
+
avatarUrl: identity.avatarUrl ?? data?.fallbackAvatarUrl ?? null,
|
|
2060
2094
|
role: session.role
|
|
2061
2095
|
},
|
|
2062
2096
|
userMenu,
|