@gtkx/navigation 2.0.0-beta.11 → 2.0.0-beta.13

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.
Files changed (121) hide show
  1. package/README.md +3 -3
  2. package/dist/drawer/create-drawer-navigator.d.ts +3 -1
  3. package/dist/drawer/create-drawer-navigator.d.ts.map +1 -1
  4. package/dist/drawer/create-drawer-navigator.js +10 -10
  5. package/dist/drawer/create-drawer-navigator.js.map +1 -1
  6. package/dist/drawer/drawer-item-list.d.ts.map +1 -1
  7. package/dist/drawer/drawer-item-list.js +3 -2
  8. package/dist/drawer/drawer-item-list.js.map +1 -1
  9. package/dist/drawer/drawer-router.d.ts.map +1 -1
  10. package/dist/drawer/drawer-router.js.map +1 -1
  11. package/dist/drawer/drawer-status.d.ts.map +1 -1
  12. package/dist/drawer/drawer-view.d.ts.map +1 -1
  13. package/dist/drawer/drawer-view.js +6 -6
  14. package/dist/drawer/drawer-view.js.map +1 -1
  15. package/dist/drawer/types.d.ts +2 -0
  16. package/dist/drawer/types.d.ts.map +1 -1
  17. package/dist/drawer/types.js.map +1 -1
  18. package/dist/index.d.ts +6 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +5 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/shared/header-bar.d.ts.map +1 -1
  23. package/dist/shared/header-bar.js +2 -2
  24. package/dist/shared/header-bar.js.map +1 -1
  25. package/dist/shared/routes.d.ts.map +1 -1
  26. package/dist/shared/scene-page.d.ts +3 -1
  27. package/dist/shared/scene-page.d.ts.map +1 -1
  28. package/dist/shared/scene-page.js +4 -7
  29. package/dist/shared/scene-page.js.map +1 -1
  30. package/dist/shared/use-has-loaded.d.ts +3 -0
  31. package/dist/shared/use-has-loaded.d.ts.map +1 -0
  32. package/dist/shared/use-has-loaded.js +10 -0
  33. package/dist/shared/use-has-loaded.js.map +1 -0
  34. package/dist/shared/use-pop-to-top-on-blur.d.ts.map +1 -1
  35. package/dist/split-view/create-split-view-navigator.d.ts +7 -2
  36. package/dist/split-view/create-split-view-navigator.d.ts.map +1 -1
  37. package/dist/split-view/create-split-view-navigator.js +2 -6
  38. package/dist/split-view/create-split-view-navigator.js.map +1 -1
  39. package/dist/split-view/split-view-collapsed.d.ts +11 -0
  40. package/dist/split-view/split-view-collapsed.d.ts.map +1 -0
  41. package/dist/split-view/split-view-collapsed.js +17 -0
  42. package/dist/split-view/split-view-collapsed.js.map +1 -0
  43. package/dist/split-view/split-view.d.ts.map +1 -1
  44. package/dist/split-view/split-view.js +41 -20
  45. package/dist/split-view/split-view.js.map +1 -1
  46. package/dist/split-view/types.d.ts +9 -2
  47. package/dist/split-view/types.d.ts.map +1 -1
  48. package/dist/split-view/types.js.map +1 -1
  49. package/dist/stack/create-stack-navigator.d.ts +3 -1
  50. package/dist/stack/create-stack-navigator.d.ts.map +1 -1
  51. package/dist/stack/create-stack-navigator.js +0 -1
  52. package/dist/stack/create-stack-navigator.js.map +1 -1
  53. package/dist/stack/stack-pages.d.ts.map +1 -1
  54. package/dist/stack/stack-pages.js +3 -5
  55. package/dist/stack/stack-pages.js.map +1 -1
  56. package/dist/stack/stack-view.d.ts.map +1 -1
  57. package/dist/stack/stack-view.js +6 -14
  58. package/dist/stack/stack-view.js.map +1 -1
  59. package/dist/stack/sync-navigation-stack.d.ts.map +1 -1
  60. package/dist/stack/types.d.ts.map +1 -1
  61. package/dist/stack/types.js.map +1 -1
  62. package/dist/tab-view/create-tab-view-navigator.d.ts +32 -0
  63. package/dist/tab-view/create-tab-view-navigator.d.ts.map +1 -0
  64. package/dist/tab-view/create-tab-view-navigator.js +21 -0
  65. package/dist/tab-view/create-tab-view-navigator.js.map +1 -0
  66. package/dist/tab-view/page-registry.d.ts +34 -0
  67. package/dist/tab-view/page-registry.d.ts.map +1 -0
  68. package/dist/tab-view/page-registry.js +70 -0
  69. package/dist/tab-view/page-registry.js.map +1 -0
  70. package/dist/tab-view/tab-view-host.d.ts +25 -0
  71. package/dist/tab-view/tab-view-host.d.ts.map +1 -0
  72. package/dist/tab-view/tab-view-host.js +284 -0
  73. package/dist/tab-view/tab-view-host.js.map +1 -0
  74. package/dist/tab-view/tab-view-router.d.ts +34 -0
  75. package/dist/tab-view/tab-view-router.d.ts.map +1 -0
  76. package/dist/tab-view/tab-view-router.js +359 -0
  77. package/dist/tab-view/tab-view-router.js.map +1 -0
  78. package/dist/tab-view/types.d.ts +240 -0
  79. package/dist/tab-view/types.d.ts.map +1 -0
  80. package/dist/tab-view/types.js +2 -0
  81. package/dist/tab-view/types.js.map +1 -0
  82. package/dist/tabs/create-tab-navigator.d.ts +3 -1
  83. package/dist/tabs/create-tab-navigator.d.ts.map +1 -1
  84. package/dist/tabs/create-tab-navigator.js +0 -1
  85. package/dist/tabs/create-tab-navigator.js.map +1 -1
  86. package/dist/tabs/tab-view.d.ts.map +1 -1
  87. package/dist/tabs/tab-view.js +5 -7
  88. package/dist/tabs/tab-view.js.map +1 -1
  89. package/dist/tabs/types.d.ts +2 -0
  90. package/dist/tabs/types.d.ts.map +1 -1
  91. package/dist/tabs/types.js.map +1 -1
  92. package/dist/theme.d.ts.map +1 -1
  93. package/dist/theme.js +2 -2
  94. package/dist/theme.js.map +1 -1
  95. package/package.json +9 -19
  96. package/src/drawer/create-drawer-navigator.tsx +23 -11
  97. package/src/drawer/drawer-item-list.tsx +16 -12
  98. package/src/drawer/drawer-router.ts +4 -2
  99. package/src/drawer/drawer-view.tsx +18 -18
  100. package/src/drawer/types.ts +6 -3
  101. package/src/index.ts +31 -5
  102. package/src/shared/header-bar.tsx +2 -2
  103. package/src/shared/scene-page.tsx +7 -8
  104. package/src/shared/use-has-loaded.ts +13 -0
  105. package/src/split-view/create-split-view-navigator.tsx +16 -1
  106. package/src/split-view/split-view-collapsed.ts +21 -0
  107. package/src/split-view/split-view.tsx +102 -49
  108. package/src/split-view/types.ts +13 -5
  109. package/src/stack/create-stack-navigator.tsx +11 -1
  110. package/src/stack/stack-pages.ts +14 -12
  111. package/src/stack/stack-view.tsx +10 -16
  112. package/src/stack/types.ts +4 -3
  113. package/src/tab-view/create-tab-view-navigator.tsx +122 -0
  114. package/src/tab-view/page-registry.ts +139 -0
  115. package/src/tab-view/tab-view-host.tsx +474 -0
  116. package/src/tab-view/tab-view-router.ts +528 -0
  117. package/src/tab-view/types.ts +291 -0
  118. package/src/tabs/create-tab-navigator.tsx +11 -1
  119. package/src/tabs/tab-view.tsx +28 -22
  120. package/src/tabs/types.ts +6 -3
  121. package/src/theme.ts +2 -3
