Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(example): create modal in the example #59

Merged
merged 16 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@react-navigation/bottom-tabs": "^6.5.11",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-native-modal": "^13.0.1",
"react-native-web": "^0.19.6"
},
"resolutions": {
Expand Down
57 changes: 57 additions & 0 deletions packages/example/src/components/modals/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import styled from '@emotion/native';
import React from 'react';
import { View, ModalProps } from 'react-native';
import { Typography } from '../../design-system/components/Typography';
import { Spacer } from '../../design-system/components/Spacer';
import { SpatialNavigationRoot } from '../../../../lib/src/spatial-navigation/components/Root';
import { useLockModal } from '../../hooks/useLockModal';
import { colors } from '../../design-system/theme/colors';

type CustomModalProps = ModalProps & {
isModalVisible: boolean;
setIsModalVisible: (isVisible: boolean) => void;
children: React.ReactNode;
title: string;
};

export const Modal = ({ isModalVisible, setIsModalVisible, children, title }: CustomModalProps) => {
useLockModal({ isModalVisible, setIsModalVisible });

if (!isModalVisible) return null;

return (
<SpatialNavigationRoot>
<StyledModal>
<ModalContentContainer>
<Typography variant="title" fontWeight="strong">
{title}
</Typography>
<Spacer gap="$8" />
{children}
</ModalContentContainer>
</StyledModal>
</SpatialNavigationRoot>
);
};

const StyledModal = styled(View)({
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
justifyContent: 'center',
alignItems: 'center',
});

const ModalContentContainer = styled(View)({
minHeight: 200,
minWidth: 200,
backgroundColor: colors.background.main,
borderWidth: 2,
borderColor: colors.primary.light,
padding: 32,
margin: 16,
borderRadius: 16,
justifyContent: 'center',
});
61 changes: 61 additions & 0 deletions packages/example/src/components/modals/SubtitlesModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { DefaultFocus } from '../../../../lib/src/spatial-navigation/context/DefaultFocusContext';
import { Button } from '../../design-system/components/Button';
import { Spacer } from '../../design-system/components/Spacer';
import { Modal } from './Modal';
import { useLockModal } from '../../hooks/useLockModal';

interface SubtitlesModalProps {
isModalVisible: boolean;
setIsModalVisible: (isVisible: boolean) => void;
setSubtitles: (subtitles: string) => void;
}

export const SubtitlesModal = ({
isModalVisible,
setIsModalVisible,
setSubtitles,
}: SubtitlesModalProps) => {
useLockModal({ isModalVisible, setIsModalVisible });

return (
<Modal
isModalVisible={isModalVisible}
setIsModalVisible={setIsModalVisible}
title={'Choose subtitles'}
>
<DefaultFocus>
<Button
label="English"
onSelect={() => {
setSubtitles('English');
setIsModalVisible(false);
}}
/>
</DefaultFocus>
<Spacer gap="$8" />
<Button
label="Spanish"
onSelect={() => {
setSubtitles('Spanish');
setIsModalVisible(false);
}}
/>
<Spacer gap="$8" />
<Button
label="Portuguese"
onSelect={() => {
setSubtitles('Portuguese');
setIsModalVisible(false);
}}
/>
<Spacer gap="$8" />
<Button
label="None"
onSelect={() => {
setSubtitles('No');
setIsModalVisible(false);
}}
/>
</Modal>
);
};
46 changes: 46 additions & 0 deletions packages/example/src/hooks/useLockModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useEffect } from 'react';
thomasrebam marked this conversation as resolved.
Show resolved Hide resolved
import { useLockSpatialNavigation } from '../../../lib/src/spatial-navigation/context/LockSpatialNavigationContext';
import { EventArg, useNavigation } from '@react-navigation/native';

interface UseLockProps {
isModalVisible: boolean;
setIsModalVisible: (isVisible: boolean) => void;
}

// This hook is used to lock the spatial navigation of parent navigator when a modal is open
// and to prevent the user from closing the modal by pressing the back button
export const useLockModal = ({ isModalVisible, setIsModalVisible }: UseLockProps) => {
useLockParentSpatialNavigator(isModalVisible);
usePreventNavigationGoBack(isModalVisible, setIsModalVisible);
};

