@the-portland-company/shell 0.3.0 → 0.3.1
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 +42 -0
- package/dist/index.cjs +247 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -7
- package/dist/index.d.ts +73 -7
- package/dist/index.js +248 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1 — 2026-05-13
|
|
4
|
+
|
|
5
|
+
Closes the last two visual gaps in the shell-v3 chrome vs production.
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Header icon order**: Removed the `devNotesMenu` slot from
|
|
10
|
+
`<Header>`'s icon row. Previously the shell appended DevNotes (the
|
|
11
|
+
"Task" icon) AFTER `headerIconsSlot`, forcing it to the rightmost
|
|
12
|
+
position. That broke production order (Fuel → Stack → Bell → Task →
|
|
13
|
+
Support → Avatar). Apps must now inline DevNotesMenu inside
|
|
14
|
+
`headerIconsSlot` at the position they want. The `devNotesMenu` prop
|
|
15
|
+
on `<ShellChrome>` is still accepted for backward compat but is
|
|
16
|
+
ignored at render time.
|
|
17
|
+
- **Sidebar footer commit info**: Replaced the plain-text
|
|
18
|
+
`"staging v2.34.1 #51e4e3f"` row with a full port of the legacy
|
|
19
|
+
production `CommitCopyButton` (env chip + last-4 SHA + version +
|
|
20
|
+
optional diagnostics icon, plus a second-line byline `| Mon D |
|
|
21
|
+
firstName |`). Clicking the env chip copies the full SHA. Hovering
|
|
22
|
+
shows the full commit message body when `commitLog` is supplied.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- `<CommitCopyButton>` — new exported component. Ported from
|
|
27
|
+
`react/app/src/layouts/AuthenticatedLayout.tsx::CommitCopyButton`
|
|
28
|
+
(lines 3017–3284). Accepts `envNode` (pre-rendered chip),
|
|
29
|
+
`environmentLabel` (default styled chip — green/orange/red for
|
|
30
|
+
local/staging/production), `commit`, `version`, `commitDate`,
|
|
31
|
+
`commitAuthor`, `commitLog`, and `onDiagnosticsClick`. Used by the
|
|
32
|
+
shell's `<Sidebar>` footer; also exported for apps that want to mount
|
|
33
|
+
it elsewhere.
|
|
34
|
+
- `ShellFooterValue.envNode?: ReactNode` — pre-rendered chip override
|
|
35
|
+
(useful when the app already has its own `EnvironmentBanner`).
|
|
36
|
+
- `ShellFooterValue.onDiagnosticsClick?: () => void` — gates the
|
|
37
|
+
diagnostics icon. When unset, the icon is omitted.
|
|
38
|
+
|
|
39
|
+
### Doc-only
|
|
40
|
+
|
|
41
|
+
- `ShellProviderProps.support` doc no longer claims the shell renders
|
|
42
|
+
a `<SupportRequestButton />` automatically. It never did — apps wire
|
|
43
|
+
their own support trigger via `headerIconsSlot`.
|
|
44
|
+
|
|
3
45
|
## 0.3.0 — 2026-05-13
|
|
4
46
|
|
|
5
47
|
Visual-parity rebuild. Ports the legacy production sidebar + header chrome
|
package/dist/index.cjs
CHANGED
|
@@ -1450,8 +1450,7 @@ function Header({ onOpen, id }) {
|
|
|
1450
1450
|
breadcrumbs,
|
|
1451
1451
|
headerActions,
|
|
1452
1452
|
headerIconsSlot,
|
|
1453
|
-
brandLogoSrc
|
|
1454
|
-
devNotesMenu
|
|
1453
|
+
brandLogoSrc
|
|
1455
1454
|
} = useShellChrome();
|
|
1456
1455
|
const mobileNavBg = react.useColorModeValue("white", "gray.900");
|
|
1457
1456
|
const mobileNavBorderColor = react.useColorModeValue("gray.200", "gray.700");
|
|
@@ -1527,8 +1526,7 @@ function Header({ onOpen, id }) {
|
|
|
1527
1526
|
},
|
|
1528
1527
|
children: [
|
|
1529
1528
|
headerActions,
|
|
1530
|
-
headerIconsSlot
|
|
1531
|
-
devNotesMenu
|
|
1529
|
+
headerIconsSlot
|
|
1532
1530
|
]
|
|
1533
1531
|
}
|
|
1534
1532
|
),
|
|
@@ -2184,6 +2182,237 @@ function ModePill() {
|
|
|
2184
2182
|
] }) });
|
|
2185
2183
|
}
|
|
2186
2184
|
var ModePill_default = ModePill;
|
|
2185
|
+
function ActivityIcon() {
|
|
2186
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2187
|
+
"svg",
|
|
2188
|
+
{
|
|
2189
|
+
width: "12",
|
|
2190
|
+
height: "12",
|
|
2191
|
+
viewBox: "0 0 24 24",
|
|
2192
|
+
fill: "none",
|
|
2193
|
+
stroke: "currentColor",
|
|
2194
|
+
strokeWidth: "2",
|
|
2195
|
+
strokeLinecap: "round",
|
|
2196
|
+
strokeLinejoin: "round",
|
|
2197
|
+
"aria-hidden": "true",
|
|
2198
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "22 12 18 12 15 21 9 3 6 12 2 12" })
|
|
2199
|
+
}
|
|
2200
|
+
);
|
|
2201
|
+
}
|
|
2202
|
+
function defaultEnvChip(label) {
|
|
2203
|
+
if (!label) return null;
|
|
2204
|
+
const lower = label.toLowerCase();
|
|
2205
|
+
if (lower.includes("prod")) {
|
|
2206
|
+
return { color: "#ef4444", bg: "#fee2e2", border: "#fecaca", name: label };
|
|
2207
|
+
}
|
|
2208
|
+
if (lower.includes("stag")) {
|
|
2209
|
+
return { color: "#f97316", bg: "#ffedd5", border: "#fed7aa", name: label };
|
|
2210
|
+
}
|
|
2211
|
+
if (lower.includes("local") || lower.includes("dev")) {
|
|
2212
|
+
return { color: "#22c55e", bg: "#dcfce7", border: "#bbf7d0", name: label };
|
|
2213
|
+
}
|
|
2214
|
+
return { color: "#6b7280", bg: "#f3f4f6", border: "#e5e7eb", name: label };
|
|
2215
|
+
}
|
|
2216
|
+
var PLACEHOLDER_SHA_VALUES = /* @__PURE__ */ new Set(["unknown", "n/a", "null", "undefined", ""]);
|
|
2217
|
+
function isMeaningfulCommit(value) {
|
|
2218
|
+
if (typeof value !== "string") return false;
|
|
2219
|
+
const trimmed = value.trim();
|
|
2220
|
+
if (!trimmed) return false;
|
|
2221
|
+
return !PLACEHOLDER_SHA_VALUES.has(trimmed.toLowerCase());
|
|
2222
|
+
}
|
|
2223
|
+
function isMeaningfulAuthor(value) {
|
|
2224
|
+
if (typeof value !== "string") return false;
|
|
2225
|
+
const trimmed = value.trim();
|
|
2226
|
+
if (!trimmed) return false;
|
|
2227
|
+
return !PLACEHOLDER_SHA_VALUES.has(trimmed.toLowerCase());
|
|
2228
|
+
}
|
|
2229
|
+
function getFirstName(value) {
|
|
2230
|
+
if (!value) return "";
|
|
2231
|
+
const stripped = value.replace(/<[^>]+>/g, "").trim();
|
|
2232
|
+
if (!stripped) return "";
|
|
2233
|
+
const [firstToken] = stripped.split(/\s+/);
|
|
2234
|
+
return firstToken || stripped;
|
|
2235
|
+
}
|
|
2236
|
+
function CommitCopyButton({
|
|
2237
|
+
envNode,
|
|
2238
|
+
environmentLabel,
|
|
2239
|
+
commit,
|
|
2240
|
+
version = "",
|
|
2241
|
+
commitDate = "",
|
|
2242
|
+
commitAuthor = "",
|
|
2243
|
+
commitLog = "",
|
|
2244
|
+
onDiagnosticsClick
|
|
2245
|
+
}) {
|
|
2246
|
+
const safeCommit = isMeaningfulCommit(commit) ? commit.trim() : "";
|
|
2247
|
+
const { hasCopied, onCopy } = react.useClipboard(safeCommit);
|
|
2248
|
+
const shortCommit = safeCommit ? safeCommit.slice(-4) : "";
|
|
2249
|
+
const copiedAnimation = react$2.keyframes`
|
|
2250
|
+
0% { opacity: 0; transform: translateY(6px); }
|
|
2251
|
+
20% { opacity: 1; transform: translateY(0); }
|
|
2252
|
+
100% { opacity: 0; transform: translateY(-8px); }
|
|
2253
|
+
`;
|
|
2254
|
+
const formattedDate = react$1.useMemo(() => {
|
|
2255
|
+
if (!commitDate) return "";
|
|
2256
|
+
const parsed = new Date(commitDate);
|
|
2257
|
+
if (Number.isNaN(parsed.getTime())) return commitDate;
|
|
2258
|
+
return parsed.toLocaleDateString(void 0, { month: "short", day: "numeric" });
|
|
2259
|
+
}, [commitDate]);
|
|
2260
|
+
const metaLine = react$1.useMemo(() => {
|
|
2261
|
+
const firstName = isMeaningfulAuthor(commitAuthor) ? getFirstName(commitAuthor) : "";
|
|
2262
|
+
return [formattedDate, firstName].filter(Boolean).join(" | ");
|
|
2263
|
+
}, [formattedDate, commitAuthor]);
|
|
2264
|
+
const normalizedCommitLog = react$1.useMemo(() => {
|
|
2265
|
+
if (commitLog?.trim()) {
|
|
2266
|
+
return commitLog.replace(/\r\n/g, "\n").replace(/\\n/g, "\n");
|
|
2267
|
+
}
|
|
2268
|
+
return "";
|
|
2269
|
+
}, [commitLog]);
|
|
2270
|
+
const tooltipContent = normalizedCommitLog.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2271
|
+
react.Box,
|
|
2272
|
+
{
|
|
2273
|
+
maxW: "600px",
|
|
2274
|
+
width: "min(600px, 90vw)",
|
|
2275
|
+
maxH: "80vh",
|
|
2276
|
+
whiteSpace: "pre-wrap",
|
|
2277
|
+
overflowY: "auto",
|
|
2278
|
+
overflowX: "auto",
|
|
2279
|
+
fontSize: "xs",
|
|
2280
|
+
fontFamily: "mono",
|
|
2281
|
+
wordBreak: "break-word",
|
|
2282
|
+
children: normalizedCommitLog
|
|
2283
|
+
}
|
|
2284
|
+
) : void 0;
|
|
2285
|
+
const envChip = react$1.useMemo(() => {
|
|
2286
|
+
if (envNode) return envNode;
|
|
2287
|
+
const chip = defaultEnvChip(environmentLabel);
|
|
2288
|
+
if (!chip) return null;
|
|
2289
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2290
|
+
react.Box,
|
|
2291
|
+
{
|
|
2292
|
+
as: "span",
|
|
2293
|
+
display: "inline-flex",
|
|
2294
|
+
alignItems: "center",
|
|
2295
|
+
px: "1.5",
|
|
2296
|
+
py: "0.5",
|
|
2297
|
+
borderWidth: "1px",
|
|
2298
|
+
borderColor: chip.border,
|
|
2299
|
+
bg: chip.bg,
|
|
2300
|
+
color: chip.color,
|
|
2301
|
+
borderRadius: "md",
|
|
2302
|
+
fontSize: "2xs",
|
|
2303
|
+
fontWeight: "600",
|
|
2304
|
+
lineHeight: "1",
|
|
2305
|
+
textTransform: "capitalize",
|
|
2306
|
+
"aria-label": `Environment: ${chip.name}`,
|
|
2307
|
+
children: chip.name
|
|
2308
|
+
}
|
|
2309
|
+
);
|
|
2310
|
+
}, [envNode, environmentLabel]);
|
|
2311
|
+
const showEnv = Boolean(envChip);
|
|
2312
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2313
|
+
react.VStack,
|
|
2314
|
+
{
|
|
2315
|
+
justify: "center",
|
|
2316
|
+
align: "center",
|
|
2317
|
+
borderRadius: "md",
|
|
2318
|
+
py: 0.5,
|
|
2319
|
+
px: 1,
|
|
2320
|
+
position: "relative",
|
|
2321
|
+
spacing: 0,
|
|
2322
|
+
textAlign: "center",
|
|
2323
|
+
w: "full",
|
|
2324
|
+
children: [
|
|
2325
|
+
/* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { justify: "center", align: "center", gap: 2, whiteSpace: "nowrap", children: [
|
|
2326
|
+
showEnv ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2327
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Box, { flexShrink: 0, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2328
|
+
react.Tooltip,
|
|
2329
|
+
{
|
|
2330
|
+
label: tooltipContent,
|
|
2331
|
+
isDisabled: !tooltipContent,
|
|
2332
|
+
hasArrow: true,
|
|
2333
|
+
placement: "top-start",
|
|
2334
|
+
openDelay: 150,
|
|
2335
|
+
closeOnClick: false,
|
|
2336
|
+
shouldWrapChildren: true,
|
|
2337
|
+
modifiers: [
|
|
2338
|
+
{ name: "preventOverflow", options: { padding: 16 } },
|
|
2339
|
+
{ name: "offset", options: { offset: [0, 12] } }
|
|
2340
|
+
],
|
|
2341
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2342
|
+
react.Button,
|
|
2343
|
+
{
|
|
2344
|
+
variant: "unstyled",
|
|
2345
|
+
minW: "auto",
|
|
2346
|
+
h: "auto",
|
|
2347
|
+
p: 0,
|
|
2348
|
+
lineHeight: "1",
|
|
2349
|
+
color: "inherit",
|
|
2350
|
+
onClick: onCopy,
|
|
2351
|
+
"aria-label": "Copy commit ID",
|
|
2352
|
+
isDisabled: !safeCommit,
|
|
2353
|
+
children: envChip
|
|
2354
|
+
}
|
|
2355
|
+
)
|
|
2356
|
+
}
|
|
2357
|
+
) }),
|
|
2358
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "2xs", color: "gray.300", flexShrink: 0, children: "|" })
|
|
2359
|
+
] }) : null,
|
|
2360
|
+
shortCommit ? /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "2xs", color: hasCopied ? "green.500" : "gray.400", flexShrink: 0, children: shortCommit }) : null,
|
|
2361
|
+
version ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2362
|
+
shortCommit ? /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "2xs", color: "gray.300", flexShrink: 0, children: "|" }) : null,
|
|
2363
|
+
/* @__PURE__ */ jsxRuntime.jsxs(react.Text, { fontSize: "2xs", color: "gray.400", flexShrink: 0, children: [
|
|
2364
|
+
"v",
|
|
2365
|
+
version
|
|
2366
|
+
] })
|
|
2367
|
+
] }) : null,
|
|
2368
|
+
onDiagnosticsClick ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2369
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "2xs", color: "gray.300", flexShrink: 0, children: "|" }),
|
|
2370
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Tooltip, { label: "Diagnostics", hasArrow: true, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2371
|
+
react.Button,
|
|
2372
|
+
{
|
|
2373
|
+
variant: "unstyled",
|
|
2374
|
+
minW: "auto",
|
|
2375
|
+
h: "auto",
|
|
2376
|
+
p: 0,
|
|
2377
|
+
lineHeight: "1",
|
|
2378
|
+
color: "gray.400",
|
|
2379
|
+
_hover: { color: "gray.600" },
|
|
2380
|
+
onClick: (e) => {
|
|
2381
|
+
e.stopPropagation();
|
|
2382
|
+
onDiagnosticsClick();
|
|
2383
|
+
},
|
|
2384
|
+
"aria-label": "Diagnostics",
|
|
2385
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(react.Icon, { as: ActivityIcon, boxSize: 3 })
|
|
2386
|
+
}
|
|
2387
|
+
) })
|
|
2388
|
+
] }) : null
|
|
2389
|
+
] }),
|
|
2390
|
+
metaLine ? /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { fontSize: "2xs", color: "gray.500", textAlign: "center", whiteSpace: "nowrap", children: [
|
|
2391
|
+
"| ",
|
|
2392
|
+
metaLine,
|
|
2393
|
+
" |"
|
|
2394
|
+
] }) : null,
|
|
2395
|
+
hasCopied && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2396
|
+
react.Box,
|
|
2397
|
+
{
|
|
2398
|
+
position: "absolute",
|
|
2399
|
+
bottom: "100%",
|
|
2400
|
+
mb: "6px",
|
|
2401
|
+
px: "2",
|
|
2402
|
+
py: "1",
|
|
2403
|
+
fontSize: "xs",
|
|
2404
|
+
bg: "gray.700",
|
|
2405
|
+
color: "white",
|
|
2406
|
+
borderRadius: "md",
|
|
2407
|
+
animation: `${copiedAnimation} 0.9s ease-out`,
|
|
2408
|
+
pointerEvents: "none",
|
|
2409
|
+
children: "Copied"
|
|
2410
|
+
}
|
|
2411
|
+
)
|
|
2412
|
+
]
|
|
2413
|
+
}
|
|
2414
|
+
);
|
|
2415
|
+
}
|
|
2187
2416
|
function Sidebar({ onClose, id }) {
|
|
2188
2417
|
const { brandLogoSrc } = useShellChrome();
|
|
2189
2418
|
const navItems = useShellNavItems()?.items ?? [];
|
|
@@ -2316,17 +2545,19 @@ function Sidebar({ onClose, id }) {
|
|
|
2316
2545
|
}
|
|
2317
2546
|
)
|
|
2318
2547
|
] }, `${l.label}-${idx}`)) }),
|
|
2319
|
-
(footer.version || footer.commit || footer.environmentLabel) && /* @__PURE__ */ jsxRuntime.
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
footer.
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
footer.
|
|
2328
|
-
|
|
2329
|
-
|
|
2548
|
+
(footer.version || footer.commit || footer.commitFull || footer.environmentLabel || footer.envNode) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2549
|
+
CommitCopyButton,
|
|
2550
|
+
{
|
|
2551
|
+
envNode: footer.envNode,
|
|
2552
|
+
environmentLabel: footer.environmentLabel,
|
|
2553
|
+
commit: footer.commitFull ?? footer.commit,
|
|
2554
|
+
version: footer.version,
|
|
2555
|
+
commitDate: footer.commitDate,
|
|
2556
|
+
commitAuthor: footer.commitAuthor,
|
|
2557
|
+
commitLog: footer.commitLog,
|
|
2558
|
+
onDiagnosticsClick: footer.onDiagnosticsClick
|
|
2559
|
+
}
|
|
2560
|
+
)
|
|
2330
2561
|
] })
|
|
2331
2562
|
}
|
|
2332
2563
|
)
|
|
@@ -2750,6 +2981,7 @@ exports.BrandIcon = BrandIcon;
|
|
|
2750
2981
|
exports.BrandLogo = BrandLogo;
|
|
2751
2982
|
exports.BreadcrumbBar = BreadcrumbBar;
|
|
2752
2983
|
exports.Card = Card;
|
|
2984
|
+
exports.CommitCopyButton = CommitCopyButton;
|
|
2753
2985
|
exports.Footer = Footer;
|
|
2754
2986
|
exports.GlobalUiIdProvider = GlobalUiIdProvider;
|
|
2755
2987
|
exports.Header = Header;
|