@@ -0,0 +1,291 @@
1
+ import type * as Adw from "@gtkx/gi/adw";
2
+ import type * as Gio from "@gtkx/gi/gio";
3
+ import type * as GObject from "@gtkx/gi/gobject";
4
+ import type { AdwTabDropProps } from "@gtkx/react/internal";
5
+ import type {
6
+ DefaultNavigatorOptions,
7
+ Descriptor,
8
+ NavigationHelpers,
9
+ NavigationProp,
10
+ NavigationState,
11
+ ParamListBase,
12
+ RouteProp,
13
+ } from "@react-navigation/core";
14
+ import type { ReactNode } from "react";
15
+ import type { HeaderOptions } from "../shared/types.js";
16
+
17
+ /** Navigation state of a tab view navigator. Pinned routes come first in `routes`, in `pinnedKeys` order. */
18
+ type TabViewNavigationState<ParamList extends ParamListBase> = NavigationState<ParamList> & {
19
+ /** Type of the router, in this case `tabview`. */
20
+ type: "tabview";
21
+ /** Keys of the pinned routes. */
22
+ pinnedKeys: string[];
23
+ /** Key of the tab each tab was opened from, by route key. */
24
+ parents: Record<string, string>;
25
+ };
26
+
27
+ /** Options accepted when opening a tab. */
28
+ type TabViewOpenOptions = {
29
+ /** Key of the tab the new one is opened from; the new tab follows that tab and its descendants, which are selected again when it closes. */
30
+ parent?: string;
31
+ /** Whether the new tab is selected; defaults to `true`. */
32
+ select?: boolean;
33
+ /** Position among the unpinned tabs; defaults to the end. */
34
+ position?: number;
35
+ };
36
+
37
+ /** Actions specific to the tab view router. */
38
+ type TabViewActionType =
39
+ | {
40
+ type: "OPEN_TAB";
41
+ payload: {
42
+ name: string;
43
+ params?: object;
44
+ key?: string;
45
+ parent?: string;
46
+ select?: boolean;
47
+ position?: number;
48
+ pinned?: boolean;
49
+ };
50
+ }
51
+ | { type: "CLOSE_TAB"; payload: { key?: string } }
52
+ | { type: "CLOSE_OTHER_TABS"; payload: { key?: string } }
53
+ | { type: "CLOSE_TABS_BEFORE"; payload: { key?: string } }
54
+ | { type: "CLOSE_TABS_AFTER"; payload: { key?: string } }
55
+ | { type: "SELECT_TAB"; payload: { key: string } }
56
+ | { type: "REORDER_TAB"; payload: { key: string; position: number } }
57
+ | { type: "PIN_TAB"; payload: { key: string; pinned: boolean } };
58
+
59
+ /** Action helpers added to the navigation object of tab view screens. Keys default to the selected tab. */
60
+ type TabViewActionHelpers<ParamList extends ParamListBase> = {
61
+ /** Opens a new tab for a screen, or selects the open tab whose `getId` matches. */
62
+ openTab<RouteName extends keyof ParamList>(
63
+ name: RouteName,
64
+ params?: ParamList[RouteName],
65
+ options?: TabViewOpenOptions,
66
+ ): void;
67
+ /** Closes a tab. Closing the last tab is left to the parent navigator or `onUnhandledAction`. */
68
+ closeTab(key?: string): void;
69
+ /** Closes every unpinned tab except one. */
70
+ closeOtherTabs(key?: string): void;
71
+ /** Closes the unpinned tabs before one. */
72
+ closeTabsBefore(key?: string): void;
73
+ /** Closes the unpinned tabs after one. */
74
+ closeTabsAfter(key?: string): void;
75
+ /** Selects a tab. */
76
+ selectTab(key: string): void;
77
+ /** Moves a tab within its pinned or unpinned group. */
78
+ reorderTab(key: string, position: number): void;
79
+ /** Pins a tab, moving it after the other pinned tabs, or unpins it, moving it before the unpinned tabs. */
80
+ pinTab(key: string, pinned: boolean): void;
81
+ };
82
+
83
+ /** Events the tab view navigator emits on top of React Navigation's core events. */
84
+ type TabViewNavigationEventMap = {
85
+ /** The user selected a tab natively. */
86
+ tabPress: {
87
+ /** No payload. */
88
+ data: undefined;
89
+ /** Calling `preventDefault` keeps the current tab. */
90
+ canPreventDefault: true;
91
+ };
92
+ /** The user activated the tab's indicator icon. */
93
+ indicatorActivated: {
94
+ /** No payload. */
95
+ data: undefined;
96
+ };
97
+ };
98
+
99
+ /** An icon given by theme name or as a `Gio.Icon`. */
100
+ type TabViewIcon = string | Gio.Icon;
101
+
102
+ /** Per-screen options of the tab view navigator. */
103
+ type TabViewNavigationOptions = HeaderOptions & {
104
+ /** Renders a custom top bar instead of the default `AdwHeaderBar`. */
105
+ header?: (props: TabViewHeaderProps) => ReactNode;
106
+ /** Icon shown in the tab; `null` shows the view's default icon. */
107
+ icon?: TabViewIcon | null;
108
+ /** Tooltip of the tab; supports Pango markup. */
109
+ tooltip?: string;
110
+ /** Search keyword for the tab overview. */
111
+ keyword?: string;
112
+ /** Whether the tab shows a loading spinner instead of its icon. */
113
+ loading?: boolean;
114
+ /** Whether the tab is highlighted as needing attention. */
115
+ needsAttention?: boolean;
116
+ /** Indicator icon shown at the end of the tab. */
117
+ indicatorIcon?: TabViewIcon | null;
118
+ /** Whether clicking the indicator emits `indicatorActivated`. */
119
+ indicatorActivatable?: boolean;
120
+ /** Tooltip of the indicator icon; supports Pango markup. */
121
+ indicatorTooltip?: string;
122
+ /** Whether the overview thumbnail stays live while the tab is not selected. */
123
+ liveThumbnail?: boolean;
124
+ /** Horizontal alignment of the overview thumbnail, from 0 to 1. */
125
+ thumbnailXalign?: number;
126
+ /** Vertical alignment of the overview thumbnail, from 0 to 1. */
127
+ thumbnailYalign?: number;
128
+ /** Whether the screen mounts on first selection instead of as soon as the tab opens; defaults to `true`. */
129
+ lazy?: boolean;
130
+ };
131
+
132
+ /** The screen a new tab opens, as returned by the overview's `onCreateTab`. */
133
+ type TabViewTarget = {
134
+ /** Name of the screen to open. */
135
+ name: string;
136
+ /** Params of the new tab. */
137
+ params?: object;
138
+ };
139
+
140
+ /** Settings of the `AdwTabOverview` rendered around the view. */
141
+ type TabViewOverviewConfig = {
142
+ /**
143
+ * Whether the overview is open. When given, the overview follows it: the user opening or closing the overview
144
+ * calls `onOpenChange`, and a value the app does not update is restored. Leave it out to let the overview open
145
+ * and close on its own.
146
+ */
147
+ open?: boolean;
148
+ /** Called when the overview opens or closes natively. */
149
+ onOpenChange?: (open: boolean) => void;
150
+ /** Whether the overview shows a new tab button; defaults to `false`. */
151
+ enableNewTab?: boolean;
152
+ /** Whether the overview offers search; defaults to `true`. */
153
+ enableSearch?: boolean;
154
+ /** Returns the screen the new tab button opens. */
155
+ onCreateTab?: () => TabViewTarget;
156
+ };
157
+
158
+ /** Additional drop target of the tab bar and overview. */
159
+ type TabViewExtraDropTarget = NonNullable<AdwTabDropProps["extraDropTarget"]>;
160
+
161
+ /** Props of the tab view navigator beyond the options every navigator shares. */
162
+ type TabViewNavigationConfig = {
163
+ /** A view created before the navigator renders, such as one returned from a `create-window` handler. */
164
+ view?: Adw.TabView;
165
+ /** Whether the tab bar renders; defaults to `true`. */
166
+ tabBarVisible?: boolean;
167
+ /** Whether the tab bar hides with a single tab; defaults to `true`. */
168
+ tabBarAutohide?: boolean;
169
+ /** Whether tabs expand to fill the bar; defaults to `true`. */
170
+ tabBarExpand?: boolean;
171
+ /** Whether close buttons sit at the start of tabs; defaults to `false`. */
172
+ tabBarInverted?: boolean;
173
+ /** Renders an `AdwTabOverview` around the view. */
174
+ overview?: TabViewOverviewConfig;
175
+ /** An existing menu model to use as the tabs' context menu. Use `renderMenu` to declare the menu in JSX instead. */
176
+ menuModel?: Gio.MenuModel | null;
177
+ /**
178
+ * Renders the tabs' context menu. Attach `ref` to a `GMenu`, or to any menu model element, anywhere in the
179
+ * returned tree; the navigator renders the tree outside the widget hierarchy and uses that model. A navigator
180
+ * given both `renderMenu` and a `menuModel` throws.
181
+ */
182
+ renderMenu?: (ref: (menu: Gio.MenuModel | null) => void) => ReactNode;
183
+ /** Additional content accepted by drops on tabs. */
184
+ extraDropTarget?: TabViewExtraDropTarget | null;
185
+ /** Handles content dropped on a tab; returns whether the drop was accepted. */
186
+ onExtraDragDrop?: (route: RouteProp<ParamListBase>, value: GObject.Value) => boolean;
187
+ /** Returns the view of a new window when a tab is dragged out of this one. */
188
+ onCreateWindow?: () => Adw.TabView | null;
189
+ /** Called with the tab whose context menu opens, or `null` when it closes, after the chosen menu action has run. */
190
+ onSetupMenu?: (route: RouteProp<ParamListBase> | null) => void;
191
+ /** Keyboard shortcuts the view handles. */
192
+ shortcuts?: Adw.TabViewShortcuts;
193
+ /** Icon of tabs without an `icon` option. */
194
+ defaultIcon?: TabViewIcon | null;
195
+ };
196
+
197
+ /** Options of the tab view router. */
198
+ type TabViewRouterOptions = {
199
+ /** Screen of the tab opened when the view starts empty; defaults to the first screen. */
200
+ initialRouteName?: string;
201
+ /**
202
+ * Whether closing the last tab replaces it with a new tab of the initial route, instead of leaving that close
203
+ * unhandled for a parent navigator or the container's `onUnhandledAction`. Use it for a tab view inside a section
204
+ * of the app rather than a window of its own; defaults to `false`.
205
+ */
206
+ replaceLastTab?: boolean;
207
+ };
208
+
209
+ /** Navigation object of a tab view screen. */
210
+ type TabViewNavigationProp<
211
+ ParamList extends ParamListBase,
212
+ RouteName extends keyof ParamList = keyof ParamList,
213
+ NavigatorID extends string | undefined = undefined,
214
+ > = NavigationProp<
215
+ ParamList,
216
+ RouteName,
217
+ NavigatorID,
218
+ TabViewNavigationState<ParamList>,
219
+ TabViewNavigationOptions,
220
+ TabViewNavigationEventMap
221
+ > &
222
+ TabViewActionHelpers<ParamList>;
223
+
224
+ /** Props a tab view screen component receives. */
225
+ type TabViewScreenProps<
226
+ ParamList extends ParamListBase,
227
+ RouteName extends keyof ParamList = keyof ParamList,
228
+ NavigatorID extends string | undefined = undefined,
229
+ > = {
230
+ /** Navigation object of the screen. */
231
+ navigation: TabViewNavigationProp<ParamList, RouteName, NavigatorID>;
232
+ /** The route the screen renders. */
233
+ route: RouteProp<ParamList, RouteName>;
234
+ };
235
+
236
+ /** Arguments of a custom tab view `header` renderer. */
237
+ type TabViewHeaderProps = {
238
+ /** The selected route. */
239
+ route: RouteProp<ParamListBase>;
240
+ /** Navigation object of the selected route. */
241
+ navigation: TabViewNavigationProp<ParamListBase>;
242
+ /** Resolved options of the selected route. */
243
+ options: TabViewNavigationOptions;
244
+ };
245
+
246
+ /** Navigation helpers of the tab view navigator itself. */
247
+ type TabViewNavigationHelpers = NavigationHelpers<ParamListBase, TabViewNavigationEventMap> &
248
+ TabViewActionHelpers<ParamListBase>;
249
+
250
+ /** Descriptor of one tab view route. */
251
+ type TabViewDescriptor = Descriptor<
252
+ TabViewNavigationOptions,
253
+ TabViewNavigationProp<ParamListBase>,
254
+ RouteProp<ParamListBase>
255
+ >;
256
+ /** Descriptors of the tab view routes, keyed by route key. */
257
+ type TabViewDescriptorMap = Record<string, TabViewDescriptor>;
258
+
259
+ /** Props of the tab view `Navigator` component. */
260
+ type TabViewNavigatorProps = DefaultNavigatorOptions<
261
+ ParamListBase,
262
+ string | undefined,
263
+ TabViewNavigationState<ParamListBase>,
264
+ TabViewNavigationOptions,
265
+ TabViewNavigationEventMap,
266
+ TabViewNavigationProp<ParamListBase>
267
+ > &
268
+ TabViewRouterOptions &
269
+ TabViewNavigationConfig;
270
+
271
+ export type {
272
+ TabViewActionHelpers,
273
+ TabViewActionType,
274
+ TabViewDescriptor,
275
+ TabViewDescriptorMap,
276
+ TabViewExtraDropTarget,
277
+ TabViewHeaderProps,
278
+ TabViewIcon,
279
+ TabViewNavigationConfig,
280
+ TabViewNavigationEventMap,
281
+ TabViewNavigationHelpers,
282
+ TabViewNavigationOptions,
283
+ TabViewNavigationProp,
284
+ TabViewNavigationState,
285
+ TabViewNavigatorProps,
286
+ TabViewOpenOptions,
287
+ TabViewOverviewConfig,
288
+ TabViewRouterOptions,
289
+ TabViewScreenProps,
290
+ TabViewTarget,
291
+ };
@@ -59,7 +59,17 @@ function createTabNavigator<
59
59
  const ParamList extends ParamListBase,
