@the-portland-company/shell 0.95.0 → 0.96.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.
@@ -33,6 +33,51 @@ type AiCreditsStateProps = {
33
33
  };
34
34
  declare function AiCreditsState({ kind, orgId, isAccountAdmin, lastOutputAt, onCheckAgain, formatTime, className, style, }: AiCreditsStateProps): react_jsx_runtime.JSX.Element;
35
35
 
36
+ type RowMenuPlacement = 'below' | 'above';
37
+ /**
38
+ * Where the panel goes: below the trigger, right-aligned to it, unless it does
39
+ * not fit below and there is more room above. Clamped inside the viewport.
40
+ */
41
+ declare function rowMenuPosition(trigger: {
42
+ top: number;
43
+ bottom: number;
44
+ right: number;
45
+ }, panel: {
46
+ width: number;
47
+ height: number;
48
+ }, viewport: {
49
+ width: number;
50
+ height: number;
51
+ }): {
52
+ top: number;
53
+ left: number;
54
+ placement: RowMenuPlacement;
55
+ };
56
+ declare function RowMenu({ label, title, icon, children, triggerClassName, triggerStyle, panelClassName, panelStyle, onOpenChange, }: {
57
+ /** The trigger's accessible name, e.g. "More actions for Spring appeal". */
58
+ label?: string;
59
+ /** Hover text on the trigger. */
60
+ title?: string;
61
+ /** The trigger's content; defaults to "⋯". */
62
+ icon?: ReactNode;
63
+ /** Menu items: give each role="menuitem" (or use RowMenuItem). */
64
+ children: ReactNode;
65
+ triggerClassName?: string;
66
+ triggerStyle?: CSSProperties;
67
+ panelClassName?: string;
68
+ panelStyle?: CSSProperties;
69
+ onOpenChange?: (open: boolean) => void;
70
+ }): react_jsx_runtime.JSX.Element;
71
+ /** A plain button menu item with the default look. Any element with role="menuitem" works too. */
72
+ declare function RowMenuItem({ onSelect, disabled, danger, className, style, children, }: {
73
+ onSelect?: () => void;
74
+ disabled?: boolean;
75
+ danger?: boolean;
76
+ className?: string;
77
+ style?: CSSProperties;
78
+ children: ReactNode;
79
+ }): react_jsx_runtime.JSX.Element;
80
+
36
81
  type FormColumnProps = {
37
82
  children: ReactNode;
38
83
  className?: string;
@@ -1189,4 +1234,4 @@ type NavAppShellProps = {
1189
1234
  };
1190
1235
  declare function NavAppShell({ sidebar, topBar, betaBanner, contentWrapper, accountMenuPlacement, modeId, children, }: NavAppShellProps): react_jsx_runtime.JSX.Element;
1191
1236
 
1192
- export { FuelAction as $, AI_CREDITS_STATE_TITLES as A, type BreadcrumbBarProps as B, Card as C, CORE_APP_ORIGIN as D, CORE_BILLING_PATH as E, FormColumn as F, CREDIT_TYPE_LABELS as G, HeaderTabBar as H, CREDIT_TYPE_ORDER as I, type CampaignFeatureAvailability as J, KNOWN_TAB_GLYPHS as K, type ChromeMe as L, type ChromeNotificationAlert as M, type NavItem as N, type ChromeNotificationImport as O, type PageHeaderProps as P, type ChromeNotificationQuarantine as Q, type ChromeNotificationReply as R, type StandardNavIconKey as S, type TabGlyphComponent as T, type ChromeNotificationsPayload as U, type ChromeOrgSummary as V, type CommunicationsFuelStatus as W, type CreditHealthState as X, type CreditTypeKey as Y, CreditsAction as Z, type CreditsIconState as _, AiCreditsState as a, type FuelChannelStatus as a0, NavAppShell as a1, type NavAppShellProps as a2, NavBetaBanner as a3, type NavBetaBannerProps as a4, type NavBrand as a5, NavChromeProvider as a6, NavDisplayAction as a7, type NavLinkProps as a8, type NavLinkedAccount as a9, TopBarWidgetSlot as aA, clearBetaBannerDismissal as aB, creditGaugeRatio as aC, creditStateWord as aD, creditTooltipLine as aE, creditsAriaLabel as aF, creditsIconState as aG, envChipClasses as aH, isNavItemActive as aI, modeIdFromLabel as aJ, resolveOrgLogoUrl as aK, shortEnvLabel as aL, shortUserName as aM, standardPolitogyNav as aN, topBarIconButtonClass as aO, useChromeMe as aP, useChromeOrgs as aQ, useNavChromeDedupedFetch as aR, useNavChromeFetcher as aS, useThemePreference as aT, type NavModeOption as aa, type NavOrg as ab, type NavRoleBadge as ac, NavSidebar as ad, type NavSidebarProps as ae, type NavTab as af, NavTabStrip as ag, type NavTabStripProps as ah, NavThemeControl as ai, NavTopBar as aj, type NavTopBarAction as ak, type NavTopBarProps as al, type NavUser as am, NotificationsAction as an, PageHeader as ao, type PageHeaderMode as ap, SPECS_ORIGIN as aq, SpecOverlayAction as ar, type StandardNavOptions as as, SupportAction as at, type ThemePreference as au, TopBarCountBadge as av, type TopBarIconTone as aw, TopBarPanelArrow as ax, TopBarPopover as ay, TopBarTooltip as az, type AiCreditsStateKind as b, type CommsNotification as c, type CommsNotificationKind as d, type HeaderTabBarItem as e, type NotificationsAdapter as f, type NotificationsFeed as g, aiCreditsWalletUrl as h, createCommsNotificationsAdapter as i, emptyNotificationsFeed as j, type NavIcon as k, type NavBreadcrumb as l, type StandardNavMode as m, normalizeNotificationsFeed as n, type NavLinkComponent as o, type NavChromeFetcher as p, type NavMode as q, resolveTabGlyph as r, type NavUserMenu as s, type NavOrgOption as t, type NavFooterLink as u, type NavFooter as v, type NavDisplayMode as w, BETA_BANNER_DISMISS_KEY as x, BreadcrumbBar as y, CAMPAIGN_FEATURE_AVAILABILITY as z };
1237
+ export { type CreditHealthState as $, AI_CREDITS_STATE_TITLES as A, type BreadcrumbBarProps as B, Card as C, BETA_BANNER_DISMISS_KEY as D, BreadcrumbBar as E, FormColumn as F, CAMPAIGN_FEATURE_AVAILABILITY as G, HeaderTabBar as H, CORE_APP_ORIGIN as I, CORE_BILLING_PATH as J, KNOWN_TAB_GLYPHS as K, CREDIT_TYPE_LABELS as L, CREDIT_TYPE_ORDER as M, type NavItem as N, type CampaignFeatureAvailability as O, type PageHeaderProps as P, type ChromeMe as Q, RowMenu as R, type StandardNavIconKey as S, type TabGlyphComponent as T, type ChromeNotificationAlert as U, type ChromeNotificationImport as V, type ChromeNotificationQuarantine as W, type ChromeNotificationReply as X, type ChromeNotificationsPayload as Y, type ChromeOrgSummary as Z, type CommunicationsFuelStatus as _, AiCreditsState as a, type CreditTypeKey as a0, CreditsAction as a1, type CreditsIconState as a2, FuelAction as a3, type FuelChannelStatus as a4, NavAppShell as a5, type NavAppShellProps as a6, NavBetaBanner as a7, type NavBetaBannerProps as a8, type NavBrand as a9, type TopBarIconTone as aA, TopBarPanelArrow as aB, TopBarPopover as aC, TopBarTooltip as aD, TopBarWidgetSlot as aE, clearBetaBannerDismissal as aF, creditGaugeRatio as aG, creditStateWord as aH, creditTooltipLine as aI, creditsAriaLabel as aJ, creditsIconState as aK, envChipClasses as aL, isNavItemActive as aM, modeIdFromLabel as aN, resolveOrgLogoUrl as aO, shortEnvLabel as aP, shortUserName as aQ, standardPolitogyNav as aR, topBarIconButtonClass as aS, useChromeMe as aT, useChromeOrgs as aU, useNavChromeDedupedFetch as aV, useNavChromeFetcher as aW, useThemePreference as aX, NavChromeProvider as aa, NavDisplayAction as ab, type NavLinkProps as ac, type NavLinkedAccount as ad, type NavModeOption as ae, type NavOrg as af, type NavRoleBadge as ag, NavSidebar as ah, type NavSidebarProps as ai, type NavTab as aj, NavTabStrip as ak, type NavTabStripProps as al, NavThemeControl as am, NavTopBar as an, type NavTopBarAction as ao, type NavTopBarProps as ap, type NavUser as aq, NotificationsAction as ar, PageHeader as as, type PageHeaderMode as at, SPECS_ORIGIN as au, SpecOverlayAction as av, type StandardNavOptions as aw, SupportAction as ax, type ThemePreference as ay, TopBarCountBadge as az, type AiCreditsStateKind as b, type CommsNotification as c, type CommsNotificationKind as d, type HeaderTabBarItem as e, type NotificationsAdapter as f, type NotificationsFeed as g, RowMenuItem as h, type RowMenuPlacement as i, aiCreditsWalletUrl as j, createCommsNotificationsAdapter as k, emptyNotificationsFeed as l, rowMenuPosition as m, normalizeNotificationsFeed as n, type NavIcon as o, type NavBreadcrumb as p, type StandardNavMode as q, resolveTabGlyph as r, type NavLinkComponent as s, type NavChromeFetcher as t, type NavMode as u, type NavUserMenu as v, type NavOrgOption as w, type NavFooterLink as x, type NavFooter as y, type NavDisplayMode as z };
@@ -33,6 +33,51 @@ type AiCreditsStateProps = {
33
33
  };
34
34
  declare function AiCreditsState({ kind, orgId, isAccountAdmin, lastOutputAt, onCheckAgain, formatTime, className, style, }: AiCreditsStateProps): react_jsx_runtime.JSX.Element;
35
35
 
36
+ type RowMenuPlacement = 'below' | 'above';
37
+ /**
38
+ * Where the panel goes: below the trigger, right-aligned to it, unless it does
39
+ * not fit below and there is more room above. Clamped inside the viewport.
40
+ */
41
+ declare function rowMenuPosition(trigger: {
42
+ top: number;
43
+ bottom: number;
44
+ right: number;
45
+ }, panel: {
46
+ width: number;
47
+ height: number;
48
+ }, viewport: {
49
+ width: number;
50
+ height: number;
51
+ }): {
52
+ top: number;
53
+ left: number;
54
+ placement: RowMenuPlacement;
55
+ };
56
+ declare function RowMenu({ label, title, icon, children, triggerClassName, triggerStyle, panelClassName, panelStyle, onOpenChange, }: {
57
+ /** The trigger's accessible name, e.g. "More actions for Spring appeal". */
58
+ label?: string;
59
+ /** Hover text on the trigger. */
60
+ title?: string;
61
+ /** The trigger's content; defaults to "⋯". */
62
+ icon?: ReactNode;
63
+ /** Menu items: give each role="menuitem" (or use RowMenuItem). */
64
+ children: ReactNode;
65
+ triggerClassName?: string;
66
+ triggerStyle?: CSSProperties;
67
+ panelClassName?: string;
68
+ panelStyle?: CSSProperties;
69
+ onOpenChange?: (open: boolean) => void;
70
+ }): react_jsx_runtime.JSX.Element;
71
+ /** A plain button menu item with the default look. Any element with role="menuitem" works too. */
72
+ declare function RowMenuItem({ onSelect, disabled, danger, className, style, children, }: {
73
+ onSelect?: () => void;
74
+ disabled?: boolean;
75
+ danger?: boolean;
76
+ className?: string;
77
+ style?: CSSProperties;
78
+ children: ReactNode;
79
+ }): react_jsx_runtime.JSX.Element;
80
+
36
81
  type FormColumnProps = {
37
82
  children: ReactNode;
38
83
  className?: string;
@@ -1189,4 +1234,4 @@ type NavAppShellProps = {
1189
1234
  };
1190
1235
  declare function NavAppShell({ sidebar, topBar, betaBanner, contentWrapper, accountMenuPlacement, modeId, children, }: NavAppShellProps): react_jsx_runtime.JSX.Element;
1191
1236
 
1192
- export { FuelAction as $, AI_CREDITS_STATE_TITLES as A, type BreadcrumbBarProps as B, Card as C, CORE_APP_ORIGIN as D, CORE_BILLING_PATH as E, FormColumn as F, CREDIT_TYPE_LABELS as G, HeaderTabBar as H, CREDIT_TYPE_ORDER as I, type CampaignFeatureAvailability as J, KNOWN_TAB_GLYPHS as K, type ChromeMe as L, type ChromeNotificationAlert as M, type NavItem as N, type ChromeNotificationImport as O, type PageHeaderProps as P, type ChromeNotificationQuarantine as Q, type ChromeNotificationReply as R, type StandardNavIconKey as S, type TabGlyphComponent as T, type ChromeNotificationsPayload as U, type ChromeOrgSummary as V, type CommunicationsFuelStatus as W, type CreditHealthState as X, type CreditTypeKey as Y, CreditsAction as Z, type CreditsIconState as _, AiCreditsState as a, type FuelChannelStatus as a0, NavAppShell as a1, type NavAppShellProps as a2, NavBetaBanner as a3, type NavBetaBannerProps as a4, type NavBrand as a5, NavChromeProvider as a6, NavDisplayAction as a7, type NavLinkProps as a8, type NavLinkedAccount as a9, TopBarWidgetSlot as aA, clearBetaBannerDismissal as aB, creditGaugeRatio as aC, creditStateWord as aD, creditTooltipLine as aE, creditsAriaLabel as aF, creditsIconState as aG, envChipClasses as aH, isNavItemActive as aI, modeIdFromLabel as aJ, resolveOrgLogoUrl as aK, shortEnvLabel as aL, shortUserName as aM, standardPolitogyNav as aN, topBarIconButtonClass as aO, useChromeMe as aP, useChromeOrgs as aQ, useNavChromeDedupedFetch as aR, useNavChromeFetcher as aS, useThemePreference as aT, type NavModeOption as aa, type NavOrg as ab, type NavRoleBadge as ac, NavSidebar as ad, type NavSidebarProps as ae, type NavTab as af, NavTabStrip as ag, type NavTabStripProps as ah, NavThemeControl as ai, NavTopBar as aj, type NavTopBarAction as ak, type NavTopBarProps as al, type NavUser as am, NotificationsAction as an, PageHeader as ao, type PageHeaderMode as ap, SPECS_ORIGIN as aq, SpecOverlayAction as ar, type StandardNavOptions as as, SupportAction as at, type ThemePreference as au, TopBarCountBadge as av, type TopBarIconTone as aw, TopBarPanelArrow as ax, TopBarPopover as ay, TopBarTooltip as az, type AiCreditsStateKind as b, type CommsNotification as c, type CommsNotificationKind as d, type HeaderTabBarItem as e, type NotificationsAdapter as f, type NotificationsFeed as g, aiCreditsWalletUrl as h, createCommsNotificationsAdapter as i, emptyNotificationsFeed as j, type NavIcon as k, type NavBreadcrumb as l, type StandardNavMode as m, normalizeNotificationsFeed as n, type NavLinkComponent as o, type NavChromeFetcher as p, type NavMode as q, resolveTabGlyph as r, type NavUserMenu as s, type NavOrgOption as t, type NavFooterLink as u, type NavFooter as v, type NavDisplayMode as w, BETA_BANNER_DISMISS_KEY as x, BreadcrumbBar as y, CAMPAIGN_FEATURE_AVAILABILITY as z };
1237
+ export { type CreditHealthState as $, AI_CREDITS_STATE_TITLES as A, type BreadcrumbBarProps as B, Card as C, BETA_BANNER_DISMISS_KEY as D, BreadcrumbBar as E, FormColumn as F, CAMPAIGN_FEATURE_AVAILABILITY as G, HeaderTabBar as H, CORE_APP_ORIGIN as I, CORE_BILLING_PATH as J, KNOWN_TAB_GLYPHS as K, CREDIT_TYPE_LABELS as L, CREDIT_TYPE_ORDER as M, type NavItem as N, type CampaignFeatureAvailability as O, type PageHeaderProps as P, type ChromeMe as Q, RowMenu as R, type StandardNavIconKey as S, type TabGlyphComponent as T, type ChromeNotificationAlert as U, type ChromeNotificationImport as V, type ChromeNotificationQuarantine as W, type ChromeNotificationReply as X, type ChromeNotificationsPayload as Y, type ChromeOrgSummary as Z, type CommunicationsFuelStatus as _, AiCreditsState as a, type CreditTypeKey as a0, CreditsAction as a1, type CreditsIconState as a2, FuelAction as a3, type FuelChannelStatus as a4, NavAppShell as a5, type NavAppShellProps as a6, NavBetaBanner as a7, type NavBetaBannerProps as a8, type NavBrand as a9, type TopBarIconTone as aA, TopBarPanelArrow as aB, TopBarPopover as aC, TopBarTooltip as aD, TopBarWidgetSlot as aE, clearBetaBannerDismissal as aF, creditGaugeRatio as aG, creditStateWord as aH, creditTooltipLine as aI, creditsAriaLabel as aJ, creditsIconState as aK, envChipClasses as aL, isNavItemActive as aM, modeIdFromLabel as aN, resolveOrgLogoUrl as aO, shortEnvLabel as aP, shortUserName as aQ, standardPolitogyNav as aR, topBarIconButtonClass as aS, useChromeMe as aT, useChromeOrgs as aU, useNavChromeDedupedFetch as aV, useNavChromeFetcher as aW, useThemePreference as aX, NavChromeProvider as aa, NavDisplayAction as ab, type NavLinkProps as ac, type NavLinkedAccount as ad, type NavModeOption as ae, type NavOrg as af, type NavRoleBadge as ag, NavSidebar as ah, type NavSidebarProps as ai, type NavTab as aj, NavTabStrip as ak, type NavTabStripProps as al, NavThemeControl as am, NavTopBar as an, type NavTopBarAction as ao, type NavTopBarProps as ap, type NavUser as aq, NotificationsAction as ar, PageHeader as as, type PageHeaderMode as at, SPECS_ORIGIN as au, SpecOverlayAction as av, type StandardNavOptions as aw, SupportAction as ax, type ThemePreference as ay, TopBarCountBadge as az, type AiCreditsStateKind as b, type CommsNotification as c, type CommsNotificationKind as d, type HeaderTabBarItem as e, type NotificationsAdapter as f, type NotificationsFeed as g, RowMenuItem as h, type RowMenuPlacement as i, aiCreditsWalletUrl as j, createCommsNotificationsAdapter as k, emptyNotificationsFeed as l, rowMenuPosition as m, normalizeNotificationsFeed as n, type NavIcon as o, type NavBreadcrumb as p, type StandardNavMode as q, resolveTabGlyph as r, type NavLinkComponent as s, type NavChromeFetcher as t, type NavMode as u, type NavUserMenu as v, type NavOrgOption as w, type NavFooterLink as x, type NavFooter as y, type NavDisplayMode as z };
package/dist/index.cjs CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  var react = require('@chakra-ui/react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
+ var react$1 = require('react');
6
+ var reactDom = require('react-dom');
5
7
  var clsx5 = require('clsx');
6
8
  var reactRouterDom = require('react-router-dom');
7
- var react$1 = require('react');
8
- require('react-dom');
9
9
  var lu = require('react-icons/lu');
10
10
 
11
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -920,6 +920,258 @@ function AiCreditsState({
920
920
  )
921
921
  ] });
922
922
  }
