Skip to content

Commit a6e70e3

Browse files
committed
added web example
1 parent d3a472e commit a6e70e3

16 files changed

Lines changed: 20134 additions & 1232 deletions

example-web/index.html

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta
6+
name="viewport"
7+
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
8+
/>
9+
<title>react-native-safe-area-context Web Example</title>
10+
<style>
11+
html,
12+
body,
13+
#root {
14+
height: 100%;
15+
margin: 0;
16+
padding: 0;
17+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
18+
sans-serif;
19+
}
20+
</style>
21+
</head>
22+
<body>
23+
<div id="root"></div>
24+
<script type="module" src="/src/index.tsx"></script>
25+
</body>
26+
</html>

example-web/package.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "safe-area-example-web",
3+
"version": "0.0.1",
4+
"private": true,
5+
"scripts": {
6+
"start": "vite",
7+
"build": "vite build",
8+
"preview": "vite preview"
9+
},
10+
"dependencies": {
11+
"react": "19.1.0",
12+
"react-dom": "19.1.0",
13+
"react-native-web": "^0.19.13"
14+
},
15+
"devDependencies": {
16+
"@types/react": "^19.0.0",
17+
"@types/react-dom": "^19.0.0",
18+
"@vitejs/plugin-react": "^4.3.0",
19+
"typescript": "^5.5.2",
20+
"vite": "^6.0.0"
21+
}
22+
}

