@the-portland-company/shell 0.71.1 → 0.72.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/dist/native.cjs CHANGED
@@ -6,6 +6,7 @@ var clsx = require('clsx');
6
6
  var fi = require('react-icons/fi');
7
7
  var reactDom = require('react-dom');
8
8
  var jsxRuntime = require('react/jsx-runtime');
9
+ var lu = require('react-icons/lu');
9
10
 
10
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
12
 
@@ -1917,6 +1918,45 @@ function useThemePreference() {
1917
1918
  function FormColumn({ children, className }) {
1918
1919
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-shell-form-column": "", className: clsx__default.default("w-full max-w-[960px]", className), children });
1919
1920
  }
1921
+ var standardNavIcons = {
1922
+ home: lu.LuHouse,
1923
+ users: lu.LuUsers,
1924
+ mail: lu.LuMail,
1925
+ messageSquare: lu.LuMessageSquare,
1926
+ layout: lu.LuLayoutDashboard,
1927
+ activity: lu.LuActivity,
1928
+ lifeBuoy: lu.LuLifeBuoy,
1929
+ grid: lu.LuLayoutGrid,
1930
+ list: lu.LuList,
1931
+ upload: lu.LuUpload,
1932
+ edit: lu.LuPencil,
1933
+ fileText: lu.LuFileText,
1934
+ send: lu.LuSend,
1935
+ clock: lu.LuClock,
1936
+ user: lu.LuUser,
1937
+ barChart: lu.LuChartColumn,
1938
+ briefcase: lu.LuBriefcase,
1939
+ settings: lu.LuSettings,
1940
+ creditCard: lu.LuCreditCard,
1941
+ dollarSign: lu.LuDollarSign,
1942
+ share: lu.LuShare2,
1943
+ // Campaign / Petition mode slots.
1944
+ phone: lu.LuPhone,
1945
+ map: lu.LuMap,
1946
+ mapPin: lu.LuMapPin,
1947
+ target: lu.LuTarget,
1948
+ flag: lu.LuFlag,
1949
+ layoutDashboard: lu.LuLayoutDashboard,
1950
+ usersRound: lu.LuUsersRound,
1951
+ mousePointerClick: lu.LuMousePointerClick,
1952
+ clipboardList: lu.LuClipboardList,
1953
+ circleUser: lu.LuCircleUser,
1954
+ crosshair: lu.LuCrosshair,
1955
+ landmark: lu.LuLandmark,
1956
+ chartNoAxes: lu.LuChartNoAxesColumn,
1957
+ doorOpen: lu.LuDoorOpen,
1958
+ signpost: lu.LuSignpost
1959
+ };
1920
1960
 
1921
1961
  // src/native/standardNav.ts
1922
1962
  var CAMPAIGN_FEATURE_AVAILABILITY = {
@@ -2030,7 +2070,7 @@ var APP_SIGNS_CHILDREN = [
2030
2070
  function standardPolitogyNav(opts) {
2031
2071
  const base = opts.coreBaseUrl.replace(/\/+$/, "");
2032
2072
  const abs = (path) => `${base}${path.startsWith("/") ? path : `/${path}`}`;
2033
- const icon = (key) => opts.icons?.[key];
2073
+ const icon = (key) => opts.icons?.[key] ?? standardNavIcons[key];
2034
2074
  const orgParam = opts.activeOrgId ? `org=${opts.activeOrgId}` : "";
2035
2075
  const withOrg = (url) => orgParam ? `${url}${url.includes("?") ? "&" : "?"}${orgParam}` : url;
2036
2076
  const leaves = (children) => children.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(abs(c.path)) }));
@@ -2242,6 +2282,24 @@ function hasActiveChild(item, pathname, activeFn) {
2242
2282
  )
2243
2283
  );
2244
2284
  }
