Merge branch 'hailey/dialogs-pt7-rework' into hailey/dialogs-pt8
This commit is contained in:
@@ -1,110 +1,12 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {AccessibilityProps, ViewStyle} from 'react-native'
|
|
||||||
import {PressableEvent} from 'react-native-gesture-handler/lib/typescript/components/Pressable/PressableProps'
|
|
||||||
import {
|
|
||||||
BlueskyBottomSheetPressable,
|
|
||||||
BlueskyBottomSheetPressableProps,
|
|
||||||
} from '@haileyok/bluesky-bottom-sheet'
|
|
||||||
|
|
||||||
import {atoms as a} from '#/alf'
|
import {Button, ButtonProps} from '#/components/Button'
|
||||||
import {
|
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'
|
||||||
ButtonContext,
|
|
||||||
useSharedButtonStyles,
|
|
||||||
VariantProps,
|
|
||||||
} from '#/components/Button'
|
|
||||||
|
|
||||||
export function BottomSheetButton({
|
|
||||||
children,
|
|
||||||
label,
|
|
||||||
color,
|
|
||||||
variant,
|
|
||||||
shape = 'default',
|
|
||||||
size,
|
|
||||||
disabled,
|
|
||||||
style,
|
|
||||||
...rest
|
|
||||||
}: BlueskyBottomSheetPressableProps &
|
|
||||||
AccessibilityProps &
|
|
||||||
VariantProps & {
|
|
||||||
/**
|
|
||||||
* For a11y, try to make this descriptive and clear
|
|
||||||
*/
|
|
||||||
label: string
|
|
||||||
}) {
|
|
||||||
const [state, setState] = React.useState({
|
|
||||||
pressed: false,
|
|
||||||
hovered: false,
|
|
||||||
focused: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
const onPressInOuter = rest.onPressIn
|
|
||||||
const onPressIn = React.useCallback(
|
|
||||||
(e: PressableEvent) => {
|
|
||||||
setState(s => ({
|
|
||||||
...s,
|
|
||||||
pressed: true,
|
|
||||||
}))
|
|
||||||
onPressInOuter?.(e)
|
|
||||||
},
|
|
||||||
[setState, onPressInOuter],
|
|
||||||
)
|
|
||||||
const onPressOutOuter = rest.onPressOut
|
|
||||||
const onPressOut = React.useCallback(
|
|
||||||
(e: PressableEvent) => {
|
|
||||||
setState(s => ({
|
|
||||||
...s,
|
|
||||||
pressed: false,
|
|
||||||
}))
|
|
||||||
onPressOutOuter?.(e)
|
|
||||||
},
|
|
||||||
[setState, onPressOutOuter],
|
|
||||||
)
|
|
||||||
|
|
||||||
const {baseStyles, hoverStyles} = useSharedButtonStyles({
|
|
||||||
/**
|
|
||||||
* For a11y, try to make this descriptive and clear
|
|
||||||
*/
|
|
||||||
color,
|
|
||||||
variant,
|
|
||||||
shape,
|
|
||||||
size,
|
|
||||||
disabled,
|
|
||||||
})
|
|
||||||
|
|
||||||
const context = React.useMemo<ButtonContext>(
|
|
||||||
() => ({
|
|
||||||
...state,
|
|
||||||
variant,
|
|
||||||
color,
|
|
||||||
size,
|
|
||||||
disabled: disabled || false,
|
|
||||||
}),
|
|
||||||
[state, variant, color, size, disabled],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
export function BottomSheetButton({children, ...rest}: ButtonProps) {
|
||||||
return (
|
return (
|
||||||
<BlueskyBottomSheetPressable
|
<Button {...rest} Component={NormalizedRNGHPressable}>
|
||||||
style={[
|
{children}
|
||||||
a.flex_row,
|
</Button>
|
||||||
a.align_center,
|
|
||||||
a.justify_center,
|
|
||||||
baseStyles,
|
|
||||||
style as ViewStyle,
|
|
||||||
...(state.hovered || state.pressed ? [hoverStyles] : []),
|
|
||||||
]}
|
|
||||||
aria-label={label}
|
|
||||||
aria-pressed={state.pressed}
|
|
||||||
accessibilityLabel={label}
|
|
||||||
accessibilityHint={undefined}
|
|
||||||
accessibilityState={{
|
|
||||||
disabled: disabled || false,
|
|
||||||
}}
|
|
||||||
onPressIn={onPressIn}
|
|
||||||
onPressOut={onPressOut}
|
|
||||||
{...rest}>
|
|
||||||
<ButtonContext.Provider value={context}>
|
|
||||||
{typeof children === 'function' ? children(context) : children}
|
|
||||||
</ButtonContext.Provider>
|
|
||||||
</BlueskyBottomSheetPressable>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {BlueskyBottomSheetPressable} from '@haileyok/bluesky-bottom-sheet'
|
|
||||||
import {StackActions, useNavigation} from '@react-navigation/native'
|
import {StackActions, useNavigation} from '@react-navigation/native'
|
||||||
|
|
||||||
import {NavigationProp} from '#/lib/routes/types'
|
import {NavigationProp} from '#/lib/routes/types'
|
||||||
@@ -7,6 +6,7 @@ import {flatten, useTheme} from '#/alf'
|
|||||||
import {useDialogContext} from '#/components/Dialog'
|
import {useDialogContext} from '#/components/Dialog'
|
||||||
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
||||||
import {InlineLinkProps, useLink} from '#/components/Link'
|
import {InlineLinkProps, useLink} from '#/components/Link'
|
||||||
|
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {router} from '#/routes'
|
import {router} from '#/routes'
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ export function BottomSheetInlineLinkText({
|
|||||||
|
|
||||||
// eslint-disable-next-line bsky-internal/avoid-unwrapped-text
|
// eslint-disable-next-line bsky-internal/avoid-unwrapped-text
|
||||||
return (
|
return (
|
||||||
<BlueskyBottomSheetPressable
|
<NormalizedRNGHPressable
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
onLongPress={onLongPress}
|
onLongPress={onLongPress}
|
||||||
onPressIn={onPressIn}
|
onPressIn={onPressIn}
|
||||||
@@ -87,6 +87,6 @@ export function BottomSheetInlineLinkText({
|
|||||||
]}>
|
]}>
|
||||||
{children}
|
{children}
|
||||||
</Text>
|
</Text>
|
||||||
</BlueskyBottomSheetPressable>
|
</NormalizedRNGHPressable>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+240
-245
@@ -15,7 +15,9 @@ import {
|
|||||||
import {LinearGradient} from 'expo-linear-gradient'
|
import {LinearGradient} from 'expo-linear-gradient'
|
||||||
|
|
||||||
import {atoms as a, flatten, select, tokens, useTheme, web} from '#/alf'
|
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 {Props as SVGIconProps} from '#/components/icons/common'
|
||||||
|
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
export type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'gradient'
|
export type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'gradient'
|
||||||
@@ -87,10 +89,10 @@ export type ButtonProps = Pick<
|
|||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
hoverStyle?: StyleProp<ViewStyle>
|
hoverStyle?: StyleProp<ViewStyle>
|
||||||
children: NonTextElements | ((context: ButtonContext) => NonTextElements)
|
children: NonTextElements | ((context: ButtonContext) => NonTextElements)
|
||||||
|
Component?: React.ComponentType<PressableProps>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ButtonTextProps = TextProps &
|
export type ButtonTextProps = TextProps & VariantProps & {disabled?: boolean}
|
||||||
VariantProps & {disabled?: boolean | null}
|
|
||||||
|
|
||||||
const Context = React.createContext<VariantProps & ButtonState>({
|
const Context = React.createContext<VariantProps & ButtonState>({
|
||||||
hovered: false,
|
hovered: false,
|
||||||
@@ -98,7 +100,6 @@ const Context = React.createContext<VariantProps & ButtonState>({
|
|||||||
pressed: false,
|
pressed: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
})
|
})
|
||||||
export const ButtonContext = Context
|
|
||||||
|
|
||||||
export function useButtonContext() {
|
export function useButtonContext() {
|
||||||
return React.useContext(Context)
|
return React.useContext(Context)
|
||||||
@@ -116,10 +117,23 @@ export const Button = React.forwardRef<View, ButtonProps>(
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
style,
|
style,
|
||||||
hoverStyle: hoverStyleProp,
|
hoverStyle: hoverStyleProp,
|
||||||
|
Component,
|
||||||
...rest
|
...rest
|
||||||
},
|
},
|
||||||
ref,
|
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({
|
const [state, setState] = React.useState({
|
||||||
pressed: false,
|
pressed: false,
|
||||||
hovered: false,
|
hovered: false,
|
||||||
@@ -183,13 +197,226 @@ export const Button = React.forwardRef<View, ButtonProps>(
|
|||||||
}))
|
}))
|
||||||
}, [setState])
|
}, [setState])
|
||||||
|
|
||||||
const {baseStyles, hoverStyles} = useSharedButtonStyles({
|
const {baseStyles, hoverStyles} = React.useMemo(() => {
|
||||||
color,
|
const baseStyles: ViewStyle[] = []
|
||||||
variant,
|
const hoverStyles: ViewStyle[] = []
|
||||||
disabled,
|
|
||||||
shape,
|
if (color === 'primary') {
|
||||||
size,
|
if (variant === 'solid') {
|
||||||
})
|
if (!disabled) {
|
||||||
|
baseStyles.push({
|
||||||
|
backgroundColor: t.palette.primary_500,
|
||||||
|
})
|
||||||
|
hoverStyles.push({
|
||||||
|
backgroundColor: t.palette.primary_600,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
baseStyles.push({
|
||||||
|
backgroundColor: select(t.name, {
|
||||||
|
light: t.palette.primary_700,
|
||||||
|
dim: t.palette.primary_300,
|
||||||
|
dark: t.palette.primary_300,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (variant === 'outline') {
|
||||||
|
baseStyles.push(a.border, t.atoms.bg, {
|
||||||
|
borderWidth: 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!disabled) {
|
||||||
|
baseStyles.push(a.border, {
|
||||||
|
borderColor: t.palette.primary_500,
|
||||||
|
})
|
||||||
|
hoverStyles.push(a.border, {
|
||||||
|
backgroundColor: t.palette.primary_50,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
baseStyles.push(a.border, {
|
||||||
|
borderColor: t.palette.primary_200,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (variant === 'ghost') {
|
||||||
|
if (!disabled) {
|
||||||
|
baseStyles.push(t.atoms.bg)
|
||||||
|
hoverStyles.push({
|
||||||
|
backgroundColor: t.palette.primary_100,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (color === 'secondary') {
|
||||||
|
if (variant === 'solid') {
|
||||||
|
if (!disabled) {
|
||||||
|
baseStyles.push(t.atoms.bg_contrast_25)
|
||||||
|
hoverStyles.push(t.atoms.bg_contrast_50)
|
||||||
|
} else {
|
||||||
|
baseStyles.push(t.atoms.bg_contrast_100)
|
||||||
|
}
|
||||||
|
} else if (variant === 'outline') {
|
||||||
|
baseStyles.push(a.border, t.atoms.bg, {
|
||||||
|
borderWidth: 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!disabled) {
|
||||||
|
baseStyles.push(a.border, {
|
||||||
|
borderColor: t.palette.contrast_300,
|
||||||
|
})
|
||||||
|
hoverStyles.push(t.atoms.bg_contrast_50)
|
||||||
|
} else {
|
||||||
|
baseStyles.push(a.border, {
|
||||||
|
borderColor: t.palette.contrast_200,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (variant === 'ghost') {
|
||||||
|
if (!disabled) {
|
||||||
|
baseStyles.push(t.atoms.bg)
|
||||||
|
hoverStyles.push({
|
||||||
|
backgroundColor: t.palette.contrast_25,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (color === 'secondary_inverted') {
|
||||||
|
if (variant === 'solid') {
|
||||||
|
if (!disabled) {
|
||||||
|
baseStyles.push({
|
||||||
|
backgroundColor: t.palette.contrast_900,
|
||||||
|
})
|
||||||
|
hoverStyles.push({
|
||||||
|
backgroundColor: t.palette.contrast_950,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
baseStyles.push({
|
||||||
|
backgroundColor: t.palette.contrast_600,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (variant === 'outline') {
|
||||||
|
baseStyles.push(a.border, t.atoms.bg, {
|
||||||
|
borderWidth: 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!disabled) {
|
||||||
|
baseStyles.push(a.border, {
|
||||||
|
borderColor: t.palette.contrast_300,
|
||||||
|
})
|
||||||
|
hoverStyles.push(t.atoms.bg_contrast_50)
|
||||||
|
} else {
|
||||||
|
baseStyles.push(a.border, {
|
||||||
|
borderColor: t.palette.contrast_200,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (variant === 'ghost') {
|
||||||
|
if (!disabled) {
|
||||||
|
baseStyles.push(t.atoms.bg)
|
||||||
|
hoverStyles.push({
|
||||||
|
backgroundColor: t.palette.contrast_25,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (color === 'negative') {
|
||||||
|
if (variant === 'solid') {
|
||||||
|
if (!disabled) {
|
||||||
|
baseStyles.push({
|
||||||
|
backgroundColor: t.palette.negative_500,
|
||||||
|
})
|
||||||
|
hoverStyles.push({
|
||||||
|
backgroundColor: t.palette.negative_600,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
baseStyles.push({
|
||||||
|
backgroundColor: select(t.name, {
|
||||||
|
light: t.palette.negative_700,
|
||||||
|
dim: t.palette.negative_300,
|
||||||
|
dark: t.palette.negative_300,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (variant === 'outline') {
|
||||||
|
baseStyles.push(a.border, t.atoms.bg, {
|
||||||
|
borderWidth: 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!disabled) {
|
||||||
|
baseStyles.push(a.border, {
|
||||||
|
borderColor: t.palette.negative_500,
|
||||||
|
})
|
||||||
|
hoverStyles.push(a.border, {
|
||||||
|
backgroundColor: t.palette.negative_50,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
baseStyles.push(a.border, {
|
||||||
|
borderColor: t.palette.negative_200,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (variant === 'ghost') {
|
||||||
|
if (!disabled) {
|
||||||
|
baseStyles.push(t.atoms.bg)
|
||||||
|
hoverStyles.push({
|
||||||
|
backgroundColor: t.palette.negative_100,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shape === 'default') {
|
||||||
|
if (size === 'large') {
|
||||||
|
baseStyles.push({
|
||||||
|
paddingVertical: 13,
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
borderRadius: 8,
|
||||||
|
gap: 8,
|
||||||
|
})
|
||||||
|
} else if (size === 'small') {
|
||||||
|
baseStyles.push({
|
||||||
|
paddingVertical: 8,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
borderRadius: 6,
|
||||||
|
gap: 6,
|
||||||
|
})
|
||||||
|
} else if (size === 'tiny') {
|
||||||
|
baseStyles.push({
|
||||||
|
paddingVertical: 4,
|
||||||
|
paddingHorizontal: 8,
|
||||||
|
borderRadius: 4,
|
||||||
|
gap: 4,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (shape === 'round' || shape === 'square') {
|
||||||
|
if (size === 'large') {
|
||||||
|
if (shape === 'round') {
|
||||||
|
baseStyles.push({height: 46, width: 46})
|
||||||
|
} else {
|
||||||
|
baseStyles.push({height: 44, width: 44})
|
||||||
|
}
|
||||||
|
} else if (size === 'small') {
|
||||||
|
if (shape === 'round') {
|
||||||
|
baseStyles.push({height: 36, width: 36})
|
||||||
|
} else {
|
||||||
|
baseStyles.push({height: 34, width: 34})
|
||||||
|
}
|
||||||
|
} else if (size === 'tiny') {
|
||||||
|
if (shape === 'round') {
|
||||||
|
baseStyles.push({height: 22, width: 22})
|
||||||
|
} else {
|
||||||
|
baseStyles.push({height: 21, width: 21})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shape === 'round') {
|
||||||
|
baseStyles.push(a.rounded_full)
|
||||||
|
} else if (shape === 'square') {
|
||||||
|
if (size === 'tiny') {
|
||||||
|
baseStyles.push(a.rounded_xs)
|
||||||
|
} else {
|
||||||
|
baseStyles.push(a.rounded_sm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseStyles,
|
||||||
|
hoverStyles,
|
||||||
|
}
|
||||||
|
}, [t, variant, color, size, shape, disabled])
|
||||||
|
|
||||||
const {gradientColors, gradientHoverColors, gradientLocations} =
|
const {gradientColors, gradientHoverColors, gradientLocations} =
|
||||||
React.useMemo(() => {
|
React.useMemo(() => {
|
||||||
@@ -237,10 +464,11 @@ export const Button = React.forwardRef<View, ButtonProps>(
|
|||||||
const flattenedBaseStyles = flatten([baseStyles, style])
|
const flattenedBaseStyles = flatten([baseStyles, style])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Component
|
||||||
role="button"
|
role="button"
|
||||||
accessibilityHint={undefined} // optional
|
accessibilityHint={undefined} // optional
|
||||||
{...rest}
|
{...rest}
|
||||||
|
// @ts-expect-error ref type
|
||||||
ref={ref}
|
ref={ref}
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
aria-pressed={state.pressed}
|
aria-pressed={state.pressed}
|
||||||
@@ -288,245 +516,12 @@ export const Button = React.forwardRef<View, ButtonProps>(
|
|||||||
<Context.Provider value={context}>
|
<Context.Provider value={context}>
|
||||||
{typeof children === 'function' ? children(context) : children}
|
{typeof children === 'function' ? children(context) : children}
|
||||||
</Context.Provider>
|
</Context.Provider>
|
||||||
</Pressable>
|
</Component>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
Button.displayName = 'Button'
|
Button.displayName = 'Button'
|
||||||
|
|
||||||
export function useSharedButtonStyles({
|
|
||||||
color,
|
|
||||||
variant,
|
|
||||||
disabled,
|
|
||||||
shape,
|
|
||||||
size,
|
|
||||||
}: VariantProps & {disabled?: boolean | null}) {
|
|
||||||
const t = useTheme()
|
|
||||||
|
|
||||||
const {baseStyles, hoverStyles} = React.useMemo(() => {
|
|
||||||
const baseStyles: ViewStyle[] = []
|
|
||||||
const hoverStyles: ViewStyle[] = []
|
|
||||||
|
|
||||||
if (color === 'primary') {
|
|
||||||
if (variant === 'solid') {
|
|
||||||
if (!disabled) {
|
|
||||||
baseStyles.push({
|
|
||||||
backgroundColor: t.palette.primary_500,
|
|
||||||
})
|
|
||||||
hoverStyles.push({
|
|
||||||
backgroundColor: t.palette.primary_600,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
baseStyles.push({
|
|
||||||
backgroundColor: select(t.name, {
|
|
||||||
light: t.palette.primary_700,
|
|
||||||
dim: t.palette.primary_300,
|
|
||||||
dark: t.palette.primary_300,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (variant === 'outline') {
|
|
||||||
baseStyles.push(a.border, t.atoms.bg, {
|
|
||||||
borderWidth: 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!disabled) {
|
|
||||||
baseStyles.push(a.border, {
|
|
||||||
borderColor: t.palette.primary_500,
|
|
||||||
})
|
|
||||||
hoverStyles.push(a.border, {
|
|
||||||
backgroundColor: t.palette.primary_50,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
baseStyles.push(a.border, {
|
|
||||||
borderColor: t.palette.primary_200,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (variant === 'ghost') {
|
|
||||||
if (!disabled) {
|
|
||||||
baseStyles.push(t.atoms.bg)
|
|
||||||
hoverStyles.push({
|
|
||||||
backgroundColor: t.palette.primary_100,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (color === 'secondary') {
|
|
||||||
if (variant === 'solid') {
|
|
||||||
if (!disabled) {
|
|
||||||
baseStyles.push(t.atoms.bg_contrast_25)
|
|
||||||
hoverStyles.push(t.atoms.bg_contrast_50)
|
|
||||||
} else {
|
|
||||||
baseStyles.push(t.atoms.bg_contrast_100)
|
|
||||||
}
|
|
||||||
} else if (variant === 'outline') {
|
|
||||||
baseStyles.push(a.border, t.atoms.bg, {
|
|
||||||
borderWidth: 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!disabled) {
|
|
||||||
baseStyles.push(a.border, {
|
|
||||||
borderColor: t.palette.contrast_300,
|
|
||||||
})
|
|
||||||
hoverStyles.push(t.atoms.bg_contrast_50)
|
|
||||||
} else {
|
|
||||||
baseStyles.push(a.border, {
|
|
||||||
borderColor: t.palette.contrast_200,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (variant === 'ghost') {
|
|
||||||
if (!disabled) {
|
|
||||||
baseStyles.push(t.atoms.bg)
|
|
||||||
hoverStyles.push({
|
|
||||||
backgroundColor: t.palette.contrast_25,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (color === 'secondary_inverted') {
|
|
||||||
if (variant === 'solid') {
|
|
||||||
if (!disabled) {
|
|
||||||
baseStyles.push({
|
|
||||||
backgroundColor: t.palette.contrast_900,
|
|
||||||
})
|
|
||||||
hoverStyles.push({
|
|
||||||
backgroundColor: t.palette.contrast_950,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
baseStyles.push({
|
|
||||||
backgroundColor: t.palette.contrast_600,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (variant === 'outline') {
|
|
||||||
baseStyles.push(a.border, t.atoms.bg, {
|
|
||||||
borderWidth: 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!disabled) {
|
|
||||||
baseStyles.push(a.border, {
|
|
||||||
borderColor: t.palette.contrast_300,
|
|
||||||
})
|
|
||||||
hoverStyles.push(t.atoms.bg_contrast_50)
|
|
||||||
} else {
|
|
||||||
baseStyles.push(a.border, {
|
|
||||||
borderColor: t.palette.contrast_200,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (variant === 'ghost') {
|
|
||||||
if (!disabled) {
|
|
||||||
baseStyles.push(t.atoms.bg)
|
|
||||||
hoverStyles.push({
|
|
||||||
backgroundColor: t.palette.contrast_25,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (color === 'negative') {
|
|
||||||
if (variant === 'solid') {
|
|
||||||
if (!disabled) {
|
|
||||||
baseStyles.push({
|
|
||||||
backgroundColor: t.palette.negative_500,
|
|
||||||
})
|
|
||||||
hoverStyles.push({
|
|
||||||
backgroundColor: t.palette.negative_600,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
baseStyles.push({
|
|
||||||
backgroundColor: select(t.name, {
|
|
||||||
light: t.palette.negative_700,
|
|
||||||
dim: t.palette.negative_300,
|
|
||||||
dark: t.palette.negative_300,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (variant === 'outline') {
|
|
||||||
baseStyles.push(a.border, t.atoms.bg, {
|
|
||||||
borderWidth: 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!disabled) {
|
|
||||||
baseStyles.push(a.border, {
|
|
||||||
borderColor: t.palette.negative_500,
|
|
||||||
})
|
|
||||||
hoverStyles.push(a.border, {
|
|
||||||
backgroundColor: t.palette.negative_50,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
baseStyles.push(a.border, {
|
|
||||||
borderColor: t.palette.negative_200,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (variant === 'ghost') {
|
|
||||||
if (!disabled) {
|
|
||||||
baseStyles.push(t.atoms.bg)
|
|
||||||
hoverStyles.push({
|
|
||||||
backgroundColor: t.palette.negative_100,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shape === 'default') {
|
|
||||||
if (size === 'large') {
|
|
||||||
baseStyles.push({
|
|
||||||
paddingVertical: 13,
|
|
||||||
paddingHorizontal: 20,
|
|
||||||
borderRadius: 8,
|
|
||||||
gap: 8,
|
|
||||||
})
|
|
||||||
} else if (size === 'small') {
|
|
||||||
baseStyles.push({
|
|
||||||
paddingVertical: 8,
|
|
||||||
paddingHorizontal: 12,
|
|
||||||
borderRadius: 6,
|
|
||||||
gap: 6,
|
|
||||||
})
|
|
||||||
} else if (size === 'tiny') {
|
|
||||||
baseStyles.push({
|
|
||||||
paddingVertical: 4,
|
|
||||||
paddingHorizontal: 8,
|
|
||||||
borderRadius: 4,
|
|
||||||
gap: 4,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (shape === 'round' || shape === 'square') {
|
|
||||||
if (size === 'large') {
|
|
||||||
if (shape === 'round') {
|
|
||||||
baseStyles.push({height: 46, width: 46})
|
|
||||||
} else {
|
|
||||||
baseStyles.push({height: 44, width: 44})
|
|
||||||
}
|
|
||||||
} else if (size === 'small') {
|
|
||||||
if (shape === 'round') {
|
|
||||||
baseStyles.push({height: 36, width: 36})
|
|
||||||
} else {
|
|
||||||
baseStyles.push({height: 34, width: 34})
|
|
||||||
}
|
|
||||||
} else if (size === 'tiny') {
|
|
||||||
if (shape === 'round') {
|
|
||||||
baseStyles.push({height: 22, width: 22})
|
|
||||||
} else {
|
|
||||||
baseStyles.push({height: 21, width: 21})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shape === 'round') {
|
|
||||||
baseStyles.push(a.rounded_full)
|
|
||||||
} else if (shape === 'square') {
|
|
||||||
if (size === 'tiny') {
|
|
||||||
baseStyles.push(a.rounded_xs)
|
|
||||||
} else {
|
|
||||||
baseStyles.push(a.rounded_sm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
baseStyles,
|
|
||||||
hoverStyles,
|
|
||||||
}
|
|
||||||
}, [t, variant, color, size, shape, disabled])
|
|
||||||
|
|
||||||
return {baseStyles, hoverStyles}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useSharedButtonTextStyles() {
|
export function useSharedButtonTextStyles() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {color, variant, disabled, size} = useButtonContext()
|
const {color, variant, disabled, size} = useButtonContext()
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
|
|
||||||
export const Context = React.createContext<DialogContextProps>({
|
export const Context = React.createContext<DialogContextProps>({
|
||||||
close: () => {},
|
close: () => {},
|
||||||
|
insideDialog: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function useDialogContext() {
|
export function useDialogContext() {
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ export function OuterWithoutPortal({
|
|||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
const closeCallbacks = React.useRef<(() => void)[]>([])
|
const closeCallbacks = React.useRef<(() => void)[]>([])
|
||||||
const {setDialogIsOpen} = useDialogStateControlContext()
|
const {setDialogIsOpen} = useDialogStateControlContext()
|
||||||
// @TODO DIALOG REFACTOR - can i get rid of this? seems pointless tbh
|
|
||||||
|
|
||||||
const callQueuedCallbacks = React.useCallback(() => {
|
const callQueuedCallbacks = React.useCallback(() => {
|
||||||
for (const cb of closeCallbacks.current) {
|
for (const cb of closeCallbacks.current) {
|
||||||
@@ -104,21 +103,13 @@ export function OuterWithoutPortal({
|
|||||||
[open, close],
|
[open, close],
|
||||||
)
|
)
|
||||||
|
|
||||||
// @TODO DIALOG REFACTOR - what is this? rm i think?
|
const context = React.useMemo(() => ({close, insideDialog: true}), [close])
|
||||||
// React.useEffect(() => {
|
|
||||||
// return () => {
|
|
||||||
// setDialogIsOpen(control.id, false)
|
|
||||||
// }
|
|
||||||
// }, [control.id, setDialogIsOpen])
|
|
||||||
|
|
||||||
const context = React.useMemo(() => ({close}), [close])
|
|
||||||
|
|
||||||
const Wrapper = isIOS ? View : GestureHandlerRootView
|
const Wrapper = isIOS ? View : GestureHandlerRootView
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Context.Provider value={context}>
|
<Context.Provider value={context}>
|
||||||
<BlueskyBottomSheetView
|
<BlueskyBottomSheetView
|
||||||
// handleIndicatorStyle={{backgroundColor: t.palette.primary_500}} // @TODO DIALOG REFACTOR need to add this to lib!*/
|
|
||||||
ref={ref}
|
ref={ref}
|
||||||
topInset={30}
|
topInset={30}
|
||||||
bottomInset={insets.bottom}
|
bottomInset={insets.bottom}
|
||||||
|
|||||||
@@ -229,10 +229,6 @@ export const InnerFlatList = React.forwardRef<
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export function Handle() {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Close() {
|
export function Close() {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {close} = React.useContext(Context)
|
const {close} = React.useContext(Context)
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export type DialogControlProps = DialogControlRefProps & {
|
|||||||
|
|
||||||
export type DialogContextProps = {
|
export type DialogContextProps = {
|
||||||
close: DialogControlProps['close']
|
close: DialogControlProps['close']
|
||||||
|
insideDialog: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DialogControlOpenOptions = {
|
export type DialogControlOpenOptions = {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {StyleProp, View, ViewStyle} from 'react-native'
|
import {StyleProp, View, ViewStyle} from 'react-native'
|
||||||
import {BlueskyBottomSheetPressable as Pressable} from '@haileyok/bluesky-bottom-sheet'
|
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import flattenReactChildren from 'react-keyed-flatten-children'
|
import flattenReactChildren from 'react-keyed-flatten-children'
|
||||||
@@ -19,6 +18,7 @@ import {
|
|||||||
ItemTextProps,
|
ItemTextProps,
|
||||||
TriggerProps,
|
TriggerProps,
|
||||||
} from '#/components/Menu/types'
|
} from '#/components/Menu/types'
|
||||||
|
import {NormalizedRNGHPressable} from '#/components/NormalizedRNGHPressable'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -117,7 +117,7 @@ export function Item({children, label, style, onPress, ...rest}: ItemProps) {
|
|||||||
} = useInteractionState()
|
} = useInteractionState()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<NormalizedRNGHPressable
|
||||||
{...rest}
|
{...rest}
|
||||||
accessibilityHint=""
|
accessibilityHint=""
|
||||||
accessibilityLabel={label}
|
accessibilityLabel={label}
|
||||||
@@ -151,7 +151,7 @@ export function Item({children, label, style, onPress, ...rest}: ItemProps) {
|
|||||||
<ItemContext.Provider value={{disabled: Boolean(rest.disabled)}}>
|
<ItemContext.Provider value={{disabled: Boolean(rest.disabled)}}>
|
||||||
{children}
|
{children}
|
||||||
</ItemContext.Provider>
|
</ItemContext.Provider>
|
||||||
</Pressable>
|
</NormalizedRNGHPressable>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import {
|
|||||||
GestureResponderEvent,
|
GestureResponderEvent,
|
||||||
PressableProps,
|
PressableProps,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {PressableEvent} from 'react-native-gesture-handler/lib/typescript/components/Pressable/PressableProps'
|
|
||||||
import {BlueskyBottomSheetPressableProps} from '@haileyok/bluesky-bottom-sheet'
|
|
||||||
|
|
||||||
import {TextStyleProp, ViewStyleProp} from '#/alf'
|
import {TextStyleProp, ViewStyleProp} from '#/alf'
|
||||||
import * as Dialog from '#/components/Dialog'
|
import * as Dialog from '#/components/Dialog'
|
||||||
@@ -89,10 +87,10 @@ export type TriggerChildProps =
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ItemProps = React.PropsWithChildren<
|
export type ItemProps = React.PropsWithChildren<
|
||||||
Omit<BlueskyBottomSheetPressableProps, 'style'> &
|
Omit<PressableProps, 'style'> &
|
||||||
ViewStyleProp & {
|
ViewStyleProp & {
|
||||||
label: string
|
label: string
|
||||||
onPress: (e: PressableEvent | GestureResponderEvent) => void
|
onPress: (e: GestureResponderEvent) => void
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {
|
||||||
|
GestureResponderEvent,
|
||||||
|
MeasureOnSuccessCallback,
|
||||||
|
NativeMouseEvent,
|
||||||
|
NativeSyntheticEvent,
|
||||||
|
PressableProps,
|
||||||
|
} from 'react-native'
|
||||||
|
import {Pressable as BSPressable} from 'react-native-gesture-handler'
|
||||||
|
import {PressableEvent} from 'react-native-gesture-handler/lib/typescript/components/Pressable/PressableProps'
|
||||||
|
|
||||||
|
function pressableEventToGestureResponderEvent(
|
||||||
|
event: PressableEvent,
|
||||||
|
target: NormalizedRNGHPressable,
|
||||||
|
): GestureResponderEvent {
|
||||||
|
return {
|
||||||
|
nativeEvent: {
|
||||||
|
...event.nativeEvent,
|
||||||
|
touches: [],
|
||||||
|
changedTouches: [],
|
||||||
|
identifier: event.nativeEvent.identifier.toString(),
|
||||||
|
target: event.nativeEvent.target.toString(),
|
||||||
|
},
|
||||||
|
// @ts-expect-error
|
||||||
|
target: target,
|
||||||
|
// @ts-expect-error
|
||||||
|
currentTarget: target,
|
||||||
|
preventDefault() {},
|
||||||
|
stopPropagation() {},
|
||||||
|
cancelable: false,
|
||||||
|
defaultPrevented: false,
|
||||||
|
eventPhase: 0,
|
||||||
|
isTrusted: false,
|
||||||
|
bubbles: false,
|
||||||
|
timeStamp: event.nativeEvent.timestamp,
|
||||||
|
isDefaultPrevented(): boolean {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
isPropagationStopped(): boolean {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
persist() {},
|
||||||
|
type: 'press',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pressableEventToMouseEvent(
|
||||||
|
event: PressableEvent,
|
||||||
|
target: NormalizedRNGHPressable,
|
||||||
|
): MouseEvent & NativeSyntheticEvent<NativeMouseEvent> {
|
||||||
|
return {
|
||||||
|
...event.nativeEvent,
|
||||||
|
// @ts-expect-error
|
||||||
|
target: target,
|
||||||
|
// @ts-expect-error
|
||||||
|
currentTarget: target,
|
||||||
|
preventDefault() {},
|
||||||
|
stopPropagation() {},
|
||||||
|
cancelable: false,
|
||||||
|
defaultPrevented: false,
|
||||||
|
eventPhase: 0,
|
||||||
|
isTrusted: false,
|
||||||
|
bubbles: false,
|
||||||
|
timeStamp: event.nativeEvent.timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NormalizedRNGHPressable extends React.Component<PressableProps> {
|
||||||
|
static displayName = 'Pressable'
|
||||||
|
|
||||||
|
measure = (_: MeasureOnSuccessCallback) => {}
|
||||||
|
|
||||||
|
measureLayout = (_: number) => {}
|
||||||
|
|
||||||
|
measureInWindow = (
|
||||||
|
_: (x: number, y: number, width: number, height: number) => void,
|
||||||
|
) => {}
|
||||||
|
|
||||||
|
setNativeProps = (_: PressableProps) => {}
|
||||||
|
|
||||||
|
focus = () => {}
|
||||||
|
|
||||||
|
blur = () => {}
|
||||||
|
|
||||||
|
onPress = (event: PressableEvent) => {
|
||||||
|
if (!this.props.onPress) return
|
||||||
|
this.props.onPress(pressableEventToGestureResponderEvent(event, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
onLongPress = (event: PressableEvent) => {
|
||||||
|
if (!this.props.onLongPress) return
|
||||||
|
this.props.onLongPress(pressableEventToGestureResponderEvent(event, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
onPressIn = (event: PressableEvent) => {
|
||||||
|
if (!this.props.onPressIn) return
|
||||||
|
this.props.onPressIn(pressableEventToGestureResponderEvent(event, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
onPressOut = (event: PressableEvent) => {
|
||||||
|
if (!this.props.onPressOut) return
|
||||||
|
this.props.onPressOut(pressableEventToGestureResponderEvent(event, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
onHoverIn = (event: PressableEvent) => {
|
||||||
|
if (!this.props.onHoverIn) return
|
||||||
|
this.props.onHoverIn(pressableEventToMouseEvent(event, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
onHoverOut = (event: PressableEvent) => {
|
||||||
|
if (!this.props.onHoverOut) return
|
||||||
|
this.props.onHoverOut(pressableEventToMouseEvent(event, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<BSPressable
|
||||||
|
{...this.props}
|
||||||
|
onPress={this.onPress}
|
||||||
|
onLongPress={this.onLongPress}
|
||||||
|
onPressIn={this.onPressIn}
|
||||||
|
onPressOut={this.onPressOut}
|
||||||
|
onHoverIn={this.onHoverIn}
|
||||||
|
onHoverOut={this.onHoverOut}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import {Pressable as NormalizedRNGHPressable} from 'react-native'
|
||||||
|
|
||||||
|
export {NormalizedRNGHPressable}
|
||||||
Reference in New Issue
Block a user