60
60
  const NavigatorID extends string | undefined = string | undefined,
61
61
  const TypeBag extends NavigatorTypeBagBase = TabTypeBag<ParamList, NavigatorID>,
62
- const Config extends StaticConfig<TypeBag> | undefined = undefined,
62
+ >(): TypedNavigator<TypeBag, undefined>;
63
+ /** Creates a tab navigator rendered with `AdwViewStack` and an `AdwViewSwitcher`. */
64
+ function createTabNavigator<
65
+ const ParamList extends ParamListBase,
66
+ const NavigatorID extends string | undefined = string | undefined,
67
+ const TypeBag extends NavigatorTypeBagBase = TabTypeBag<ParamList, NavigatorID>,
68
+ const Config extends StaticConfig<TypeBag> = StaticConfig<TypeBag>,
69
+ >(config: Config): TypedNavigator<TypeBag, Config>;
70
+ function createTabNavigator<
71
+ const TypeBag extends NavigatorTypeBagBase,
72
+ const Config extends StaticConfig<TypeBag> | undefined,
63
73
  >(config?: Config): TypedNavigator<TypeBag, Config> {
64
74
  return createNavigatorFactory(TabNavigator)(config) as TypedNavigator<TypeBag, Config>;
65
75
  }
@@ -23,25 +23,29 @@ type TabHeaderProps = {
23
23
 
24
24
  type TabPageProps = {
25
25
  descriptor: TabDescriptor;
26
+ isFocused: boolean;
26
27
  isLoaded: boolean;
27
28
  };
28
29
 
29
30
  const useTabSelection = (navigation: TabNavigationHelpers): ((name: string | null) => void) =>
30
- useCallback((name: string | null) => {
31
- const current = navigation.getState();
32
- const focusedKey = getFocusedRoute(current).key;
33
- const route = current.routes.find((candidate) => candidate.key === name);
34
-
35
- if (route === undefined || route.key === focusedKey) {
36
- return;
37
- }
38
-
39
- const event = navigation.emit({ type: "tabPress", target: route.key, canPreventDefault: true });
40
-
41
- if (!event.defaultPrevented) {
42
- navigation.dispatch({ ...CommonActions.navigate(route.name, route.params), target: current.key });
43
- }
44
- }, [navigation]);
31
+ useCallback(
32
+ (name: string | null) => {
33
+ const current = navigation.getState();
34
+ const focusedKey = getFocusedRoute(current).key;
35
+ const route = current.routes.find((candidate) => candidate.key === name);
36
+
37
+ if (route === undefined || route.key === focusedKey) {
38
+ return;
39
+ }
40
+
41
+ const event = navigation.emit({ type: "tabPress", target: route.key, canPreventDefault: true });
42
+
43
+ if (!event.defaultPrevented) {
44
+ navigation.dispatch({ ...CommonActions.navigate(route.name, route.params), target: current.key });
45
+ }
46
+ },
47
+ [navigation],
48
+ );
45
49
 
46
50
  const defaultTabHeader = ({ descriptor, viewSwitcher }: TabHeaderProps): ReactElement => (
47
51
  <HeaderBar
@@ -67,16 +71,18 @@ const TabHeader = (props: TabHeaderProps): ReactNode => {
67
71
  );
68
72
  };
69
73
 
70
- const TabPage = ({ descriptor, isLoaded }: TabPageProps): ReactNode => {
74
+ const TabPage = ({ descriptor, isFocused, isLoaded }: TabPageProps): ReactNode => {
71
75
  const { route, options } = descriptor;
72
76
 
73
77
  return (
74
78
  <ScenePage
75
79
  name={route.key}
76
80
  title={options.tabBarLabel ?? options.title ?? route.name}
81
+ useUnderline={options.useUnderline}
77
82
  iconName={options.tabBarIcon}
78
83
  badgeNumber={options.tabBarBadge}
79
84
  needsAttention={options.needsAttention}
85
+ isFocused={isFocused}
80
86
  isLoaded={isLoaded || options.lazy === false}
81
87
  render={() => descriptor.render()}
82
88
  />
@@ -89,19 +95,18 @@ const TabView = ({ state, navigation, descriptors, tabBarPosition = "top" }: Tab
89
95
  const descriptor = requireDescriptor(descriptors, focused.key);
90
96
  const onVisibleChildChanged = useTabSelection(navigation);
91
97
 
92
- const viewSwitcher = stack === null
93
- ? undefined
94
- : <AdwViewSwitcher stack={stack} policy={Adw.ViewSwitcherPolicy.WIDE} />;
98
+ const viewSwitcher =
99
+ stack === null ? undefined : <AdwViewSwitcher stack={stack} policy={Adw.ViewSwitcherPolicy.WIDE} />;
95
100
 
96
101
  const hasSwitcherBar = tabBarPosition === "bottom" && stack !== null;
97
102
  usePopToTopOnBlur(state, descriptors, navigation);
98
103
 
99
104
  return (
100
105
  <AdwToolbarView
101
- topBar={(
106
+ top={
102
107
  <TabHeader descriptor={descriptor} viewSwitcher={tabBarPosition === "top" ? viewSwitcher : undefined} />
103
- )}
104
- bottomBar={hasSwitcherBar ? <AdwViewSwitcherBar stack={stack} reveal /> : undefined}
108
+ }
109
+ bottom={hasSwitcherBar ? <AdwViewSwitcherBar stack={stack} reveal /> : undefined}
105
110
  >
106
111
  <AdwViewStack
107
112
  ref={setStack}
@@ -113,6 +118,7 @@ const TabView = ({ state, navigation, descriptors, tabBarPosition = "top" }: Tab
113
118
  <TabPage
114
119
  key={route.key}
115
120
  descriptor={requireDescriptor(descriptors, route.key)}
121
+ isFocused={route.key === focused.key}
116
122
  isLoaded={route.key === focused.key || state.preloadedRouteKeys.includes(route.key)}
117
123
  />
118
124
  ))}
package/src/tabs/types.ts CHANGED
@@ -29,6 +29,8 @@ type TabNavigationOptions = HeaderOptions & {
29
29
  header?: (props: TabHeaderProps) => ReactNode;
30
30
  /** Label shown in the view switcher; defaults to `title`, then to the route name. */
31
31
  tabBarLabel?: string;
32
+ /** Whether underscores in the tab label indicate mnemonics; defaults to `false`. */
33
+ useUnderline?: boolean;
32
34
  /** Icon name shown in the view switcher. */
33
35
  tabBarIcon?: string;
34
36
  /** Badge number shown in the view switcher; `0` hides the badge. */
@@ -61,7 +63,8 @@ type TabNavigationProp<
61
63
  TabNavigationState<ParamList>,
62
64
  TabNavigationOptions,
63
65
  TabNavigationEventMap
64
- > & TabActionHelpers<ParamList>;
66
+ > &
67
+ TabActionHelpers<ParamList>;
65
68
 
66
69
  /** Props a tab screen component receives. */
67
70
  type TabScreenProps<
@@ -103,8 +106,8 @@ type TabNavigatorProps = DefaultNavigatorOptions<
103
106
  TabNavigationEventMap,
104
107
  TabNavigationProp<ParamListBase>
105
108
  > &
106
- TabRouterOptions &
107
- TabNavigationConfig;
109
+ TabRouterOptions &
110
+ TabNavigationConfig;
108
111
 
109
112
  export type {
110
113
  TabDescriptor,
package/src/theme.ts CHANGED
@@ -11,7 +11,6 @@ type AdwaitaTheme = {
11
11
  };
12
12
 
13
13
  declare module "@react-navigation/core" {
14
- // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
15
14
  interface Theme extends AdwaitaTheme {}
16
15
  }
17
16
 
@@ -22,8 +21,8 @@ const DarkTheme: AdwaitaTheme = { dark: true, highContrast: false };
22
21
 
23
22
  const useAdwaitaTheme = (): AdwaitaTheme => {
24
23
  const manager = Adw.StyleManager.getDefault();
25
- const isDark = useProperty(manager, "dark") ?? manager.getDark();
26
- const isHighContrast = useProperty(manager, "highContrast") ?? manager.getHighContrast();
24
+ const isDark = useProperty(manager, "dark");
25
+ const isHighContrast = useProperty(manager, "highContrast");
27
26
 
28
27
  return useMemo(() => ({ dark: isDark, highContrast: isHighContrast }), [isDark, isHighContrast]);
29
28
  };