const useLockParentSpatialNavigator = (isModalVisible: boolean) => {
const { lock, unlock } = useLockSpatialNavigation();
useEffect(() => {
if (isModalVisible) {
lock();
return () => {
unlock();
};
}
}, [isModalVisible, lock, unlock]);
};

const usePreventNavigationGoBack = (
isModalVisible: boolean,
setIsModalVisible: (isVisible: boolean) => void,
) => {
const navigation = useNavigation();
useEffect(() => {
if (isModalVisible) {
const navigationListener = (e: EventArg<'beforeRemove', true>) => {
e.preventDefault();
setIsModalVisible(false);
};
navigation.addListener('beforeRemove', navigationListener);
return () => {
navigation.removeListener('beforeRemove', navigationListener);
};
}
}, [navigation, isModalVisible, setIsModalVisible]);
};
11 changes: 11 additions & 0 deletions packages/example/src/pages/ProgramDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ import { Spacer } from '../design-system/components/Spacer';
import { Typography } from '../design-system/components/Typography';
import { ProgramListWithTitle } from '../modules/program/view/ProgramListWithTitle';
import { Button } from '../design-system/components/Button';
import { useState } from 'react';
import { SubtitlesModal } from '../components/modals/SubtitlesModal';

export const ProgramDetail = ({
route,
}: {
route: RouteProp<RootStackParamList, 'ProgramDetail'>;
}) => {
const [isModalVisible, setIsModalVisible] = useState(false);
const [subtitles, setSubtitles] = useState('No');
const { programInfo } = route.params;

return (
Expand All @@ -38,12 +42,19 @@ export const ProgramDetail = ({
<Spacer gap="$8" />
{/* eslint-disable-next-line no-console */}
<Button label="More info" onSelect={() => console.log('More info!')} />
<Spacer gap="$8" />
<Button label={`${subtitles} subtitles`} onSelect={() => setIsModalVisible(true)} />
</Box>
</DefaultFocus>
</Container>
<Spacer gap="$5" />
<ProgramListWithTitle title="You may also like..."></ProgramListWithTitle>
</Box>
<SubtitlesModal
isModalVisible={isModalVisible}
setIsModalVisible={setIsModalVisible}
thomasrebam marked this conversation as resolved.
Show resolved Hide resolved
setSubtitles={setSubtitles}
/>
</Page>
);
};
Expand Down
25 changes: 24 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14156,7 +14156,7 @@ __metadata:
languageName: node
linkType: hard

"prop-types@npm:^15.8.1":
"prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
Expand Down Expand Up @@ -14366,6 +14366,15 @@ __metadata:
languageName: node
linkType: hard

"react-native-animatable@npm:1.3.3":
version: 1.3.3
resolution: "react-native-animatable@npm:1.3.3"
dependencies:
prop-types: ^15.7.2
checksum: eb35821de36ae4eb00f97d99fc22ed79bd017248092ff1299f9d46a7ab946de16d2e6d6bfbf4cab5ef77d0d3bf47684aec761a7670ec7d36aae8d77ab8ddd171
languageName: node
linkType: hard

"react-native-keyevent-expo-config-plugin@npm:^1.0.49":
version: 1.0.49
resolution: "react-native-keyevent-expo-config-plugin@npm:1.0.49"
Expand All @@ -14386,6 +14395,19 @@ __metadata:
languageName: node
linkType: hard

"react-native-modal@npm:^13.0.1":
version: 13.0.1
resolution: "react-native-modal@npm:13.0.1"
dependencies:
prop-types: ^15.6.2
react-native-animatable: 1.3.3
peerDependencies:
react: "*"
react-native: ">=0.65.0"
checksum: 15985fd6aaae7a2134ec1003c63abd384f4a17beabd0a80b74033c98eccee29161aa07150f479373fb43106cfb33b5837b7a4f1d2b721ff03b3727490c830a07
languageName: node
linkType: hard

"react-native-safe-area-context@npm:^4.8.2":
version: 4.8.2
resolution: "react-native-safe-area-context@npm:4.8.2"
Expand Down Expand Up @@ -14550,6 +14572,7 @@ __metadata:
prettier: ^2.8.8
react: ^18.2.0
react-dom: ^18.2.0
react-native-modal: ^13.0.1
react-native-web: ^0.19.6
style-loader: ^3.3.3
ts-loader: ^9.4.4
Expand Down
Loading