example-web/src/App.tsx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import * as React from 'react';
2+
import { View, Text, Pressable, StyleSheet } from 'react-native';
3+
import SafeAreaViewExample from './examples/SafeAreaViewExample';
4+
import SafeAreaViewEdgesExample from './examples/SafeAreaViewEdgesExample';
5+
import HooksExample from './examples/HooksExample';
6+
import ListenerExample from './examples/ListenerExample';
7+
8+
const EXAMPLES = [
9+
{
10+
key: 'safe-area-view',
11+
title: 'SafeAreaView',
12+
component: SafeAreaViewExample,
13+
},
14+
{ key: 'edges', title: 'Edges', component: SafeAreaViewEdgesExample },
15+
{ key: 'hooks', title: 'Hooks', component: HooksExample },
16+
{ key: 'listener', title: 'Listener', component: ListenerExample },
17+
] as const;
18+
19+
export default function App() {
20+
const [activeKey, setActiveKey] =
21+
React.useState<(typeof EXAMPLES)[number]['key']>('safe-area-view');
22+
const ActiveComponent = EXAMPLES.find((e) => e.key === activeKey)!.component;
23+
24+
return (
25+
<View style={styles.container}>
26+
<View style={styles.tabBar}>
27+
{EXAMPLES.map((example) => (
28+
<Pressable
29+
key={example.key}
30+
style={[styles.tab, activeKey === example.key && styles.activeTab]}
31+
onPress={() => setActiveKey(example.key)}
32+
>
33+
<Text
34+
style={[
35+
styles.tabText,
36+
activeKey === example.key && styles.activeTabText,
37+
]}
38+
>
39+
{example.title}
40+
</Text>
41+
</Pressable>
42+
))}
43+
</View>
44+
<View style={styles.content}>
45+
<ActiveComponent />
46+
</View>
47+
</View>
48+
);
49+
}
50+
51+
const styles = StyleSheet.create({
52+
container: {
53+
flex: 1,
54+
},
55+
tabBar: {
56+
flexDirection: 'row',
57+
backgroundColor: '#222f3e',
58+
},
59+
tab: {
60+
flex: 1,
61+
paddingVertical: 12,
62+
alignItems: 'center',
63+
},
64+
activeTab: {
65+
borderBottomWidth: 3,
66+
borderBottomColor: '#10ac84',
67+
},
68+
tabText: {
69+
fontSize: 14,
70+
fontWeight: '600',
71+
color: '#8395a7',
72+
},
73+
activeTabText: {
74+
color: '#ffffff',
75+
},
76+
content: {
77+
flex: 1,
78+
},
79+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import * as React from 'react';
2+
import { Text, View } from 'react-native';
3+
4+
export function Card({
5+
title,
6+
children,
7+
}: {
8+
title: string;
9+
children: React.ReactNode;
10+
}) {
11+
return (
12+
<View style={{ padding: 16, backgroundColor: 'white', marginBottom: 4 }}>
13+
<Text
14+
style={{
15+
fontSize: 20,
16+
fontWeight: 'bold',
17+
marginBottom: 16,
18+
color: '#292929',
19+
}}
20+
>
21+
{title}
22+
</Text>
23+
{children}
24+
</View>
25+
);
26+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import * as React from 'react';
2+
import { Text } from 'react-native';
3+
4+
export function DataView({ data }: { data: object | null | undefined }) {
5+
return (
6+
<Text style={{ fontSize: 16, lineHeight: 24, color: '#292929' }}>
7+
{data == null
8+
? 'null'
9+
: Object.entries(data)
10+
.map(([key, value]) => `${key}: ${value}`)
11+
.join('\n')}
12+
</Text>
13+
);
14+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import * as React from 'react';
2+
import { View, Text, ScrollView, StyleSheet } from 'react-native';
3+
import {
4+
SafeAreaProvider,
5+
useSafeAreaInsets,
6+
useSafeAreaFrame,
7+
initialWindowMetrics,
8+
} from 'react-native-safe-area-context';
9+
import { DataView } from '../components/DataView';
10+
import { Card } from '../components/Card';
11+
12+
function HooksExampleScreen() {
13+
const insets = useSafeAreaInsets();
14+
const frame = useSafeAreaFrame();
15+
16+
return (
17+
<View
18+
style={{
19+
width: frame.width,
20+
height: frame.height,
21+
backgroundColor: 'red',
22+
paddingTop: insets.top - BORDER_WIDTH,
23+
paddingLeft: insets.left - BORDER_WIDTH,
24+
paddingBottom: insets.bottom - BORDER_WIDTH,
25+
paddingRight: insets.right - BORDER_WIDTH,
26+
borderColor: 'blue',
27+
borderWidth: BORDER_WIDTH,
28+
}}
29+
>
30+
<ScrollView style={{ flex: 1, backgroundColor: '#eee' }}>
31+
<Card title="Provider insets">
32+
<DataView data={insets} />
33+
</Card>
34+
<Card title="Provider frame">
35+
<DataView data={frame} />
36+
</Card>
37+
<Card title="Initial window insets">
38+
<DataView data={initialWindowMetrics?.insets} />
39+
</Card>
40+
<Card title="Initial window frame">
41+
<DataView data={initialWindowMetrics?.frame} />
42+
</Card>
43+
<Card title="Note">
44+
<Text style={styles.note}>
45+
On desktop browsers, insets will be 0. The CSS env(safe-area-inset-*)
46+
values only report non-zero on devices with notches (e.g. iPhone in
47+
Safari). The frame values reflect the current window dimensions.
48+
</Text>
49+
</Card>
50+
</ScrollView>
51+
</View>
52+
);
53+
}
54+
55+
const BORDER_WIDTH = 8;
56+
57+
export default function HooksExample() {
58+
return (
59+
<View style={{ flex: 1 }}>
60+
<SafeAreaProvider>
61+
<HooksExampleScreen />
62+
</SafeAreaProvider>
63+
</View>
64+
);
65+
}
66+
67+
const styles = StyleSheet.create({
68+
note: {
69+
fontSize: 14,
70+
lineHeight: 20,
71+
color: '#576574',
72+
},
73+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as React from 'react';
2+
import { View } from 'react-native';
3+
import {
4+
EdgeInsets,
5+
Rect,
6+
SafeAreaListener,
7+
} from 'react-native-safe-area-context';
8+
import { DataView } from '../components/DataView';
9+
import { Card } from '../components/Card';
10+
11+
export default function ListenerExample() {
12+
const [data, setData] = React.useState<{
13+
insets: EdgeInsets;
14+
frame: Rect;
15+
} | null>(null);
16+
17+
return (
18+
<SafeAreaListener onChange={setData}>
19+
<View style={{ flex: 1, backgroundColor: '#eee' }}>
20+
<Card title="Listener insets">
21+
<DataView data={data?.insets} />
22+
</Card>
23+
<Card title="Listener frame">
24+
<DataView data={data?.frame} />
25+
</Card>
26+
</View>
27+
</SafeAreaListener>
28+
);
29+
}

0 commit comments

Comments
 (0)