@dloizides/ui-nav 1.6.0 → 1.7.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 +42 -0
- package/README.md +30 -0
- package/dist/index.d.mts +130 -3
- package/dist/index.d.ts +130 -3
- package/dist/index.js +211 -47
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +183 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.7.0
|
|
4
|
+
|
|
5
|
+
Two additive navigation capabilities on the horizontal bar, plus a unifying component.
|
|
6
|
+
|
|
7
|
+
**Priority+ overflow ("…" menu) on `NavBar`.** Above the `collapseBelow` breakpoint the
|
|
8
|
+
inline links sit on ONE non-wrapping row; when they don't all fit, a measure pass
|
|
9
|
+
(`useNavOverflow` + the pure `computeVisibleCount`) keeps the leading items that fit inline
|
|
10
|
+
and collapses the rest behind a **"More ▾"** trigger — the shared `@dloizides/ui-layout`
|
|
11
|
+
`ModalDropdown`, so the overflow menu is portalled, keyboard-navigable, and dismissed on
|
|
12
|
+
outside-click / Escape like every other menu. No item is ever cut off; the surplus simply
|
|
13
|
+
moves into the dropdown. When the active route lives in the overflow set the trigger wears
|
|
14
|
+
the accent pill so it stays visibly reachable. BELOW `collapseBelow` the whole set still
|
|
15
|
+
collapses into the responsive hamburger drawer (the two mechanisms never overlap). Two new
|
|
16
|
+
optional props localize the trigger: `overflowLabel` (visible + accessible, default `"More"`)
|
|
17
|
+
and `overflowHint`. New `NAV_TEST_IDS.navBarOverflow` (`navbar-overflow`).
|
|
18
|
+
|
|
19
|
+
**`Nav` — one component, two orientations.** `<Nav orientation="horizontal" />` renders the
|
|
20
|
+
`NavBar`; `<Nav orientation="vertical" />` renders the `Sidebar` — from the SAME `NavItem[]`,
|
|
21
|
+
so an app flips between a top bar and a side rail without swapping components. `orientation`
|
|
22
|
+
defaults to `"horizontal"`; the remaining props are a discriminated union of the delegate's
|
|
23
|
+
props (TypeScript enforces the right prop set per orientation). Vertical nav is the existing
|
|
24
|
+
`Sidebar` (stacked, vertically scrolling — no overflow menu needed).
|
|
25
|
+
|
|
26
|
+
**Backwards compatible.** Purely additive — `Sidebar`, `Topbar`, `NavBar`, `AppShell`, and
|
|
27
|
+
the role-gating helpers keep their exact signatures; the new overflow props are optional
|
|
28
|
+
(default `"More"` / `""`) so aml-v2 (the only `NavBar` consumer) and every `Sidebar`/`Topbar`
|
|
29
|
+
consumer (erevna / katalogos / kefi / agora) are untouched. New exports (`Nav`, `NavProps`,
|
|
30
|
+
`NavOrientation`, `NavOverflowMenu`, `NavOverflowMenuProps`, `NAV_LINK_GAP`) are additive.
|
|
31
|
+
|
|
32
|
+
## 1.6.1
|
|
33
|
+
|
|
34
|
+
Keep the expanded links on ONE row — the row must be `nowrap` so `flex-shrink` distributes
|
|
35
|
+
negative space (a `wrap` row drops the right slot onto a 2nd line instead of shrinking the
|
|
36
|
+
links). Renames the internal expanded links style to `linksRow` (grow + shrink-to-0,
|
|
37
|
+
`minWidth:0`, `overflow:hidden`) with a per-link `linkCell` (never shrinks, so each link keeps
|
|
38
|
+
its natural measured width). Brand + right stay pinned (`flexShrink:0`).
|
|
39
|
+
|
|
40
|
+
## 1.6.0
|
|
41
|
+
|
|
42
|
+
Keep the bar to ONE row — horizontal-scroll / clip the links instead of wrapping the bar
|
|
43
|
+
onto a second line when brand + links + right slot overflow the available width.
|
|
44
|
+
|
|
3
45
|
## 1.5.0
|
|
4
46
|
|
|
5
47
|
Make the `AppShell` back-office `sidebar` layout **responsive** — a mobile drawer.
|
package/README.md
CHANGED
|
@@ -68,9 +68,39 @@ import { NavBar, type NavItem } from '@dloizides/ui-nav';
|
|
|
68
68
|
menuLabel={FM('menu.toggle')} // a11y label for the hamburger
|
|
69
69
|
menuHint={FM('menu.toggleHint')}
|
|
70
70
|
collapseBelow={760} // hamburger under this viewport width
|
|
71
|
+
overflowLabel={FM('menu.more')} // "More ▾" priority+ trigger label
|
|
72
|
+
overflowHint={FM('menu.moreHint')}
|
|
71
73
|
/>
|
|
72
74
|
```
|
|
73
75
|
|
|
76
|
+
**Priority+ overflow ("…" menu).** Above `collapseBelow` the links sit on ONE
|
|
77
|
+
non-wrapping row. When they don't all fit, a measure pass keeps the leading items
|
|
78
|
+
that fit inline and collapses the rest behind a **"More ▾"** trigger — the shared
|
|
79
|
+
`@dloizides/ui-layout` `ModalDropdown` — so no item is ever cut off; the surplus
|
|
80
|
+
moves into a portalled, keyboard-navigable dropdown. If the active route lives in
|
|
81
|
+
the overflow set, the trigger wears the accent pill so it stays reachable. Localize
|
|
82
|
+
the trigger with the optional `overflowLabel` (visible + accessible, default `"More"`)
|
|
83
|
+
and `overflowHint`. Below `collapseBelow` the whole set still collapses into the
|
|
84
|
+
responsive hamburger drawer, so the two mechanisms never overlap.
|
|
85
|
+
|
|
86
|
+
### One component, two orientations (`Nav`)
|
|
87
|
+
|
|
88
|
+
`Nav` renders EITHER the horizontal `NavBar` or the vertical `Sidebar` from the same
|
|
89
|
+
`NavItem[]`, chosen by a single `orientation` prop — flip between a top bar and a side
|
|
90
|
+
rail without swapping components or re-plumbing props. `orientation` defaults to
|
|
91
|
+
`"horizontal"`; the remaining props are a discriminated union of the delegate's props
|
|
92
|
+
(TypeScript enforces the right set per orientation — e.g. `title` only on vertical,
|
|
93
|
+
`collapseBelow` / `overflowLabel` only on horizontal).
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import { Nav, type NavItem } from '@dloizides/ui-nav';
|
|
97
|
+
|
|
98
|
+
<Nav orientation="horizontal" items={items} pathname={p} onNavigate={go} regionLabel={r} /> // NavBar
|
|
99
|
+
<Nav orientation="vertical" items={items} pathname={p} onNavigate={go} title={t} regionLabel={r} /> // Sidebar
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`Nav` is purely additive: `Sidebar` / `Topbar` / `NavBar` stay exported and unchanged.
|
|
103
|
+
|
|
74
104
|
An app that renders a `Sidebar` today switches to a top bar by swapping the
|
|
75
105
|
`Sidebar` element for `NavBar` (same `items` / `pathname` / `onNavigate`) — e.g.
|
|
76
106
|
the AML v2 app drops `NavBar` into the `AppShell` `header` (or `nav`) slot so its
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ViewStyle } from 'react-native';
|
|
3
|
+
import { DropdownVariant } from '@dloizides/ui-layout';
|
|
3
4
|
import { resolveAccessibleRoutes, RoleRouteTable, RoleRoute } from '@dloizides/auth-web';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -161,10 +162,19 @@ declare const Topbar: ({ left, language, notificationSlot, user, account, logout
|
|
|
161
162
|
* hover bg=`surfaceElevated`, active=`palette.primary`, ring=`palette.primary`).
|
|
162
163
|
* Hover/focus are web-only (react-native-web); native stays at the rest style.
|
|
163
164
|
*
|
|
165
|
+
* Overflow ("…" priority+ menu). Above the `collapseBelow` breakpoint the links sit
|
|
166
|
+
* on ONE row; when they don't all fit, a measure pass ({@link useNavOverflow} +
|
|
167
|
+
* {@link computeVisibleCount}) keeps the leading items that fit inline and collapses
|
|
168
|
+
* the rest behind a "More ▾" trigger — the shared `ModalDropdown` (see
|
|
169
|
+
* {@link NavOverflowMenu}) — so no item is ever cut off. BELOW `collapseBelow` the
|
|
170
|
+
* whole set still collapses into the responsive hamburger drawer (all items stacked),
|
|
171
|
+
* so the two mechanisms don't overlap: hamburger for true mobile, "…" for the
|
|
172
|
+
* in-between desktop case where only SOME items spill.
|
|
173
|
+
*
|
|
164
174
|
* Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,
|
|
165
175
|
* icon set, or store imports. Labels are pre-localized strings, icons are render
|
|
166
176
|
* slots, and every colour is read from the theme. This is purely additive —
|
|
167
|
-
* `Sidebar`/`Topbar` are unchanged.
|
|
177
|
+
* `Sidebar`/`Topbar` are unchanged and the new overflow labels are optional.
|
|
168
178
|
*/
|
|
169
179
|
|
|
170
180
|
interface NavBarProps {
|
|
@@ -190,10 +200,118 @@ interface NavBarProps {
|
|
|
190
200
|
renderMenuIcon?: (color: string, open: boolean) => React.ReactNode;
|
|
191
201
|
/** Collapse the links behind a hamburger below this viewport width (default 760). */
|
|
192
202
|
collapseBelow?: number;
|
|
203
|
+
/**
|
|
204
|
+
* Localized visible + accessible label for the "More ▾" overflow trigger shown when
|
|
205
|
+
* the inline links don't all fit on one row (priority+ menu). Defaults to `"More"`.
|
|
206
|
+
*/
|
|
207
|
+
overflowLabel?: string;
|
|
208
|
+
/** Localized accessibility hint for the overflow trigger. */
|
|
209
|
+
overflowHint?: string;
|
|
193
210
|
/** Extra container style overrides. */
|
|
194
211
|
containerStyle?: ViewStyle | ViewStyle[];
|
|
195
212
|
}
|
|
196
|
-
declare const NavBar: ({ items, pathname, onNavigate, regionLabel, navigateHint, brand, right, menuLabel, menuHint, renderMenuIcon, collapseBelow, containerStyle, }: NavBarProps) => React.ReactElement;
|
|
213
|
+
declare const NavBar: ({ items, pathname, onNavigate, regionLabel, navigateHint, brand, right, menuLabel, menuHint, renderMenuIcon, collapseBelow, overflowLabel, overflowHint, containerStyle, }: NavBarProps) => React.ReactElement;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* `Nav` — ONE component that renders EITHER the horizontal top bar (`NavBar`) or the
|
|
217
|
+
* vertical rail (`Sidebar`) from the same `NavItem[]`, chosen by a single
|
|
218
|
+
* `orientation` prop. It lets an app flip its navigation between a top bar and a side
|
|
219
|
+
* menu without swapping components or re-plumbing props:
|
|
220
|
+
*
|
|
221
|
+
* <Nav orientation="horizontal" items={items} pathname={p} onNavigate={go} .../> // NavBar
|
|
222
|
+
* <Nav orientation="vertical" items={items} pathname={p} onNavigate={go} .../> // Sidebar
|
|
223
|
+
*
|
|
224
|
+
* `orientation` defaults to `"horizontal"`. The remaining props are exactly the
|
|
225
|
+
* delegate's props — a discriminated union — so TypeScript enforces the right prop
|
|
226
|
+
* set per orientation (e.g. `title` is required only for the vertical/Sidebar side,
|
|
227
|
+
* `collapseBelow` / `overflowLabel` only for the horizontal/NavBar side).
|
|
228
|
+
*
|
|
229
|
+
* `Nav` is purely additive: `NavBar` and `Sidebar` remain exported and unchanged, so
|
|
230
|
+
* every existing consumer (erevna / katalogos / kefi / agora) is untouched. Vertical
|
|
231
|
+
* navigation is the existing Sidebar — stacked links that scroll vertically, so it
|
|
232
|
+
* needs no overflow menu; the priority+ "…" overflow is a horizontal-bar concern.
|
|
233
|
+
*/
|
|
234
|
+
|
|
235
|
+
/** Which axis the navigation renders on. */
|
|
236
|
+
type NavOrientation = 'horizontal' | 'vertical';
|
|
237
|
+
type NavProps = ({
|
|
238
|
+
orientation?: 'horizontal';
|
|
239
|
+
} & NavBarProps) | ({
|
|
240
|
+
orientation: 'vertical';
|
|
241
|
+
} & SidebarProps);
|
|
242
|
+
declare const Nav: (props: NavProps) => React.ReactElement;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* NavBarLink — a SINGLE horizontal `NavBar` link, extracted so each link owns its
|
|
246
|
+
* own hover/focus state (React hooks can't be per-item inside a map otherwise).
|
|
247
|
+
*
|
|
248
|
+
* It renders the v1 `.gn-links a` affordance, THEME-DRIVEN (no hard-coded colours
|
|
249
|
+
* beyond white ink on the accent pill):
|
|
250
|
+
* - rest → muted text (`colors.rest`), no background
|
|
251
|
+
* - hover → text brightens to full contrast (`colors.hoverText`) + a subtle
|
|
252
|
+
* rounded-pill background (`colors.hoverBg`, e.g. v1 `#16223a`)
|
|
253
|
+
* - active → solid accent pill (`colors.activeBg`) with white ink + aria-current
|
|
254
|
+
* - focus → a themed keyboard focus ring (`colors.ring`)
|
|
255
|
+
* Hover/focus are WEB-only (react-native-web fires `onHoverIn/Out`); on native
|
|
256
|
+
* those handlers never fire, so the link stays at its rest style.
|
|
257
|
+
*/
|
|
258
|
+
|
|
259
|
+
/** Theme-resolved colours a link needs, computed once by `NavBar`. */
|
|
260
|
+
interface NavBarLinkColors {
|
|
261
|
+
/** Muted link text at rest. */
|
|
262
|
+
rest: string;
|
|
263
|
+
/** Brightened link text on hover. */
|
|
264
|
+
hoverText: string;
|
|
265
|
+
/** Subtle hover-pill background. */
|
|
266
|
+
hoverBg: string;
|
|
267
|
+
/** Active-pill background (accent). */
|
|
268
|
+
activeBg: string;
|
|
269
|
+
/** Focus-ring colour. */
|
|
270
|
+
ring: string;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* NavOverflowMenu — the "More ▾" trigger + dropdown that holds the `NavBar` items
|
|
275
|
+
* which don't fit inline (the priority+ overflow set).
|
|
276
|
+
*
|
|
277
|
+
* It REUSES the shared `@dloizides/ui-layout` `ModalDropdown` — the exact component
|
|
278
|
+
* every other menu in the app uses — so the overflow menu is portalled, keyboard
|
|
279
|
+
* navigable, dismissed on outside-click / Escape, and opens on click, looking
|
|
280
|
+
* identical to the rest of the app's menus. The overflow entries are the same
|
|
281
|
+
* `NavItem`s (label + route + active state); selecting one navigates via the same
|
|
282
|
+
* `onNavigate` the inline links use.
|
|
283
|
+
*
|
|
284
|
+
* The trigger is a rounded pill matching a `NavBarLink`: muted at rest, and — when
|
|
285
|
+
* the ACTIVE route lives in the overflow set — it wears the accent pill so the
|
|
286
|
+
* active item stays visibly reachable behind the "…". The dropdown marks that same
|
|
287
|
+
* item selected (its `value` is the active overflow route). a11y: `ModalDropdown`
|
|
288
|
+
* owns the trigger's `role="button"` + `aria-expanded` + caller-supplied label/hint,
|
|
289
|
+
* and gives the options keyboard navigation.
|
|
290
|
+
*
|
|
291
|
+
* Contract discipline (as the rest of `@dloizides/ui-nav`): no FM / router / icon
|
|
292
|
+
* set / store; the label + hint are pre-localized strings from the caller and every
|
|
293
|
+
* colour comes from the theme (via the `NavBarLinkColors` the `NavBar` computed).
|
|
294
|
+
*/
|
|
295
|
+
|
|
296
|
+
interface NavOverflowMenuProps {
|
|
297
|
+
/** The items that spilled out of the inline row. */
|
|
298
|
+
items: NavItem[];
|
|
299
|
+
/** Current active route/path — decides the active-pill + selected option. */
|
|
300
|
+
pathname: string;
|
|
301
|
+
/** Navigation callback — receives the chosen item's `route`. */
|
|
302
|
+
onNavigate: (route: string) => void;
|
|
303
|
+
/** Theme-resolved link colours (same set the inline links use). */
|
|
304
|
+
colors: NavBarLinkColors;
|
|
305
|
+
/** Localized visible + accessible label for the trigger (e.g. "More"). */
|
|
306
|
+
label: string;
|
|
307
|
+
/** Localized accessibility hint for the trigger. */
|
|
308
|
+
hint: string;
|
|
309
|
+
/** testID for the trigger (options default to `` `${testID}-option-${route}` ``). */
|
|
310
|
+
testID: string;
|
|
311
|
+
/** Force a dropdown variant (default: responsive — inline menu on desktop). */
|
|
312
|
+
variant?: DropdownVariant;
|
|
313
|
+
}
|
|
314
|
+
declare const NavOverflowMenu: ({ items, pathname, onNavigate, colors, label, hint, testID, variant, }: NavOverflowMenuProps) => React.ReactElement;
|
|
197
315
|
|
|
198
316
|
/**
|
|
199
317
|
* MobileDrawer — the below-the-breakpoint face of `AppShell`'s back-office
|
|
@@ -334,6 +452,8 @@ declare const NAV_TEST_IDS: {
|
|
|
334
452
|
readonly navBarToggle: "navbar-toggle";
|
|
335
453
|
/** links container in the horizontal NavBar. */
|
|
336
454
|
readonly navBarLinks: "navbar-links";
|
|
455
|
+
/** the "More ▾" priority+ overflow trigger in the horizontal NavBar (shown when items spill). */
|
|
456
|
+
readonly navBarOverflow: "navbar-overflow";
|
|
337
457
|
};
|
|
338
458
|
/** Suffixes appended to an `AppShell`'s required `testID` to name its regions. */
|
|
339
459
|
declare const APP_SHELL_SUFFIX: {
|
|
@@ -399,6 +519,13 @@ declare function roleRoutesToNavItems(routes: RoleRoute[], translate: (key: stri
|
|
|
399
519
|
declare function accessibleNavItems(user: NavUser, table: RoleRouteTable, translate: (key: string) => string): NavItem[];
|
|
400
520
|
|
|
401
521
|
declare const ACTIVE_BORDER_RADIUS = 4;
|
|
522
|
+
/**
|
|
523
|
+
* Horizontal gap (px) between adjacent inline items in the `NavBar` links row.
|
|
524
|
+
* Single source of truth: it is both the row's `columnGap` AND the gap the
|
|
525
|
+
* priority+ overflow fit ({@link computeVisibleCount}) reasons about, so the two
|
|
526
|
+
* can never drift apart.
|
|
527
|
+
*/
|
|
528
|
+
declare const NAV_LINK_GAP = 4;
|
|
402
529
|
declare const navStyles: {
|
|
403
530
|
sidebarContainer: {
|
|
404
531
|
width: number;
|
|
@@ -521,4 +648,4 @@ declare const NAV_ICON_SIZE = 14;
|
|
|
521
648
|
/** Chevron icon size for expandable sections. */
|
|
522
649
|
declare const CHEVRON_ICON_SIZE = 12;
|
|
523
650
|
|
|
524
|
-
export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, NAV_ICON_SIZE, NAV_TEST_IDS, NavBar, type NavBarProps, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavUser, type ShellMessage, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, expandableStyles, isRouteActive, navStyles, resolveContentMaxWidth, roleRoutesToNavItems, useContentMaxWidth };
|
|
651
|
+
export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, 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, type NavUser, type ShellMessage, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, expandableStyles, isRouteActive, navStyles, resolveContentMaxWidth, roleRoutesToNavItems, useContentMaxWidth };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ViewStyle } from 'react-native';
|
|
3
|
+
import { DropdownVariant } from '@dloizides/ui-layout';
|
|
3
4
|
import { resolveAccessibleRoutes, RoleRouteTable, RoleRoute } from '@dloizides/auth-web';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -161,10 +162,19 @@ declare const Topbar: ({ left, language, notificationSlot, user, account, logout
|
|
|
161
162
|
* hover bg=`surfaceElevated`, active=`palette.primary`, ring=`palette.primary`).
|
|
162
163
|
* Hover/focus are web-only (react-native-web); native stays at the rest style.
|
|
163
164
|
*
|
|
165
|
+
* Overflow ("…" priority+ menu). Above the `collapseBelow` breakpoint the links sit
|
|
166
|
+
* on ONE row; when they don't all fit, a measure pass ({@link useNavOverflow} +
|
|
167
|
+
* {@link computeVisibleCount}) keeps the leading items that fit inline and collapses
|
|
168
|
+
* the rest behind a "More ▾" trigger — the shared `ModalDropdown` (see
|
|
169
|
+
* {@link NavOverflowMenu}) — so no item is ever cut off. BELOW `collapseBelow` the
|
|
170
|
+
* whole set still collapses into the responsive hamburger drawer (all items stacked),
|
|
171
|
+
* so the two mechanisms don't overlap: hamburger for true mobile, "…" for the
|
|
172
|
+
* in-between desktop case where only SOME items spill.
|
|
173
|
+
*
|
|
164
174
|
* Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,
|
|
165
175
|
* icon set, or store imports. Labels are pre-localized strings, icons are render
|
|
166
176
|
* slots, and every colour is read from the theme. This is purely additive —
|
|
167
|
-
* `Sidebar`/`Topbar` are unchanged.
|
|
177
|
+
* `Sidebar`/`Topbar` are unchanged and the new overflow labels are optional.
|
|
168
178
|
*/
|
|
169
179
|
|
|
170
180
|
interface NavBarProps {
|
|
@@ -190,10 +200,118 @@ interface NavBarProps {
|
|
|
190
200
|
renderMenuIcon?: (color: string, open: boolean) => React.ReactNode;
|
|
191
201
|
/** Collapse the links behind a hamburger below this viewport width (default 760). */
|
|
192
202
|
collapseBelow?: number;
|
|
203
|
+
/**
|
|
204
|
+
* Localized visible + accessible label for the "More ▾" overflow trigger shown when
|
|
205
|
+
* the inline links don't all fit on one row (priority+ menu). Defaults to `"More"`.
|
|
206
|
+
*/
|
|
207
|
+
overflowLabel?: string;
|
|
208
|
+
/** Localized accessibility hint for the overflow trigger. */
|
|
209
|
+
overflowHint?: string;
|
|
193
210
|
/** Extra container style overrides. */
|
|
194
211
|
containerStyle?: ViewStyle | ViewStyle[];
|
|
195
212
|
}
|
|
196
|
-
declare const NavBar: ({ items, pathname, onNavigate, regionLabel, navigateHint, brand, right, menuLabel, menuHint, renderMenuIcon, collapseBelow, containerStyle, }: NavBarProps) => React.ReactElement;
|
|
213
|
+
declare const NavBar: ({ items, pathname, onNavigate, regionLabel, navigateHint, brand, right, menuLabel, menuHint, renderMenuIcon, collapseBelow, overflowLabel, overflowHint, containerStyle, }: NavBarProps) => React.ReactElement;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* `Nav` — ONE component that renders EITHER the horizontal top bar (`NavBar`) or the
|
|
217
|
+
* vertical rail (`Sidebar`) from the same `NavItem[]`, chosen by a single
|
|
218
|
+
* `orientation` prop. It lets an app flip its navigation between a top bar and a side
|
|
219
|
+
* menu without swapping components or re-plumbing props:
|
|
220
|
+
*
|
|
221
|
+
* <Nav orientation="horizontal" items={items} pathname={p} onNavigate={go} .../> // NavBar
|
|
222
|
+
* <Nav orientation="vertical" items={items} pathname={p} onNavigate={go} .../> // Sidebar
|
|
223
|
+
*
|
|
224
|
+
* `orientation` defaults to `"horizontal"`. The remaining props are exactly the
|
|
225
|
+
* delegate's props — a discriminated union — so TypeScript enforces the right prop
|
|
226
|
+
* set per orientation (e.g. `title` is required only for the vertical/Sidebar side,
|
|
227
|
+
* `collapseBelow` / `overflowLabel` only for the horizontal/NavBar side).
|
|
228
|
+
*
|
|
229
|
+
* `Nav` is purely additive: `NavBar` and `Sidebar` remain exported and unchanged, so
|
|
230
|
+
* every existing consumer (erevna / katalogos / kefi / agora) is untouched. Vertical
|
|
231
|
+
* navigation is the existing Sidebar — stacked links that scroll vertically, so it
|
|
232
|
+
* needs no overflow menu; the priority+ "…" overflow is a horizontal-bar concern.
|
|
233
|
+
*/
|
|
234
|
+
|
|
235
|
+
/** Which axis the navigation renders on. */
|
|
236
|
+
type NavOrientation = 'horizontal' | 'vertical';
|
|
237
|
+
type NavProps = ({
|
|
238
|
+
orientation?: 'horizontal';
|
|
239
|
+
} & NavBarProps) | ({
|
|
240
|
+
orientation: 'vertical';
|
|
241
|
+
} & SidebarProps);
|
|
242
|
+
declare const Nav: (props: NavProps) => React.ReactElement;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* NavBarLink — a SINGLE horizontal `NavBar` link, extracted so each link owns its
|
|
246
|
+
* own hover/focus state (React hooks can't be per-item inside a map otherwise).
|
|
247
|
+
*
|
|
248
|
+
* It renders the v1 `.gn-links a` affordance, THEME-DRIVEN (no hard-coded colours
|
|
249
|
+
* beyond white ink on the accent pill):
|
|
250
|
+
* - rest → muted text (`colors.rest`), no background
|
|
251
|
+
* - hover → text brightens to full contrast (`colors.hoverText`) + a subtle
|
|
252
|
+
* rounded-pill background (`colors.hoverBg`, e.g. v1 `#16223a`)
|
|
253
|
+
* - active → solid accent pill (`colors.activeBg`) with white ink + aria-current
|
|
254
|
+
* - focus → a themed keyboard focus ring (`colors.ring`)
|
|
255
|
+
* Hover/focus are WEB-only (react-native-web fires `onHoverIn/Out`); on native
|
|
256
|
+
* those handlers never fire, so the link stays at its rest style.
|
|
257
|
+
*/
|
|
258
|
+
|
|
259
|
+
/** Theme-resolved colours a link needs, computed once by `NavBar`. */
|
|
260
|
+
interface NavBarLinkColors {
|
|
261
|
+
/** Muted link text at rest. */
|
|
262
|
+
rest: string;
|
|
263
|
+
/** Brightened link text on hover. */
|
|
264
|
+
hoverText: string;
|
|
265
|
+
/** Subtle hover-pill background. */
|
|
266
|
+
hoverBg: string;
|
|
267
|
+
/** Active-pill background (accent). */
|
|
268
|
+
activeBg: string;
|
|
269
|
+
/** Focus-ring colour. */
|
|
270
|
+
ring: string;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* NavOverflowMenu — the "More ▾" trigger + dropdown that holds the `NavBar` items
|
|
275
|
+
* which don't fit inline (the priority+ overflow set).
|
|
276
|
+
*
|
|
277
|
+
* It REUSES the shared `@dloizides/ui-layout` `ModalDropdown` — the exact component
|
|
278
|
+
* every other menu in the app uses — so the overflow menu is portalled, keyboard
|
|
279
|
+
* navigable, dismissed on outside-click / Escape, and opens on click, looking
|
|
280
|
+
* identical to the rest of the app's menus. The overflow entries are the same
|
|
281
|
+
* `NavItem`s (label + route + active state); selecting one navigates via the same
|
|
282
|
+
* `onNavigate` the inline links use.
|
|
283
|
+
*
|
|
284
|
+
* The trigger is a rounded pill matching a `NavBarLink`: muted at rest, and — when
|
|
285
|
+
* the ACTIVE route lives in the overflow set — it wears the accent pill so the
|
|
286
|
+
* active item stays visibly reachable behind the "…". The dropdown marks that same
|
|
287
|
+
* item selected (its `value` is the active overflow route). a11y: `ModalDropdown`
|
|
288
|
+
* owns the trigger's `role="button"` + `aria-expanded` + caller-supplied label/hint,
|
|
289
|
+
* and gives the options keyboard navigation.
|
|
290
|
+
*
|
|
291
|
+
* Contract discipline (as the rest of `@dloizides/ui-nav`): no FM / router / icon
|
|
292
|
+
* set / store; the label + hint are pre-localized strings from the caller and every
|
|
293
|
+
* colour comes from the theme (via the `NavBarLinkColors` the `NavBar` computed).
|
|
294
|
+
*/
|
|
295
|
+
|
|
296
|
+
interface NavOverflowMenuProps {
|
|
297
|
+
/** The items that spilled out of the inline row. */
|
|
298
|
+
items: NavItem[];
|
|
299
|
+
/** Current active route/path — decides the active-pill + selected option. */
|
|
300
|
+
pathname: string;
|
|
301
|
+
/** Navigation callback — receives the chosen item's `route`. */
|
|
302
|
+
onNavigate: (route: string) => void;
|
|
303
|
+
/** Theme-resolved link colours (same set the inline links use). */
|
|
304
|
+
colors: NavBarLinkColors;
|
|
305
|
+
/** Localized visible + accessible label for the trigger (e.g. "More"). */
|
|
306
|
+
label: string;
|
|
307
|
+
/** Localized accessibility hint for the trigger. */
|
|
308
|
+
hint: string;
|
|
309
|
+
/** testID for the trigger (options default to `` `${testID}-option-${route}` ``). */
|
|
310
|
+
testID: string;
|
|
311
|
+
/** Force a dropdown variant (default: responsive — inline menu on desktop). */
|
|
312
|
+
variant?: DropdownVariant;
|
|
313
|
+
}
|
|
314
|
+
declare const NavOverflowMenu: ({ items, pathname, onNavigate, colors, label, hint, testID, variant, }: NavOverflowMenuProps) => React.ReactElement;
|
|
197
315
|
|
|
198
316
|
/**
|
|
199
317
|
* MobileDrawer — the below-the-breakpoint face of `AppShell`'s back-office
|
|
@@ -334,6 +452,8 @@ declare const NAV_TEST_IDS: {
|
|
|
334
452
|
readonly navBarToggle: "navbar-toggle";
|
|
335
453
|
/** links container in the horizontal NavBar. */
|
|
336
454
|
readonly navBarLinks: "navbar-links";
|
|
455
|
+
/** the "More ▾" priority+ overflow trigger in the horizontal NavBar (shown when items spill). */
|
|
456
|
+
readonly navBarOverflow: "navbar-overflow";
|
|
337
457
|
};
|
|
338
458
|
/** Suffixes appended to an `AppShell`'s required `testID` to name its regions. */
|
|
339
459
|
declare const APP_SHELL_SUFFIX: {
|
|
@@ -399,6 +519,13 @@ declare function roleRoutesToNavItems(routes: RoleRoute[], translate: (key: stri
|
|
|
399
519
|
declare function accessibleNavItems(user: NavUser, table: RoleRouteTable, translate: (key: string) => string): NavItem[];
|
|
400
520
|
|
|
401
521
|
declare const ACTIVE_BORDER_RADIUS = 4;
|
|
522
|
+
/**
|
|
523
|
+
* Horizontal gap (px) between adjacent inline items in the `NavBar` links row.
|
|
524
|
+
* Single source of truth: it is both the row's `columnGap` AND the gap the
|
|
525
|
+
* priority+ overflow fit ({@link computeVisibleCount}) reasons about, so the two
|
|
526
|
+
* can never drift apart.
|
|
527
|
+
*/
|
|
528
|
+
declare const NAV_LINK_GAP = 4;
|
|
402
529
|
declare const navStyles: {
|
|
403
530
|
sidebarContainer: {
|
|
404
531
|
width: number;
|
|
@@ -521,4 +648,4 @@ declare const NAV_ICON_SIZE = 14;
|
|
|
521
648
|
/** Chevron icon size for expandable sections. */
|
|
522
649
|
declare const CHEVRON_ICON_SIZE = 12;
|
|
523
650
|
|
|
524
|
-
export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, NAV_ICON_SIZE, NAV_TEST_IDS, NavBar, type NavBarProps, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavUser, type ShellMessage, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, expandableStyles, isRouteActive, navStyles, resolveContentMaxWidth, roleRoutesToNavItems, useContentMaxWidth };
|
|
651
|
+
export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, 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, type NavUser, type ShellMessage, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, expandableStyles, isRouteActive, navStyles, resolveContentMaxWidth, roleRoutesToNavItems, useContentMaxWidth };
|