@dloizides/ui-nav 1.12.0 → 1.13.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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.13.1
4
+
5
+ - **Fix (mobile drawer: a sub-item / leaf tap dismissed the drawer WITHOUT navigating).**
6
+ On a phone-width viewport, tapping a leaf inside the open `MobileDrawer` closed the drawer
7
+ but the route never changed — verified live on finreg via Playwright (real Chromium, real
8
+ pointer events); every jsdom unit test stayed green because it wired `onClose` to an inert
9
+ `jest.fn()` that never unmounts anything.
10
+ - **Root cause.** `MobileDrawer` closes on a nav press via a NATIVE
11
+ `panel.addEventListener('click', …)`. react-native-web fires a leaf's `onPress` from its
12
+ `onClick`, dispatched through REACT's synthetic event system whose root listener sits on the
13
+ app-root container — an ANCESTOR of the panel. So on a real click the native panel listener
14
+ runs FIRST (during the DOM bubble), and closing synchronously there ran `setDrawerOpen(false)`,
15
+ unmounting the panel and tearing the leaf out of the tree BEFORE React could dispatch its
16
+ `onPress`. The navigation call never ran.
17
+ - **Fix.** The drawer's close is now DEFERRED to the next macrotask (`setTimeout(…, 0)`), so
18
+ React finishes dispatching the tapped leaf's `onPress` (the navigation) for the current click;
19
+ the panel then unmounts on the following tick, after the route has already changed. Scrim tap
20
+ and group-header toggle are unchanged.
21
+ - **No API change.** All 7 portals get the fix on their next bump.
22
+
3
23
  ## 1.11.0
4
24
 
5
25
  - **Feature (an expandable nav group now auto-opens when the current route is inside it).**
