@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.
- package/README.md +3 -3
- package/dist/drawer/create-drawer-navigator.d.ts +3 -1
- package/dist/drawer/create-drawer-navigator.d.ts.map +1 -1
- package/dist/drawer/create-drawer-navigator.js +10 -10
- package/dist/drawer/create-drawer-navigator.js.map +1 -1
- package/dist/drawer/drawer-item-list.d.ts.map +1 -1
- package/dist/drawer/drawer-item-list.js +3 -2
- package/dist/drawer/drawer-item-list.js.map +1 -1
- package/dist/drawer/drawer-router.d.ts.map +1 -1
- package/dist/drawer/drawer-router.js.map +1 -1
- package/dist/drawer/drawer-status.d.ts.map +1 -1
- package/dist/drawer/drawer-view.d.ts.map +1 -1
- package/dist/drawer/drawer-view.js +6 -6
- package/dist/drawer/drawer-view.js.map +1 -1
- package/dist/drawer/types.d.ts +2 -0
- package/dist/drawer/types.d.ts.map +1 -1
- package/dist/drawer/types.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/shared/header-bar.d.ts.map +1 -1
- package/dist/shared/header-bar.js +2 -2
- package/dist/shared/header-bar.js.map +1 -1
- package/dist/shared/routes.d.ts.map +1 -1
- package/dist/shared/scene-page.d.ts +3 -1
- package/dist/shared/scene-page.d.ts.map +1 -1
- package/dist/shared/scene-page.js +4 -7
- package/dist/shared/scene-page.js.map +1 -1
- package/dist/shared/use-has-loaded.d.ts +3 -0
- package/dist/shared/use-has-loaded.d.ts.map +1 -0
- package/dist/shared/use-has-loaded.js +10 -0
- package/dist/shared/use-has-loaded.js.map +1 -0
- package/dist/shared/use-pop-to-top-on-blur.d.ts.map +1 -1
- package/dist/split-view/create-split-view-navigator.d.ts +7 -2
- package/dist/split-view/create-split-view-navigator.d.ts.map +1 -1
- package/dist/split-view/create-split-view-navigator.js +2 -6
- package/dist/split-view/create-split-view-navigator.js.map +1 -1
- package/dist/split-view/split-view-collapsed.d.ts +11 -0
- package/dist/split-view/split-view-collapsed.d.ts.map +1 -0
- package/dist/split-view/split-view-collapsed.js +17 -0
- package/dist/split-view/split-view-collapsed.js.map +1 -0
- package/dist/split-view/split-view.d.ts.map +1 -1
- package/dist/split-view/split-view.js +41 -20
- package/dist/split-view/split-view.js.map +1 -1
- package/dist/split-view/types.d.ts +9 -2
- package/dist/split-view/types.d.ts.map +1 -1
- package/dist/split-view/types.js.map +1 -1
- package/dist/stack/create-stack-navigator.d.ts +3 -1
- package/dist/stack/create-stack-navigator.d.ts.map +1 -1
- package/dist/stack/create-stack-navigator.js +0 -1
- package/dist/stack/create-stack-navigator.js.map +1 -1
- package/dist/stack/stack-pages.d.ts.map +1 -1
- package/dist/stack/stack-pages.js +3 -5
- package/dist/stack/stack-pages.js.map +1 -1
- package/dist/stack/stack-view.d.ts.map +1 -1
- package/dist/stack/stack-view.js +6 -14
- package/dist/stack/stack-view.js.map +1 -1
- package/dist/stack/sync-navigation-stack.d.ts.map +1 -1
- package/dist/stack/types.d.ts.map +1 -1
- package/dist/stack/types.js.map +1 -1
- package/dist/tab-view/create-tab-view-navigator.d.ts +32 -0
- package/dist/tab-view/create-tab-view-navigator.d.ts.map +1 -0
- package/dist/tab-view/create-tab-view-navigator.js +21 -0
- package/dist/tab-view/create-tab-view-navigator.js.map +1 -0
- package/dist/tab-view/page-registry.d.ts +34 -0
- package/dist/tab-view/page-registry.d.ts.map +1 -0
- package/dist/tab-view/page-registry.js +70 -0
- package/dist/tab-view/page-registry.js.map +1 -0
- package/dist/tab-view/tab-view-host.d.ts +25 -0
- package/dist/tab-view/tab-view-host.d.ts.map +1 -0
- package/dist/tab-view/tab-view-host.js +284 -0
- package/dist/tab-view/tab-view-host.js.map +1 -0
- package/dist/tab-view/tab-view-router.d.ts +34 -0
- package/dist/tab-view/tab-view-router.d.ts.map +1 -0
- package/dist/tab-view/tab-view-router.js +359 -0
- package/dist/tab-view/tab-view-router.js.map +1 -0
- package/dist/tab-view/types.d.ts +240 -0
- package/dist/tab-view/types.d.ts.map +1 -0
- package/dist/tab-view/types.js +2 -0
- package/dist/tab-view/types.js.map +1 -0
- package/dist/tabs/create-tab-navigator.d.ts +3 -1
- package/dist/tabs/create-tab-navigator.d.ts.map +1 -1
- package/dist/tabs/create-tab-navigator.js +0 -1
- package/dist/tabs/create-tab-navigator.js.map +1 -1
- package/dist/tabs/tab-view.d.ts.map +1 -1
- package/dist/tabs/tab-view.js +5 -7
- package/dist/tabs/tab-view.js.map +1 -1
- package/dist/tabs/types.d.ts +2 -0
- package/dist/tabs/types.d.ts.map +1 -1
- package/dist/tabs/types.js.map +1 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +2 -2
- package/dist/theme.js.map +1 -1
- package/package.json +9 -19
- package/src/drawer/create-drawer-navigator.tsx +23 -11
- package/src/drawer/drawer-item-list.tsx +16 -12
- package/src/drawer/drawer-router.ts +4 -2
- package/src/drawer/drawer-view.tsx +18 -18
- package/src/drawer/types.ts +6 -3
- package/src/index.ts +31 -5
- package/src/shared/header-bar.tsx +2 -2
- package/src/shared/scene-page.tsx +7 -8
- package/src/shared/use-has-loaded.ts +13 -0
- package/src/split-view/create-split-view-navigator.tsx +16 -1
- package/src/split-view/split-view-collapsed.ts +21 -0
- package/src/split-view/split-view.tsx +102 -49
- package/src/split-view/types.ts +13 -5
- package/src/stack/create-stack-navigator.tsx +11 -1
- package/src/stack/stack-pages.ts +14 -12
- package/src/stack/stack-view.tsx +10 -16
- package/src/stack/types.ts +4 -3
- package/src/tab-view/create-tab-view-navigator.tsx +122 -0
- package/src/tab-view/page-registry.ts +139 -0
- package/src/tab-view/tab-view-host.tsx +474 -0
- package/src/tab-view/tab-view-router.ts +528 -0
- package/src/tab-view/types.ts +291 -0
- package/src/tabs/create-tab-navigator.tsx +11 -1
- package/src/tabs/tab-view.tsx +28 -22
- package/src/tabs/types.ts +6 -3
- package/src/theme.ts +2 -3
|
@@ -70,7 +70,17 @@ function createStackNavigator<
|
|
|
70
70
|
const ParamList extends ParamListBase,
|
|
71
71
|
const NavigatorID extends string | undefined = string | undefined,
|
|
72
72
|
const TypeBag extends NavigatorTypeBagBase = StackTypeBag<ParamList, NavigatorID>,
|
|
73
|
-
|
|
73
|
+
>(): TypedNavigator<TypeBag, undefined>;
|
|
74
|
+
/** Creates a stack navigator rendered with `AdwNavigationView`: pushes and pops animate like native Adwaita pages. */
|
|
75
|
+
function createStackNavigator<
|
|
76
|
+
const ParamList extends ParamListBase,
|
|
77
|
+
const NavigatorID extends string | undefined = string | undefined,
|
|
78
|
+
const TypeBag extends NavigatorTypeBagBase = StackTypeBag<ParamList, NavigatorID>,
|
|
79
|
+
const Config extends StaticConfig<TypeBag> = StaticConfig<TypeBag>,
|
|
80
|
+
>(config: Config): TypedNavigator<TypeBag, Config>;
|
|
81
|
+
function createStackNavigator<
|
|
82
|
+
const TypeBag extends NavigatorTypeBagBase,
|
|
83
|
+
const Config extends StaticConfig<TypeBag> | undefined,
|
|
74
84
|
>(config?: Config): TypedNavigator<TypeBag, Config> {
|
|
75
85
|
return createNavigatorFactory(StackNavigator)(config) as TypedNavigator<TypeBag, Config>;
|
|
76
86
|
}
|
package/src/stack/stack-pages.ts
CHANGED
|
@@ -100,27 +100,29 @@ const useStackPages = (
|
|
|
100
100
|
): StackPages => {
|
|
101
101
|
const [tracking, setTracking] = useState<PageTracking>(() => initialTracking(state, descriptors, offset));
|
|
102
102
|
|
|
103
|
-
if (
|
|
103
|
+
if (
|
|
104
|
+
!hasSameMembers(tracking.order, neededKeys(state, tracking.closing, offset)) ||
|
|
104
105
|
tracking.focusedKey !== getFocusedKey(state, offset) ||
|
|
105
|
-
tracking.descriptors !== descriptors
|
|
106
|
+
tracking.descriptors !== descriptors
|
|
107
|
+
) {
|
|
106
108
|
setTracking(advance(tracking, state, descriptors, offset));
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
const release = useCallback((key: string) => {
|
|
110
|
-
setTracking((current) =>
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
112
|
+
setTracking((current) =>
|
|
113
|
+
current.closing[key] === undefined
|
|
114
|
+
? current
|
|
115
|
+
: {
|
|
116
|
+
...current,
|
|
117
|
+
order: current.order.filter((entry) => entry !== key),
|
|
118
|
+
closing: withoutKeys(current.closing, [key]),
|
|
119
|
+
},
|
|
120
|
+
);
|
|
117
121
|
}, []);
|
|
118
122
|
|
|
119
123
|
const sources = { state, descriptors, closing: tracking.closing };
|
|
120
124
|
|
|
121
|
-
const pages = tracking.order
|
|
122
|
-
.map((key) => resolvePage(key, sources, describe))
|
|
123
|
-
.filter((page) => page !== undefined);
|
|
125
|
+
const pages = tracking.order.map((key) => resolvePage(key, sources, describe)).filter((page) => page !== undefined);
|
|
124
126
|
|
|
125
127
|
return { pages, release };
|
|
126
128
|
};
|
package/src/stack/stack-view.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import type * as Adw from "@gtkx/gi/adw";
|
|
|
2
2
|
import type { ParamListBase, StackNavigationState } from "@react-navigation/core";
|
|
3
3
|
import type { ReactNode, RefObject } from "react";
|
|
4
4
|
import { AdwNavigationPage, AdwNavigationView, AdwToolbarView } from "@gtkx/jsx/adw";
|
|
5
|
+
import { useLatestRef } from "@gtkx/react/internal";
|
|
5
6
|
import { useCallback, useEffect, useRef } from "react";
|
|
6
7
|
import type { Describe } from "./stack-pages.js";
|
|
7
8
|
import type { OptionsByKey } from "./sync-navigation-stack.js";
|
|
@@ -47,16 +48,6 @@ const previousDescriptor = (
|
|
|
47
48
|
return previousKey === undefined ? undefined : descriptors[previousKey];
|
|
48
49
|
};
|
|
49
50
|
|
|
50
|
-
const useLatest = <T,>(value: T): RefObject<T> => {
|
|
51
|
-
const ref = useRef(value);
|
|
52
|
-
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
ref.current = value;
|
|
55
|
-
}, [value]);
|
|
56
|
-
|
|
57
|
-
return ref;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
51
|
const useStackSync = (
|
|
61
52
|
viewRef: ViewRef,
|
|
62
53
|
state: StackNavigationState<ParamListBase>,
|
|
@@ -84,7 +75,7 @@ const usePoppedHandler = (
|
|
|
84
75
|
options: RefObject<OptionsByKey>,
|
|
85
76
|
offset: number,
|
|
86
77
|
): (() => void) => {
|
|
87
|
-
const navigationRef =
|
|
78
|
+
const navigationRef = useLatestRef(navigation);
|
|
88
79
|
const isScheduledRef = useRef(false);
|
|
89
80
|
|
|
90
81
|
return useCallback(() => {
|
|
@@ -114,11 +105,14 @@ const StackPageContent = ({ descriptor, previous }: Omit<StackPageProps, "naviga
|
|
|
114
105
|
|
|
115
106
|
const back = previous === undefined ? undefined : { title: previous.options.title ?? previous.route.name };
|
|
116
107
|
|
|
117
|
-
const topBar =
|
|
118
|
-
|
|
119
|
-
|
|
108
|
+
const topBar =
|
|
109
|
+
options.header === undefined ? (
|
|
110
|
+
<HeaderBar options={options} showBackButton={options.headerBackVisible ?? true} />
|
|
111
|
+
) : (
|
|
112
|
+
<>{options.header({ route, navigation, options, back })}</>
|
|
113
|
+
);
|
|
120
114
|
|
|
121
|
-
return <AdwToolbarView
|
|
115
|
+
return <AdwToolbarView top={topBar}>{descriptor.render()}</AdwToolbarView>;
|
|
122
116
|
};
|
|
123
117
|
|
|
124
118
|
const StackPage = ({ descriptor, previous, navigation, onHidden }: StackPageProps): ReactNode => {
|
|
@@ -166,7 +160,7 @@ const StackView = (props: StackViewProps): ReactNode => {
|
|
|
166
160
|
const { state, navigation, descriptors, describe, popOnEscape, offset = 0 } = props;
|
|
167
161
|
const viewRef = useRef<Adw.NavigationView | null>(null);
|
|
168
162
|
const { pages, release } = useStackPages(state, descriptors, describe, offset);
|
|
169
|
-
const options =
|
|
163
|
+
const options = useLatestRef<OptionsByKey>(Object.fromEntries(pages.map((page) => [page.route.key, page.options])));
|
|
170
164
|
const onPopped = usePoppedHandler(viewRef, navigation, options, offset);
|
|
171
165
|
useStackSync(viewRef, state, options, offset);
|
|
172
166
|
|
package/src/stack/types.ts
CHANGED
|
@@ -68,7 +68,8 @@ type StackNavigationProp<
|
|
|
68
68
|
StackNavigationState<ParamList>,
|
|
69
69
|
StackNavigationOptions,
|
|
70
70
|
StackNavigationEventMap
|
|
71
|
-
> &
|
|
71
|
+
> &
|
|
72
|
+
StackActionHelpers<ParamList>;
|
|
72
73
|
|
|
73
74
|
/** Props a stack screen component receives. */
|
|
74
75
|
type StackScreenProps<
|
|
@@ -112,8 +113,8 @@ type StackNavigatorProps = DefaultNavigatorOptions<
|
|
|
112
113
|
StackNavigationEventMap,
|
|
113
114
|
StackNavigationProp<ParamListBase>
|
|
114
115
|
> &
|
|
115
|
-
StackRouterOptions &
|
|
116
|
-
StackNavigationConfig;
|
|
116
|
+
StackRouterOptions &
|
|
117
|
+
StackNavigationConfig;
|
|
117
118
|
|
|
118
119
|
export type {
|
|
119
120
|
StackDescriptor,
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NavigatorTypeBagBase,
|
|
3
|
+
ParamListBase,
|
|
4
|
+
StaticConfig,
|
|
5
|
+
StaticScreenFactory,
|
|
6
|
+
TypedNavigator,
|
|
7
|
+
} from "@react-navigation/core";
|
|
8
|
+
import type { ReactNode } from "react";
|
|
9
|
+
import * as Adw from "@gtkx/gi/adw";
|
|
10
|
+
import { createNavigatorFactory, createScreenFactory, useNavigationBuilder } from "@react-navigation/core";
|
|
11
|
+
import { useState } from "react";
|
|
12
|
+
import type {
|
|
13
|
+
TabViewActionHelpers,
|
|
14
|
+
TabViewNavigationEventMap,
|
|
15
|
+
TabViewNavigationOptions,
|
|
16
|
+
TabViewNavigationProp,
|
|
17
|
+
TabViewNavigationState,
|
|
18
|
+
TabViewNavigatorProps,
|
|
19
|
+
TabViewRouterOptions,
|
|
20
|
+
} from "./types.js";
|
|
21
|
+
import { readExistingTabs } from "./page-registry.js";
|
|
22
|
+
import { TabViewHost } from "./tab-view-host.js";
|
|
23
|
+
import { createTabViewRouter } from "./tab-view-router.js";
|
|
24
|
+
|
|
25
|
+
/** Type bag describing the tab view navigator to React Navigation's typed APIs. */
|
|
26
|
+
type TabViewTypeBag<
|
|
27
|
+
ParamList extends ParamListBase = ParamListBase,
|
|
28
|
+
NavigatorID extends string | undefined = string | undefined,
|
|
29
|
+
> = {
|
|
30
|
+
/** Route names and their params. */
|
|
31
|
+
ParamList: ParamList;
|
|
32
|
+
/** Optional navigator id. */
|
|
33
|
+
NavigatorID: NavigatorID;
|
|
34
|
+
/** Shape of the navigator state. */
|
|
35
|
+
State: TabViewNavigationState<ParamList>;
|
|
36
|
+
/** Per-screen options. */
|
|
37
|
+
ScreenOptions: TabViewNavigationOptions;
|
|
38
|
+
/** Events the navigator emits. */
|
|
39
|
+
EventMap: TabViewNavigationEventMap;
|
|
40
|
+
/** Navigation object per route. */
|
|
41
|
+
NavigationList: {
|
|
42
|
+
[RouteName in keyof ParamList]: TabViewNavigationProp<ParamList, RouteName, NavigatorID>;
|
|
43
|
+
};
|
|
44
|
+
/** The navigator component. */
|
|
45
|
+
Navigator: typeof TabViewNavigator;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/** Declares a typed screen of a tab view navigator for the static configuration API. */
|
|
49
|
+
const createTabViewScreen: StaticScreenFactory<TabViewTypeBag> = createScreenFactory<TabViewTypeBag>();
|
|
50
|
+
|
|
51
|
+
/** Renders each open route of a {@link createTabViewNavigator} as a page of an `Adw.TabView`. */
|
|
52
|
+
function TabViewNavigator({
|
|
53
|
+
view: providedView,
|
|
54
|
+
tabBarVisible,
|
|
55
|
+
tabBarAutohide,
|
|
56
|
+
tabBarExpand,
|
|
57
|
+
tabBarInverted,
|
|
58
|
+
overview,
|
|
59
|
+
menuModel,
|
|
60
|
+
renderMenu,
|
|
61
|
+
extraDropTarget,
|
|
62
|
+
onExtraDragDrop,
|
|
63
|
+
onCreateWindow,
|
|
64
|
+
onSetupMenu,
|
|
65
|
+
shortcuts,
|
|
66
|
+
defaultIcon,
|
|
67
|
+
...options
|
|
68
|
+
}: TabViewNavigatorProps): ReactNode {
|
|
69
|
+
const [view] = useState(() => providedView ?? new Adw.TabView());
|
|
70
|
+
const [router] = useState(() => createTabViewRouter(() => readExistingTabs(view)));
|
|
71
|
+
const { state, descriptors, navigation, render } = useNavigationBuilder<
|
|
72
|
+
TabViewNavigationState<ParamListBase>,
|
|
73
|
+
TabViewRouterOptions,
|
|
74
|
+
TabViewActionHelpers<ParamListBase>,
|
|
75
|
+
TabViewNavigationOptions,
|
|
76
|
+
TabViewNavigationEventMap
|
|
77
|
+
>(router, options);
|
|
78
|
+
|
|
79
|
+
return render(
|
|
80
|
+
<TabViewHost
|
|
81
|
+
view={view}
|
|
82
|
+
state={state}
|
|
83
|
+
navigation={navigation}
|
|
84
|
+
descriptors={descriptors}
|
|
85
|
+
tabBarVisible={tabBarVisible}
|
|
86
|
+
tabBarAutohide={tabBarAutohide}
|
|
87
|
+
tabBarExpand={tabBarExpand}
|
|
88
|
+
tabBarInverted={tabBarInverted}
|
|
89
|
+
overview={overview}
|
|
90
|
+
menuModel={menuModel}
|
|
91
|
+
renderMenu={renderMenu}
|
|
92
|
+
extraDropTarget={extraDropTarget}
|
|
93
|
+
onExtraDragDrop={onExtraDragDrop}
|
|
94
|
+
onCreateWindow={onCreateWindow}
|
|
95
|
+
onSetupMenu={onSetupMenu}
|
|
96
|
+
shortcuts={shortcuts}
|
|
97
|
+
defaultIcon={defaultIcon}
|
|
98
|
+
/>,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Creates a navigator whose routes are the pages of an `Adw.TabView`, with a tab bar and an optional overview. */
|
|
103
|
+
function createTabViewNavigator<
|
|
104
|
+
const ParamList extends ParamListBase,
|
|
105
|
+
const NavigatorID extends string | undefined = string | undefined,
|
|
106
|
+
const TypeBag extends NavigatorTypeBagBase = TabViewTypeBag<ParamList, NavigatorID>,
|
|
107
|
+
>(): TypedNavigator<TypeBag, undefined>;
|
|
108
|
+
/** Creates a navigator whose routes are the pages of an `Adw.TabView`, with a tab bar and an optional overview. */
|
|
109
|
+
function createTabViewNavigator<
|
|
110
|
+
const ParamList extends ParamListBase,
|
|
111
|
+
const NavigatorID extends string | undefined = string | undefined,
|
|
112
|
+
const TypeBag extends NavigatorTypeBagBase = TabViewTypeBag<ParamList, NavigatorID>,
|
|
113
|
+
const Config extends StaticConfig<TypeBag> = StaticConfig<TypeBag>,
|
|
114
|
+
>(config: Config): TypedNavigator<TypeBag, Config>;
|
|
115
|
+
function createTabViewNavigator<
|
|
116
|
+
const TypeBag extends NavigatorTypeBagBase,
|
|
117
|
+
const Config extends StaticConfig<TypeBag> | undefined,
|
|
118
|
+
>(config?: Config): TypedNavigator<TypeBag, Config> {
|
|
119
|
+
return createNavigatorFactory(TabViewNavigator)(config) as TypedNavigator<TypeBag, Config>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { createTabViewNavigator, createTabViewScreen, TabViewNavigator, type TabViewTypeBag };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
+
import * as Adw from "@gtkx/gi/adw";
|
|
3
|
+
import type { ParamListBase } from "@react-navigation/core";
|
|
4
|
+
import type { ExistingTab } from "./tab-view-router.js";
|
|
5
|
+
import type { TabViewNavigationOptions, TabViewNavigationState } from "./types.js";
|
|
6
|
+
|
|
7
|
+
type Route = TabViewNavigationState<ParamListBase>["routes"][number];
|
|
8
|
+
|
|
9
|
+
/** Page property values last written from a route's options. */
|
|
10
|
+
type AppliedOptions = Pick<
|
|
11
|
+
TabViewNavigationOptions,
|
|
12
|
+
| "icon"
|
|
13
|
+
| "indicatorActivatable"
|
|
14
|
+
| "indicatorIcon"
|
|
15
|
+
| "indicatorTooltip"
|
|
16
|
+
| "keyword"
|
|
17
|
+
| "liveThumbnail"
|
|
18
|
+
| "loading"
|
|
19
|
+
| "needsAttention"
|
|
20
|
+
| "thumbnailXalign"
|
|
21
|
+
| "thumbnailYalign"
|
|
22
|
+
| "tooltip"
|
|
23
|
+
> & { title?: string };
|
|
24
|
+
|
|
25
|
+
/** A native page a tab view navigator created or adopted, with the host its content renders into. */
|
|
26
|
+
type PageRecord = {
|
|
27
|
+
route: Route;
|
|
28
|
+
page: Adw.TabPage;
|
|
29
|
+
host: Adw.Bin;
|
|
30
|
+
applied: AppliedOptions;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** The pages of one navigator by route key, notifying React when the set changes. */
|
|
34
|
+
type PageStore = {
|
|
35
|
+
get: (key: string) => PageRecord | undefined;
|
|
36
|
+
set: (record: PageRecord) => void;
|
|
37
|
+
delete: (key: string) => void;
|
|
38
|
+
keys: () => string[];
|
|
39
|
+
subscribe: (listener: () => void) => () => void;
|
|
40
|
+
getVersion: () => number;
|
|
41
|
+
/** Key of the route whose page was selected by the last sync, so native selection changes are not undone. */
|
|
42
|
+
lastFocus: string | undefined;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const records = new WeakMap<Adw.TabPage, PageRecord>();
|
|
46
|
+
|
|
47
|
+
const recordOf = (page: Adw.TabPage): PageRecord | undefined => records.get(page);
|
|
48
|
+
|
|
49
|
+
const registerPage = (record: PageRecord): void => {
|
|
50
|
+
records.set(record.page, record);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const ownerOf = (page: Adw.TabPage): Adw.TabView | null => {
|
|
54
|
+
let widget: Gtk.Widget | null = page.getChild();
|
|
55
|
+
|
|
56
|
+
while (widget !== null) {
|
|
57
|
+
if (widget instanceof Adw.TabView) {
|
|
58
|
+
return widget;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
widget = widget.getParent();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return null;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const readExistingTabs = (view: Adw.TabView): ExistingTab[] => {
|
|
68
|
+
const selected = view.getSelectedPage();
|
|
69
|
+
const tabs: ExistingTab[] = [];
|
|
70
|
+
|
|
71
|
+
for (let position = 0; position < view.getNPages(); position += 1) {
|
|
72
|
+
const page = view.getNthPage(position);
|
|
73
|
+
const record = records.get(page);
|
|
74
|
+
|
|
75
|
+
if (record === undefined) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const parent = page.getParent();
|
|
80
|
+
const parentRecord = parent === null ? undefined : records.get(parent);
|
|
81
|
+
|
|
82
|
+
tabs.push({
|
|
83
|
+
route: record.route,
|
|
84
|
+
pinned: page.getPinned(),
|
|
85
|
+
parent: parentRecord?.route.key,
|
|
86
|
+
selected: page === selected,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return tabs;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const createPageStore = (): PageStore => {
|
|
94
|
+
const byKey = new Map<string, PageRecord>();
|
|
95
|
+
const listeners = new Set<() => void>();
|
|
96
|
+
let version = 0;
|
|
97
|
+
|
|
98
|
+
const notify = (): void => {
|
|
99
|
+
version += 1;
|
|
100
|
+
|
|
101
|
+
for (const listener of listeners) {
|
|
102
|
+
listener();
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
get: (key) => byKey.get(key),
|
|
108
|
+
set: (record) => {
|
|
109
|
+
byKey.set(record.route.key, record);
|
|
110
|
+
notify();
|
|
111
|
+
},
|
|
112
|
+
delete: (key) => {
|
|
113
|
+
if (byKey.delete(key)) {
|
|
114
|
+
notify();
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
keys: () => [...byKey.keys()],
|
|
118
|
+
subscribe: (listener) => {
|
|
119
|
+
listeners.add(listener);
|
|
120
|
+
|
|
121
|
+
return () => {
|
|
122
|
+
listeners.delete(listener);
|
|
123
|
+
};
|
|
124
|
+
},
|
|
125
|
+
getVersion: () => version,
|
|
126
|
+
lastFocus: undefined,
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export {
|
|
131
|
+
type AppliedOptions,
|
|
132
|
+
createPageStore,
|
|
133
|
+
ownerOf,
|
|
134
|
+
type PageRecord,
|
|
135
|
+
type PageStore,
|
|
136
|
+
readExistingTabs,
|
|
137
|
+
recordOf,
|
|
138
|
+
registerPage,
|
|
139
|
+
};
|