923
+ var GAP = 4;
924
+ var EDGE = 8;
925
+ var closeOpenRowMenu = null;
926
+ var TRIGGER_STYLE = {
927
+ display: "inline-flex",
928
+ alignItems: "center",
929
+ justifyContent: "center",
930
+ width: 28,
931
+ height: 28,
932
+ borderRadius: 6,
933
+ border: "none",
934
+ background: "transparent",
935
+ color: "var(--color-text-muted, #6b7280)",
936
+ cursor: "pointer",
937
+ lineHeight: 1
938
+ };
939
+ var PANEL_STYLE = {
940
+ minWidth: 160,
941
+ padding: 4,
942
+ border: "1px solid var(--color-border, #e5e7eb)",
943
+ borderRadius: 8,
944
+ background: "var(--color-surface, #fff)",
945
+ boxShadow: "0 10px 24px rgba(15, 23, 42, 0.12)",
946
+ display: "flex",
947
+ flexDirection: "column",
948
+ textAlign: "left"
949
+ };
950
+ var ITEM_STYLE = {
951
+ display: "flex",
952
+ alignItems: "center",
953
+ gap: 8,
954
+ width: "100%",
955
+ padding: "6px 10px",
956
+ border: "none",
957
+ borderRadius: 6,
958
+ background: "transparent",
959
+ font: "inherit",
960
+ fontSize: 14,
961
+ color: "var(--color-text, #2F3136)",
962
+ textAlign: "left",
963
+ cursor: "pointer"
964
+ };
965
+ function rowMenuPosition(trigger, panel, viewport) {
966
+ const below = viewport.height - trigger.bottom - GAP - EDGE;
967
+ const above = trigger.top - GAP - EDGE;
968
+ const placement = panel.height > below && above > below ? "above" : "below";
969
+ const rawTop = placement === "above" ? trigger.top - GAP - panel.height : trigger.bottom + GAP;
970
+ const top = Math.max(EDGE, Math.min(rawTop, viewport.height - panel.height - EDGE));
971
+ const left = Math.max(EDGE, Math.min(trigger.right - panel.width, viewport.width - panel.width - EDGE));
972
+ return { top, left, placement };
973
+ }
974
+ function menuItems(panel) {
975
+ if (!panel) return [];
976
+ return Array.from(panel.querySelectorAll('[role="menuitem"]')).filter(
977
+ (el) => !el.disabled && el.getAttribute("aria-disabled") !== "true"
978
+ );
979
+ }
980
+ function RowMenu({
981
+ label = "More actions",
982
+ title,
983
+ icon,
984
+ children,
985
+ triggerClassName,
986
+ triggerStyle,
987
+ panelClassName,
988
+ panelStyle,
989
+ onOpenChange
990
+ }) {
991
+ const [open, setOpen] = react$1.useState(false);
992
+ const [pos, setPos] = react$1.useState(null);
993
+ const triggerRef = react$1.useRef(null);
994
+ const panelRef = react$1.useRef(null);
995
+ const focusFirstRef = react$1.useRef(false);
996
+ const onOpenChangeRef = react$1.useRef(onOpenChange);
997
+ onOpenChangeRef.current = onOpenChange;
998
+ const close = react$1.useCallback((restoreFocus = false) => {
999
+ setOpen(false);
1000
+ if (restoreFocus) triggerRef.current?.focus();
1001
+ }, []);
1002
+ const place = react$1.useCallback(() => {
1003
+ const t = triggerRef.current;
1004
+ const p = panelRef.current;
1005
+ if (!t || !p) return;
1006
+ const r = t.getBoundingClientRect();
1007
+ setPos(rowMenuPosition(
1008
+ { top: r.top, bottom: r.bottom, right: r.right },
1009
+ { width: p.offsetWidth, height: p.offsetHeight },
1010
+ { width: window.innerWidth, height: window.innerHeight }
1011
+ ));
1012
+ }, []);
1013
+ react$1.useEffect(() => {
1014
+ onOpenChangeRef.current?.(open);
1015
+ if (!open) {
1016
+ setPos(null);
1017
+ return;
1018
+ }
1019
+ const mine = () => setOpen(false);
1020
+ if (closeOpenRowMenu && closeOpenRowMenu !== mine) closeOpenRowMenu();
1021
+ closeOpenRowMenu = mine;
1022
+ return () => {
1023
+ if (closeOpenRowMenu === mine) closeOpenRowMenu = null;
1024
+ };
1025
+ }, [open]);
1026
+ react$1.useLayoutEffect(() => {
1027
+ if (!open) return;
1028
+ place();
1029
+ const p = panelRef.current;
1030
+ if (!p || typeof ResizeObserver === "undefined") return;
1031
+ const ro = new ResizeObserver(() => place());
1032
+ ro.observe(p);
1033
+ return () => ro.disconnect();
1034
+ }, [open, place]);
1035
+ react$1.useEffect(() => {
1036
+ if (!open || !pos || !focusFirstRef.current) return;
1037
+ focusFirstRef.current = false;
1038
+ menuItems(panelRef.current)[0]?.focus();
1039
+ }, [open, pos]);
1040
+ react$1.useEffect(() => {
1041
+ if (!open) return;
1042
+ const inside = (n) => n instanceof Node && (!!triggerRef.current?.contains(n) || !!panelRef.current?.contains(n));
1043
+ const onPointerDown = (e) => {
1044
+ if (!inside(e.target)) close();
1045
+ };
1046
+ const onKey = (e) => {
1047
+ if (e.key === "Escape") {
1048
+ e.stopPropagation();
1049
+ close(true);
1050
+ }
1051
+ };
1052
+ const onScroll = (e) => {
1053
+ if (!inside(e.target)) close();
1054
+ };
1055
+ const onResize = () => close();
1056
+ document.addEventListener("pointerdown", onPointerDown, true);
1057
+ document.addEventListener("keydown", onKey, true);
1058
+ window.addEventListener("scroll", onScroll, true);
1059
+ window.addEventListener("resize", onResize);
1060
+ return () => {
1061
+ document.removeEventListener("pointerdown", onPointerDown, true);
1062
+ document.removeEventListener("keydown", onKey, true);
1063
+ window.removeEventListener("scroll", onScroll, true);
1064
+ window.removeEventListener("resize", onResize);
1065
+ };
1066
+ }, [open, close]);
1067
+ function onTriggerKeyDown(e) {
1068
+ if (e.key === "ArrowDown" || (e.key === "Enter" || e.key === " ") && !open) {
1069
+ e.preventDefault();
1070
+ focusFirstRef.current = true;
1071
+ if (open) menuItems(panelRef.current)[0]?.focus();
1072
+ else setOpen(true);
1073
+ }
1074
+ }
1075
+ function onPanelKeyDown(e) {
1076
+ e.stopPropagation();
1077
+ if (e.key === "Tab") {
1078
+ close();
1079
+ return;
1080
+ }
1081
+ if (e.key !== "ArrowDown" && e.key !== "ArrowUp" && e.key !== "Home" && e.key !== "End") return;
1082
+ const items = menuItems(panelRef.current);
1083
+ if (items.length === 0) return;
1084
+ e.preventDefault();
1085
+ const at = items.indexOf(document.activeElement);
1086
+ const next = e.key === "Home" ? 0 : e.key === "End" ? items.length - 1 : e.key === "ArrowDown" ? (at + 1) % items.length : (at - 1 + items.length) % items.length;
1087
+ items[next]?.focus();
1088
+ }
1089
+ function onPanelClick(e) {
1090
+ e.stopPropagation();
1091
+ const item = e.target.closest?.('[role="menuitem"]');
1092
+ if (!item || !panelRef.current?.contains(item)) return;
1093
+ if (item.disabled || item.getAttribute("aria-disabled") === "true") return;
1094
+ setTimeout(() => close(), 0);
1095
+ }
1096
+ const panel = open && typeof document !== "undefined" ? reactDom.createPortal(
1097
+ /* @__PURE__ */ jsxRuntime.jsx(
1098
+ "div",
1099
+ {
1100
+ ref: panelRef,
1101
+ role: "menu",
1102
+ "aria-label": label,
1103
+ "data-row-menu": "",
1104
+ "data-placement": pos?.placement,
1105
+ className: panelClassName,
1106
+ onClick: onPanelClick,
1107
+ onKeyDown: onPanelKeyDown,
1108
+ style: {
1109
+ ...panelClassName ? null : PANEL_STYLE,
1110
+ ...panelStyle,
1111
+ position: "fixed",
1112
+ zIndex: 1e3,
1113
+ top: pos?.top ?? 0,
1114
+ left: pos?.left ?? 0,
1115
+ right: "auto",
1116
+ bottom: "auto",
1117
+ margin: 0,
1118
+ visibility: pos ? "visible" : "hidden"
1119
+ },
1120
+ children
1121
+ }
1122
+ ),
1123
+ document.body
1124
+ ) : null;
1125
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1126
+ /* @__PURE__ */ jsxRuntime.jsx(
1127
+ "button",
1128
+ {
1129
+ ref: triggerRef,
1130
+ type: "button",
1131
+ className: triggerClassName,
1132
+ style: { ...triggerClassName ? null : TRIGGER_STYLE, ...triggerStyle },
1133
+ "aria-label": label,
1134
+ title,
1135
+ "aria-haspopup": "menu",
1136
+ "aria-expanded": open,
1137
+ "data-open": open ? "" : void 0,
1138
+ onClick: (e) => {
1139
+ e.stopPropagation();
1140
+ setOpen((v) => !v);
1141
+ },
1142
+ onKeyDown: onTriggerKeyDown,
1143
+ children: icon ?? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u22EF" })
1144
+ }
1145
+ ),
1146
+ panel
1147
+ ] });
1148
+ }
1149
+ function RowMenuItem({
1150
+ onSelect,
1151
+ disabled,
1152
+ danger,
1153
+ className,
1154
+ style,
1155
+ children
1156
+ }) {
1157
+ return /* @__PURE__ */ jsxRuntime.jsx(
1158
+ "button",
1159
+ {
1160
+ type: "button",
1161
+ role: "menuitem",
1162
+ className,
1163
+ disabled,
1164
+ onClick: onSelect,
1165
+ style: {
1166
+ ...className ? null : ITEM_STYLE,
1167
+ ...className || !danger ? null : { color: "var(--color-red, #e63946)" },
1168
+ ...className || !disabled ? null : { opacity: 0.5, cursor: "default" },
1169
+ ...style
1170
+ },
1171
+ children
1172
+ }
1173
+ );
1174
+ }
923
1175
  function FormColumn({ children, className }) {
924
1176
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-shell-form-column": "", className: clsx5__default.default("w-full max-w-[960px]", className), children });
925
1177
  }