2285
+ function firstLeafHref(item) {
2286
+ for (const c of item.children ?? []) {
2287
+ if (c.kind === "section") continue;
2288
+ if (c.href) return c.href;
2289
+ const deep = firstLeafHref(c);
2290
+ if (deep) return deep;
2291
+ }
2292
+ return void 0;
2293
+ }
2294
+ function modeIdFromLabel(label) {
2295
+ const l = label?.trim().toLowerCase();
2296
+ return l ? l.replace(/\s+mode$/, "") : void 0;
2297
+ }
2298
+ function shortUserName(name) {
2299
+ const parts = name.trim().split(/\s+/).filter(Boolean);
2300
+ if (parts.length < 2) return parts[0] ?? "";
2301
+ return `${parts[0]} ${parts[parts.length - 1][0].toUpperCase()}.`;
2302
+ }
2245
2303
  function shortEnvLabel(label) {
2246
2304
  const l = label.trim().toLowerCase();
2247
2305
  if (l === "production") return "prod";
@@ -2358,7 +2416,6 @@ function NavSidebar({
2358
2416
  react.useEffect(() => {
2359
2417
  setOpenGroup(activeGroupKey);
2360
2418
  }, [activeGroupKey]);
2361
- const toggleGroup = (key) => setOpenGroup((prev) => prev === key ? null : key);
2362
2419
  return /* @__PURE__ */ jsxRuntime.jsxs(RailCollapsibleContext.Provider, { value: collapsible, children: [
2363
2420
  open ? /* @__PURE__ */ jsxRuntime.jsx(
2364
2421
  "div",
@@ -2698,21 +2755,16 @@ function NavSidebar({
2698
2755
  });
2699
2756
  }
2700
2757
  if (item.children && item.children.length > 0) {
2701
- const key = groupKeyOf(item, idx);
2702
2758
  const selfActive = item.href ? activeFn(pathname, item.href) : false;
2703
2759
  const parentActive = selfActive || hasActiveChild(item, pathname, activeFn);
2704
2760
  return /* @__PURE__ */ jsxRuntime.jsx(
2705
- NavGroup,
2761
+ NavRow,
2706
2762
  {
2707
- item,
2763
+ item: { ...item, href: item.href ?? firstLeafHref(item), children: void 0 },
2708
2764
  active: parentActive,
2709
- open: openGroup === key,
2710
- onToggle: () => toggleGroup(key),
2711
- pathname,
2712
- activeFn,
2713
2765
  Link
2714
2766
  },
2715
- key
2767
+ item.href ?? groupKeyOf(item, idx)
2716
2768
  );
2717
2769
  }
2718
2770
  const active = item.href ? activeFn(pathname, item.href) : false;
@@ -3000,142 +3052,6 @@ function NavRow({
3000
3052
  }
3001
3053
  );
3002
3054
  }
3003
- function NavGroup({
3004
- item,
3005
- active,
3006
- open,
3007
- onToggle,
3008
- pathname,
3009
- activeFn,
3010
- Link
3011
- }) {
3012
- const rc = useRailCollapse();
3013
- const Icon = item.icon;
3014
- const headerClasses = [
3015
- "group relative block w-full overflow-hidden text-left transition",
3016
- open ? "rounded-t-[5px]" : "rounded-[5px]",
3017
- active ? NAV_TOP_ACTIVE_CLASS : open ? "bg-[color:var(--sidebar-row-hover-bg,var(--panel))] text-[color:var(--sidebar-text,var(--foreground))]" : NAV_TOP_INACTIVE_CLASS
3018
- ].join(" ");
3019
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3020
- /* @__PURE__ */ jsxRuntime.jsxs(
3021
- "button",
3022
- {
3023
- type: "button",
3024
- onClick: () => {
3025
- onToggle();
3026
- item.onClick?.();
3027
- },
3028
- "aria-expanded": open,
3029
- title: item.label,
3030
- className: headerClasses,
3031
- children: [
3032
- active ? /* @__PURE__ */ jsxRuntime.jsx(NavActiveRail, {}) : null,
3033
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative z-10 flex items-center ${NAV_TOP_ROW_CLASS(active)} ${rc("max-md:justify-center max-md:px-0")}`, children: [
3034
- Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: NAV_TOP_ICON_SIZE, className: "shrink-0 text-current" }) : null,
3035
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `min-w-0 flex-1 truncate ${rc("max-md:hidden")}`, children: item.label }),
3036
- /* @__PURE__ */ jsxRuntime.jsx(NavRowBadge, { value: item.badge }),
3037
- /* @__PURE__ */ jsxRuntime.jsx(
3038
- ChevronDown,
3039
- {
3040
- className: [
3041
- "shrink-0 opacity-80 transition-transform duration-200",
3042
- open ? "rotate-180" : "",
3043
- rc("max-md:hidden")
3044
- ].join(" ")
3045
- }
3046
- )
3047
- ] })
3048
- ]
3049
- }
3050
- ),
3051
- open ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: `overflow-hidden rounded-b-md bg-[color:var(--nav-submenu-bg)] p-1 ${rc("max-md:hidden")}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-0.5", children: item.children.map((child, i) => {
3052
- if (child.kind === "section") {
3053
- return /* @__PURE__ */ jsxRuntime.jsx(
3054
- NavSectionRow,
3055
- {
3056
- label: child.label,
3057
- first: i === 0,
3058
- variant: "sub"
3059
- },
3060
- `sub-section-${i}-${child.label}`
3061
- );
3062
- }
3063
- const childActive = child.href ? activeFn(pathname, child.href) : false;
3064
- if (child.children && child.children.length > 0) {
3065
- return /* @__PURE__ */ jsxRuntime.jsx(
3066
- NavSubGroup,
3067
- {
3068
- item: child,
3069
- pathname,
3070
- activeFn,
3071
- Link
3072
- },
3073
- child.href ?? `subgrp-${i}-${child.label}`
3074
- );
3075
- }
3076
- return /* @__PURE__ */ jsxRuntime.jsx(
3077
- NavRow,
3078
- {
3079
- item: child,
3080
- active: childActive,
3081
- Link,
3082
- variant: "sub"
3083
- },
3084
- child.href ?? `sub-${i}-${child.label}`
3085
- );
3086
- }) }) }) : null
3087
- ] });
3088
- }
3089
- function NavSubGroup({
3090
- item,
3091
- pathname,
3092
- activeFn,
3093
- Link
3094
- }) {
3095
- const ownsActive = (item.href ? activeFn(pathname, item.href) : false) || (item.children ?? []).some((c) => c.href ? activeFn(pathname, c.href) : false);
3096
- const [open, setOpen] = react.useState(ownsActive);
3097
- react.useEffect(() => {
3098
- if (ownsActive) setOpen(true);
3099
- }, [ownsActive]);
3100
- const Icon = item.icon;
3101
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3102
- /* @__PURE__ */ jsxRuntime.jsxs(
3103
- "button",
3104
- {
3105
- type: "button",
3106
- onClick: () => setOpen((v) => !v),
3107
- "aria-expanded": open,
3108
- className: [
3109
- "flex w-full items-center gap-2.5 rounded px-3 py-1.5 text-left text-[13px] font-medium transition",
3110
- 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)]"
3111
- ].join(" "),
3112
- children: [
3113
- Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: 15, className: "shrink-0 text-current" }) : null,
3114
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: item.label }),
3115
- /* @__PURE__ */ jsxRuntime.jsx(
3116
- ChevronDown,
3117
- {
3118
- className: [
3119
- "shrink-0 opacity-70 transition-transform duration-200",
3120
- open ? "rotate-180" : ""
3121
- ].join(" ")
3122
- }
3123
- )
3124
- ]
3125
- }
3126
- ),
3127
- open ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-4 flex flex-col gap-0.5 border-l border-[color:var(--line)] pl-2", children: item.children.map((leaf, i) => /* @__PURE__ */ jsxRuntime.jsx(
3128
- NavRow,
3129
- {
3130
- item: leaf,
3131
- active: leaf.href ? activeFn(pathname, leaf.href) : false,
3132
- Link,
3133
- variant: "sub"
3134
- },
3135
- leaf.href ?? `subsub-${i}-${leaf.label}`
3136
- )) }) : null
3137
- ] });
3138
- }
3139
3055
  function OrgIdCopyButton({ id }) {
3140
3056
  const [copied, setCopied] = react.useState(false);
3141
3057
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -3435,8 +3351,8 @@ function NavSidebarUserCard({
3435
3351
  }) {
3436
3352
  const rawName = user.name?.trim() || "";
3437
3353
  const hasRealName = rawName.length > 0 && !rawName.includes("@");
3438
- const displayName = hasRealName ? rawName : user.email ?? "Signed in";
3439
- const initials = (hasRealName ? rawName : user.email ?? "P").slice(0, 2).toUpperCase();
3354
+ const displayName = hasRealName ? shortUserName(rawName) : user.email ?? "Signed in";
3355
+ const initials = hasRealName ? rawName.split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0]).join("").toUpperCase() : (user.email ?? "P").slice(0, 2).toUpperCase();
3440
3356
  const secondary = hasRealName ? user.email || [user.tier, user.role].filter(Boolean).join(" \xB7 ") || "member" : [user.tier, user.role].filter(Boolean).join(" \xB7 ") || "member";
