@the-portland-company/shell 0.11.3 → 0.12.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 +49 -0
- package/dist/chunk-2GFWARYP.js.map +1 -0
- package/dist/index.cjs +39 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +14 -21
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +29 -17
- package/dist/native.cjs.map +1 -1
- package/dist/native.js +4 -16
- package/dist/native.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-VTGRJ4HV.js +0 -25
- package/dist/chunk-VTGRJ4HV.js.map +0 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { FiUser, FiSettings, FiMessageSquare, FiMail, FiInfo, FiSun, FiMoon, FiHelpCircle, FiLifeBuoy, FiAlertCircle, FiAlertTriangle, FiBell, FiGrid, FiZap } from 'react-icons/fi';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
// src/lib/brandGlyphs.tsx
|
|
5
|
+
var GLYPHS = {
|
|
6
|
+
bolt: FiZap,
|
|
7
|
+
zap: FiZap,
|
|
8
|
+
grid: FiGrid,
|
|
9
|
+
apps: FiGrid,
|
|
10
|
+
bell: FiBell,
|
|
11
|
+
notification: FiBell,
|
|
12
|
+
"alert-triangle": FiAlertTriangle,
|
|
13
|
+
alert: FiAlertTriangle,
|
|
14
|
+
"alert-circle": FiAlertCircle,
|
|
15
|
+
"life-buoy": FiLifeBuoy,
|
|
16
|
+
"life-ring": FiLifeBuoy,
|
|
17
|
+
support: FiLifeBuoy,
|
|
18
|
+
"help-circle": FiHelpCircle,
|
|
19
|
+
moon: FiMoon,
|
|
20
|
+
sun: FiSun,
|
|
21
|
+
info: FiInfo,
|
|
22
|
+
mail: FiMail,
|
|
23
|
+
"message-square": FiMessageSquare,
|
|
24
|
+
settings: FiSettings,
|
|
25
|
+
user: FiUser
|
|
26
|
+
};
|
|
27
|
+
function resolveBrandGlyph(name) {
|
|
28
|
+
if (!name) return null;
|
|
29
|
+
return GLYPHS[name.trim().toLowerCase()] ?? null;
|
|
30
|
+
}
|
|
31
|
+
function useTopBarIconSlotGlyph(slot) {
|
|
32
|
+
const [name, setName] = useState(null);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (typeof window === "undefined") return;
|
|
35
|
+
const read = () => {
|
|
36
|
+
const raw = window.getComputedStyle(document.documentElement).getPropertyValue(`--topbar-icon-${slot}`).trim().replace(/^['"]|['"]$/g, "");
|
|
37
|
+
setName(raw.length > 0 ? raw : null);
|
|
38
|
+
};
|
|
39
|
+
read();
|
|
40
|
+
const observer = new MutationObserver(read);
|
|
41
|
+
observer.observe(document.head, { childList: true, subtree: true });
|
|
42
|
+
return () => observer.disconnect();
|
|
43
|
+
}, [slot]);
|
|
44
|
+
return name;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { resolveBrandGlyph, useTopBarIconSlotGlyph };
|
|
48
|
+
//# sourceMappingURL=chunk-2GFWARYP.js.map
|
|
49
|
+
//# sourceMappingURL=chunk-2GFWARYP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/brandGlyphs.tsx","../src/lib/topbarIconSlot.ts"],"names":[],"mappings":";;;;AAgCA,IAAM,MAAA,GAAyC;AAAA,EAC7C,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;AClCO,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-2GFWARYP.js","sourcesContent":["import type { ComponentType } from 'react'\nimport {\n FiAlertCircle,\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 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
|
@@ -1653,9 +1653,10 @@ function NavItem({
|
|
|
1653
1653
|
const hasActiveChild = Array.isArray(subItems) && subItems.some((item) => matchesSubItem(item.href || ""));
|
|
1654
1654
|
const isParentActive = isActive || hasActiveChild;
|
|
1655
1655
|
const isSubMenuOpen = isExpanded !== void 0 ? isExpanded : hasSubItems && subItems.some((item) => matchesSubItem(item.href || ""));
|
|
1656
|
-
const
|
|
1657
|
-
const
|
|
1658
|
-
const
|
|
1656
|
+
const submenuBg = "var(--sidebar-submenu-bg, #F1F5F9)";
|
|
1657
|
+
const expandedRowBg = isParentActive ? modeConfig?.primaryColor || "brand.500" : isSubMenuOpen ? submenuBg : "transparent";
|
|
1658
|
+
const expandedRowTextColor = isParentActive ? "white" : isSubMenuOpen ? "var(--sidebar-text, #1A202C)" : "var(--sidebar-text-muted, #4A5568)";
|
|
1659
|
+
const disabledRowBg = isSubItem ? submenuBg : "transparent";
|
|
1659
1660
|
const disabledRowTextColor = "gray.400";
|
|
1660
1661
|
const renderIcon = (activeForHover) => {
|
|
1661
1662
|
if (brandIcon) {
|
|
@@ -1708,8 +1709,8 @@ function NavItem({
|
|
|
1708
1709
|
bg: isDisabled ? disabledRowBg : expandedRowBg,
|
|
1709
1710
|
color: isDisabled ? disabledRowTextColor : expandedRowTextColor,
|
|
1710
1711
|
_hover: {
|
|
1711
|
-
bg: isDisabled ? disabledRowBg : isParentActive ? modeConfig?.accentColor || "brand.600" : "
|
|
1712
|
-
color: isDisabled ? disabledRowTextColor : isParentActive ? "white" : "
|
|
1712
|
+
bg: isDisabled ? disabledRowBg : isParentActive ? modeConfig?.accentColor || "brand.600" : "var(--sidebar-hover-bg, #E2E8F0)",
|
|
1713
|
+
color: isDisabled ? disabledRowTextColor : isParentActive ? "white" : "var(--sidebar-text, #1A202C)"
|
|
1713
1714
|
},
|
|
1714
1715
|
"aria-disabled": isDisabled ? "true" : "false",
|
|
1715
1716
|
onClick: (e) => {
|
|
@@ -1750,8 +1751,8 @@ function NavItem({
|
|
|
1750
1751
|
bg: isDisabled ? disabledRowBg : expandedRowBg,
|
|
1751
1752
|
color: isDisabled ? disabledRowTextColor : expandedRowTextColor,
|
|
1752
1753
|
_hover: {
|
|
1753
|
-
bg: isDisabled ? disabledRowBg : hasActiveChild ? modeConfig?.accentColor || "brand.600" : "
|
|
1754
|
-
color: isDisabled ? disabledRowTextColor : hasActiveChild ? "white" : "
|
|
1754
|
+
bg: isDisabled ? disabledRowBg : hasActiveChild ? modeConfig?.accentColor || "brand.600" : "var(--sidebar-hover-bg, #E2E8F0)",
|
|
1755
|
+
color: isDisabled ? disabledRowTextColor : hasActiveChild ? "white" : "var(--sidebar-text, #1A202C)"
|
|
1755
1756
|
},
|
|
1756
1757
|
"aria-disabled": isDisabled ? "true" : "false",
|
|
1757
1758
|
onClick: (e) => {
|
|
@@ -1784,7 +1785,7 @@ function NavItem({
|
|
|
1784
1785
|
py: "1",
|
|
1785
1786
|
borderTopRadius: 0,
|
|
1786
1787
|
borderBottomRadius: "md",
|
|
1787
|
-
bg:
|
|
1788
|
+
bg: submenuBg,
|
|
1788
1789
|
children: subItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1789
1790
|
NavItem,
|
|
1790
1791
|
{
|
|
@@ -1839,10 +1840,10 @@ function NavItem({
|
|
|
1839
1840
|
opacity: 1,
|
|
1840
1841
|
pointerEvents: isDisabled ? "none" : "auto",
|
|
1841
1842
|
"data-nav-item-active": String(rowActive),
|
|
1842
|
-
bg: isDisabled ? disabledRowBg : rowActive ? isSubItem ? "
|
|
1843
|
+
bg: isDisabled ? disabledRowBg : rowActive ? isSubItem ? "var(--sidebar-hover-bg, #EDF2F7)" : modeConfig?.primaryColor || "brand.500" : "transparent",
|
|
1843
1844
|
color: isDisabled ? disabledRowTextColor : rowActive ? isSubItem ? modeConfig?.primaryColor || "brand.500" : "white" : "gray.600",
|
|
1844
1845
|
_hover: {
|
|
1845
|
-
bg: isDisabled ? disabledRowBg : rowActive ? isSubItem ? "
|
|
1846
|
+
bg: isDisabled ? disabledRowBg : rowActive ? isSubItem ? "var(--sidebar-hover-bg, #E2E8F0)" : modeConfig?.accentColor || "brand.600" : "var(--sidebar-hover-bg, #EDF2F7)",
|
|
1846
1847
|
color: isDisabled ? disabledRowTextColor : rowActive ? isSubItem ? modeConfig?.primaryColor || "brand.500" : "white" : "gray.900"
|
|
1847
1848
|
},
|
|
1848
1849
|
"aria-disabled": isDisabled ? "true" : "false",
|
|
@@ -2655,6 +2656,32 @@ function AppLayout({
|
|
|
2655
2656
|
overlaySlot
|
|
2656
2657
|
] });
|
|
2657
2658
|
}
|
|
2659
|
+
var GLYPHS = {
|
|
2660
|
+
bolt: fi.FiZap,
|
|
2661
|
+
zap: fi.FiZap,
|
|
2662
|
+
grid: fi.FiGrid,
|
|
2663
|
+
apps: fi.FiGrid,
|
|
2664
|
+
bell: fi.FiBell,
|
|
2665
|
+
notification: fi.FiBell,
|
|
2666
|
+
"alert-triangle": fi.FiAlertTriangle,
|
|
2667
|
+
alert: fi.FiAlertTriangle,
|
|
2668
|
+
"alert-circle": fi.FiAlertCircle,
|
|
2669
|
+
"life-buoy": fi.FiLifeBuoy,
|
|
2670
|
+
"life-ring": fi.FiLifeBuoy,
|
|
2671
|
+
support: fi.FiLifeBuoy,
|
|
2672
|
+
"help-circle": fi.FiHelpCircle,
|
|
2673
|
+
moon: fi.FiMoon,
|
|
2674
|
+
sun: fi.FiSun,
|
|
2675
|
+
info: fi.FiInfo,
|
|
2676
|
+
mail: fi.FiMail,
|
|
2677
|
+
"message-square": fi.FiMessageSquare,
|
|
2678
|
+
settings: fi.FiSettings,
|
|
2679
|
+
user: fi.FiUser
|
|
2680
|
+
};
|
|
2681
|
+
function resolveBrandGlyph(name) {
|
|
2682
|
+
if (!name) return null;
|
|
2683
|
+
return GLYPHS[name.trim().toLowerCase()] ?? null;
|
|
2684
|
+
}
|
|
2658
2685
|
function useTopBarIconSlotGlyph(slot) {
|
|
2659
2686
|
const [name, setName] = react$1.useState(null);
|
|
2660
2687
|
react$1.useEffect(() => {
|
|
@@ -2673,16 +2700,8 @@ function useTopBarIconSlotGlyph(slot) {
|
|
|
2673
2700
|
var TopBarIcon = react$1.forwardRef(
|
|
2674
2701
|
function TopBarIcon2({ slot, fallbackIcon, isSelected, ...rest }, ref) {
|
|
2675
2702
|
const glyphName = useTopBarIconSlotGlyph(slot);
|
|
2676
|
-
const
|
|
2677
|
-
|
|
2678
|
-
{
|
|
2679
|
-
name: glyphName,
|
|
2680
|
-
style: {
|
|
2681
|
-
width: "var(--topbar-icon-size, 20px)",
|
|
2682
|
-
height: "var(--topbar-icon-size, 20px)"
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
|
-
) : fallbackIcon;
|
|
2703
|
+
const Glyph = resolveBrandGlyph(glyphName);
|
|
2704
|
+
const icon = Glyph ? /* @__PURE__ */ jsxRuntime.jsx(Glyph, { size: "var(--topbar-icon-size, 20px)" }) : fallbackIcon;
|
|
2686
2705
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2687
2706
|
react.IconButton,
|
|
2688
2707
|
{
|