@@ -2054,6 +2306,8 @@ exports.HeaderTabBar = HeaderTabBar;
2054
2306
  exports.KNOWN_TAB_GLYPHS = KNOWN_TAB_GLYPHS;
2055
2307
  exports.PageContainer = PageContainer;
2056
2308
  exports.PageHeader = PageHeader;
2309
+ exports.RowMenu = RowMenu;
2310
+ exports.RowMenuItem = RowMenuItem;
2057
2311
  exports.ShellChromeContext = ShellChromeContext;
2058
2312
  exports.ShellFooterContext = ShellFooterContext;
2059
2313
  exports.ShellLinkedAccountsContext = ShellLinkedAccountsContext;
@@ -2082,6 +2336,7 @@ exports.normalizeNotificationsFeed = normalizeNotificationsFeed;
2082
2336
  exports.politogyTheme = politogyTheme;
2083
2337
  exports.registerShellPrecache = registerShellPrecache;
2084
2338
  exports.resolveTabGlyph = resolveTabGlyph;
2339
+ exports.rowMenuPosition = rowMenuPosition;
2085
2340
  exports.useAppRegistry = useAppRegistry;
2086
2341
  exports.useCurrentApp = useCurrentApp;
2087
2342
  exports.useShellAuth = useShellAuth;