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

[Sheets] [Pt. 7] Part seven rework, much simplier! #5582

Merged
merged 22 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 12 additions & 0 deletions src/components/BottomSheetButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react'

import {Button, ButtonProps} from '#/components/Button'
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'

export function BottomSheetButton({children, ...rest}: ButtonProps) {
return (
<Button {...rest} Component={NormalizedRNGHPressable}>
{children}
</Button>
)
}
92 changes: 92 additions & 0 deletions src/components/BottomSheetLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React from 'react'
import {StackActions, useNavigation} from '@react-navigation/native'

import {NavigationProp} from '#/lib/routes/types'
import {flatten, useTheme} from '#/alf'
import {useDialogContext} from '#/components/Dialog'
import {useInteractionState} from '#/components/hooks/useInteractionState'
import {InlineLinkProps, useLink} from '#/components/Link'
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'
import {Text} from '#/components/Typography'
import {router} from '#/routes'

export function BottomSheetInlineLinkText({
children,
to,
action = 'push',
disableMismatchWarning,
style,
onPress: outerOnPress,
label,
shareOnLongPress,
disableUnderline,
...rest
}: InlineLinkProps) {
const t = useTheme()
const stringChildren = typeof children === 'string'
const navigation = useNavigation<NavigationProp>()
const dialog = useDialogContext()

const {href, isExternal, onLongPress} = useLink({
to,
displayText: stringChildren ? children : '',
action,
disableMismatchWarning,
onPress: outerOnPress,
shareOnLongPress,
})
const {
state: pressed,
onIn: onPressIn,
onOut: onPressOut,
} = useInteractionState()

const onPress = () => {
if (isExternal) {
return
}

dialog.close()

if (action === 'push') {
navigation.dispatch(StackActions.push(...router.matchPath(href)))
} else if (action === 'replace') {
navigation.dispatch(StackActions.replace(...router.matchPath(href)))
} else if (action === 'navigate') {
// @ts-ignore
navigation.navigate(...router.matchPath(href))
} else {
throw Error('Unsupported navigator action.')
}
}

const flattenedStyle = flatten(style) || {}

// eslint-disable-next-line bsky-internal/avoid-unwrapped-text
return (
<NormalizedRNGHPressable
onPress={onPress}
onLongPress={onLongPress}
onPressIn={onPressIn}
onPressOut={onPressOut}
role="link"
accessibilityLabel={label}
accessibilityHint=""
style={{flexDirection: 'row'}}>
<Text
{...rest}
style={[
{color: t.palette.primary_500},
pressed &&
!disableUnderline && {
textDecorationLine: 'underline',
textDecorationColor:
flattenedStyle.color ?? t.palette.primary_500,
},
flattenedStyle,
]}>
{children}
</Text>
</NormalizedRNGHPressable>
)
}
3 changes: 3 additions & 0 deletions src/components/BottomSheetLink.web.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import {Link as BottomSheetLink} from './Link'

export {BottomSheetLink}
20 changes: 18 additions & 2 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import {
import {LinearGradient} from 'expo-linear-gradient'

import {atoms as a, flatten, select, tokens, useTheme, web} from '#/alf'
import {useDialogContext} from '#/components/Dialog'
import {Props as SVGIconProps} from '#/components/icons/common'
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'
import {Text} from '#/components/Typography'

export type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'gradient'
Expand Down Expand Up @@ -87,6 +89,7 @@ export type ButtonProps = Pick<
style?: StyleProp<ViewStyle>
hoverStyle?: StyleProp<ViewStyle>
children: NonTextElements | ((context: ButtonContext) => NonTextElements)
Component?: React.ComponentType<PressableProps>
}

