@the-portland-company/shell 0.47.1 → 0.48.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 +36 -0
- package/dist/app-chrome.cjs +49 -16
- package/dist/app-chrome.cjs.map +1 -1
- package/dist/app-chrome.d.cts +21 -3
- package/dist/app-chrome.d.ts +21 -3
- package/dist/app-chrome.js +14 -6
- package/dist/app-chrome.js.map +1 -1
- package/dist/chrome.css +8 -0
- package/dist/{chunk-PS6IIPPE.js → chunk-DYD2J5CC.js} +38 -13
- package/dist/chunk-DYD2J5CC.js.map +1 -0
- package/dist/native.cjs +36 -11
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +10 -0
- package/dist/native.d.ts +10 -0
- package/dist/native.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-PS6IIPPE.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
## 0.48.0 — 2026-08-13
|
|
2
|
+
|
|
3
|
+
V1-parity round 2, driven by a measured element-by-element audit of a live V1
|
|
4
|
+
build against 0.47.1. Two kinds of change: one global conformance fix, and a
|
|
5
|
+
set of registry/Mode opt-ins that are byte-identical for apps that declare
|
|
6
|
+
nothing.
|
|
7
|
+
|
|
8
|
+
### Fixed — the sidebar now consumes its own Brand tokens (GLOBAL)
|
|
9
|
+
|
|
10
|
+
"Sidebar width, colors, item radius, and spacing come from `--sidebar-*`"
|
|
11
|
+
(Reference/UI-Platform) — but the chrome painted the bar from `--surface-1`
|
|
12
|
+
and rows from `--muted`, so `--sidebar-bg: #FFFFFF` and
|
|
13
|
+
`--sidebar-text: #2F3136` were dead tokens and a Brand edit to them did
|
|
14
|
+
nothing. Consuming them changes every app toward what the Brand editor
|
|
15
|
+
declares: white rail, dark rows in light; the same #161616 ramp in dark
|
|
16
|
+
(dark values added to chrome.css's own `.dark` block so stylesheet order
|
|
17
|
+
between chrome.css and the runtime sheet cannot flip them). This also ends
|
|
18
|
+
the app-wide 3.65:1 AA failure on every inactive row (now 12.6:1).
|
|
19
|
+
|
|
20
|
+
### Added — opt-in, byte-identical defaults
|
|
21
|
+
|
|
22
|
+
- **Org pill takes the Mode accent** (`--mode-accent` / `--mode-on-accent`,
|
|
23
|
+
the latter luminance-derived by the Brand API). Neutral everywhere a Mode
|
|
24
|
+
declares nothing, and in dark.
|
|
25
|
+
- **`navShape: 'flat'` (registry)** — a rail whose whole tree nests under one
|
|
26
|
+
entry renders the children at the root: no parent "Dashboard" row, no
|
|
27
|
+
accordion; rows take the wash active treatment (V1's rail rows).
|
|
28
|
+
- **`beta: false` (registry)** — omits the Beta banner strip for that app.
|
|
29
|
+
- **`'title'` grant** — a granted app's pages may publish the top-bar title
|
|
30
|
+
("Batches", not the app name on every page).
|
|
31
|
+
- **Granted breadcrumbs now REPLACE the derived trail** (like core): a page
|
|
32
|
+
that publishes none shows none, instead of inheriting
|
|
33
|
+
"Dashboard › <page>" from a tree it opted out of.
|
|
34
|
+
|
|
35
|
+
Petitions is the only registry row using any of these.
|
|
36
|
+
|
|
1
37
|
## 0.47.1 — 2026-08-13
|
|
2
38
|
|
|
3
39
|
Two fixes found by running a consuming app's WCAG contrast gate against 0.47.0.
|
package/dist/app-chrome.cjs
CHANGED
|
@@ -1766,7 +1766,7 @@ function NavSidebar({
|
|
|
1766
1766
|
setOpenGroup(activeGroupKey);
|
|
1767
1767
|
}, [activeGroupKey]);
|
|
1768
1768
|
const toggleGroup = (key) => setOpenGroup((prev) => prev === key ? null : key);
|
|
1769
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "fixed inset-y-0 left-0 z-30 hidden w-[240px] flex-col border-r border-[color:var(--line)] bg-[color:var(--nav-surface)] lg:flex", children: [
|
|
1769
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "fixed inset-y-0 left-0 z-30 hidden w-[240px] flex-col border-r border-[color:var(--line)] bg-[color:var(--sidebar-bg,var(--nav-surface))] lg:flex", children: [
|
|
1770
1770
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1771
1771
|
Link,
|
|
1772
1772
|
{
|
|
@@ -1792,7 +1792,7 @@ function NavSidebar({
|
|
|
1792
1792
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-y-auto px-4 pb-2", children: [
|
|
1793
1793
|
org ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3", children: [
|
|
1794
1794
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center justify-between px-1", children: [
|
|
1795
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Organization" }),
|
|
1795
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--sidebar-text-muted,var(--muted))]", children: "Organization" }),
|
|
1796
1796
|
org.id && !org.loading ? /* @__PURE__ */ jsxRuntime.jsx(OrgIdCopyButton, { id: org.id }) : null
|
|
1797
1797
|
] }),
|
|
1798
1798
|
org.loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-2.5 rounded-md border border-[color:var(--line)] bg-[color:var(--panel-elevated)] px-2.5 py-2 shadow-sm", children: [
|
|
@@ -1812,7 +1812,7 @@ function NavSidebar({
|
|
|
1812
1812
|
),
|
|
1813
1813
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading organization" })
|
|
1814
1814
|
] }) : org.organizations && org.organizations.length > 0 && org.onSwitch ? /* @__PURE__ */ jsxRuntime.jsxs("details", { "data-nav-details": true, className: "group relative", children: [
|
|
1815
|
-
/* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex w-full cursor-pointer list-none items-center justify-between gap-2 rounded-md border border-[color:var(--line)] bg-[color:var(--panel-elevated)] px-2.5 py-2 text-left text-[color:var(--foreground)] shadow-sm transition hover:bg-[color:var(--panel)] [&::-webkit-details-marker]:hidden", children: [
|
|
1815
|
+
/* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex w-full cursor-pointer list-none items-center justify-between gap-2 rounded-md border border-[color:var(--mode-accent,var(--line))] bg-[color:var(--mode-accent,var(--panel-elevated))] px-2.5 py-2 text-left text-[color:var(--mode-on-accent,var(--foreground))] shadow-sm transition hover:bg-[color:var(--mode-accent-strong,var(--panel))] [&::-webkit-details-marker]:hidden", children: [
|
|
1816
1816
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-2.5", children: [
|
|
1817
1817
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1818
1818
|
"span",
|
|
@@ -1875,7 +1875,7 @@ function NavSidebar({
|
|
|
1875
1875
|
{
|
|
1876
1876
|
type: "button",
|
|
1877
1877
|
onClick: org.onClick,
|
|
1878
|
-
className: "flex w-full items-center justify-between gap-2 rounded-md border border-[color:var(--line)] bg-[color:var(--panel-elevated)] px-2.5 py-2 text-left text-[color:var(--foreground)] shadow-sm transition hover:bg-[color:var(--panel)]",
|
|
1878
|
+
className: "flex w-full items-center justify-between gap-2 rounded-md border border-[color:var(--mode-accent,var(--line))] bg-[color:var(--mode-accent,var(--panel-elevated))] px-2.5 py-2 text-left text-[color:var(--mode-on-accent,var(--foreground))] shadow-sm transition hover:bg-[color:var(--mode-accent-strong,var(--panel))]",
|
|
1879
1879
|
children: [
|
|
1880
1880
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-2.5", children: [
|
|
1881
1881
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1940,7 +1940,7 @@ function NavSidebar({
|
|
|
1940
1940
|
}
|
|
1941
1941
|
) }) : null,
|
|
1942
1942
|
/* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "flex flex-col gap-1", children: [
|
|
1943
|
-
nav.groupLabel ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-2 pb-1 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: nav.groupLabel }) : null,
|
|
1943
|
+
nav.groupLabel ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-2 pb-1 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--sidebar-text-muted,var(--muted))]", children: nav.groupLabel }) : null,
|
|
1944
1944
|
nav.items.map((item, idx) => {
|
|
1945
1945
|
if (item.kind === "section") {
|
|
1946
1946
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1952,6 +1952,30 @@ function NavSidebar({
|
|
|
1952
1952
|
`section-${idx}-${item.label}`
|
|
1953
1953
|
);
|
|
1954
1954
|
}
|
|
1955
|
+
if (nav.flatten && item.children && item.children.length > 0) {
|
|
1956
|
+
return item.children.map((child, i) => {
|
|
1957
|
+
if (child.kind === "section") {
|
|
1958
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1959
|
+
NavSectionRow,
|
|
1960
|
+
{
|
|
1961
|
+
label: child.label,
|
|
1962
|
+
first: idx === 0 && i === 0
|
|
1963
|
+
},
|
|
1964
|
+
`flat-section-${idx}-${i}-${child.label}`
|
|
1965
|
+
);
|
|
1966
|
+
}
|
|
1967
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1968
|
+
NavRow,
|
|
1969
|
+
{
|
|
1970
|
+
item: child,
|
|
1971
|
+
active: child.href ? activeFn(pathname, child.href) : false,
|
|
1972
|
+
Link,
|
|
1973
|
+
variant: "flat"
|
|
1974
|
+
},
|
|
1975
|
+
child.href ?? `flat-${idx}-${i}-${child.label}`
|
|
1976
|
+
);
|
|
1977
|
+
});
|
|
1978
|
+
}
|
|
1955
1979
|
if (item.children && item.children.length > 0) {
|
|
1956
1980
|
const key = groupKeyOf(item, idx);
|
|
1957
1981
|
const selfActive = item.href ? activeFn(pathname, item.href) : false;
|
|
@@ -2059,7 +2083,7 @@ function NavSectionRow({
|
|
|
2059
2083
|
"p",
|
|
2060
2084
|
{
|
|
2061
2085
|
className: [
|
|
2062
|
-
"text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]",
|
|
2086
|
+
"text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--sidebar-text-muted,var(--muted))]",
|
|
2063
2087
|
variant === "sub" ? "px-3 pb-0.5" : "px-2 pb-1",
|
|
2064
2088
|
first ? "" : "mt-3"
|
|
2065
2089
|
].join(" "),
|
|
@@ -2075,14 +2099,15 @@ function NavRow({
|
|
|
2075
2099
|
}) {
|
|
2076
2100
|
const Icon = item.icon;
|
|
2077
2101
|
const isSub = variant === "sub";
|
|
2078
|
-
const
|
|
2102
|
+
const washActive = variant !== "top";
|
|
2103
|
+
const activeClasses = washActive ? "bg-[color:var(--mode-accent-surface,var(--panel-elevated))] text-[color:var(--color-accent)] shadow-sm" : "bg-[color:var(--color-accent)] text-white shadow-sm";
|
|
2079
2104
|
const wrapperClasses = [
|
|
2080
2105
|
"group relative block overflow-hidden rounded-md transition",
|
|
2081
|
-
active ? activeClasses : "text-[color:var(--muted)] hover:text-white"
|
|
2106
|
+
active ? activeClasses : "text-[color:var(--sidebar-text,var(--muted))] hover:text-white"
|
|
2082
2107
|
].join(" ");
|
|
2083
2108
|
const rowPadding = isSub ? "px-3 py-1.5 text-[13px]" : "px-3 py-2 text-sm";
|
|
2084
2109
|
const iconSize = isSub ? 16 : 18;
|
|
2085
|
-
const iconClass = active && !
|
|
2110
|
+
const iconClass = active && !washActive ? "text-white" : "text-current";
|
|
2086
2111
|
const inner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2087
2112
|
!active ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2088
2113
|
"span",
|
|
@@ -2147,7 +2172,7 @@ function NavGroup({
|
|
|
2147
2172
|
const headerClasses = [
|
|
2148
2173
|
"group relative block w-full overflow-hidden text-left transition",
|
|
2149
2174
|
open ? "rounded-t-md" : "rounded-md",
|
|
2150
|
-
active ? "bg-[color:var(--color-accent)] text-white shadow-sm" : open ? "bg-[color:var(--panel)] text-[color:var(--foreground)]" : "text-[color:var(--muted)] hover:text-white"
|
|
2175
|
+
active ? "bg-[color:var(--color-accent)] text-white shadow-sm" : open ? "bg-[color:var(--panel)] text-[color:var(--foreground)]" : "text-[color:var(--sidebar-text,var(--muted))] hover:text-white"
|
|
2151
2176
|
].join(" ");
|
|
2152
2177
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2153
2178
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -2244,7 +2269,7 @@ function NavSubGroup({
|
|
|
2244
2269
|
"aria-expanded": open,
|
|
2245
2270
|
className: [
|
|
2246
2271
|
"flex w-full items-center gap-2.5 rounded px-3 py-1.5 text-left text-[13px] font-medium transition",
|
|
2247
|
-
ownsActive ? "text-[color:var(--color-accent)]" : "text-[color:var(--muted)] hover:bg-[color:var(--nav-row-hover)] hover:text-[color:var(--foreground)]"
|
|
2272
|
+
ownsActive ? "text-[color:var(--color-accent)]" : "text-[color:var(--sidebar-text,var(--muted))] hover:bg-[color:var(--nav-row-hover)] hover:text-[color:var(--foreground)]"
|
|
2248
2273
|
].join(" "),
|
|
2249
2274
|
children: [
|
|
2250
2275
|
Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: 15, className: "shrink-0 text-current" }) : null,
|
|
@@ -3037,7 +3062,11 @@ var POLITOGY_APPS = {
|
|
|
3037
3062
|
// <main>), and its adjudication case is addressed per sheet and per line —
|
|
3038
3063
|
// a trail derived from the nav tree reads "Dashboard › Adjudication" on
|
|
3039
3064
|
// every one of those URLs and cannot name the record you are actually on.
|
|
3040
|
-
|
|
3065
|
+
// 'title' for the same reason: its pages have real names ("Batches"),
|
|
3066
|
+
// where the registry can only say "Petitions".
|
|
3067
|
+
grants: ["contentWrapper", "breadcrumbs", "title"],
|
|
3068
|
+
navShape: "flat",
|
|
3069
|
+
beta: false
|
|
3041
3070
|
},
|
|
3042
3071
|
// Campaign Mode apps — each scoped to Campaign, so they render the Campaign
|
|
3043
3072
|
// tree and a static Campaign pill. Not yet deployed; hidden from the Campaign
|
|
@@ -3178,7 +3207,7 @@ function FrameBody({
|
|
|
3178
3207
|
() => deriveBreadcrumbs(navItems, pathname, { search, origin: meta.origin }),
|
|
3179
3208
|
[navItems, pathname, search, meta.origin]
|
|
3180
3209
|
);
|
|
3181
|
-
const breadcrumbs = core ? core.page?.breadcrumbs : granted("breadcrumbs")
|
|
3210
|
+
const breadcrumbs = core ? core.page?.breadcrumbs : grants?.includes("breadcrumbs") ? granted("breadcrumbs") : derivedBreadcrumbs;
|
|
3182
3211
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3183
3212
|
NavAppShell,
|
|
3184
3213
|
{
|
|
@@ -3191,7 +3220,11 @@ function FrameBody({
|
|
|
3191
3220
|
title: "Politogy"
|
|
3192
3221
|
},
|
|
3193
3222
|
nav: {
|
|
3194
|
-
|
|
3223
|
+
// A flat rail's sub-menu IS the nav, so the 'tabs only' preference
|
|
3224
|
+
// (which strips children) would leave one childless parent row —
|
|
3225
|
+
// flat apps ignore the stripping.
|
|
3226
|
+
items: navDisplay === "tabs" && meta.navShape !== "flat" ? navItems.map(({ children: _sub, ...item }) => item) : navItems,
|
|
3227
|
+
flatten: meta.navShape === "flat"
|
|
3195
3228
|
},
|
|
3196
3229
|
// The app's own workspace is NOT the organization — it is a per-app
|
|
3197
3230
|
// bootstrap account with a different id in every app. Showing it while
|
|
@@ -3210,13 +3243,13 @@ function FrameBody({
|
|
|
3210
3243
|
footer,
|
|
3211
3244
|
linkComponent
|
|
3212
3245
|
},
|
|
3213
|
-
betaBanner: {},
|
|
3246
|
+
betaBanner: meta.beta === false ? void 0 : {},
|
|
3214
3247
|
modeId: appMode,
|
|
3215
3248
|
contentWrapper: core?.contentWrapper ?? granted("contentWrapper"),
|
|
3216
3249
|
topBar: {
|
|
3217
3250
|
// Core's pages publish their own identity; every other app is one
|
|
3218
3251
|
// product surface and takes its registry title.
|
|
3219
|
-
title: core?.page?.title ?? meta.title,
|
|
3252
|
+
title: core?.page?.title ?? (grants?.includes("title") ? data?.frame?.title : void 0) ?? meta.title,
|
|
3220
3253
|
breadcrumbs,
|
|
3221
3254
|
user: {
|
|
3222
3255
|
name: identity.userName,
|