@dloizides/ui-nav 1.10.2 → 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/CHANGELOG.md +23 -0
- package/dist/index.d.mts +95 -1
- package/dist/index.d.ts +95 -1
- package/dist/index.js +216 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +215 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StyleSheet, Platform, TouchableOpacity, View, Text, useWindowDimensions, ActivityIndicator, ScrollView, Pressable } from 'react-native';
|
|
1
|
+
import { StyleSheet, Platform, TouchableOpacity, View, Text, useWindowDimensions, ActivityIndicator, ScrollView, Pressable, TextInput } from 'react-native';
|
|
2
2
|
import { useUi, UiProvider } from '@dloizides/ui-feedback';
|
|
3
3
|
import React2, { useState, useCallback, useMemo, useEffect, useRef } from 'react';
|
|
4
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
@@ -13,6 +13,7 @@ function isRouteActive(pathname, route) {
|
|
|
13
13
|
return pathname === route || pathname.startsWith(`${route}/`);
|
|
14
14
|
}
|
|
15
15
|
var ACTIVE_BORDER_RADIUS = 4;
|
|
16
|
+
var ACTIVE_ACCENT_WIDTH = 3;
|
|
16
17
|
var NAV_LINK_GAP = 4;
|
|
17
18
|
var navStyles = StyleSheet.create({
|
|
18
19
|
// --- Sidebar ---
|
|
@@ -236,23 +237,39 @@ var collapsedRailStyles = StyleSheet.create({
|
|
|
236
237
|
slot: { alignItems: "center" }
|
|
237
238
|
});
|
|
238
239
|
var expandableStyles = StyleSheet.create({
|
|
240
|
+
// Every leaf reserves the accent-bar gutter (a TRANSPARENT left border of the
|
|
241
|
+
// same width the active item colours in) so activation never shifts the row.
|
|
239
242
|
childItem: {
|
|
240
|
-
borderRadius:
|
|
243
|
+
borderRadius: 6,
|
|
241
244
|
flexDirection: "row",
|
|
242
245
|
alignItems: "center",
|
|
243
|
-
paddingVertical:
|
|
246
|
+
paddingVertical: 9,
|
|
247
|
+
borderLeftWidth: ACTIVE_ACCENT_WIDTH,
|
|
248
|
+
borderLeftColor: "transparent"
|
|
244
249
|
},
|
|
245
250
|
childItemText: { fontSize: 14 },
|
|
246
251
|
childItemTextWithIcon: { fontSize: 14, marginLeft: 6 },
|
|
247
252
|
chevron: { marginLeft: "auto" },
|
|
248
|
-
childrenContainer: { overflow: "hidden" },
|
|
253
|
+
childrenContainer: { overflow: "hidden", marginBottom: 4 },
|
|
249
254
|
header: {
|
|
250
|
-
borderRadius:
|
|
255
|
+
borderRadius: 6,
|
|
251
256
|
flexDirection: "row",
|
|
252
257
|
alignItems: "center",
|
|
253
258
|
paddingVertical: 8
|
|
254
259
|
},
|
|
260
|
+
// Depth-0 module groups render as docs-style SECTION HEADERS: extra top rhythm
|
|
261
|
+
// to separate one module from the next.
|
|
262
|
+
sectionHeader: { marginTop: 12 },
|
|
255
263
|
headerText: { fontSize: 15, fontWeight: "600", marginLeft: 6 },
|
|
264
|
+
// The section-label look: small, uppercased, tracked, muted — the aml-screening
|
|
265
|
+
// docs treatment ("START HERE" / "REFERENCE"), kept on an interactive toggle.
|
|
266
|
+
sectionHeaderText: {
|
|
267
|
+
fontSize: 12,
|
|
268
|
+
fontWeight: "700",
|
|
269
|
+
marginLeft: 6,
|
|
270
|
+
textTransform: "uppercase",
|
|
271
|
+
letterSpacing: 0.8
|
|
272
|
+
},
|
|
256
273
|
iconWrapper: { width: 20, alignItems: "center" }
|
|
257
274
|
});
|
|
258
275
|
var BASE_INDENT = 12;
|
|
@@ -283,6 +300,13 @@ function hoverTransitionStyle(reducedMotion) {
|
|
|
283
300
|
function ariaCurrentProps(isActive) {
|
|
284
301
|
return isActive ? { "aria-current": "page" } : {};
|
|
285
302
|
}
|
|
303
|
+
function ariaExpandedProps(expanded) {
|
|
304
|
+
return { "aria-expanded": expanded };
|
|
305
|
+
}
|
|
306
|
+
function hasActiveDescendant(item, pathname) {
|
|
307
|
+
if (isRouteActive(pathname, item.route)) return true;
|
|
308
|
+
return (item.children ?? []).some((child) => hasActiveDescendant(child, pathname));
|
|
309
|
+
}
|
|
286
310
|
var NavExpandableItem = ({
|
|
287
311
|
item,
|
|
288
312
|
pathname,
|
|
@@ -293,7 +317,7 @@ var NavExpandableItem = ({
|
|
|
293
317
|
renderChevron,
|
|
294
318
|
depth = 0
|
|
295
319
|
}) => {
|
|
296
|
-
const [expanded, setExpanded] = useState(
|
|
320
|
+
const [expanded, setExpanded] = useState(() => hasActiveDescendant(item, pathname));
|
|
297
321
|
const [focused, setFocused] = useState(false);
|
|
298
322
|
const { theme } = useUi();
|
|
299
323
|
const colors = theme.colors;
|
|
@@ -302,9 +326,15 @@ var NavExpandableItem = ({
|
|
|
302
326
|
const indent = depth * BASE_INDENT;
|
|
303
327
|
const hasChildren = Array.isArray(item.children) && item.children.length > 0;
|
|
304
328
|
const isActive = isRouteActive(pathname, item.route);
|
|
329
|
+
const isSectionHeader = hasChildren && depth === 0;
|
|
305
330
|
const activeItemStyle = useMemo(
|
|
306
|
-
() => ({
|
|
307
|
-
|
|
331
|
+
() => ({
|
|
332
|
+
backgroundColor: colors.border,
|
|
333
|
+
borderRadius: ACTIVE_BORDER_RADIUS,
|
|
334
|
+
borderLeftWidth: ACTIVE_ACCENT_WIDTH,
|
|
335
|
+
borderLeftColor: primaryColor
|
|
336
|
+
}),
|
|
337
|
+
[colors.border, primaryColor]
|
|
308
338
|
);
|
|
309
339
|
const paddingStyle = useMemo(() => ({ paddingLeft: indent + BASE_INDENT }), [indent]);
|
|
310
340
|
const headerPaddingStyle = useMemo(() => ({ paddingLeft: indent }), [indent]);
|
|
@@ -350,14 +380,29 @@ var NavExpandableItem = ({
|
|
|
350
380
|
accessibilityLabel: item.label,
|
|
351
381
|
accessibilityRole: "button",
|
|
352
382
|
accessibilityState: { expanded },
|
|
353
|
-
style: [
|
|
383
|
+
style: [
|
|
384
|
+
expandableStyles.header,
|
|
385
|
+
isSectionHeader ? expandableStyles.sectionHeader : void 0,
|
|
386
|
+
headerPaddingStyle,
|
|
387
|
+
focusRingStyle(focused, primaryColor)
|
|
388
|
+
],
|
|
354
389
|
testID: item.testID ?? item.key,
|
|
355
390
|
onBlur: () => setFocused(false),
|
|
356
391
|
onFocus: () => setFocused(true),
|
|
357
392
|
onPress: toggle,
|
|
393
|
+
...ariaExpandedProps(expanded),
|
|
358
394
|
children: [
|
|
359
|
-
typeof item.renderIcon === "function" ? /* @__PURE__ */ jsx(View, { style: expandableStyles.iconWrapper, children: item.renderIcon(colors.text, NAV_ICON_SIZE) }) : null,
|
|
360
|
-
/* @__PURE__ */ jsx(
|
|
395
|
+
typeof item.renderIcon === "function" ? /* @__PURE__ */ jsx(View, { style: expandableStyles.iconWrapper, children: item.renderIcon(isSectionHeader ? colors.textSecondary : colors.text, NAV_ICON_SIZE) }) : null,
|
|
396
|
+
/* @__PURE__ */ jsx(
|
|
397
|
+
Text,
|
|
398
|
+
{
|
|
399
|
+
style: [
|
|
400
|
+
isSectionHeader ? expandableStyles.sectionHeaderText : expandableStyles.headerText,
|
|
401
|
+
{ color: isSectionHeader ? colors.textSecondary : colors.text }
|
|
402
|
+
],
|
|
403
|
+
children: item.label
|
|
404
|
+
}
|
|
405
|
+
),
|
|
361
406
|
typeof renderChevron === "function" ? /* @__PURE__ */ jsx(View, { style: expandableStyles.chevron, children: renderChevron(expanded, colors.textSecondary, CHEVRON_ICON_SIZE) }) : null
|
|
362
407
|
]
|
|
363
408
|
}
|
|
@@ -1002,6 +1047,7 @@ var DRAWER_WIDTH = 280;
|
|
|
1002
1047
|
var SCRIM_Z_INDEX = 1;
|
|
1003
1048
|
var PANEL_Z_INDEX = 2;
|
|
1004
1049
|
var NAV_ACTIVATABLE_SELECTOR = 'a, [role="button"], [role="link"]';
|
|
1050
|
+
var NAV_TOGGLE_SELECTOR = "[aria-expanded]";
|
|
1005
1051
|
var DEFAULT_DRAWER_LABELS = {
|
|
1006
1052
|
openLabel: "Menu",
|
|
1007
1053
|
openHint: "Open the navigation menu",
|
|
@@ -1064,8 +1110,10 @@ var MobileDrawer = ({
|
|
|
1064
1110
|
if (node === null || typeof node.addEventListener !== "function") return void 0;
|
|
1065
1111
|
const handleClick = (event) => {
|
|
1066
1112
|
const target = event.target;
|
|
1067
|
-
|
|
1068
|
-
|
|
1113
|
+
if (target === null) return;
|
|
1114
|
+
const activatable = target.closest(NAV_ACTIVATABLE_SELECTOR);
|
|
1115
|
+
const isToggle = activatable !== null && activatable.closest(NAV_TOGGLE_SELECTOR) !== null;
|
|
1116
|
+
if (activatable !== null && !isToggle) onClose();
|
|
1069
1117
|
};
|
|
1070
1118
|
node.addEventListener("click", handleClick);
|
|
1071
1119
|
return () => node.removeEventListener("click", handleClick);
|
|
@@ -1478,6 +1526,159 @@ var DarkModeControl = ({
|
|
|
1478
1526
|
}
|
|
1479
1527
|
);
|
|
1480
1528
|
};
|
|
1529
|
+
|
|
1530
|
+
// src/commandPaletteFilter.ts
|
|
1531
|
+
function haystack(item) {
|
|
1532
|
+
return [item.label, item.hint ?? "", ...item.keywords ?? []].join(" ").toLowerCase();
|
|
1533
|
+
}
|
|
1534
|
+
function filterCommands(items, query) {
|
|
1535
|
+
const tokens = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
1536
|
+
if (tokens.length === 0) return [...items];
|
|
1537
|
+
return items.filter((item) => {
|
|
1538
|
+
const hay = haystack(item);
|
|
1539
|
+
return tokens.every((token) => hay.includes(token));
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
var SCRIM_COLOR2 = "rgba(0, 0, 0, 0.5)";
|
|
1543
|
+
var OVERLAY_Z_INDEX = 60;
|
|
1544
|
+
var PANEL_MAX_WIDTH = 560;
|
|
1545
|
+
var PANEL_TOP_OFFSET = 88;
|
|
1546
|
+
var LIST_MAX_HEIGHT = 360;
|
|
1547
|
+
var KEY_DOWN = "ArrowDown";
|
|
1548
|
+
var KEY_UP = "ArrowUp";
|
|
1549
|
+
var KEY_ENTER = "Enter";
|
|
1550
|
+
var KEY_ESCAPE = "Escape";
|
|
1551
|
+
var styles4 = StyleSheet.create({
|
|
1552
|
+
overlay: { ...StyleSheet.absoluteFillObject, zIndex: OVERLAY_Z_INDEX, alignItems: "center" },
|
|
1553
|
+
scrim: { ...StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR2 },
|
|
1554
|
+
panel: {
|
|
1555
|
+
marginTop: PANEL_TOP_OFFSET,
|
|
1556
|
+
width: "92%",
|
|
1557
|
+
maxWidth: PANEL_MAX_WIDTH,
|
|
1558
|
+
borderRadius: 12,
|
|
1559
|
+
borderWidth: 1,
|
|
1560
|
+
overflow: "hidden"
|
|
1561
|
+
},
|
|
1562
|
+
input: { fontSize: 16, paddingHorizontal: 16, paddingVertical: 14, borderBottomWidth: 1 },
|
|
1563
|
+
list: { maxHeight: LIST_MAX_HEIGHT },
|
|
1564
|
+
row: { flexDirection: "row", alignItems: "center", paddingHorizontal: 16, paddingVertical: 12, columnGap: 10 },
|
|
1565
|
+
rowText: { flex: 1 },
|
|
1566
|
+
rowLabel: { fontSize: 15, fontWeight: "600" },
|
|
1567
|
+
rowHint: { fontSize: 12, marginTop: 2 },
|
|
1568
|
+
empty: { paddingHorizontal: 16, paddingVertical: 20, fontSize: 14 }
|
|
1569
|
+
});
|
|
1570
|
+
var PaletteRow = ({ item, selected, onChoose }) => {
|
|
1571
|
+
const { theme } = useUi();
|
|
1572
|
+
const colors = theme.colors;
|
|
1573
|
+
return /* @__PURE__ */ jsxs(
|
|
1574
|
+
Pressable,
|
|
1575
|
+
{
|
|
1576
|
+
accessibilityHint: item.hint,
|
|
1577
|
+
accessibilityLabel: item.label,
|
|
1578
|
+
accessibilityRole: "button",
|
|
1579
|
+
accessibilityState: { selected },
|
|
1580
|
+
style: [styles4.row, selected ? { backgroundColor: colors.border } : void 0],
|
|
1581
|
+
testID: item.testID ?? item.key,
|
|
1582
|
+
onPress: () => onChoose(item),
|
|
1583
|
+
children: [
|
|
1584
|
+
typeof item.renderIcon === "function" ? item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) : null,
|
|
1585
|
+
/* @__PURE__ */ jsxs(View, { style: styles4.rowText, children: [
|
|
1586
|
+
/* @__PURE__ */ jsx(Text, { style: [styles4.rowLabel, { color: colors.text }], children: item.label }),
|
|
1587
|
+
item.hint ? /* @__PURE__ */ jsx(Text, { style: [styles4.rowHint, { color: colors.textSecondary }], children: item.hint }) : null
|
|
1588
|
+
] })
|
|
1589
|
+
]
|
|
1590
|
+
}
|
|
1591
|
+
);
|
|
1592
|
+
};
|
|
1593
|
+
var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
1594
|
+
const { theme } = useUi();
|
|
1595
|
+
const colors = theme.colors;
|
|
1596
|
+
const [query, setQuery] = useState("");
|
|
1597
|
+
const [selected, setSelected] = useState(0);
|
|
1598
|
+
const inputRef = useRef(null);
|
|
1599
|
+
const results = useMemo(() => filterCommands(items, query), [items, query]);
|
|
1600
|
+
useEffect(() => {
|
|
1601
|
+
if (!open) return;
|
|
1602
|
+
setQuery("");
|
|
1603
|
+
setSelected(0);
|
|
1604
|
+
inputRef.current?.focus();
|
|
1605
|
+
}, [open]);
|
|
1606
|
+
useEffect(() => {
|
|
1607
|
+
setSelected((prev) => Math.min(prev, Math.max(0, results.length - 1)));
|
|
1608
|
+
}, [results.length]);
|
|
1609
|
+
const choose = useCallback(
|
|
1610
|
+
(item) => {
|
|
1611
|
+
item.onSelect();
|
|
1612
|
+
onClose();
|
|
1613
|
+
},
|
|
1614
|
+
[onClose]
|
|
1615
|
+
);
|
|
1616
|
+
const onKeyPress = useCallback(
|
|
1617
|
+
(event) => {
|
|
1618
|
+
const key = event.nativeEvent.key;
|
|
1619
|
+
if (key === KEY_DOWN) setSelected((i) => Math.min(i + 1, results.length - 1));
|
|
1620
|
+
else if (key === KEY_UP) setSelected((i) => Math.max(i - 1, 0));
|
|
1621
|
+
else if (key === KEY_ESCAPE) onClose();
|
|
1622
|
+
else if (key === KEY_ENTER && results[selected]) choose(results[selected]);
|
|
1623
|
+
},
|
|
1624
|
+
[results, selected, choose, onClose]
|
|
1625
|
+
);
|
|
1626
|
+
if (!open) return null;
|
|
1627
|
+
return /* @__PURE__ */ jsxs(View, { style: styles4.overlay, children: [
|
|
1628
|
+
/* @__PURE__ */ jsx(
|
|
1629
|
+
Pressable,
|
|
1630
|
+
{
|
|
1631
|
+
accessibilityHint: labels.closeHint,
|
|
1632
|
+
accessibilityLabel: labels.closeLabel,
|
|
1633
|
+
accessibilityRole: "button",
|
|
1634
|
+
style: styles4.scrim,
|
|
1635
|
+
testID: `${testID ?? "command-palette"}-scrim`,
|
|
1636
|
+
onPress: onClose
|
|
1637
|
+
}
|
|
1638
|
+
),
|
|
1639
|
+
/* @__PURE__ */ jsxs(
|
|
1640
|
+
View,
|
|
1641
|
+
{
|
|
1642
|
+
"aria-modal": true,
|
|
1643
|
+
"aria-label": labels.regionLabel,
|
|
1644
|
+
role: "dialog",
|
|
1645
|
+
style: [styles4.panel, { backgroundColor: colors.surface, borderColor: colors.border }],
|
|
1646
|
+
testID: testID ?? "command-palette",
|
|
1647
|
+
children: [
|
|
1648
|
+
/* @__PURE__ */ jsx(
|
|
1649
|
+
TextInput,
|
|
1650
|
+
{
|
|
1651
|
+
ref: inputRef,
|
|
1652
|
+
accessibilityLabel: labels.placeholder,
|
|
1653
|
+
placeholder: labels.placeholder,
|
|
1654
|
+
placeholderTextColor: colors.textSecondary,
|
|
1655
|
+
style: [styles4.input, { color: colors.text, borderBottomColor: colors.border }],
|
|
1656
|
+
testID: `${testID ?? "command-palette"}-input`,
|
|
1657
|
+
value: query,
|
|
1658
|
+
onChangeText: setQuery,
|
|
1659
|
+
onKeyPress
|
|
1660
|
+
}
|
|
1661
|
+
),
|
|
1662
|
+
results.length === 0 ? /* @__PURE__ */ jsx(Text, { style: [styles4.empty, { color: colors.textSecondary }], children: labels.emptyText }) : /* @__PURE__ */ jsx(ScrollView, { keyboardShouldPersistTaps: "handled", style: styles4.list, children: results.map((item, index) => /* @__PURE__ */ jsx(PaletteRow, { item, selected: index === selected, onChoose: choose }, item.key)) })
|
|
1663
|
+
]
|
|
1664
|
+
}
|
|
1665
|
+
)
|
|
1666
|
+
] });
|
|
1667
|
+
};
|
|
1668
|
+
var LAUNCH_KEY = "k";
|
|
1669
|
+
function useCommandPaletteHotkey(onOpen, enabled = true) {
|
|
1670
|
+
useEffect(() => {
|
|
1671
|
+
if (!enabled || typeof document === "undefined") return void 0;
|
|
1672
|
+
const handler = (event) => {
|
|
1673
|
+
const isLauncher = event.key.toLowerCase() === LAUNCH_KEY && (event.metaKey || event.ctrlKey);
|
|
1674
|
+
if (!isLauncher) return;
|
|
1675
|
+
event.preventDefault();
|
|
1676
|
+
onOpen();
|
|
1677
|
+
};
|
|
1678
|
+
document.addEventListener("keydown", handler);
|
|
1679
|
+
return () => document.removeEventListener("keydown", handler);
|
|
1680
|
+
}, [onOpen, enabled]);
|
|
1681
|
+
}
|
|
1481
1682
|
function roleRoutesToNavItems(routes, translate) {
|
|
1482
1683
|
return routes.map((entry) => ({
|
|
1483
1684
|
key: entry.role,
|
|
@@ -1489,6 +1690,6 @@ function accessibleNavItems(user, table, translate) {
|
|
|
1489
1690
|
return roleRoutesToNavItems(resolveAccessibleRoutes(user, table), translate);
|
|
1490
1691
|
}
|
|
1491
1692
|
|
|
1492
|
-
export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, AppShell, BASE_INDENT, CHEVRON_ICON_SIZE, CollapsedRail, DEFAULT_COLLAPSED_RAIL_MAX, DarkModeControl, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_TEST_IDS, Nav, NavBar, NavExpandableItem, NavOverflowMenu, NavShell, PillNav, RAIL_FULL_BREAKPOINT, Sidebar, Topbar, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, isRouteActive, navStyles, pillNavStyles, resolveContentMaxWidth, resolveRailMode, roleRoutesToNavItems, useContentMaxWidth };
|
|
1693
|
+
export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, AppShell, BASE_INDENT, CHEVRON_ICON_SIZE, CollapsedRail, CommandPalette, DEFAULT_COLLAPSED_RAIL_MAX, DarkModeControl, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_TEST_IDS, Nav, NavBar, NavExpandableItem, NavOverflowMenu, NavShell, PillNav, RAIL_FULL_BREAKPOINT, Sidebar, Topbar, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, isRouteActive, navStyles, pillNavStyles, resolveContentMaxWidth, resolveRailMode, roleRoutesToNavItems, useCommandPaletteHotkey, useContentMaxWidth };
|
|
1493
1694
|
//# sourceMappingURL=index.mjs.map
|
|
1494
1695
|
//# sourceMappingURL=index.mjs.map
|