package/dist/index.d.mts CHANGED
@@ -972,6 +972,35 @@ interface CommandPaletteProps {
972
972
  /** The overlay palette. Renders null when closed. */
973
973
  declare const CommandPalette: ({ open, items, onClose, labels, testID }: CommandPaletteProps) => React.ReactElement | null;
974
974
 
975
+ /**
976
+ * CommandPaletteTrigger — the VISIBLE, discoverable affordance that opens the
977
+ * {@link CommandPalette}. A ⌘K shortcut alone is invisible; a docs-style search
978
+ * pill (muted placeholder on the left, a keyboard-shortcut badge on the right)
979
+ * tells operators the palette exists and is one click away. Place it in a shell
980
+ * header / sidebar; wire `onPress` to the same open handler as the ⌘K hotkey.
981
+ *
982
+ * Self-contained on purpose: the shared icon set has no magnifier, so this uses
983
+ * text + a shortcut badge (the recognizable "Search … ⌘K" pattern) rather than a
984
+ * render-slot icon — one less thing every consumer must supply. Colours come from
985
+ * the `@dloizides/ui-feedback` UiProvider theme; the label/shortcut are
986
+ * pre-localized strings (package discipline: no FM/router imports).
987
+ */
988
+
989
+ interface CommandPaletteTriggerProps {
990
+ /** Placeholder-style label, e.g. "Search". */
991
+ label: string;
992
+ /** a11y hint describing what activating it does. */
993
+ hint: string;
994
+ /** The shortcut badge text, e.g. "⌘K" (already chosen per-platform by the caller). */
995
+ shortcut: string;
996
+ /** Open the palette (same handler as the ⌘K hotkey). */
997
+ onPress: () => void;
998
+ /** testID for the trigger. */
999
+ testID: string;
1000
+ }
1001
+ /** The visible "Search … ⌘K" pill that opens the command palette. */
1002
+ declare const CommandPaletteTrigger: ({ label, hint, shortcut, onPress, testID, }: CommandPaletteTriggerProps) => React.ReactElement;
1003
+
975
1004
  /**
976
1005
  * Call `onOpen` when the operator presses ⌘K (macOS) or Ctrl-K (Windows/Linux),
977
1006
  * anywhere in the document. `enabled=false` unbinds (e.g. when the shell has no
@@ -1232,4 +1261,4 @@ declare const NAV_ICON_SIZE = 14;
1232
1261
  /** Chevron icon size for expandable sections. */
1233
1262
  declare const CHEVRON_ICON_SIZE = 12;
1234
1263
 
1235
- export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, CollapsedRail, type CollapsedRailProps, type CollapsedRailRange, type CommandItem, CommandPalette, type CommandPaletteLabels, type CommandPaletteProps, DEFAULT_COLLAPSED_RAIL_MAX, DarkModeControl, type DarkModeControlProps, type DarkModeOption, type DarkModeVariant, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_TEST_IDS, Nav, NavBar, type NavBarProps, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavOrientation, NavOverflowMenu, type NavOverflowMenuProps, type NavProps, NavShell, type NavShellCollapsedRail, type NavShellLayout, type NavShellProps, type NavShellSideRail, type NavShellTopBar, type NavUser, PillNav, type PillNavProps, RAIL_FULL_BREAKPOINT, type RailMode, type ResolveRailModeArgs, type ShellMessage, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, isRouteActive, navStyles, pillNavStyles, resolveContentMaxWidth, resolveRailMode, roleRoutesToNavItems, useCommandPaletteHotkey, useContentMaxWidth };
1264
+ export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, CollapsedRail, type CollapsedRailProps, type CollapsedRailRange, type CommandItem, CommandPalette, type CommandPaletteLabels, type CommandPaletteProps, CommandPaletteTrigger, type CommandPaletteTriggerProps, DEFAULT_COLLAPSED_RAIL_MAX, DarkModeControl, type DarkModeControlProps, type DarkModeOption, type DarkModeVariant, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_TEST_IDS, Nav, NavBar, type NavBarProps, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavOrientation, NavOverflowMenu, type NavOverflowMenuProps, type NavProps, NavShell, type NavShellCollapsedRail, type NavShellLayout, type NavShellProps, type NavShellSideRail, type NavShellTopBar, type NavUser, PillNav, type PillNavProps, RAIL_FULL_BREAKPOINT, type RailMode, type ResolveRailModeArgs, type ShellMessage, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, isRouteActive, navStyles, pillNavStyles, resolveContentMaxWidth, resolveRailMode, roleRoutesToNavItems, useCommandPaletteHotkey, useContentMaxWidth };
package/dist/index.d.ts CHANGED
@@ -972,6 +972,35 @@ interface CommandPaletteProps {
972
972
  /** The overlay palette. Renders null when closed. */
973
973
  declare const CommandPalette: ({ open, items, onClose, labels, testID }: CommandPaletteProps) => React.ReactElement | null;
974
974
 
975
+ /**
976
+ * CommandPaletteTrigger — the VISIBLE, discoverable affordance that opens the
977
+ * {@link CommandPalette}. A ⌘K shortcut alone is invisible; a docs-style search
978
+ * pill (muted placeholder on the left, a keyboard-shortcut badge on the right)
979
+ * tells operators the palette exists and is one click away. Place it in a shell
980
+ * header / sidebar; wire `onPress` to the same open handler as the ⌘K hotkey.
981
+ *
982
+ * Self-contained on purpose: the shared icon set has no magnifier, so this uses
983
+ * text + a shortcut badge (the recognizable "Search … ⌘K" pattern) rather than a
984
+ * render-slot icon — one less thing every consumer must supply. Colours come from
985
+ * the `@dloizides/ui-feedback` UiProvider theme; the label/shortcut are
986
+ * pre-localized strings (package discipline: no FM/router imports).
987
+ */
988
+
989
+ interface CommandPaletteTriggerProps {
990
+ /** Placeholder-style label, e.g. "Search". */
991
+ label: string;
992
+ /** a11y hint describing what activating it does. */
993
+ hint: string;
994
+ /** The shortcut badge text, e.g. "⌘K" (already chosen per-platform by the caller). */
995
+ shortcut: string;
996
+ /** Open the palette (same handler as the ⌘K hotkey). */
997
+ onPress: () => void;
998
+ /** testID for the trigger. */
999
+ testID: string;
1000
+ }
1001
+ /** The visible "Search … ⌘K" pill that opens the command palette. */
1002
+ declare const CommandPaletteTrigger: ({ label, hint, shortcut, onPress, testID, }: CommandPaletteTriggerProps) => React.ReactElement;
1003
+
975
1004
  /**
976
1005
  * Call `onOpen` when the operator presses ⌘K (macOS) or Ctrl-K (Windows/Linux),
977
1006
  * anywhere in the document. `enabled=false` unbinds (e.g. when the shell has no
@@ -1232,4 +1261,4 @@ declare const NAV_ICON_SIZE = 14;
1232
1261
  /** Chevron icon size for expandable sections. */
1233
1262
  declare const CHEVRON_ICON_SIZE = 12;
1234
1263
 
1235
- export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, CollapsedRail, type CollapsedRailProps, type CollapsedRailRange, type CommandItem, CommandPalette, type CommandPaletteLabels, type CommandPaletteProps, DEFAULT_COLLAPSED_RAIL_MAX, DarkModeControl, type DarkModeControlProps, type DarkModeOption, type DarkModeVariant, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_TEST_IDS, Nav, NavBar, type NavBarProps, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavOrientation, NavOverflowMenu, type NavOverflowMenuProps, type NavProps, NavShell, type NavShellCollapsedRail, type NavShellLayout, type NavShellProps, type NavShellSideRail, type NavShellTopBar, type NavUser, PillNav, type PillNavProps, RAIL_FULL_BREAKPOINT, type RailMode, type ResolveRailModeArgs, type ShellMessage, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, isRouteActive, navStyles, pillNavStyles, resolveContentMaxWidth, resolveRailMode, roleRoutesToNavItems, useCommandPaletteHotkey, useContentMaxWidth };
1264
+ export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, CollapsedRail, type CollapsedRailProps, type CollapsedRailRange, type CommandItem, CommandPalette, type CommandPaletteLabels, type CommandPaletteProps, CommandPaletteTrigger, type CommandPaletteTriggerProps, DEFAULT_COLLAPSED_RAIL_MAX, DarkModeControl, type DarkModeControlProps, type DarkModeOption, type DarkModeVariant, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_TEST_IDS, Nav, NavBar, type NavBarProps, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavOrientation, NavOverflowMenu, type NavOverflowMenuProps, type NavProps, NavShell, type NavShellCollapsedRail, type NavShellLayout, type NavShellProps, type NavShellSideRail, type NavShellTopBar, type NavUser, PillNav, type PillNavProps, RAIL_FULL_BREAKPOINT, type RailMode, type ResolveRailModeArgs, type ShellMessage, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, isRouteActive, navStyles, pillNavStyles, resolveContentMaxWidth, resolveRailMode, roleRoutesToNavItems, useCommandPaletteHotkey, useContentMaxWidth };
package/dist/index.js CHANGED
@@ -1054,6 +1054,10 @@ var SCRIM_Z_INDEX = 1;
1054
1054
  var PANEL_Z_INDEX = 2;