export type ButtonTextProps = TextProps & VariantProps & {disabled?: boolean}
Expand Down Expand Up @@ -114,10 +117,22 @@ export const Button = React.forwardRef<View, ButtonProps>(
disabled = false,
style,
hoverStyle: hoverStyleProp,
Component,
...rest
},
ref,
) => {
// This will pick the correct default pressable to use. If we are inside a dialog, we need to use the RNGH
// pressable so that it is usable inside the dialog.
const {insideDialog} = useDialogContext()
if (!Component) {
if (insideDialog) {
Component = NormalizedRNGHPressable
} else {
Component = Pressable
}
}

const t = useTheme()
const [state, setState] = React.useState({
pressed: false,
Expand Down Expand Up @@ -449,10 +464,11 @@ export const Button = React.forwardRef<View, ButtonProps>(
const flattenedBaseStyles = flatten([baseStyles, style])

return (
<Pressable
<Component
role="button"
accessibilityHint={undefined} // optional
{...rest}
// @ts-expect-error ref type
ref={ref}
aria-label={label}
aria-pressed={state.pressed}
Expand Down Expand Up @@ -500,7 +516,7 @@ export const Button = React.forwardRef<View, ButtonProps>(
<Context.Provider value={context}>
{typeof children === 'function' ? children(context) : children}
</Context.Provider>
</Pressable>
</Component>
)
},
)
Expand Down
1 change: 1 addition & 0 deletions src/components/Dialog/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {

export const Context = React.createContext<DialogContextProps>({
close: () => {},
insideDialog: false,
})

export function useDialogContext() {
Expand Down
42 changes: 11 additions & 31 deletions src/components/Dialog/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
import React, {useImperativeHandle} from 'react'
import {StyleProp, View, ViewStyle} from 'react-native'
import {StyleProp, TextInput, View, ViewStyle} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {
BottomSheetFlatList,
BottomSheetFlatListMethods,
BottomSheetTextInput,
BottomSheetView,
} from '@discord/bottom-sheet/src'
import {BottomSheetFlatListProps} from '@discord/bottom-sheet/src/components/bottomSheetScrollable/types'
import {BlueskyBottomSheetView} from '@haileyok/bluesky-bottom-sheet'

import {logger} from '#/logger'
import {useDialogStateControlContext} from '#/state/dialogs'
import {List, ListMethods, ListProps} from '#/view/com/util/List'
import {ScrollView} from '#/view/com/util/Views'
import {atoms as a, flatten, useTheme} from '#/alf'
import {Context} from '#/components/Dialog/context'
Expand All @@ -27,7 +21,7 @@ export {useDialogContext, useDialogControl} from '#/components/Dialog/context'
export * from '#/components/Dialog/types'
export * from '#/components/Dialog/utils'
// @ts-ignore
export const Input = createInput(BottomSheetTextInput)
export const Input = createInput(TextInput)

export function Outer({
children,
Expand Down Expand Up @@ -88,7 +82,7 @@ export function Outer({
[open, close],
)

const context = React.useMemo(() => ({close}), [close])
const context = React.useMemo(() => ({close, insideDialog: true}), [close])

return (
<Portal>
Expand Down Expand Up @@ -116,20 +110,16 @@ export function Outer({
export function Inner({children, style}: DialogInnerProps) {
const insets = useSafeAreaInsets()
return (
<BottomSheetView
<View
style={[
a.py_xl,
a.px_xl,
{
paddingTop: 40,
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
paddingBottom: insets.bottom + a.pb_5xl.paddingBottom,
},
flatten(style),
style,
]}>
{children}
</BottomSheetView>
</View>
)
}

Expand All @@ -146,30 +136,20 @@ export const ScrollableInner = React.forwardRef<ScrollView, DialogInnerProps>(
)

export const InnerFlatList = React.forwardRef<
BottomSheetFlatListMethods,
BottomSheetFlatListProps<any> & {webInnerStyle?: StyleProp<ViewStyle>}
ListMethods,
ListProps<any> & {webInnerStyle?: StyleProp<ViewStyle>}
>(function InnerFlatList({style, contentContainerStyle, ...props}, ref) {
const insets = useSafeAreaInsets()

return (
<BottomSheetFlatList
<List
keyboardShouldPersistTaps="handled"
contentContainerStyle={[a.pb_4xl, flatten(contentContainerStyle)]}
ListFooterComponent={
<View style={{height: insets.bottom + a.pt_5xl.paddingTop}} />
}
ref={ref}
{...props}
style={[
a.flex_1,
a.p_xl,
a.pt_0,
a.h_full,
{
marginTop: 40,
},
flatten(style),
]}
style={style}
/>
)
})
Expand Down
1 change: 1 addition & 0 deletions src/components/Dialog/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export type DialogControlProps = DialogControlRefProps & {

export type DialogContextProps = {
close: DialogControlProps['close']
insideDialog: boolean
}

export type DialogControlOpenOptions = {
Expand Down
46 changes: 43 additions & 3 deletions src/components/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {shouldClickOpenNewTab} from '#/platform/urls'
import {useModalControls} from '#/state/modals'
import {useOpenLink} from '#/state/preferences/in-app-browser'
import {atoms as a, flatten, TextStyleProp, useTheme, web} from '#/alf'
import {BottomSheetButton} from '#/components/BottomSheetButton'
import {Button, ButtonProps} from '#/components/Button'
import {useInteractionState} from '#/components/hooks/useInteractionState'
import {Text, TextProps} from '#/components/Typography'
Expand Down Expand Up @@ -103,17 +104,17 @@ export function useLink({
linkRequiresWarning(href, displayText),
)

if (requiresWarning) {
if (isWeb) {
e.preventDefault()
}

if (requiresWarning) {
openModal({
name: 'link-warning',
text: displayText,
href: href,
})
} else {
e.preventDefault()

if (isExternal) {
openLink(href)
} else {
Expand Down Expand Up @@ -241,6 +242,45 @@ export function Link({
)
}

export function BottomSheetLink({
children,
to,
action = 'push',
onPress: outerOnPress,
download,
...rest
}: LinkProps) {
const {href, isExternal, onPress} = useLink({
to,
displayText: typeof children === 'string' ? children : '',
action,
onPress: outerOnPress,
})

return (
<BottomSheetButton
{...rest}
style={[a.justify_start, flatten(rest.style)]}
role="link"
accessibilityRole="link"
href={href}
onPress={download ? undefined : onPress}
{...web({
hrefAttrs: {
target: download ? undefined : isExternal ? 'blank' : undefined,
rel: isExternal ? 'noopener noreferrer' : undefined,
download,
},
dataSet: {
// no underline, only `InlineLink` has underlines
noUnderline: '1',
},
})}>
{children}
</BottomSheetButton>
)
}

export type InlineLinkProps = React.PropsWithChildren<
BaseLinkProps & TextStyleProp & Pick<TextProps, 'selectable'>
> &
Expand Down
6 changes: 3 additions & 3 deletions src/components/Menu/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react'
import {StyleProp, View, ViewStyle} from 'react-native'
import {BlueskyBottomSheetPressable as Pressable} from '@haileyok/bluesky-bottom-sheet'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import flattenReactChildren from 'react-keyed-flatten-children'
Expand All @@ -19,6 +18,7 @@ import {
ItemTextProps,
TriggerProps,
} from '#/components/Menu/types'
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'
import {Text} from '#/components/Typography'

export {
Expand Down Expand Up @@ -117,7 +117,7 @@ export function Item({children, label, style, onPress, ...rest}: ItemProps) {
} = useInteractionState()

return (
<Pressable
<NormalizedRNGHPressable
{...rest}
accessibilityHint=""
accessibilityLabel={label}
Expand Down Expand Up @@ -151,7 +151,7 @@ export function Item({children, label, style, onPress, ...rest}: ItemProps) {
<ItemContext.Provider value={{disabled: Boolean(rest.disabled)}}>
{children}
</ItemContext.Provider>
</Pressable>
</NormalizedRNGHPressable>
)
}

Expand Down
Loading