@dloizides/ui-nav 1.0.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 ADDED
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0
4
+
5
+ Initial release. `Sidebar` (leaf + expandable items, active-route highlight, header/footer
6
+ slots), `Topbar` (logo/language/notification/user/account/logout slots), and the
7
+ `accessibleNavItems` / `roleRoutesToNavItems` role-gating helpers (reusing
8
+ `resolveAccessibleRoutes` from `@dloizides/auth-web`). Chrome + metrics ported verbatim from
9
+ the byte-identical erevna-web / katalogos-web nav twins; every colour reads from the
10
+ `@dloizides/ui-feedback` UiProvider theme.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 dloizides
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # @dloizides/ui-nav
2
+
3
+ Config-driven, brand-agnostic React Native (RN-web) **navigation shell** for the
4
+ dloizides.com portfolio: `Sidebar` + `Topbar`, promoted from the byte-identical
5
+ erevna-web / katalogos-web nav twins. The *chrome* is shared; the *item data* stays with
6
+ your app — the components render a caller-supplied `NavItem[]` (labels already localized,
7
+ icons as render slots) and route every colour through the shared `@dloizides/ui-feedback`
8
+ UiProvider theme.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install @dloizides/ui-nav @dloizides/ui-feedback @dloizides/auth-web
14
+ ```
15
+
16
+ Peer deps: `@dloizides/ui-feedback >= 1.2.0`, `@dloizides/auth-web >= 1.5.0`, `react >= 18`,
17
+ `react-native >= 0.74` (use `react-native-web` on web).
18
+
19
+ ## Usage
20
+
21
+ ```tsx
22
+ import { Sidebar, Topbar, accessibleNavItems, type NavItem } from '@dloizides/ui-nav';
23
+
24
+ const items: NavItem[] = buildItems(); // your role-filtered / grouped items
25
+
26
+ <Sidebar
27
+ items={items}
28
+ pathname={usePathname()}
29
+ onNavigate={(route) => router.push(route)}
30
+ title={FM('menu.title')}
31
+ regionLabel={FM('accessibility.navigationRegion')}
32
+ navigateHint={(label) => FM('menu.navigateToHint', label)}
33
+ expandHint={FM('menu.expandSection')}
34
+ collapseHint={FM('menu.collapseSection')}
35
+ renderChevron={(open, color, size) => <SvgIcon name={open ? 'chevronUp' : 'chevronDown'} color={color} size={size} />}
36
+ header={<HomeShortcut />}
37
+ footer={<><DarkModeToggle /><LogoutButton /></>}
38
+ />
39
+
40
+ <Topbar
41
+ left={<TenantLogo />}
42
+ language={{ label: FM(`topbar.lang.${locale}`), hint: FM('topbar.langHint'), onPress: toggleLocale }}
43
+ notificationSlot={<NotificationBell />}
44
+ user={{ name: displayName, email }}
45
+ logout={{ label: FM('topbar.logout'), hint: FM('topbar.logoutHint'), onPress: logout, testID: 'logout-button' }}
46
+ />
47
+ ```
48
+
49
+ ### Role gating
50
+
51
+ `accessibleNavItems(user, roleRouteTable, translate)` builds the `NavItem[]` a user's roles
52
+ unlock, reusing `resolveAccessibleRoutes` from `@dloizides/auth-web` (most privileged first,
53
+ empty when none) — no duplicated role logic.
54
+
55
+ ## License
56
+
57
+ MIT
@@ -0,0 +1,271 @@
1
+ import React from 'react';
2
+ import { ViewStyle } from 'react-native';
3
+ import { resolveAccessibleRoutes, RoleRouteTable, RoleRoute } from '@dloizides/auth-web';
4
+
5
+ /**
6
+ * Active-route matcher shared by the sidebar entries. Ported verbatim from the
7
+ * twin app sidebars: an item is active when the current pathname equals its
8
+ * route or is nested under it (`/foo` matches `/foo` and `/foo/bar`, but `/`
9
+ * only matches `/`).
10
+ */
11
+ declare function isRouteActive(pathname: string, route: string): boolean;
12
+
13
+ /**
14
+ * Public prop types for the `@dloizides/ui-nav` config-driven navigation shell.
15
+ *
16
+ * The rendering chrome (sidebar + topbar) was byte-identical across erevna-web
17
+ * and katalogos-web; only the *item data* (which routes, how they group) differs
18
+ * per app. So this package renders a caller-supplied `NavItem[]` — labels are
19
+ * pre-localized strings and icons are render slots, keeping the package free of
20
+ * any app's i18n helper, icon set, router, or store.
21
+ */
22
+
23
+ /** One navigation entry. Labels are already localized by the caller. */
24
+ interface NavItem {
25
+ /** Stable key + default testID. */
26
+ key: string;
27
+ /** Localized display label. */
28
+ label: string;
29
+ /** Route/path this item navigates to (passed back to `onNavigate`). */
30
+ route: string;
31
+ /** Optional testID override (defaults to `key`). */
32
+ testID?: string;
33
+ /**
34
+ * Optional leading icon. Receives the resolved foreground colour and a size,
35
+ * so the app supplies its own icon component without this package importing
36
+ * an icon set.
37
+ */
38
+ renderIcon?: (color: string, size: number) => React.ReactNode;
39
+ /** Optional nested items — rendered as an expandable section. */
40
+ children?: NavItem[];
41
+ }
42
+
43
+ /**
44
+ * Sidebar — the config-driven left navigation shell promoted from the
45
+ * byte-identical erevna-web / katalogos-web `Sidebar`. It renders a caller
46
+ * supplied `NavItem[]` (leaf + expandable), highlights the active route, and
47
+ * exposes header/footer slots for app-specific chrome (title, dark-mode toggle,
48
+ * logout, notification bell). Every colour is read from the UiProvider theme.
49
+ */
50
+
51
+ interface SidebarProps {
52
+ /** Nav entries — already role-filtered / grouped by the app. */
53
+ items: NavItem[];
54
+ /** Current active route/path. */
55
+ pathname: string;
56
+ /** Navigation callback — receives a `NavItem.route`. */
57
+ onNavigate: (route: string) => void;
58
+ /** Localized menu title (heading). */
59
+ title: string;
60
+ /** Localized accessibility label for the navigation landmark. */
61
+ regionLabel: string;
62
+ /** a11y hint for a leaf item, given its label. Defaults to the label. */
63
+ navigateHint?: (label: string) => string;
64
+ /** a11y hint shown when an expandable section is collapsed. */
65
+ expandHint?: string;
66
+ /** a11y hint shown when an expandable section is expanded. */
67
+ collapseHint?: string;
68
+ /** Optional chevron renderer for expandable sections. */
69
+ renderChevron?: (expanded: boolean, color: string, size: number) => React.ReactNode;
70
+ /** Optional header slot rendered above the items (e.g. a Home shortcut). */
71
+ header?: React.ReactNode;
72
+ /** Optional footer slot rendered after a flex spacer (dark-mode toggle, logout). */
73
+ footer?: React.ReactNode;
74
+ /** Extra container style overrides. */
75
+ containerStyle?: ViewStyle | ViewStyle[];
76
+ }
77
+ declare const Sidebar: ({ items, pathname, onNavigate, title, regionLabel, navigateHint, expandHint, collapseHint, renderChevron, header, footer, containerStyle, }: SidebarProps) => React.ReactElement;
78
+
79
+ /**
80
+ * Topbar — the config-driven top navigation bar promoted from the byte-identical
81
+ * erevna-web / katalogos-web `Topbar`. Structured slots replace the app-specific
82
+ * wiring: a `left` logo slot, an optional language toggle, a notification slot,
83
+ * an optional user block, an optional account button, and a required logout
84
+ * action. Every colour comes from the UiProvider theme.
85
+ */
86
+
87
+ interface TopbarAction {
88
+ label: string;
89
+ hint: string;
90
+ onPress: () => void;
91
+ testID?: string;
92
+ }
93
+ interface TopbarUser {
94
+ name: string;
95
+ email: string;
96
+ }
97
+ interface TopbarProps {
98
+ /** Left slot — typically the tenant logo. */
99
+ left?: React.ReactNode;
100
+ /** Optional language toggle. */
101
+ language?: {
102
+ label: string;
103
+ hint: string;
104
+ onPress: () => void;
105
+ };
106
+ /** Optional notification slot (e.g. a notification bell). */
107
+ notificationSlot?: React.ReactNode;
108
+ /** Optional user identity block. */
109
+ user?: TopbarUser;
110
+ /** Optional account button. */
111
+ account?: TopbarAction;
112
+ /** Required logout action. */
113
+ logout: TopbarAction;
114
+ /** Extra container style overrides. */
115
+ containerStyle?: ViewStyle | ViewStyle[];
116
+ }
117
+ declare const Topbar: ({ left, language, notificationSlot, user, account, logout, containerStyle, }: TopbarProps) => React.ReactElement;
118
+
119
+ /**
120
+ * NavExpandableItem — a single sidebar entry that is either a leaf (navigates)
121
+ * or an expandable section (toggles nested children). Ported from the twin
122
+ * erevna/katalogos `Sidebar/NavExpandableItem`, made config-driven: labels are
123
+ * pre-localized strings, icons are render slots, colours come from `useUi`.
124
+ */
125
+
126
+ interface NavExpandableItemProps {
127
+ item: NavItem;
128
+ pathname: string;
129
+ onNavigate: (route: string) => void;
130
+ /** a11y hint for a leaf item, given its label. */
131
+ navigateHint: (label: string) => string;
132
+ /** a11y hint shown when the section is collapsed (press expands). */
133
+ expandHint: string;
134
+ /** a11y hint shown when the section is expanded (press collapses). */
135
+ collapseHint: string;
136
+ /** Optional chevron icon renderer for expandable sections. */
137
+ renderChevron?: (expanded: boolean, color: string, size: number) => React.ReactNode;
138
+ depth?: number;
139
+ }
140
+ declare const NavExpandableItem: ({ item, pathname, onNavigate, navigateHint, expandHint, collapseHint, renderChevron, depth, }: NavExpandableItemProps) => React.ReactElement;
141
+
142
+ /**
143
+ * Role-gated nav helpers — build a `NavItem[]` from a user's roles, reusing the
144
+ * existing `resolveAccessibleRoutes` from `@dloizides/auth-web` (the same helper
145
+ * the multi-role dashboard nav uses) rather than reimplementing role filtering.
146
+ *
147
+ * The app supplies its ordered `RoleRouteTable` (role → route + optional
148
+ * `labelKey`) and a `translate` fn (its `FM`); this returns the ordered set of
149
+ * `NavItem`s the user's roles unlock — most privileged first, empty when none.
150
+ */
151
+
152
+ /** The user shape `resolveAccessibleRoutes` accepts (derived — no extra dep). */
153
+ type NavUser = Parameters<typeof resolveAccessibleRoutes>[0];
154
+ /** Map already-resolved role routes to nav items, localizing each `labelKey`. */
155
+ declare function roleRoutesToNavItems(routes: RoleRoute[], translate: (key: string) => string): NavItem[];
156
+ /**
157
+ * Resolve the nav items a user can reach, in table (priority) order. Wraps
158
+ * `resolveAccessibleRoutes` so role gating lives in one place.
159
+ */
160
+ declare function accessibleNavItems(user: NavUser, table: RoleRouteTable, translate: (key: string) => string): NavItem[];
161
+
162
+ declare const ACTIVE_BORDER_RADIUS = 4;
163
+ declare const navStyles: {
164
+ sidebarContainer: {
165
+ width: number;
166
+ paddingTop: number;
167
+ paddingHorizontal: number;
168
+ borderRightWidth: number;
169
+ height: "100%";
170
+ };
171
+ sidebarTitle: {
172
+ fontWeight: "700";
173
+ marginBottom: number;
174
+ };
175
+ sidebarItem: {
176
+ paddingVertical: number;
177
+ paddingHorizontal: number;
178
+ borderRadius: number;
179
+ };
180
+ sidebarItemText: {
181
+ fontSize: number;
182
+ };
183
+ sidebarSpacer: {
184
+ flex: number;
185
+ };
186
+ topbarContainer: {
187
+ height: number;
188
+ paddingHorizontal: number;
189
+ borderBottomWidth: number;
190
+ flexDirection: "row";
191
+ alignItems: "center";
192
+ justifyContent: "space-between";
193
+ };
194
+ topbarLeft: {
195
+ flex: number;
196
+ };
197
+ topbarRight: {
198
+ flexDirection: "row";
199
+ alignItems: "center";
200
+ };
201
+ topbarRowItem: {
202
+ marginHorizontal: number;
203
+ alignItems: "center";
204
+ };
205
+ topbarLabel: {
206
+ fontSize: number;
207
+ };
208
+ userBlock: {
209
+ marginHorizontal: number;
210
+ alignItems: "flex-end";
211
+ };
212
+ userName: {
213
+ fontWeight: "600";
214
+ };
215
+ userEmail: {
216
+ fontSize: number;
217
+ };
218
+ accountBtn: {
219
+ marginLeft: number;
220
+ paddingHorizontal: number;
221
+ paddingVertical: number;
222
+ borderRadius: number;
223
+ };
224
+ accountText: {
225
+ fontWeight: "600";
226
+ };
227
+ };
228
+ declare const expandableStyles: {
229
+ childItem: {
230
+ borderRadius: number;
231
+ flexDirection: "row";
232
+ alignItems: "center";
233
+ paddingVertical: number;
234
+ };
235
+ childItemText: {
236
+ fontSize: number;
237
+ };
238
+ childItemTextWithIcon: {
239
+ fontSize: number;
240
+ marginLeft: number;
241
+ };
242
+ chevron: {
243
+ marginLeft: "auto";
244
+ };
245
+ childrenContainer: {
246
+ overflow: "hidden";
247
+ };
248
+ header: {
249
+ borderRadius: number;
250
+ flexDirection: "row";
251
+ alignItems: "center";
252
+ paddingVertical: number;
253
+ };
254
+ headerText: {
255
+ fontSize: number;
256
+ fontWeight: "600";
257
+ marginLeft: number;
258
+ };
259
+ iconWrapper: {
260
+ width: number;
261
+ alignItems: "center";
262
+ };
263
+ };
264
+ /** Base indent applied per nesting depth in the expandable item. */
265
+ declare const BASE_INDENT = 12;
266
+ /** Default icon size for nav item icons. */
267
+ declare const NAV_ICON_SIZE = 14;
268
+ /** Chevron icon size for expandable sections. */
269
+ declare const CHEVRON_ICON_SIZE = 12;
270
+
271
+ export { ACTIVE_BORDER_RADIUS, BASE_INDENT, CHEVRON_ICON_SIZE, NAV_ICON_SIZE, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavUser, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, expandableStyles, isRouteActive, navStyles, roleRoutesToNavItems };
@@ -0,0 +1,271 @@
1
+ import React from 'react';
2
+ import { ViewStyle } from 'react-native';
3
+ import { resolveAccessibleRoutes, RoleRouteTable, RoleRoute } from '@dloizides/auth-web';
4
+
5
+ /**
6
+ * Active-route matcher shared by the sidebar entries. Ported verbatim from the
7
+ * twin app sidebars: an item is active when the current pathname equals its
8
+ * route or is nested under it (`/foo` matches `/foo` and `/foo/bar`, but `/`
9
+ * only matches `/`).
10
+ */
11
+ declare function isRouteActive(pathname: string, route: string): boolean;
12
+
13
+ /**
14
+ * Public prop types for the `@dloizides/ui-nav` config-driven navigation shell.
15
+ *
16
+ * The rendering chrome (sidebar + topbar) was byte-identical across erevna-web
17
+ * and katalogos-web; only the *item data* (which routes, how they group) differs
18
+ * per app. So this package renders a caller-supplied `NavItem[]` — labels are
19
+ * pre-localized strings and icons are render slots, keeping the package free of
20
+ * any app's i18n helper, icon set, router, or store.
21
+ */
22
+
23
+ /** One navigation entry. Labels are already localized by the caller. */
24
+ interface NavItem {
25
+ /** Stable key + default testID. */
26
+ key: string;
27
+ /** Localized display label. */
28
+ label: string;
29
+ /** Route/path this item navigates to (passed back to `onNavigate`). */
30
+ route: string;
31
+ /** Optional testID override (defaults to `key`). */
32
+ testID?: string;
33
+ /**
34
+ * Optional leading icon. Receives the resolved foreground colour and a size,
35
+ * so the app supplies its own icon component without this package importing
36
+ * an icon set.
37
+ */
38
+ renderIcon?: (color: string, size: number) => React.ReactNode;
39
+ /** Optional nested items — rendered as an expandable section. */
40
+ children?: NavItem[];
41
+ }
42
+
43
+ /**
44
+ * Sidebar — the config-driven left navigation shell promoted from the
45
+ * byte-identical erevna-web / katalogos-web `Sidebar`. It renders a caller
46
+ * supplied `NavItem[]` (leaf + expandable), highlights the active route, and
47
+ * exposes header/footer slots for app-specific chrome (title, dark-mode toggle,
48
+ * logout, notification bell). Every colour is read from the UiProvider theme.
49
+ */
50
+
51
+ interface SidebarProps {
52
+ /** Nav entries — already role-filtered / grouped by the app. */
53
+ items: NavItem[];
54
+ /** Current active route/path. */
55
+ pathname: string;
56
+ /** Navigation callback — receives a `NavItem.route`. */
57
+ onNavigate: (route: string) => void;
58
+ /** Localized menu title (heading). */
59
+ title: string;
60
+ /** Localized accessibility label for the navigation landmark. */
61
+ regionLabel: string;
62
+ /** a11y hint for a leaf item, given its label. Defaults to the label. */
63
+ navigateHint?: (label: string) => string;
64
+ /** a11y hint shown when an expandable section is collapsed. */
65
+ expandHint?: string;
66
+ /** a11y hint shown when an expandable section is expanded. */
67
+ collapseHint?: string;
68
+ /** Optional chevron renderer for expandable sections. */
69
+ renderChevron?: (expanded: boolean, color: string, size: number) => React.ReactNode;
70
+ /** Optional header slot rendered above the items (e.g. a Home shortcut). */
71
+ header?: React.ReactNode;
72
+ /** Optional footer slot rendered after a flex spacer (dark-mode toggle, logout). */
73
+ footer?: React.ReactNode;
74
+ /** Extra container style overrides. */
75
+ containerStyle?: ViewStyle | ViewStyle[];
76
+ }
77
+ declare const Sidebar: ({ items, pathname, onNavigate, title, regionLabel, navigateHint, expandHint, collapseHint, renderChevron, header, footer, containerStyle, }: SidebarProps) => React.ReactElement;
78
+
79
+ /**
80
+ * Topbar — the config-driven top navigation bar promoted from the byte-identical
81
+ * erevna-web / katalogos-web `Topbar`. Structured slots replace the app-specific
82
+ * wiring: a `left` logo slot, an optional language toggle, a notification slot,
83
+ * an optional user block, an optional account button, and a required logout
84
+ * action. Every colour comes from the UiProvider theme.
85
+ */
86
+
87
+ interface TopbarAction {
88
+ label: string;
89
+ hint: string;
90
+ onPress: () => void;
91
+ testID?: string;
92
+ }
93
+ interface TopbarUser {
94
+ name: string;
95
+ email: string;
96
+ }
97
+ interface TopbarProps {
98
+ /** Left slot — typically the tenant logo. */
99
+ left?: React.ReactNode;
100
+ /** Optional language toggle. */
101
+ language?: {
102
+ label: string;
103
+ hint: string;
104
+ onPress: () => void;
105
+ };
106
+ /** Optional notification slot (e.g. a notification bell). */
107
+ notificationSlot?: React.ReactNode;
108
+ /** Optional user identity block. */
109
+ user?: TopbarUser;
110
+ /** Optional account button. */
111
+ account?: TopbarAction;
112
+ /** Required logout action. */
113
+ logout: TopbarAction;
114
+ /** Extra container style overrides. */
115
+ containerStyle?: ViewStyle | ViewStyle[];
116
+ }
117
+ declare const Topbar: ({ left, language, notificationSlot, user, account, logout, containerStyle, }: TopbarProps) => React.ReactElement;
118
+
119
+ /**
120
+ * NavExpandableItem — a single sidebar entry that is either a leaf (navigates)
121
+ * or an expandable section (toggles nested children). Ported from the twin
122
+ * erevna/katalogos `Sidebar/NavExpandableItem`, made config-driven: labels are
123
+ * pre-localized strings, icons are render slots, colours come from `useUi`.
124
+ */
125
+
126
+ interface NavExpandableItemProps {
127
+ item: NavItem;
128
+ pathname: string;
129
+ onNavigate: (route: string) => void;
130
+ /** a11y hint for a leaf item, given its label. */
131
+ navigateHint: (label: string) => string;
132
+ /** a11y hint shown when the section is collapsed (press expands). */
133
+ expandHint: string;
134
+ /** a11y hint shown when the section is expanded (press collapses). */
135
+ collapseHint: string;
136
+ /** Optional chevron icon renderer for expandable sections. */
137
+ renderChevron?: (expanded: boolean, color: string, size: number) => React.ReactNode;
138
+ depth?: number;
139
+ }
140
+ declare const NavExpandableItem: ({ item, pathname, onNavigate, navigateHint, expandHint, collapseHint, renderChevron, depth, }: NavExpandableItemProps) => React.ReactElement;
141
+
142
+ /**
143
+ * Role-gated nav helpers — build a `NavItem[]` from a user's roles, reusing the
144
+ * existing `resolveAccessibleRoutes` from `@dloizides/auth-web` (the same helper
145
+ * the multi-role dashboard nav uses) rather than reimplementing role filtering.
146
+ *
147
+ * The app supplies its ordered `RoleRouteTable` (role → route + optional
148
+ * `labelKey`) and a `translate` fn (its `FM`); this returns the ordered set of
149
+ * `NavItem`s the user's roles unlock — most privileged first, empty when none.
150
+ */
151
+
152
+ /** The user shape `resolveAccessibleRoutes` accepts (derived — no extra dep). */
153
+ type NavUser = Parameters<typeof resolveAccessibleRoutes>[0];
154
+ /** Map already-resolved role routes to nav items, localizing each `labelKey`. */
155
+ declare function roleRoutesToNavItems(routes: RoleRoute[], translate: (key: string) => string): NavItem[];
156
+ /**
157
+ * Resolve the nav items a user can reach, in table (priority) order. Wraps
158
+ * `resolveAccessibleRoutes` so role gating lives in one place.
159
+ */
160
+ declare function accessibleNavItems(user: NavUser, table: RoleRouteTable, translate: (key: string) => string): NavItem[];
161
+
162
+ declare const ACTIVE_BORDER_RADIUS = 4;
163
+ declare const navStyles: {
164
+ sidebarContainer: {
165
+ width: number;
166
+ paddingTop: number;
167
+ paddingHorizontal: number;
168
+ borderRightWidth: number;
169
+ height: "100%";
170
+ };
171
+ sidebarTitle: {
172
+ fontWeight: "700";
173
+ marginBottom: number;
174
+ };
175
+ sidebarItem: {
176
+ paddingVertical: number;
177
+ paddingHorizontal: number;
178
+ borderRadius: number;
179
+ };
180
+ sidebarItemText: {
181
+ fontSize: number;
182
+ };
183
+ sidebarSpacer: {
184
+ flex: number;
185
+ };
186
+ topbarContainer: {
187
+ height: number;
188
+ paddingHorizontal: number;
189
+ borderBottomWidth: number;
190
+ flexDirection: "row";
191
+ alignItems: "center";
192
+ justifyContent: "space-between";
193
+ };
194
+ topbarLeft: {
195
+ flex: number;
196
+ };
197
+ topbarRight: {
198
+ flexDirection: "row";
199
+ alignItems: "center";
200
+ };
201
+ topbarRowItem: {
202
+ marginHorizontal: number;
203
+ alignItems: "center";
204
+ };
205
+ topbarLabel: {
206
+ fontSize: number;
207
+ };
208
+ userBlock: {
209
+ marginHorizontal: number;
210
+ alignItems: "flex-end";
211
+ };
212
+ userName: {
213
+ fontWeight: "600";
214
+ };
215
+ userEmail: {
216
+ fontSize: number;
217
+ };
218
+ accountBtn: {
219
+ marginLeft: number;
220
+ paddingHorizontal: number;
221
+ paddingVertical: number;
222
+ borderRadius: number;
223
+ };
224
+ accountText: {
225
+ fontWeight: "600";
226
+ };
227
+ };
228
+ declare const expandableStyles: {
229
+ childItem: {
230
+ borderRadius: number;
231
+ flexDirection: "row";
232
+ alignItems: "center";
233
+ paddingVertical: number;
234
+ };
235
+ childItemText: {
236
+ fontSize: number;
237
+ };
238
+ childItemTextWithIcon: {
239
+ fontSize: number;
240
+ marginLeft: number;
241
+ };
242
+ chevron: {
243
+ marginLeft: "auto";
244
+ };
245
+ childrenContainer: {
246
+ overflow: "hidden";
247
+ };
248
+ header: {
249
+ borderRadius: number;
250
+ flexDirection: "row";
251
+ alignItems: "center";
252
+ paddingVertical: number;
253
+ };
254
+ headerText: {
255
+ fontSize: number;
256
+ fontWeight: "600";
257
+ marginLeft: number;
258
+ };
259
+ iconWrapper: {
260
+ width: number;
261
+ alignItems: "center";
262
+ };
263
+ };
264
+ /** Base indent applied per nesting depth in the expandable item. */
265
+ declare const BASE_INDENT = 12;
266
+ /** Default icon size for nav item icons. */
267
+ declare const NAV_ICON_SIZE = 14;
268
+ /** Chevron icon size for expandable sections. */
269
+ declare const CHEVRON_ICON_SIZE = 12;
270
+
271
+ export { ACTIVE_BORDER_RADIUS, BASE_INDENT, CHEVRON_ICON_SIZE, NAV_ICON_SIZE, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavUser, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, expandableStyles, isRouteActive, navStyles, roleRoutesToNavItems };