Skip to content

Commit b812947

Browse files
author
Pierre Poupin
committed
chore(example): add async focus example
1 parent d72a8ce commit b812947

4 files changed

Lines changed: 71 additions & 1 deletion

File tree

packages/example/App.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { GridWithLongNodesPage } from './src/pages/GridWithLongNodesPage';
1818
import { useTVPanEvent } from './src/components/PanEvent/useTVPanEvent';
1919
import { SpatialNavigationDeviceTypeProvider } from '../lib/src/spatial-navigation/context/DeviceContext';
2020
import { ListWithVariableSize } from './src/pages/ListWithVariableSize';
21+
import { AsynchronousContent } from './src/pages/AsynchronousContent';
2122

2223
const Stack = createNativeStackNavigator<RootStackParamList>();
2324

@@ -29,6 +30,7 @@ export type RootTabParamList = {
2930
NonVirtualizedGridPage: undefined;
3031
GridWithLongNodesPage: undefined;
3132
ListWithVariableSize: undefined;
33+
AsynchronousContent: undefined;
3234
};
3335

3436
export type RootStackParamList = {
@@ -57,6 +59,7 @@ const TabNavigator = () => {
5759
<Tab.Screen name="NonVirtualizedGridPage" component={NonVirtualizedGridPage} />
5860
<Tab.Screen name="GridWithLongNodesPage" component={GridWithLongNodesPage} />
5961
<Tab.Screen name="ListWithVariableSize" component={ListWithVariableSize} />
62+
<Tab.Screen name="AsynchronousContent" component={AsynchronousContent} />
6063
</Tab.Navigator>
6164
</MenuProvider>
6265
);

packages/example/src/components/Menu/Menu.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ const menuItems: Record<keyof RootTabParamList, MenuItems> = {
5959
icon: 'LayoutDashboard',
6060
},
6161
ListWithVariableSize: { label: 'List with variable size', icon: 'LayoutDashboard' },
62+
AsynchronousContent: { label: 'Asynchronous content', icon: 'Timer' },
6263
};
6364

6465
export const Menu = ({ state, navigation }: BottomTabBarProps) => {
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { Grid3X3, Home, LayoutDashboard, LayoutGrid } from 'lucide-react-native';
1+
import { Grid3X3, Home, LayoutDashboard, LayoutGrid, Timer } from 'lucide-react-native';
22

33
export const iconsCatalog = {
44
Home: Home,
55
Grid3X3: Grid3X3,
66
LayoutGrid: LayoutGrid,
77
LayoutDashboard: LayoutDashboard,
8+
Timer: Timer,
89
};
910

1011
export type IconName = keyof typeof iconsCatalog;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { SpatialNavigationNode, SpatialNavigationView } from 'react-tv-space-navigation';
2+
import { Page } from '../components/Page';
3+
import { Button } from '../design-system/components/Button';
4+
import { Typography } from '../design-system/components/Typography';
5+
import { Box } from '../design-system/components/Box';
6+
import { Spacer } from '../design-system/components/Spacer';
7+
import { useState } from 'react';
8+
import { ActivityIndicator } from 'react-native';
9+
import styled from '@emotion/native';
10+
11+
function sleep(ms) {
12+
return new Promise((resolve) => setTimeout(resolve, ms));
13+
}
14+
15+
export const AsynchronousContent = () => {
16+
const [shouldShow, setShouldShow] = useState(false);
17+
const [isLoading, setIsLoading] = useState(false);
18+
19+
const toggle = async () => {
20+
if (isLoading) return;
21+
22+
setIsLoading(true);
23+
await sleep(1000);
24+
setIsLoading(false);
25+
26+
setShouldShow((prev) => !prev);
27+
};
28+
29+
return (
30+
<Page>
31+
<Box padding={'$8'}>
32+
<Typography>
33+
{
34+
'Here are some details about a common pitfall with this library: how do I show/hide focusable elements properly?'
35+
}
36+
</Typography>
37+
<Typography>{'Use this button to trigger an asynchronous show/hide'}</Typography>
38+
<SpatialNavigationView direction="horizontal">
39+
<Button label={shouldShow ? 'Hide' : 'Show'} onSelect={toggle} />
40+
<Spacer gap="$8" direction="horizontal" />
41+
{isLoading && <ActivityIndicator color="white" size={'large'} />}
42+
</SpatialNavigationView>
43+
<Spacer gap="$8" />
44+
<Typography>
45+
{
46+
'Then, try out the focus below. Focus should not be messed up after asynchronous modifications :)'
47+
}
48+
</Typography>
49+
<StyledNavigationRow direction="horizontal">
50+
<Button label="First button" />
51+
<SpatialNavigationNode>
52+
{shouldShow && <Button label="Second button (asynchronously showed)" />}
53+
</SpatialNavigationNode>
54+
<Button label="Third button" />
55+
</StyledNavigationRow>
56+
57+
<Typography>Check out the code to understand how it is done.</Typography>
58+
</Box>
59+
</Page>
60+
);
61+
};
62+
63+
const StyledNavigationRow = styled(SpatialNavigationView)({
64+
gap: 40,
65+
});

0 commit comments

Comments
 (0)