Skip to content

Commit

Permalink
[Sheets] [Pt. 7] Part seven rework, much simplier! (#5582)
Browse files Browse the repository at this point in the history
  • Loading branch information
haileyok authored Oct 3, 2024
1 parent 0ed5d48 commit ecf7215
Show file tree
Hide file tree
Showing 15 changed files with 341 additions and 43 deletions.
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
2 changes: 1 addition & 1 deletion src/components/Dialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,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
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
6 changes: 2 additions & 4 deletions src/components/Menu/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import {
GestureResponderEvent,
PressableProps,
} from 'react-native'
import {PressableEvent} from 'react-native-gesture-handler/lib/typescript/components/Pressable/PressableProps'
import {BueskyBottomSheetPressableProps} from '@haileyok/bluesky-bottom-sheet'

import {TextStyleProp, ViewStyleProp} from '#/alf'
import * as Dialog from '#/components/Dialog'
Expand Down Expand Up @@ -89,10 +87,10 @@ export type TriggerChildProps =
}

export type ItemProps = React.PropsWithChildren<
Omit<BueskyBottomSheetPressableProps, 'style'> &
Omit<PressableProps, 'style'> &
ViewStyleProp & {
label: string
onPress: (e: PressableEvent | GestureResponderEvent) => void
onPress: (e: GestureResponderEvent) => void
}
>

Expand Down
Loading

0 comments on commit ecf7215

Please sign in to comment.