1055
1055
  var NAV_ACTIVATABLE_SELECTOR = 'a, [role="button"], [role="link"]';
1056
1056
  var NAV_TOGGLE_SELECTOR = "[aria-expanded]";
1057
+ function deferClose(close) {
1058
+ if (typeof setTimeout === "function") setTimeout(close, 0);
1059
+ else close();
1060
+ }
1057
1061
  var DEFAULT_DRAWER_LABELS = {
1058
1062
  openLabel: "Menu",
1059
1063
  openHint: "Open the navigation menu",
@@ -1119,7 +1123,7 @@ var MobileDrawer = ({
1119
1123
  if (target === null) return;
1120
1124
  const activatable = target.closest(NAV_ACTIVATABLE_SELECTOR);
1121
1125
  const isToggle = activatable !== null && activatable.closest(NAV_TOGGLE_SELECTOR) !== null;
1122
- if (activatable !== null && !isToggle) onClose();
1126
+ if (activatable !== null && !isToggle) deferClose(onClose);
1123
1127
  };
1124
1128
  node.addEventListener("click", handleClick);
1125
1129
  return () => node.removeEventListener("click", handleClick);
@@ -1671,6 +1675,55 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
1671
1675
  )
1672
1676
  ] });
1673
1677
  };
1678
+ var MIN_TARGET = 36;
1679
+ var styles5 = reactNative.StyleSheet.create({
1680
+ trigger: {
1681
+ flexDirection: "row",
1682
+ alignItems: "center",
1683
+ justifyContent: "space-between",
1684
+ columnGap: 8,
1685
+ paddingHorizontal: 12,
1686
+ minHeight: MIN_TARGET,
1687
+ borderWidth: 1,
1688
+ borderRadius: 8
1689
+ },
1690
+ label: { fontSize: 14 },
1691
+ badge: { paddingHorizontal: 6, paddingVertical: 2, borderRadius: 4, borderWidth: 1 },
1692
+ badgeText: { fontSize: 11, fontWeight: "700" }
1693
+ });
1694
+ var CommandPaletteTrigger = ({
1695
+ label,
1696
+ hint,
1697
+ shortcut,
1698
+ onPress,
1699
+ testID
1700
+ }) => {
1701
+ const { theme } = uiFeedback.useUi();
1702
+ const colors = theme.colors;
1703
+ const primary = theme.palette.primary["500"];
1704
+ const [focused, setFocused] = React2__default.default.useState(false);
1705
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1706
+ reactNative.Pressable,
1707
+ {
1708
+ accessibilityHint: hint,
1709
+ accessibilityLabel: label,
1710
+ accessibilityRole: "button",
1711
+ style: [
1712
+ styles5.trigger,
1713
+ { backgroundColor: colors.surface, borderColor: colors.border },
1714
+ focusRingStyle(focused, primary)
1715
+ ],
1716
+ testID,
1717
+ onBlur: () => setFocused(false),
1718
+ onFocus: () => setFocused(true),
1719
+ onPress,
1720
+ children: [
1721
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.label, { color: colors.textSecondary }], children: label }),
1722
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles5.badge, { borderColor: colors.border }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.badgeText, { color: colors.textSecondary }], children: shortcut }) })
1723
+ ]
1724
+ }
1725
+ );
1726
+ };
1674
1727
  var LAUNCH_KEY = "k";
1675
1728
  function useCommandPaletteHotkey(onOpen, enabled = true) {
1676
1729
  React2.useEffect(() => {
@@ -1703,6 +1756,7 @@ exports.BASE_INDENT = BASE_INDENT;
1703
1756
  exports.CHEVRON_ICON_SIZE = CHEVRON_ICON_SIZE;
1704
1757
  exports.CollapsedRail = CollapsedRail;
1705
1758
  exports.CommandPalette = CommandPalette;
1759
+ exports.CommandPaletteTrigger = CommandPaletteTrigger;
1706
1760
  exports.DEFAULT_COLLAPSED_RAIL_MAX = DEFAULT_COLLAPSED_RAIL_MAX;
1707
1761
  exports.DarkModeControl = DarkModeControl;
1708
1762
  exports.NAV_ICON_SIZE = NAV_ICON_SIZE;