@dloizides/ui-nav 1.11.0 → 1.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/index.d.mts +95 -1
- package/dist/index.d.ts +95 -1
- package/dist/index.js +211 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +210 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -898,6 +898,87 @@ interface NavExpandableItemProps {
|
|
|
898
898
|
}
|
|
899
899
|
declare const NavExpandableItem: ({ item, pathname, onNavigate, navigateHint, expandHint, collapseHint, renderChevron, depth, }: NavExpandableItemProps) => React.ReactElement;
|
|
900
900
|
|
|
901
|
+
/**
|
|
902
|
+
* Pure matching logic for the {@link CommandPalette}. Kept framework-free so the
|
|
903
|
+
* ranking/filtering is unit-testable without rendering: a command matches when
|
|
904
|
+
* every whitespace-separated token of the query appears (case-insensitively) in
|
|
905
|
+
* its haystack (label + hint + keywords). Requiring ALL tokens lets an operator
|
|
906
|
+
* narrow with "pay dash" the way a fuzzy launcher would, without a fuzzy lib.
|
|
907
|
+
*/
|
|
908
|
+
|
|
909
|
+
/** One actionable destination/command shown in the palette. */
|
|
910
|
+
interface CommandItem {
|
|
911
|
+
/** Stable key + default testID. */
|
|
912
|
+
key: string;
|
|
913
|
+
/** Optional testID override (defaults to `key`). */
|
|
914
|
+
testID?: string;
|
|
915
|
+
/** Localized display label (what the operator reads). */
|
|
916
|
+
label: string;
|
|
917
|
+
/** Optional localized secondary line (e.g. the module it lives in). */
|
|
918
|
+
hint?: string;
|
|
919
|
+
/** Optional extra search terms not shown but matched (synonyms, route words). */
|
|
920
|
+
keywords?: readonly string[];
|
|
921
|
+
/** Invoked when the item is chosen (the consumer navigates / runs the action). */
|
|
922
|
+
onSelect: () => void;
|
|
923
|
+
/** Optional leading icon slot, same contract as `NavItem.renderIcon`. */
|
|
924
|
+
renderIcon?: (color: string, size: number) => React.ReactNode;
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* Filter `items` to those matching `query`. An empty/whitespace query returns
|
|
928
|
+
* the list unchanged (the palette opens showing everything). Order is preserved
|
|
929
|
+
* — the caller supplies items in a meaningful order (nav order).
|
|
930
|
+
*/
|
|
931
|
+
declare function filterCommands(items: readonly CommandItem[], query: string): CommandItem[];
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* CommandPalette — the shared ⌘K launcher for `@dloizides/ui-nav`. An overlay
|
|
935
|
+
* (scrim + centred panel) with a search input over a keyboard-navigable list of
|
|
936
|
+
* {@link CommandItem}s — jump to any nav destination (or run any action) without
|
|
937
|
+
* hunting the rail. Web-first (RN-web), but degrades safely: when `open` is
|
|
938
|
+
* false it renders nothing.
|
|
939
|
+
*
|
|
940
|
+
* Package discipline (as the rest of ui-nav): NO FM / router / store / icon-set
|
|
941
|
+
* imports. Labels are pre-localized strings; icons are render slots; every colour
|
|
942
|
+
* comes from the `@dloizides/ui-feedback` UiProvider theme. The consumer owns the
|
|
943
|
+
* `open` state (pair with {@link useCommandPaletteHotkey}) and each item's
|
|
944
|
+
* `onSelect` (navigate / run) — the palette just closes after a choice.
|
|
945
|
+
*/
|
|
946
|
+
|
|
947
|
+
/** Pre-localized labels for the palette chrome. */
|
|
948
|
+
interface CommandPaletteLabels {
|
|
949
|
+
/** Search input placeholder. */
|
|
950
|
+
placeholder: string;
|
|
951
|
+
/** Accessible name of the scrim (tap to close). */
|
|
952
|
+
closeLabel: string;
|
|
953
|
+
/** Accessible hint of the scrim (tap to close). */
|
|
954
|
+
closeHint: string;
|
|
955
|
+
/** Shown when the query matches nothing. */
|
|
956
|
+
emptyText: string;
|
|
957
|
+
/** Accessible label for the palette dialog landmark. */
|
|
958
|
+
regionLabel: string;
|
|
959
|
+
}
|
|
960
|
+
interface CommandPaletteProps {
|
|
961
|
+
/** Whether the palette overlay is shown. */
|
|
962
|
+
open: boolean;
|
|
963
|
+
/** The commands to search over, in a meaningful (nav) order. */
|
|
964
|
+
items: readonly CommandItem[];
|
|
965
|
+
/** Close the palette (scrim tap / Escape / after a selection). */
|
|
966
|
+
onClose: () => void;
|
|
967
|
+
/** Pre-localized chrome labels. */
|
|
968
|
+
labels: CommandPaletteLabels;
|
|
969
|
+
/** testID for the panel (defaults to `command-palette`). */
|
|
970
|
+
testID?: string;
|
|
971
|
+
}
|
|
972
|
+
/** The overlay palette. Renders null when closed. */
|
|
973
|
+
declare const CommandPalette: ({ open, items, onClose, labels, testID }: CommandPaletteProps) => React.ReactElement | null;
|
|
974
|
+
|
|
975
|
+
/**
|
|
976
|
+
* Call `onOpen` when the operator presses ⌘K (macOS) or Ctrl-K (Windows/Linux),
|
|
977
|
+
* anywhere in the document. `enabled=false` unbinds (e.g. when the shell has no
|
|
978
|
+
* palette configured), so the shortcut never fires without a handler behind it.
|
|
979
|
+
*/
|
|
980
|
+
declare function useCommandPaletteHotkey(onOpen: () => void, enabled?: boolean): void;
|
|
981
|
+
|
|
901
982
|
/**
|
|
902
983
|
* Role-gated nav helpers — build a `NavItem[]` from a user's roles, reusing the
|
|
903
984
|
* existing `resolveAccessibleRoutes` from `@dloizides/auth-web` (the same helper
|
|
@@ -1101,6 +1182,8 @@ declare const expandableStyles: {
|
|
|
1101
1182
|
flexDirection: "row";
|
|
1102
1183
|
alignItems: "center";
|
|
1103
1184
|
paddingVertical: number;
|
|
1185
|
+
borderLeftWidth: number;
|
|
1186
|
+
borderLeftColor: string;
|
|
1104
1187
|
};
|
|
1105
1188
|
childItemText: {
|
|
1106
1189
|
fontSize: number;
|
|
@@ -1114,6 +1197,7 @@ declare const expandableStyles: {
|
|
|
1114
1197
|
};
|
|
1115
1198
|
childrenContainer: {
|
|
1116
1199
|
overflow: "hidden";
|
|
1200
|
+
marginBottom: number;
|
|
1117
1201
|
};
|
|
1118
1202
|
header: {
|
|
1119
1203
|
borderRadius: number;
|
|
@@ -1121,11 +1205,21 @@ declare const expandableStyles: {
|
|
|
1121
1205
|
alignItems: "center";
|
|
1122
1206
|
paddingVertical: number;
|
|
1123
1207
|
};
|
|
1208
|
+
sectionHeader: {
|
|
1209
|
+
marginTop: number;
|
|
1210
|
+
};
|
|
1124
1211
|
headerText: {
|
|
1125
1212
|
fontSize: number;
|
|
1126
1213
|
fontWeight: "600";
|
|
1127
1214
|
marginLeft: number;
|
|
1128
1215
|
};
|
|
1216
|
+
sectionHeaderText: {
|
|
1217
|
+
fontSize: number;
|
|
1218
|
+
fontWeight: "700";
|
|
1219
|
+
marginLeft: number;
|
|
1220
|
+
textTransform: "uppercase";
|
|
1221
|
+
letterSpacing: number;
|
|
1222
|
+
};
|
|
1129
1223
|
iconWrapper: {
|
|
1130
1224
|
width: number;
|
|
1131
1225
|
alignItems: "center";
|
|
@@ -1138,4 +1232,4 @@ declare const NAV_ICON_SIZE = 14;
|
|
|
1138
1232
|
/** Chevron icon size for expandable sections. */
|
|
1139
1233
|
declare const CHEVRON_ICON_SIZE = 12;
|
|
1140
1234
|
|
|
1141
|
-
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, 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, isRouteActive, navStyles, pillNavStyles, resolveContentMaxWidth, resolveRailMode, roleRoutesToNavItems, useContentMaxWidth };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -898,6 +898,87 @@ interface NavExpandableItemProps {
|
|
|
898
898
|
}
|
|
899
899
|
declare const NavExpandableItem: ({ item, pathname, onNavigate, navigateHint, expandHint, collapseHint, renderChevron, depth, }: NavExpandableItemProps) => React.ReactElement;
|
|
900
900
|
|
|
901
|
+
/**
|
|
902
|
+
* Pure matching logic for the {@link CommandPalette}. Kept framework-free so the
|
|
903
|
+
* ranking/filtering is unit-testable without rendering: a command matches when
|
|
904
|
+
* every whitespace-separated token of the query appears (case-insensitively) in
|
|
905
|
+
* its haystack (label + hint + keywords). Requiring ALL tokens lets an operator
|
|
906
|
+
* narrow with "pay dash" the way a fuzzy launcher would, without a fuzzy lib.
|
|
907
|
+
*/
|
|
908
|
+
|
|
909
|
+
/** One actionable destination/command shown in the palette. */
|
|
910
|
+
interface CommandItem {
|
|
911
|
+
/** Stable key + default testID. */
|
|
912
|
+
key: string;
|
|
913
|
+
/** Optional testID override (defaults to `key`). */
|
|
914
|
+
testID?: string;
|
|
915
|
+
/** Localized display label (what the operator reads). */
|
|
916
|
+
label: string;
|
|
917
|
+
/** Optional localized secondary line (e.g. the module it lives in). */
|
|
918
|
+
hint?: string;
|
|
919
|
+
/** Optional extra search terms not shown but matched (synonyms, route words). */
|
|
920
|
+
keywords?: readonly string[];
|
|
921
|
+
/** Invoked when the item is chosen (the consumer navigates / runs the action). */
|
|
922
|
+
onSelect: () => void;
|
|
923
|
+
/** Optional leading icon slot, same contract as `NavItem.renderIcon`. */
|
|
924
|
+
renderIcon?: (color: string, size: number) => React.ReactNode;
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* Filter `items` to those matching `query`. An empty/whitespace query returns
|
|
928
|
+
* the list unchanged (the palette opens showing everything). Order is preserved
|
|
929
|
+
* — the caller supplies items in a meaningful order (nav order).
|
|
930
|
+
*/
|
|
931
|
+
declare function filterCommands(items: readonly CommandItem[], query: string): CommandItem[];
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* CommandPalette — the shared ⌘K launcher for `@dloizides/ui-nav`. An overlay
|
|
935
|
+
* (scrim + centred panel) with a search input over a keyboard-navigable list of
|
|
936
|
+
* {@link CommandItem}s — jump to any nav destination (or run any action) without
|
|
937
|
+
* hunting the rail. Web-first (RN-web), but degrades safely: when `open` is
|
|
938
|
+
* false it renders nothing.
|
|
939
|
+
*
|
|
940
|
+
* Package discipline (as the rest of ui-nav): NO FM / router / store / icon-set
|
|
941
|
+
* imports. Labels are pre-localized strings; icons are render slots; every colour
|
|
942
|
+
* comes from the `@dloizides/ui-feedback` UiProvider theme. The consumer owns the
|
|
943
|
+
* `open` state (pair with {@link useCommandPaletteHotkey}) and each item's
|
|
944
|
+
* `onSelect` (navigate / run) — the palette just closes after a choice.
|
|
945
|
+
*/
|
|
946
|
+
|
|
947
|
+
/** Pre-localized labels for the palette chrome. */
|
|
948
|
+
interface CommandPaletteLabels {
|
|
949
|
+
/** Search input placeholder. */
|
|
950
|
+
placeholder: string;
|
|
951
|
+
/** Accessible name of the scrim (tap to close). */
|
|
952
|
+
closeLabel: string;
|
|
953
|
+
/** Accessible hint of the scrim (tap to close). */
|
|
954
|
+
closeHint: string;
|
|
955
|
+
/** Shown when the query matches nothing. */
|
|
956
|
+
emptyText: string;
|
|
957
|
+
/** Accessible label for the palette dialog landmark. */
|
|
958
|
+
regionLabel: string;
|
|
959
|
+
}
|
|
960
|
+
interface CommandPaletteProps {
|
|
961
|
+
/** Whether the palette overlay is shown. */
|
|
962
|
+
open: boolean;
|
|
963
|
+
/** The commands to search over, in a meaningful (nav) order. */
|
|
964
|
+
items: readonly CommandItem[];
|
|
965
|
+
/** Close the palette (scrim tap / Escape / after a selection). */
|
|
966
|
+
onClose: () => void;
|
|
967
|
+
/** Pre-localized chrome labels. */
|
|
968
|
+
labels: CommandPaletteLabels;
|
|
969
|
+
/** testID for the panel (defaults to `command-palette`). */
|
|
970
|
+
testID?: string;
|
|
971
|
+
}
|
|
972
|
+
/** The overlay palette. Renders null when closed. */
|
|
973
|
+
declare const CommandPalette: ({ open, items, onClose, labels, testID }: CommandPaletteProps) => React.ReactElement | null;
|
|
974
|
+
|
|
975
|
+
/**
|
|
976
|
+
* Call `onOpen` when the operator presses ⌘K (macOS) or Ctrl-K (Windows/Linux),
|
|
977
|
+
* anywhere in the document. `enabled=false` unbinds (e.g. when the shell has no
|
|
978
|
+
* palette configured), so the shortcut never fires without a handler behind it.
|
|
979
|
+
*/
|
|
980
|
+
declare function useCommandPaletteHotkey(onOpen: () => void, enabled?: boolean): void;
|
|
981
|
+
|
|
901
982
|
/**
|
|
902
983
|
* Role-gated nav helpers — build a `NavItem[]` from a user's roles, reusing the
|
|
903
984
|
* existing `resolveAccessibleRoutes` from `@dloizides/auth-web` (the same helper
|
|
@@ -1101,6 +1182,8 @@ declare const expandableStyles: {
|
|
|
1101
1182
|
flexDirection: "row";
|
|
1102
1183
|
alignItems: "center";
|
|
1103
1184
|
paddingVertical: number;
|
|
1185
|
+
borderLeftWidth: number;
|
|
1186
|
+
borderLeftColor: string;
|
|
1104
1187
|
};
|
|
1105
1188
|
childItemText: {
|
|
1106
1189
|
fontSize: number;
|
|
@@ -1114,6 +1197,7 @@ declare const expandableStyles: {
|
|
|
1114
1197
|
};
|
|
1115
1198
|
childrenContainer: {
|
|
1116
1199
|
overflow: "hidden";
|
|
1200
|
+
marginBottom: number;
|
|
1117
1201
|
};
|
|
1118
1202
|
header: {
|
|
1119
1203
|
borderRadius: number;
|
|
@@ -1121,11 +1205,21 @@ declare const expandableStyles: {
|
|
|
1121
1205
|
alignItems: "center";
|
|
1122
1206
|
paddingVertical: number;
|
|
1123
1207
|
};
|
|
1208
|
+
sectionHeader: {
|
|
1209
|
+
marginTop: number;
|
|
1210
|
+
};
|
|
1124
1211
|
headerText: {
|
|
1125
1212
|
fontSize: number;
|
|
1126
1213
|
fontWeight: "600";
|
|
1127
1214
|
marginLeft: number;
|
|
1128
1215
|
};
|
|
1216
|
+
sectionHeaderText: {
|
|
1217
|
+
fontSize: number;
|
|
1218
|
+
fontWeight: "700";
|
|
1219
|
+
marginLeft: number;
|
|
1220
|
+
textTransform: "uppercase";
|
|
1221
|
+
letterSpacing: number;
|
|
1222
|
+
};
|
|
1129
1223
|
iconWrapper: {
|
|
1130
1224
|
width: number;
|
|
1131
1225
|
alignItems: "center";
|
|
@@ -1138,4 +1232,4 @@ declare const NAV_ICON_SIZE = 14;
|
|
|
1138
1232
|
/** Chevron icon size for expandable sections. */
|
|
1139
1233
|
declare const CHEVRON_ICON_SIZE = 12;
|
|
1140
1234
|
|
|
1141
|
-
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, 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, isRouteActive, navStyles, pillNavStyles, resolveContentMaxWidth, resolveRailMode, roleRoutesToNavItems, useContentMaxWidth };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,7 @@ function isRouteActive(pathname, route) {
|
|
|
19
19
|
return pathname === route || pathname.startsWith(`${route}/`);
|
|
20
20
|
}
|
|
21
21
|
var ACTIVE_BORDER_RADIUS = 4;
|
|
22
|
+
var ACTIVE_ACCENT_WIDTH = 3;
|
|
22
23
|
var NAV_LINK_GAP = 4;
|
|
23
24
|
var navStyles = reactNative.StyleSheet.create({
|
|
24
25
|
// --- Sidebar ---
|
|
@@ -242,23 +243,39 @@ var collapsedRailStyles = reactNative.StyleSheet.create({
|
|
|
242
243
|
slot: { alignItems: "center" }
|
|
243
244
|
});
|
|
244
245
|
var expandableStyles = reactNative.StyleSheet.create({
|
|
246
|
+
// Every leaf reserves the accent-bar gutter (a TRANSPARENT left border of the
|
|
247
|
+
// same width the active item colours in) so activation never shifts the row.
|
|
245
248
|
childItem: {
|
|
246
|
-
borderRadius:
|
|
249
|
+
borderRadius: 6,
|
|
247
250
|
flexDirection: "row",
|
|
248
251
|
alignItems: "center",
|
|
249
|
-
paddingVertical:
|
|
252
|
+
paddingVertical: 9,
|
|
253
|
+
borderLeftWidth: ACTIVE_ACCENT_WIDTH,
|
|
254
|
+
borderLeftColor: "transparent"
|
|
250
255
|
},
|
|
251
256
|
childItemText: { fontSize: 14 },
|
|
252
257
|
childItemTextWithIcon: { fontSize: 14, marginLeft: 6 },
|
|
253
258
|
chevron: { marginLeft: "auto" },
|
|
254
|
-
childrenContainer: { overflow: "hidden" },
|
|
259
|
+
childrenContainer: { overflow: "hidden", marginBottom: 4 },
|
|
255
260
|
header: {
|
|
256
|
-
borderRadius:
|
|
261
|
+
borderRadius: 6,
|
|
257
262
|
flexDirection: "row",
|
|
258
263
|
alignItems: "center",
|
|
259
264
|
paddingVertical: 8
|
|
260
265
|
},
|
|
266
|
+
// Depth-0 module groups render as docs-style SECTION HEADERS: extra top rhythm
|
|
267
|
+
// to separate one module from the next.
|
|
268
|
+
sectionHeader: { marginTop: 12 },
|
|
261
269
|
headerText: { fontSize: 15, fontWeight: "600", marginLeft: 6 },
|
|
270
|
+
// The section-label look: small, uppercased, tracked, muted — the aml-screening
|
|
271
|
+
// docs treatment ("START HERE" / "REFERENCE"), kept on an interactive toggle.
|
|
272
|
+
sectionHeaderText: {
|
|
273
|
+
fontSize: 12,
|
|
274
|
+
fontWeight: "700",
|
|
275
|
+
marginLeft: 6,
|
|
276
|
+
textTransform: "uppercase",
|
|
277
|
+
letterSpacing: 0.8
|
|
278
|
+
},
|
|
262
279
|
iconWrapper: { width: 20, alignItems: "center" }
|
|
263
280
|
});
|
|
264
281
|
var BASE_INDENT = 12;
|
|
@@ -289,6 +306,9 @@ function hoverTransitionStyle(reducedMotion) {
|
|
|
289
306
|
function ariaCurrentProps(isActive) {
|
|
290
307
|
return isActive ? { "aria-current": "page" } : {};
|
|
291
308
|
}
|
|
309
|
+
function ariaExpandedProps(expanded) {
|
|
310
|
+
return { "aria-expanded": expanded };
|
|
311
|
+
}
|
|
292
312
|
function hasActiveDescendant(item, pathname) {
|
|
293
313
|
if (isRouteActive(pathname, item.route)) return true;
|
|
294
314
|
return (item.children ?? []).some((child) => hasActiveDescendant(child, pathname));
|
|
@@ -312,9 +332,15 @@ var NavExpandableItem = ({
|
|
|
312
332
|
const indent = depth * BASE_INDENT;
|
|
313
333
|
const hasChildren = Array.isArray(item.children) && item.children.length > 0;
|
|
314
334
|
const isActive = isRouteActive(pathname, item.route);
|
|
335
|
+
const isSectionHeader = hasChildren && depth === 0;
|
|
315
336
|
const activeItemStyle = React2.useMemo(
|
|
316
|
-
() => ({
|
|
317
|
-
|
|
337
|
+
() => ({
|
|
338
|
+
backgroundColor: colors.border,
|
|
339
|
+
borderRadius: ACTIVE_BORDER_RADIUS,
|
|
340
|
+
borderLeftWidth: ACTIVE_ACCENT_WIDTH,
|
|
341
|
+
borderLeftColor: primaryColor
|
|
342
|
+
}),
|
|
343
|
+
[colors.border, primaryColor]
|
|
318
344
|
);
|
|
319
345
|
const paddingStyle = React2.useMemo(() => ({ paddingLeft: indent + BASE_INDENT }), [indent]);
|
|
320
346
|
const headerPaddingStyle = React2.useMemo(() => ({ paddingLeft: indent }), [indent]);
|
|
@@ -360,14 +386,29 @@ var NavExpandableItem = ({
|
|
|
360
386
|
accessibilityLabel: item.label,
|
|
361
387
|
accessibilityRole: "button",
|
|
362
388
|
accessibilityState: { expanded },
|
|
363
|
-
style: [
|
|
389
|
+
style: [
|
|
390
|
+
expandableStyles.header,
|
|
391
|
+
isSectionHeader ? expandableStyles.sectionHeader : void 0,
|
|
392
|
+
headerPaddingStyle,
|
|
393
|
+
focusRingStyle(focused, primaryColor)
|
|
394
|
+
],
|
|
364
395
|
testID: item.testID ?? item.key,
|
|
365
396
|
onBlur: () => setFocused(false),
|
|
366
397
|
onFocus: () => setFocused(true),
|
|
367
398
|
onPress: toggle,
|
|
399
|
+
...ariaExpandedProps(expanded),
|
|
368
400
|
children: [
|
|
369
|
-
typeof item.renderIcon === "function" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: expandableStyles.iconWrapper, children: item.renderIcon(colors.text, NAV_ICON_SIZE) }) : null,
|
|
370
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
401
|
+
typeof item.renderIcon === "function" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: expandableStyles.iconWrapper, children: item.renderIcon(isSectionHeader ? colors.textSecondary : colors.text, NAV_ICON_SIZE) }) : null,
|
|
402
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
403
|
+
reactNative.Text,
|
|
404
|
+
{
|
|
405
|
+
style: [
|
|
406
|
+
isSectionHeader ? expandableStyles.sectionHeaderText : expandableStyles.headerText,
|
|
407
|
+
{ color: isSectionHeader ? colors.textSecondary : colors.text }
|
|
408
|
+
],
|
|
409
|
+
children: item.label
|
|
410
|
+
}
|
|
411
|
+
),
|
|
371
412
|
typeof renderChevron === "function" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: expandableStyles.chevron, children: renderChevron(expanded, colors.textSecondary, CHEVRON_ICON_SIZE) }) : null
|
|
372
413
|
]
|
|
373
414
|
}
|
|
@@ -1012,6 +1053,7 @@ var DRAWER_WIDTH = 280;
|
|
|
1012
1053
|
var SCRIM_Z_INDEX = 1;
|
|
1013
1054
|
var PANEL_Z_INDEX = 2;
|
|
1014
1055
|
var NAV_ACTIVATABLE_SELECTOR = 'a, [role="button"], [role="link"]';
|
|
1056
|
+
var NAV_TOGGLE_SELECTOR = "[aria-expanded]";
|
|
1015
1057
|
var DEFAULT_DRAWER_LABELS = {
|
|
1016
1058
|
openLabel: "Menu",
|
|
1017
1059
|
openHint: "Open the navigation menu",
|
|
@@ -1074,8 +1116,10 @@ var MobileDrawer = ({
|
|
|
1074
1116
|
if (node === null || typeof node.addEventListener !== "function") return void 0;
|
|
1075
1117
|
const handleClick = (event) => {
|
|
1076
1118
|
const target = event.target;
|
|
1077
|
-
|
|
1078
|
-
|
|
1119
|
+
if (target === null) return;
|
|
1120
|
+
const activatable = target.closest(NAV_ACTIVATABLE_SELECTOR);
|
|
1121
|
+
const isToggle = activatable !== null && activatable.closest(NAV_TOGGLE_SELECTOR) !== null;
|
|
1122
|
+
if (activatable !== null && !isToggle) onClose();
|
|
1079
1123
|
};
|
|
1080
1124
|
node.addEventListener("click", handleClick);
|
|
1081
1125
|
return () => node.removeEventListener("click", handleClick);
|
|
@@ -1488,6 +1532,159 @@ var DarkModeControl = ({
|
|
|
1488
1532
|
}
|
|
1489
1533
|
);
|
|
1490
1534
|
};
|
|
1535
|
+
|
|
1536
|
+
// src/commandPaletteFilter.ts
|
|
1537
|
+
function haystack(item) {
|
|
1538
|
+
return [item.label, item.hint ?? "", ...item.keywords ?? []].join(" ").toLowerCase();
|
|
1539
|
+
}
|
|
1540
|
+
function filterCommands(items, query) {
|
|
1541
|
+
const tokens = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
1542
|
+
if (tokens.length === 0) return [...items];
|
|
1543
|
+
return items.filter((item) => {
|
|
1544
|
+
const hay = haystack(item);
|
|
1545
|
+
return tokens.every((token) => hay.includes(token));
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
var SCRIM_COLOR2 = "rgba(0, 0, 0, 0.5)";
|
|
1549
|
+
var OVERLAY_Z_INDEX = 60;
|
|
1550
|
+
var PANEL_MAX_WIDTH = 560;
|
|
1551
|
+
var PANEL_TOP_OFFSET = 88;
|
|
1552
|
+
var LIST_MAX_HEIGHT = 360;
|
|
1553
|
+
var KEY_DOWN = "ArrowDown";
|
|
1554
|
+
var KEY_UP = "ArrowUp";
|
|
1555
|
+
var KEY_ENTER = "Enter";
|
|
1556
|
+
var KEY_ESCAPE = "Escape";
|
|
1557
|
+
var styles4 = reactNative.StyleSheet.create({
|
|
1558
|
+
overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: OVERLAY_Z_INDEX, alignItems: "center" },
|
|
1559
|
+
scrim: { ...reactNative.StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR2 },
|
|
1560
|
+
panel: {
|
|
1561
|
+
marginTop: PANEL_TOP_OFFSET,
|
|
1562
|
+
width: "92%",
|
|
1563
|
+
maxWidth: PANEL_MAX_WIDTH,
|
|
1564
|
+
borderRadius: 12,
|
|
1565
|
+
borderWidth: 1,
|
|
1566
|
+
overflow: "hidden"
|
|
1567
|
+
},
|
|
1568
|
+
input: { fontSize: 16, paddingHorizontal: 16, paddingVertical: 14, borderBottomWidth: 1 },
|
|
1569
|
+
list: { maxHeight: LIST_MAX_HEIGHT },
|
|
1570
|
+
row: { flexDirection: "row", alignItems: "center", paddingHorizontal: 16, paddingVertical: 12, columnGap: 10 },
|
|
1571
|
+
rowText: { flex: 1 },
|
|
1572
|
+
rowLabel: { fontSize: 15, fontWeight: "600" },
|
|
1573
|
+
rowHint: { fontSize: 12, marginTop: 2 },
|
|
1574
|
+
empty: { paddingHorizontal: 16, paddingVertical: 20, fontSize: 14 }
|
|
1575
|
+
});
|
|
1576
|
+
var PaletteRow = ({ item, selected, onChoose }) => {
|
|
1577
|
+
const { theme } = uiFeedback.useUi();
|
|
1578
|
+
const colors = theme.colors;
|
|
1579
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1580
|
+
reactNative.Pressable,
|
|
1581
|
+
{
|
|
1582
|
+
accessibilityHint: item.hint,
|
|
1583
|
+
accessibilityLabel: item.label,
|
|
1584
|
+
accessibilityRole: "button",
|
|
1585
|
+
accessibilityState: { selected },
|
|
1586
|
+
style: [styles4.row, selected ? { backgroundColor: colors.border } : void 0],
|
|
1587
|
+
testID: item.testID ?? item.key,
|
|
1588
|
+
onPress: () => onChoose(item),
|
|
1589
|
+
children: [
|
|
1590
|
+
typeof item.renderIcon === "function" ? item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) : null,
|
|
1591
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.rowText, children: [
|
|
1592
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.rowLabel, { color: colors.text }], children: item.label }),
|
|
1593
|
+
item.hint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.rowHint, { color: colors.textSecondary }], children: item.hint }) : null
|
|
1594
|
+
] })
|
|
1595
|
+
]
|
|
1596
|
+
}
|
|
1597
|
+
);
|
|
1598
|
+
};
|
|
1599
|
+
var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
1600
|
+
const { theme } = uiFeedback.useUi();
|
|
1601
|
+
const colors = theme.colors;
|
|
1602
|
+
const [query, setQuery] = React2.useState("");
|
|
1603
|
+
const [selected, setSelected] = React2.useState(0);
|
|
1604
|
+
const inputRef = React2.useRef(null);
|
|
1605
|
+
const results = React2.useMemo(() => filterCommands(items, query), [items, query]);
|
|
1606
|
+
React2.useEffect(() => {
|
|
1607
|
+
if (!open) return;
|
|
1608
|
+
setQuery("");
|
|
1609
|
+
setSelected(0);
|
|
1610
|
+
inputRef.current?.focus();
|
|
1611
|
+
}, [open]);
|
|
1612
|
+
React2.useEffect(() => {
|
|
1613
|
+
setSelected((prev) => Math.min(prev, Math.max(0, results.length - 1)));
|
|
1614
|
+
}, [results.length]);
|
|
1615
|
+
const choose = React2.useCallback(
|
|
1616
|
+
(item) => {
|
|
1617
|
+
item.onSelect();
|
|
1618
|
+
onClose();
|
|
1619
|
+
},
|
|
1620
|
+
[onClose]
|
|
1621
|
+
);
|
|
1622
|
+
const onKeyPress = React2.useCallback(
|
|
1623
|
+
(event) => {
|
|
1624
|
+
const key = event.nativeEvent.key;
|
|
1625
|
+
if (key === KEY_DOWN) setSelected((i) => Math.min(i + 1, results.length - 1));
|
|
1626
|
+
else if (key === KEY_UP) setSelected((i) => Math.max(i - 1, 0));
|
|
1627
|
+
else if (key === KEY_ESCAPE) onClose();
|
|
1628
|
+
else if (key === KEY_ENTER && results[selected]) choose(results[selected]);
|
|
1629
|
+
},
|
|
1630
|
+
[results, selected, choose, onClose]
|
|
1631
|
+
);
|
|
1632
|
+
if (!open) return null;
|
|
1633
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.overlay, children: [
|
|
1634
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1635
|
+
reactNative.Pressable,
|
|
1636
|
+
{
|
|
1637
|
+
accessibilityHint: labels.closeHint,
|
|
1638
|
+
accessibilityLabel: labels.closeLabel,
|
|
1639
|
+
accessibilityRole: "button",
|
|
1640
|
+
style: styles4.scrim,
|
|
1641
|
+
testID: `${testID ?? "command-palette"}-scrim`,
|
|
1642
|
+
onPress: onClose
|
|
1643
|
+
}
|
|
1644
|
+
),
|
|
1645
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1646
|
+
reactNative.View,
|
|
1647
|
+
{
|
|
1648
|
+
"aria-modal": true,
|
|
1649
|
+
"aria-label": labels.regionLabel,
|
|
1650
|
+
role: "dialog",
|
|
1651
|
+
style: [styles4.panel, { backgroundColor: colors.surface, borderColor: colors.border }],
|
|
1652
|
+
testID: testID ?? "command-palette",
|
|
1653
|
+
children: [
|
|
1654
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1655
|
+
reactNative.TextInput,
|
|
1656
|
+
{
|
|
1657
|
+
ref: inputRef,
|
|
1658
|
+
accessibilityLabel: labels.placeholder,
|
|
1659
|
+
placeholder: labels.placeholder,
|
|
1660
|
+
placeholderTextColor: colors.textSecondary,
|
|
1661
|
+
style: [styles4.input, { color: colors.text, borderBottomColor: colors.border }],
|
|
1662
|
+
testID: `${testID ?? "command-palette"}-input`,
|
|
1663
|
+
value: query,
|
|
1664
|
+
onChangeText: setQuery,
|
|
1665
|
+
onKeyPress
|
|
1666
|
+
}
|
|
1667
|
+
),
|
|
1668
|
+
results.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.empty, { color: colors.textSecondary }], children: labels.emptyText }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.ScrollView, { keyboardShouldPersistTaps: "handled", style: styles4.list, children: results.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(PaletteRow, { item, selected: index === selected, onChoose: choose }, item.key)) })
|
|
1669
|
+
]
|
|
1670
|
+
}
|
|
1671
|
+
)
|
|
1672
|
+
] });
|
|
1673
|
+
};
|
|
1674
|
+
var LAUNCH_KEY = "k";
|
|
1675
|
+
function useCommandPaletteHotkey(onOpen, enabled = true) {
|
|
1676
|
+
React2.useEffect(() => {
|
|
1677
|
+
if (!enabled || typeof document === "undefined") return void 0;
|
|
1678
|
+
const handler = (event) => {
|
|
1679
|
+
const isLauncher = event.key.toLowerCase() === LAUNCH_KEY && (event.metaKey || event.ctrlKey);
|
|
1680
|
+
if (!isLauncher) return;
|
|
1681
|
+
event.preventDefault();
|
|
1682
|
+
onOpen();
|
|
1683
|
+
};
|
|
1684
|
+
document.addEventListener("keydown", handler);
|
|
1685
|
+
return () => document.removeEventListener("keydown", handler);
|
|
1686
|
+
}, [onOpen, enabled]);
|
|
1687
|
+
}
|
|
1491
1688
|
function roleRoutesToNavItems(routes, translate) {
|
|
1492
1689
|
return routes.map((entry) => ({
|
|
1493
1690
|
key: entry.role,
|
|
@@ -1505,6 +1702,7 @@ exports.AppShell = AppShell;
|
|
|
1505
1702
|
exports.BASE_INDENT = BASE_INDENT;
|
|
1506
1703
|
exports.CHEVRON_ICON_SIZE = CHEVRON_ICON_SIZE;
|
|
1507
1704
|
exports.CollapsedRail = CollapsedRail;
|
|
1705
|
+
exports.CommandPalette = CommandPalette;
|
|
1508
1706
|
exports.DEFAULT_COLLAPSED_RAIL_MAX = DEFAULT_COLLAPSED_RAIL_MAX;
|
|
1509
1707
|
exports.DarkModeControl = DarkModeControl;
|
|
1510
1708
|
exports.NAV_ICON_SIZE = NAV_ICON_SIZE;
|
|
@@ -1523,12 +1721,14 @@ exports.accessibleNavItems = accessibleNavItems;
|
|
|
1523
1721
|
exports.collapsedRailStyles = collapsedRailStyles;
|
|
1524
1722
|
exports.darkModeStyles = darkModeStyles;
|
|
1525
1723
|
exports.expandableStyles = expandableStyles;
|
|
1724
|
+
exports.filterCommands = filterCommands;
|
|
1526
1725
|
exports.isRouteActive = isRouteActive;
|
|
1527
1726
|
exports.navStyles = navStyles;
|
|
1528
1727
|
exports.pillNavStyles = pillNavStyles;
|
|
1529
1728
|
exports.resolveContentMaxWidth = resolveContentMaxWidth;
|
|
1530
1729
|
exports.resolveRailMode = resolveRailMode;
|
|
1531
1730
|
exports.roleRoutesToNavItems = roleRoutesToNavItems;
|
|
1731
|
+
exports.useCommandPaletteHotkey = useCommandPaletteHotkey;
|
|
1532
1732
|
exports.useContentMaxWidth = useContentMaxWidth;
|
|
1533
1733
|
//# sourceMappingURL=index.js.map
|
|
1534
1734
|
//# sourceMappingURL=index.js.map
|