@the-portland-company/shell 0.12.0 → 0.13.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/dist/{chunk-2GFWARYP.js → chunk-NV6WHTEZ.js} +8 -3
- package/dist/chunk-NV6WHTEZ.js.map +1 -0
- package/dist/index.cjs +63 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -4
- package/dist/index.d.ts +21 -4
- package/dist/index.js +60 -16
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +5 -0
- package/dist/native.cjs.map +1 -1
- package/dist/native.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-2GFWARYP.js.map +0 -1
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import { FiUser, FiSettings, FiMessageSquare, FiMail, FiInfo, FiSun, FiMoon, FiHelpCircle, FiLifeBuoy, FiAlertCircle, FiAlertTriangle, FiBell, FiGrid, FiZap } from 'react-icons/fi';
|
|
1
|
+
import { FiUser, FiSettings, FiMessageSquare, FiMail, FiInfo, FiSun, FiMoon, FiHelpCircle, FiLifeBuoy, FiAlertCircle, FiAlertTriangle, FiBell, FiGrid, FiZap, FiBatteryCharging, FiBattery } from 'react-icons/fi';
|
|
2
2
|
import { useState, useEffect } from 'react';
|
|
3
3
|
|
|
4
4
|
// src/lib/brandGlyphs.tsx
|
|
5
5
|
var GLYPHS = {
|
|
6
|
+
// Communications Fuel reads as a LEVEL, so its glyph is a battery. `bolt`/
|
|
7
|
+
// `zap` stay mapped for older Brand values.
|
|
8
|
+
"battery-charging": FiBatteryCharging,
|
|
9
|
+
battery: FiBattery,
|
|
10
|
+
fuel: FiBatteryCharging,
|
|
6
11
|
bolt: FiZap,
|
|
7
12
|
zap: FiZap,
|
|
8
13
|
grid: FiGrid,
|
|
@@ -45,5 +50,5 @@ function useTopBarIconSlotGlyph(slot) {
|
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
export { resolveBrandGlyph, useTopBarIconSlotGlyph };
|
|
48
|
-
//# sourceMappingURL=chunk-
|
|
49
|
-
//# sourceMappingURL=chunk-
|
|
53
|
+
//# sourceMappingURL=chunk-NV6WHTEZ.js.map
|
|
54
|
+
//# sourceMappingURL=chunk-NV6WHTEZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/brandGlyphs.tsx","../src/lib/topbarIconSlot.ts"],"names":[],"mappings":";;;;AAkCA,IAAM,MAAA,GAAyC;AAAA;AAAA;AAAA,EAG7C,kBAAA,EAAoB,iBAAA;AAAA,EACpB,OAAA,EAAS,SAAA;AAAA,EACT,IAAA,EAAM,iBAAA;AAAA,EACN,IAAA,EAAM,KAAA;AAAA,EACN,GAAA,EAAK,KAAA;AAAA,EACL,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM,MAAA;AAAA,EACN,YAAA,EAAc,MAAA;AAAA,EACd,gBAAA,EAAkB,eAAA;AAAA,EAClB,KAAA,EAAO,eAAA;AAAA,EACP,cAAA,EAAgB,aAAA;AAAA,EAChB,WAAA,EAAa,UAAA;AAAA,EACb,WAAA,EAAa,UAAA;AAAA,EACb,OAAA,EAAS,UAAA;AAAA,EACT,aAAA,EAAe,YAAA;AAAA,EACf,IAAA,EAAM,MAAA;AAAA,EACN,GAAA,EAAK,KAAA;AAAA,EACL,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM,MAAA;AAAA,EACN,gBAAA,EAAkB,eAAA;AAAA,EAClB,QAAA,EAAU,UAAA;AAAA,EACV,IAAA,EAAM;AACR,CAAA;AAOO,SAAS,kBAAkB,IAAA,EAAwD;AACxF,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,OAAO,OAAO,IAAA,CAAK,IAAA,EAAK,CAAE,WAAA,EAAa,CAAA,IAAK,IAAA;AAC9C;ACzCO,SAAS,uBAAuB,IAAA,EAAqC;AAC1E,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAwB,IAAI,CAAA;AAEpD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAEnC,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,MAAM,GAAA,GAAM,MAAA,CACT,gBAAA,CAAiB,QAAA,CAAS,eAAe,CAAA,CACzC,gBAAA,CAAiB,CAAA,cAAA,EAAiB,IAAI,EAAE,CAAA,CACxC,IAAA,EAAK,CAEL,OAAA,CAAQ,gBAAgB,EAAE,CAAA;AAC7B,MAAA,OAAA,CAAQ,GAAA,CAAI,MAAA,GAAS,CAAA,GAAI,GAAA,GAAM,IAAI,CAAA;AAAA,IACrC,CAAA;AAEA,IAAA,IAAA,EAAK;AAEL,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,IAAI,CAAA;AAC1C,IAAA,QAAA,CAAS,OAAA,CAAQ,SAAS,IAAA,EAAM,EAAE,WAAW,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AAClE,IAAA,OAAO,MAAM,SAAS,UAAA,EAAW;AAAA,EACnC,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,OAAO,IAAA;AACT","file":"chunk-NV6WHTEZ.js","sourcesContent":["import type { ComponentType } from 'react'\nimport {\n FiAlertCircle,\n FiBattery,\n FiBatteryCharging,\n FiAlertTriangle,\n FiBell,\n FiGrid,\n FiHelpCircle,\n FiInfo,\n FiLifeBuoy,\n FiMail,\n FiMessageSquare,\n FiMoon,\n FiSettings,\n FiSun,\n FiUser,\n FiZap,\n} from 'react-icons/fi'\n\nexport type GlyphComponent = ComponentType<{ size?: number | string; className?: string }>\n\n/**\n * Brand-glyph registry: maps the icon NAME the Brand API emits (e.g.\n * `--topbar-icon-comms-fuel: bolt`) to a component.\n *\n * These names are Feather/Lucide icon names, NOT asset filenames — there is no\n * `/brand/icons/<name>.svg` for them in any app, and treating them as URLs\n * renders a broken image. Resolving them against the icon library the shell\n * already depends on keeps every app consistent with zero vendored assets.\n *\n * Aliases are included where Brand and Feather disagree on a name (`bolt` vs\n * `zap`, `life-buoy` vs `life-ring`).\n */\nconst GLYPHS: Record<string, GlyphComponent> = {\n // Communications Fuel reads as a LEVEL, so its glyph is a battery. `bolt`/\n // `zap` stay mapped for older Brand values.\n 'battery-charging': FiBatteryCharging,\n battery: FiBattery,\n fuel: FiBatteryCharging,\n bolt: FiZap,\n zap: FiZap,\n grid: FiGrid,\n apps: FiGrid,\n bell: FiBell,\n notification: FiBell,\n 'alert-triangle': FiAlertTriangle,\n alert: FiAlertTriangle,\n 'alert-circle': FiAlertCircle,\n 'life-buoy': FiLifeBuoy,\n 'life-ring': FiLifeBuoy,\n support: FiLifeBuoy,\n 'help-circle': FiHelpCircle,\n moon: FiMoon,\n sun: FiSun,\n info: FiInfo,\n mail: FiMail,\n 'message-square': FiMessageSquare,\n settings: FiSettings,\n user: FiUser,\n}\n\n/**\n * Resolve a Brand glyph name to a component. Returns null for an unknown name\n * so the caller renders its own fallback — an unrecognized token must never\n * produce a broken or empty icon.\n */\nexport function resolveBrandGlyph(name: string | null | undefined): GlyphComponent | null {\n if (!name) return null\n return GLYPHS[name.trim().toLowerCase()] ?? null\n}\n\n/** Names the registry knows — exported for tests and tooling. */\nexport const KNOWN_BRAND_GLYPHS = Object.keys(GLYPHS)\n","import { useEffect, useState } from 'react'\n\n/**\n * The six canonical top-bar action slots (Reference/Global-Rules v9 → top-bar\n * icons). Each slot's GLYPH is unique and comes from the Brand API\n * `topbarIcons.items.*` tokens, exposed as `--topbar-icon-<slot>` CSS vars\n * whose value is the brand-icon NAME. Every OTHER property — size, gap, color,\n * hover, selected — is universal across all six slots.\n */\nexport type TopBarIconSlot =\n | 'comms-fuel'\n | 'apps'\n | 'notifications'\n | 'alerts'\n | 'support'\n | 'dark-mode'\n\n/**\n * Reads the glyph NAME for a slot from its `--topbar-icon-<slot>` CSS var.\n *\n * Runs in an effect because the Brand stylesheet is appended to <head> at\n * runtime (Global Rules forbids baking it into the build), so the var is not\n * resolvable during SSR or the first synchronous render. The MutationObserver\n * re-reads once the stylesheet lands so the glyph upgrades from the caller's\n * fallback without a reload.\n *\n * Returns null when the slot has no Brand glyph — callers render their own\n * fallback icon in that case.\n */\nexport function useTopBarIconSlotGlyph(slot: TopBarIconSlot): string | null {\n const [name, setName] = useState<string | null>(null)\n\n useEffect(() => {\n if (typeof window === 'undefined') return\n\n const read = () => {\n const raw = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(`--topbar-icon-${slot}`)\n .trim()\n // Brand may emit the name quoted (e.g. \"bell\"); strip the quotes.\n .replace(/^['\"]|['\"]$/g, '')\n setName(raw.length > 0 ? raw : null)\n }\n\n read()\n\n const observer = new MutationObserver(read)\n observer.observe(document.head, { childList: true, subtree: true })\n return () => observer.disconnect()\n }, [slot])\n\n return name\n}\n\n/** Path to a brand-icon SVG in the consuming app's public dir. */\nexport function brandIconSrc(name: string, basePath = '/brand/icons/') {\n return `${basePath}${name}.svg`\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1303,7 +1303,7 @@ function UserMenu() {
|
|
|
1303
1303
|
const org = useShellOrganization();
|
|
1304
1304
|
const role = useShellRole();
|
|
1305
1305
|
const navigate = reactRouterDom.useNavigate();
|
|
1306
|
-
const menuListBg =
|
|
1306
|
+
const menuListBg = "var(--topbar-bg, #FFFFFF)";
|
|
1307
1307
|
const menuListBorderColor = react.useColorModeValue("gray.200", "gray.700");
|
|
1308
1308
|
if (status !== "authenticated" || !user) return null;
|
|
1309
1309
|
const displayName = getUserDisplayName(user.raw);
|
|
@@ -1464,8 +1464,8 @@ function Header({ onOpen, id }) {
|
|
|
1464
1464
|
headerIconsSlot,
|
|
1465
1465
|
brandLogoSrc
|
|
1466
1466
|
} = useShellChrome();
|
|
1467
|
-
const mobileNavBg =
|
|
1468
|
-
const mobileNavBorderColor =
|
|
1467
|
+
const mobileNavBg = "var(--sidebar-bg, #FFFFFF)";
|
|
1468
|
+
const mobileNavBorderColor = "var(--sidebar-border, #E2E8F0)";
|
|
1469
1469
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1470
1470
|
react.Flex,
|
|
1471
1471
|
{
|
|
@@ -1533,7 +1533,8 @@ function Header({ onOpen, id }) {
|
|
|
1533
1533
|
},
|
|
1534
1534
|
'& button:not([role="menuitem"]):not([data-menu-item]) svg, & button:not([role="menuitem"]):not([data-menu-item]) img': {
|
|
1535
1535
|
width: "var(--topbar-icon-size, 20px)",
|
|
1536
|
-
height: "var(--topbar-icon-size, 20px)"
|
|
1536
|
+
height: "var(--topbar-icon-size, 20px)",
|
|
1537
|
+
strokeWidth: "var(--topbar-icon-stroke-width, 2)"
|
|
1537
1538
|
}
|
|
1538
1539
|
},
|
|
1539
1540
|
children: [
|
|
@@ -2460,8 +2461,8 @@ function Sidebar({ onClose, id }) {
|
|
|
2460
2461
|
const org = useShellOrganization();
|
|
2461
2462
|
const currentOrg = org?.currentOrg ?? null;
|
|
2462
2463
|
const location = reactRouterDom.useLocation();
|
|
2463
|
-
const sidebarBg =
|
|
2464
|
-
const sidebarBorderColor =
|
|
2464
|
+
const sidebarBg = "var(--sidebar-bg, #FFFFFF)";
|
|
2465
|
+
const sidebarBorderColor = "var(--sidebar-border, #E2E8F0)";
|
|
2465
2466
|
const [expandedMenu, setExpandedMenu] = react$1.useState(null);
|
|
2466
2467
|
react$1.useEffect(() => {
|
|
2467
2468
|
const activeMenu = navItems.find(
|
|
@@ -2657,6 +2658,11 @@ function AppLayout({
|
|
|
2657
2658
|
] });
|
|
2658
2659
|
}
|
|
2659
2660
|
var GLYPHS = {
|
|
2661
|
+
// Communications Fuel reads as a LEVEL, so its glyph is a battery. `bolt`/
|
|
2662
|
+
// `zap` stay mapped for older Brand values.
|
|
2663
|
+
"battery-charging": fi.FiBatteryCharging,
|
|
2664
|
+
battery: fi.FiBattery,
|
|
2665
|
+
fuel: fi.FiBatteryCharging,
|
|
2660
2666
|
bolt: fi.FiZap,
|
|
2661
2667
|
zap: fi.FiZap,
|
|
2662
2668
|
grid: fi.FiGrid,
|
|
@@ -2697,28 +2703,72 @@ function useTopBarIconSlotGlyph(slot) {
|
|
|
2697
2703
|
}, [slot]);
|
|
2698
2704
|
return name;
|
|
2699
2705
|
}
|
|
2706
|
+
function TopBarBadge({ count }) {
|
|
2707
|
+
if (!count || count <= 0) return null;
|
|
2708
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2709
|
+
react.Badge,
|
|
2710
|
+
{
|
|
2711
|
+
position: "absolute",
|
|
2712
|
+
top: "-2px",
|
|
2713
|
+
right: "-2px",
|
|
2714
|
+
bg: "var(--topbar-badge-bg, #E63946)",
|
|
2715
|
+
color: "var(--topbar-badge-fg, #FFFFFF)",
|
|
2716
|
+
rounded: "full",
|
|
2717
|
+
fontSize: "0.625rem",
|
|
2718
|
+
fontWeight: "bold",
|
|
2719
|
+
lineHeight: "1",
|
|
2720
|
+
minW: "1rem",
|
|
2721
|
+
h: "1rem",
|
|
2722
|
+
px: "1",
|
|
2723
|
+
display: "flex",
|
|
2724
|
+
alignItems: "center",
|
|
2725
|
+
justifyContent: "center",
|
|
2726
|
+
pointerEvents: "none",
|
|
2727
|
+
"aria-hidden": true,
|
|
2728
|
+
children: count > 9 ? "9+" : count
|
|
2729
|
+
}
|
|
2730
|
+
);
|
|
2731
|
+
}
|
|
2700
2732
|
var TopBarIcon = react$1.forwardRef(
|
|
2701
|
-
function TopBarIcon2({ slot, fallbackIcon, isSelected, ...rest }, ref) {
|
|
2733
|
+
function TopBarIcon2({ slot, fallbackIcon, isSelected, badgeCount, children, ...rest }, ref) {
|
|
2702
2734
|
const glyphName = useTopBarIconSlotGlyph(slot);
|
|
2703
2735
|
const Glyph = resolveBrandGlyph(glyphName);
|
|
2704
|
-
const icon = Glyph ? /* @__PURE__ */ jsxRuntime.jsx(Glyph, {
|
|
2705
|
-
|
|
2736
|
+
const icon = Glyph ? /* @__PURE__ */ jsxRuntime.jsx(Glyph, {}) : fallbackIcon;
|
|
2737
|
+
const button = /* @__PURE__ */ jsxRuntime.jsx(
|
|
2706
2738
|
react.IconButton,
|
|
2707
2739
|
{
|
|
2708
2740
|
ref,
|
|
2709
2741
|
icon,
|
|
2710
2742
|
variant: "ghost",
|
|
2711
2743
|
minW: "var(--topbar-icon-button-size, 32px)",
|
|
2744
|
+
w: "var(--topbar-icon-button-size, 32px)",
|
|
2712
2745
|
h: "var(--topbar-icon-button-size, 32px)",
|
|
2746
|
+
p: "0",
|
|
2713
2747
|
bg: isSelected ? "var(--topbar-icon-selected-bg, transparent)" : "transparent",
|
|
2714
2748
|
color: isSelected ? "var(--topbar-icon-selected-color, var(--topbar-icon-color, #64748B))" : "var(--topbar-icon-color, #64748B)",
|
|
2715
2749
|
_hover: {
|
|
2716
2750
|
bg: "var(--topbar-icon-hover-bg, transparent)",
|
|
2717
2751
|
color: "var(--topbar-icon-hover-color, var(--topbar-icon-color, #64748B))"
|
|
2718
2752
|
},
|
|
2753
|
+
sx: {
|
|
2754
|
+
// Normalize the glyph itself, not just its box. Covers react-icons
|
|
2755
|
+
// <svg> and brand <img> alike, and pins stroke weight so one glyph
|
|
2756
|
+
// can't read heavier than its neighbours.
|
|
2757
|
+
"& svg, & img": {
|
|
2758
|
+
width: "var(--topbar-icon-size, 20px)",
|
|
2759
|
+
height: "var(--topbar-icon-size, 20px)",
|
|
2760
|
+
strokeWidth: "var(--topbar-icon-stroke-width, 2)"
|
|
2761
|
+
}
|
|
2762
|
+
},
|
|
2719
2763
|
...rest
|
|
2720
2764
|
}
|
|
2721
2765
|
);
|
|
2766
|
+
if (!badgeCount && !children) return button;
|
|
2767
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { position: "relative", display: "inline-flex", children: [
|
|
2768
|
+
button,
|
|
2769
|
+
/* @__PURE__ */ jsxRuntime.jsx(TopBarBadge, { count: badgeCount ?? 0 }),
|
|
2770
|
+
children
|
|
2771
|
+
] });
|
|
2722
2772
|
}
|
|
2723
2773
|
);
|
|
2724
2774
|
var SUPPORT_REQUEST_SUCCESS_MESSAGE = "Your support request was sent to Politogy leadership.";
|
|
@@ -2873,12 +2923,11 @@ ${formatted}` : formatted,
|
|
|
2873
2923
|
if (!support) return null;
|
|
2874
2924
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2875
2925
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2876
|
-
|
|
2926
|
+
TopBarIcon,
|
|
2877
2927
|
{
|
|
2928
|
+
slot: "support",
|
|
2878
2929
|
"aria-label": "Request support",
|
|
2879
|
-
|
|
2880
|
-
variant: "ghost",
|
|
2881
|
-
size: "sm",
|
|
2930
|
+
fallbackIcon: /* @__PURE__ */ jsxRuntime.jsx(LifebuoyIcon, {}),
|
|
2882
2931
|
onClick: onOpen
|
|
2883
2932
|
}
|
|
2884
2933
|
),
|
|
@@ -3121,6 +3170,7 @@ exports.ShellRoleContext = ShellRoleContext;
|
|
|
3121
3170
|
exports.ShellSupportProviderContext = ShellSupportProviderContext;
|
|
3122
3171
|
exports.Sidebar = Sidebar;
|
|
3123
3172
|
exports.SupportRequestButton = SupportRequestButton;
|
|
3173
|
+
exports.TopBarBadge = TopBarBadge;
|
|
3124
3174
|
exports.TopBarIcon = TopBarIcon;
|
|
3125
3175
|
exports.UserMenu = UserMenu;
|
|
3126
3176
|
exports.buildSpeculationRules = buildSpeculationRules;
|