3441
3357
  const rc = useRailCollapse();
3442
3358
  return /* @__PURE__ */ jsxRuntime.jsxs("details", { "data-nav-details": true, className: "group/acct relative", children: [
@@ -3836,7 +3752,7 @@ function NavAppShell({
3836
3752
  return /* @__PURE__ */ jsxRuntime.jsxs(
3837
3753
  "div",
3838
3754
  {
3839
- "data-politogy-mode": modeId,
3755
+ "data-politogy-mode": modeId ?? modeIdFromLabel(sidebar.mode?.label),
3840
3756
  className: "min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]",
3841
3757
  children: [
3842
3758
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -3909,8 +3825,10 @@ exports.TopBarWidgetSlot = TopBarWidgetSlot;
3909
3825
  exports.clearBetaBannerDismissal = clearBetaBannerDismissal;
3910
3826
  exports.envChipClasses = envChipClasses;
3911
3827
  exports.isNavItemActive = isNavItemActive;
3828
+ exports.modeIdFromLabel = modeIdFromLabel;
3912
3829
  exports.resolveOrgLogoUrl = resolveOrgLogoUrl;
3913
3830
  exports.shortEnvLabel = shortEnvLabel;
3831
+ exports.shortUserName = shortUserName;
3914
3832
  exports.standardPolitogyNav = standardPolitogyNav;
3915
3833
  exports.topBarIconButtonClass = topBarIconButtonClass;
3916
3834
  exports.useChromeMe = useChromeMe;