diff options
author | Samuel Newman <mozzius@protonmail.com> | 2024-10-08 20:00:49 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-08 20:00:49 +0300 |
commit | fc82d2f6d5e8a93f0e7ce4861c5205c8a4b49c30 (patch) | |
tree | 51e618db283d28ef241f0e6f2f6180004e6cb6e7 /src/view/com | |
parent | efcf8a6ae59d9767bc2289af927a2e12bc39a054 (diff) | |
download | voidsky-fc82d2f6d5e8a93f0e7ce4861c5205c8a4b49c30.tar.zst |
Move Dialogs to Radix (#5648)
* Use Redix FocusTrap (#5638) * Use Redix FocusTrap * force resolutions on radix libs * add focus guards * use @radix-ui/dismissable-layer for escape handling * fix banner menu keypress by using `Pressable` * add menu in dialog example to storybook --------- Co-authored-by: Samuel Newman <mozzius@protonmail.com> * use DismissableLayer/FocusScope for composer * fix storybook dialog * thread Portal through Prompt and avatar/banner * fix dialog style regression * remove tamagui --------- Co-authored-by: Eric Bailey <git@esb.lol>
Diffstat (limited to 'src/view/com')
-rw-r--r-- | src/view/com/composer/Composer.tsx | 18 | ||||
-rw-r--r-- | src/view/com/composer/text-input/web/EmojiPicker.web.tsx | 19 | ||||
-rw-r--r-- | src/view/com/util/UserAvatar.tsx | 14 | ||||
-rw-r--r-- | src/view/com/util/UserBanner.tsx | 16 |
4 files changed, 27 insertions, 40 deletions
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 55c2d81ab..8cc8fba0d 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -65,7 +65,6 @@ import {useDialogStateControlContext} from '#/state/dialogs' import {emitPostCreated} from '#/state/events' import {ComposerImage, pasteImage} from '#/state/gallery' import {useModalControls} from '#/state/modals' -import {useModals} from '#/state/modals' import {useRequireAltTextEnabled} from '#/state/preferences' import { toPostLanguages, @@ -146,7 +145,6 @@ export const ComposePost = ({ const queryClient = useQueryClient() const currentDid = currentAccount!.did const {data: currentProfile} = useProfileQuery({did: currentDid}) - const {isModalActive} = useModals() const {closeComposer} = useComposerControls() const pal = usePalette('default') const {isMobile} = useWebMediaQueries() @@ -303,22 +301,6 @@ export const ComposePost = ({ } }, [onPressCancel, closeAllDialogs, closeAllModals]) - // listen to escape key on desktop web - const onEscape = useCallback( - (e: KeyboardEvent) => { - if (e.key === 'Escape') { - onPressCancel() - } - }, - [onPressCancel], - ) - useEffect(() => { - if (isWeb && !isModalActive) { - window.addEventListener('keydown', onEscape) - return () => window.removeEventListener('keydown', onEscape) - } - }, [onEscape, isModalActive]) - const onNewLink = useCallback((uri: string) => { dispatch({type: 'embed_add_uri', uri}) }, []) diff --git a/src/view/com/composer/text-input/web/EmojiPicker.web.tsx b/src/view/com/composer/text-input/web/EmojiPicker.web.tsx index ad3bb30ec..1d5dad486 100644 --- a/src/view/com/composer/text-input/web/EmojiPicker.web.tsx +++ b/src/view/com/composer/text-input/web/EmojiPicker.web.tsx @@ -6,6 +6,7 @@ import { View, } from 'react-native' import Picker from '@emoji-mart/react' +import {DismissableLayer} from '@radix-ui/react-dismissable-layer' import {textInputWebEmitter} from '#/view/com/composer/text-input/textInputWebEmitter' import {atoms as a} from '#/alf' @@ -143,13 +144,17 @@ export function EmojiPicker({state, close, pinToTop}: IProps) { {/* eslint-disable-next-line react-native-a11y/has-valid-accessibility-descriptors */} <TouchableWithoutFeedback onPress={e => e.stopPropagation()}> <View style={[{position: 'absolute'}, position]}> - <Picker - data={async () => { - return (await import('./EmojiPickerData.json')).default - }} - onEmojiSelect={onInsert} - autoFocus={true} - /> + <DismissableLayer + onFocusOutside={evt => evt.preventDefault()} + onDismiss={close}> + <Picker + data={async () => { + return (await import('./EmojiPickerData.json')).default + }} + onEmojiSelect={onInsert} + autoFocus={true} + /> + </DismissableLayer> </View> </TouchableWithoutFeedback> </View> diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index 43555ccb4..b311f7887 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -1,5 +1,5 @@ import React, {memo, useMemo} from 'react' -import {Image, StyleSheet, TouchableOpacity, View} from 'react-native' +import {Image, Pressable, StyleSheet, View} from 'react-native' import {Image as RNImage} from 'react-native-image-crop-picker' import Svg, {Circle, Path, Rect} from 'react-native-svg' import {AppBskyActorDefs, ModerationUI} from '@atproto/api' @@ -30,6 +30,7 @@ import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' import {Link} from '#/components/Link' import {MediaInsetBorder} from '#/components/MediaInsetBorder' import * as Menu from '#/components/Menu' +import {PortalComponent} from '#/components/Portal' import {ProfileHoverCard} from '#/components/ProfileHoverCard' import {openCamera, openCropper, openPicker} from '../../../lib/media/picker' @@ -50,6 +51,7 @@ interface UserAvatarProps extends BaseUserAvatarProps { interface EditableUserAvatarProps extends BaseUserAvatarProps { onSelectNewAvatar: (img: RNImage | null) => void + Portal?: PortalComponent } interface PreviewableUserAvatarProps extends BaseUserAvatarProps { @@ -266,6 +268,7 @@ let EditableUserAvatar = ({ size, avatar, onSelectNewAvatar, + Portal, }: EditableUserAvatarProps): React.ReactNode => { const t = useTheme() const pal = usePalette('default') @@ -346,10 +349,7 @@ let EditableUserAvatar = ({ <Menu.Root> <Menu.Trigger label={_(msg`Edit avatar`)}> {({props}) => ( - <TouchableOpacity - {...props} - activeOpacity={0.8} - testID="changeAvatarBtn"> + <Pressable {...props} testID="changeAvatarBtn"> {avatar ? ( <HighPriorityImage testID="userAvatarImage" @@ -363,10 +363,10 @@ let EditableUserAvatar = ({ <View style={[styles.editButtonContainer, pal.btn]}> <CameraFilled height={14} width={14} style={t.atoms.text} /> </View> - </TouchableOpacity> + </Pressable> )} </Menu.Trigger> - <Menu.Outer showCancel> + <Menu.Outer showCancel Portal={Portal}> <Menu.Group> {isNative && ( <Menu.Item diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index 622cb2129..98ff19b5d 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -1,5 +1,5 @@ import React from 'react' -import {StyleSheet, TouchableOpacity, View} from 'react-native' +import {Pressable, StyleSheet, View} from 'react-native' import {Image as RNImage} from 'react-native-image-crop-picker' import {Image} from 'expo-image' import {ModerationUI} from '@atproto/api' @@ -25,6 +25,7 @@ import { import {StreamingLive_Stroke2_Corner0_Rounded as Library} from '#/components/icons/StreamingLive' import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' import * as Menu from '#/components/Menu' +import {PortalComponent} from '#/components/Portal' import {openCamera, openCropper, openPicker} from '../../../lib/media/picker' export function UserBanner({ @@ -32,11 +33,13 @@ export function UserBanner({ banner, moderation, onSelectNewBanner, + Portal, }: { type?: 'labeler' | 'default' banner?: string | null moderation?: ModerationUI onSelectNewBanner?: (img: RNImage | null) => void + Portal?: PortalComponent }) { const pal = usePalette('default') const theme = useTheme() @@ -90,14 +93,11 @@ export function UserBanner({ // setUserBanner is only passed as prop on the EditProfile component return onSelectNewBanner ? ( - <EventStopper onKeyDown={false}> + <EventStopper onKeyDown={true}> <Menu.Root> <Menu.Trigger label={_(msg`Edit avatar`)}> {({props}) => ( - <TouchableOpacity - {...props} - activeOpacity={0.8} - testID="changeBannerBtn"> + <Pressable {...props} testID="changeBannerBtn"> {banner ? ( <Image testID="userBannerImage" @@ -115,10 +115,10 @@ export function UserBanner({ <View style={[styles.editButtonContainer, pal.btn]}> <CameraFilled height={14} width={14} style={t.atoms.text} /> </View> - </TouchableOpacity> + </Pressable> )} </Menu.Trigger> - <Menu.Outer showCancel> + <Menu.Outer showCancel Portal={Portal}> <Menu.Group> {isNative && ( <Menu.Item |