Remove use of flatten where possible (#9325)

* remove use of flatten where possible

* restore flatten where it says it's needed

* missing utils alpha
This commit is contained in:
Samuel Newman
2025-11-04 15:43:08 +02:00
committed by GitHub
parent 0bcde99025
commit 1b0fbd503e
28 changed files with 67 additions and 97 deletions
+4 -6
View File
@@ -7,7 +7,6 @@ import {
Pressable,
type PressableProps,
type StyleProp,
StyleSheet,
type TargetedEvent,
type TextProps,
type TextStyle,
@@ -512,8 +511,6 @@ export const Button = React.forwardRef<View, ButtonProps>(
[state, variant, color, size, disabled],
)
const flattenedBaseStyles = flatten([baseStyles, style])
return (
<PressableComponent
role="button"
@@ -533,9 +530,10 @@ export const Button = React.forwardRef<View, ButtonProps>(
a.align_center,
a.justify_center,
a.curve_continuous,
flattenedBaseStyles,
baseStyles,
style,
...(state.hovered || state.pressed
? [hoverStyles, flatten(hoverStyleProp)]
? [hoverStyles, hoverStyleProp]
: []),
]}
onPressIn={onPressIn}
@@ -726,7 +724,7 @@ export function useSharedButtonTextStyles() {
baseStyles.push(a.text_xs, a.leading_snug, a.font_semi_bold)
}
return StyleSheet.flatten(baseStyles)
return flatten(baseStyles)
}, [t, variant, color, size, disabled])
}
+4 -4
View File
@@ -16,7 +16,7 @@ import {RemoveScrollBar} from 'react-remove-scroll-bar'
import {logger} from '#/logger'
import {useA11y} from '#/state/a11y'
import {useDialogStateControlContext} from '#/state/dialogs'
import {atoms as a, flatten, useBreakpoints, useTheme, web} from '#/alf'
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
import {Button, ButtonIcon} from '#/components/Button'
import {Context} from '#/components/Dialog/context'
import {
@@ -180,7 +180,7 @@ export function Inner({
onClick={stopPropagation}
onStartShouldSetResponder={_ => true}
onTouchEnd={stopPropagation}
style={flatten([
style={[
a.relative,
a.rounded_md,
a.w_full,
@@ -195,7 +195,7 @@ export function Inner({
},
!reduceMotionEnabled && a.zoom_fade_in,
style,
])}>
]}>
<DismissableLayer.DismissableLayer
onInteractOutside={preventDefault}
onFocusOutside={preventDefault}
@@ -244,7 +244,7 @@ export const InnerFlatList = React.forwardRef<
contentContainerStyle={[a.h_full, a.px_0, webInnerContentContainerStyle]}>
<FlatList
ref={ref}
style={[a.h_full, gtMobile ? a.px_2xl : a.px_xl, flatten(style)]}
style={[a.h_full, gtMobile ? a.px_2xl : a.px_xl, style]}
{...props}
/>
{footer}
+1 -1
View File
@@ -186,7 +186,7 @@ export function Description({
return rt
}, [description])
if (!rt) return null
return <RichText value={rt} style={[a.leading_snug]} disableLinks {...rest} />
return <RichText value={rt} disableLinks {...rest} />
}
export function DescriptionPlaceholder() {
+2 -11
View File
@@ -2,7 +2,6 @@ import {View} from 'react-native'
import {
atoms as a,
flatten,
type TextStyleProp,
useTheme,
type ViewStyleProp,
@@ -33,17 +32,9 @@ export function IconCircle({
height: size === 'lg' ? 52 : 64,
backgroundColor: t.palette.primary_50,
},
flatten(style),
style,
]}>
<Icon
size={size}
style={[
{
color: t.palette.primary_500,
},
flatten(iconStyle),
]}
/>
<Icon size={size} style={[{color: t.palette.primary_500}, iconStyle]} />
</View>
)
}
+1 -1
View File
@@ -55,7 +55,7 @@ export function Description({value, handle}: {value?: string; handle: string}) {
const {_} = useLingui()
return value ? (
<Text numberOfLines={2}>
<RichText value={value} style={[a.leading_snug]} />
<RichText value={value} />
</Text>
) : (
<Text emoji style={[a.leading_snug]}>
+1 -1
View File
@@ -296,7 +296,7 @@ export function Link({
return (
<Button
{...rest}
style={[a.justify_start, flatten(rest.style)]}
style={[a.justify_start, rest.style]}
role="link"
accessibilityRole="link"
href={href}
+2 -2
View File
@@ -5,7 +5,7 @@ import {useLingui} from '@lingui/react'
import {cleanError} from '#/lib/strings/errors'
import {CenteredView} from '#/view/com/util/Views'
import {atoms as a, flatten, useBreakpoints, useTheme} from '#/alf'
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import {Error} from '#/components/Error'
import {Loader} from '#/components/Loader'
@@ -43,7 +43,7 @@ export function ListFooter({
a.pb_lg,
t.atoms.border_contrast_low,
{height: height ?? 180, paddingTop: 30},
flatten(style),
style,
]}>
{isFetchingNextPage ? (
<Loader size="xl" />
+2 -7
View File
@@ -7,7 +7,7 @@ import Animated, {
withTiming,
} from 'react-native-reanimated'
import {atoms as a, flatten, useTheme} from '#/alf'
import {atoms as a, useTheme} from '#/alf'
import {type Props, useCommonSVGProps} from '#/components/icons/common'
import {Loader_Stroke2_Corner0_Rounded as Icon} from '#/components/icons/Loader'
@@ -37,12 +37,7 @@ export function Loader(props: Props) {
]}>
<Icon
{...props}
style={[
a.absolute,
a.inset_0,
t.atoms.text_contrast_high,
flatten(props.style),
]}
style={[a.absolute, a.inset_0, t.atoms.text_contrast_high, props.style]}
/>
</Animated.View>
)
+2 -2
View File
@@ -1,6 +1,6 @@
import {View} from 'react-native'
import {atoms as a, flatten, useTheme} from '#/alf'
import {atoms as a, useTheme} from '#/alf'
import {type Props, useCommonSVGProps} from '#/components/icons/common'
import {Loader_Stroke2_Corner0_Rounded as Icon} from '#/components/icons/Loader'
@@ -24,7 +24,7 @@ export function Loader(props: Props) {
a.absolute,
a.inset_0,
t.atoms.text_contrast_high,
flatten(props.style),
props.style,
]}
/>
</div>
@@ -5,11 +5,11 @@ import {
useSafeAreaInsets,
} from 'react-native-safe-area-context'
import {LinearGradient} from 'expo-linear-gradient'
import {utils} from '@bsky.app/alf'
import {isAndroid, isNative} from '#/platform/detection'
import {useA11y} from '#/state/a11y'
import {atoms as a, flatten, useBreakpoints, useTheme, web} from '#/alf'
import {transparentifyColor} from '#/alf/util/colorGeneration'
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
import {FocusScope} from '#/components/FocusScope'
import {LockScroll} from '#/components/LockScroll'
@@ -47,7 +47,7 @@ export function Overlay({
) : (
<LinearGradient
colors={[
transparentifyColor(t.atoms.bg.backgroundColor, 0),
utils.alpha(t.atoms.bg.backgroundColor, 0),
t.atoms.bg.backgroundColor,
t.atoms.bg.backgroundColor,
]}
@@ -97,7 +97,7 @@ export function Overlay({
]}>
<LinearGradient
colors={[
transparentifyColor(t.atoms.bg.backgroundColor, 0),
utils.alpha(t.atoms.bg.backgroundColor, 0),
t.atoms.bg.backgroundColor,
]}
start={[0.5, 0]}
@@ -113,7 +113,7 @@ export function Overlay({
role="dialog"
aria-role="dialog"
aria-label={label}
style={flatten([
style={[
a.relative,
a.w_full,
a.p_2xl,
@@ -128,7 +128,7 @@ export function Overlay({
maxWidth: 420,
}),
],
])}>
]}>
{children}
</View>
</FocusScope>
+8 -7
View File
@@ -1,4 +1,4 @@
import {memo, useState} from 'react'
import {memo, useMemo, useState} from 'react'
import {type StyleProp, View, type ViewStyle} from 'react-native'
import {
type AppBskyFeedDefs,
@@ -25,7 +25,7 @@ import {
useProgressGuideControls,
} from '#/state/shell/progress-guide'
import * as Toast from '#/view/com/util/Toast'
import {atoms as a, flatten, useBreakpoints} from '#/alf'
import {atoms as a, useBreakpoints} from '#/alf'
import {Reply as Bubble} from '#/components/icons/Reply'
import {useFormatPostStatCount} from '#/components/PostControls/util'
import {BookmarkButton} from './BookmarkButton'
@@ -188,11 +188,12 @@ let PostControls = ({
})
}
const secondaryControlSpacingStyles = flatten([
{gap: 0}, // default, we want `gap` to be defined on the resulting object
variant !== 'compact' && a.gap_xs,
(big || gtPhone) && a.gap_sm,
])
const secondaryControlSpacingStyles = useMemo(() => {
let gap = 0 // default, we want `gap` to be defined on the resulting object
if (variant !== 'compact') gap = a.gap_xs.gap
if (big || gtPhone) gap = a.gap_sm.gap
return {gap}
}, [variant, big, gtPhone])
return (
<View
+1 -1
View File
@@ -396,7 +396,7 @@ export function Description({
<View style={[a.pt_xs]}>
<RichText
value={rt}
style={[a.leading_snug, style]}
style={style}
numberOfLines={numberOfLines}
disableLinks
/>
+3 -7
View File
@@ -48,18 +48,14 @@ export function RichText({
[value],
)
const flattenedStyle = flatten(style)
const plainStyles = [a.leading_snug, flattenedStyle]
const interactiveStyles = [
a.leading_snug,
flatten(interactiveStyle),
flattenedStyle,
]
const plainStyles = [a.leading_snug, style]
const interactiveStyles = [plainStyles, interactiveStyle]
const {text, facets} = richText
if (!facets?.length) {
if (isOnlyEmoji(text)) {
const flattenedStyle = flatten(style)
const fontSize =
(flattenedStyle.fontSize ?? a.text_sm.fontSize) * emojiMultiplier
return (
+4 -4
View File
@@ -1,9 +1,9 @@
import {Children, createContext, useContext, useMemo} from 'react'
import {View} from 'react-native'
import {utils} from '@bsky.app/alf'
import {Popover} from 'radix-ui'
import {atoms as a, flatten, select, useTheme} from '#/alf'
import {transparentifyColor} from '#/alf/util/colorGeneration'
import {
ARROW_SIZE,
BUBBLE_MAX_WIDTH,
@@ -80,9 +80,9 @@ export function Content({
{
minWidth: 'max-content',
boxShadow: select(t.name, {
light: `0 0 24px ${transparentifyColor(t.palette.black, 0.2)}`,
dark: `0 0 24px ${transparentifyColor(t.palette.black, 0.2)}`,
dim: `0 0 24px ${transparentifyColor(t.palette.black, 0.2)}`,
light: `0 0 24px ${utils.alpha(t.palette.black, 0.2)}`,
dark: `0 0 24px ${utils.alpha(t.palette.black, 0.2)}`,
dim: `0 0 24px ${utils.alpha(t.palette.black, 0.2)}`,
}),
},
])}>
+3 -3
View File
@@ -1,7 +1,7 @@
import {UITextView} from 'react-native-uitextview'
import {logger} from '#/logger'
import {atoms, flatten, useAlf, useTheme, web} from '#/alf'
import {atoms, useAlf, useTheme, web} from '#/alf'
import {
childHasEmoji,
normalizeTextStyles,
@@ -26,7 +26,7 @@ export function Text({
}: TextProps) {
const {fonts, flags} = useAlf()
const t = useTheme()
const s = normalizeTextStyles([atoms.text_sm, t.atoms.text, flatten(style)], {
const s = normalizeTextStyles([atoms.text_sm, t.atoms.text, style], {
fontScale: fonts.scaleMultiplier,
fontFamily: fonts.family,
flags,
@@ -84,7 +84,7 @@ export function P({style, ...rest}: TextProps) {
<Text
{...attr}
{...rest}
style={[atoms.text_md, atoms.leading_normal, flatten(style)]}
style={[atoms.text_md, atoms.leading_relaxed, style]}
/>
)
}
+3 -3
View File
@@ -8,7 +8,7 @@ import {FocusGuards, FocusScope} from 'radix-ui/internal'
import {logger} from '#/logger'
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import {Logo} from '#/view/icons/Logo'
import {atoms as a, flatten, useBreakpoints, web} from '#/alf'
import {atoms as a, useBreakpoints, web} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
import {Text} from '#/components/Typography'
@@ -78,7 +78,7 @@ export function WelcomeModal({control}: WelcomeModalProps) {
]}>
<FocusScope.FocusScope asChild loop trapped>
<View
style={flatten([
style={[
{
maxWidth: 800,
maxHeight: 600,
@@ -89,7 +89,7 @@ export function WelcomeModal({control}: WelcomeModalProps) {
a.rounded_lg,
a.overflow_hidden,
a.zoom_in,
])}>
]}>
<ImageBackground
source={welcomeModalBg}
style={[a.flex_1, a.justify_center]}
@@ -134,12 +134,12 @@ function MenuInner({
accessibilityRole="button"
role="button"
onPress={() => setExpanded(true)}
style={flatten([
style={[
a.rounded_full,
{height: 34, width: 34},
a.justify_center,
a.align_center,
])}>
]}>
<DotGridIcon size="lg" style={t.atoms.text_contrast_medium} />
</Pressable>
</DropdownMenu.Item>
+1 -1
View File
@@ -424,7 +424,7 @@ function PreviewMessage({message}: {message: ChatBskyConvoDefs.MessageView}) {
]}>
<RichText
value={rt}
style={[a.text_md, a.leading_snug]}
style={[a.text_md]}
interactiveStyle={a.underline}
enableTags
/>
+2 -3
View File
@@ -6,7 +6,6 @@ import {HITSLOP_10} from '#/lib/constants'
import {isNative} from '#/platform/detection'
import {
atoms as a,
flatten,
native,
type TextStyleProp,
useTheme,
@@ -233,7 +232,7 @@ export function Item({
onPressOut={onPressOut}
onFocus={onFocus}
onBlur={onBlur}
style={[a.flex_row, a.align_center, a.gap_sm, flatten(style)]}>
style={[a.flex_row, a.align_center, a.gap_sm, style]}>
{typeof children === 'function' ? children(state) : children}
</Pressable>
</ItemContext.Provider>
@@ -260,7 +259,7 @@ export function LabelText({
native({
paddingTop: 2,
}),
flatten(style),
style,
]}>
{children}
</Text>
+1 -1
View File
@@ -40,7 +40,7 @@ export function createSinglePathSVG({path}: {path: string}) {
viewBox="0 0 24 24"
width={size}
height={size}
style={[style]}>
style={style}>
{gradient}
<Path fill={fill} fillRule="evenodd" clipRule="evenodd" d={path} />
</Svg>
@@ -1,5 +1,5 @@
import React from 'react'
import {Pressable, StyleSheet, View} from 'react-native'
import {Pressable, View} from 'react-native'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import Graphemer from 'graphemer'
@@ -19,7 +19,7 @@ import {
type EmojiPickerPosition,
} from '#/view/com/composer/text-input/web/EmojiPicker'
import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useTheme} from '#/alf'
import {atoms as a, flatten, useTheme} from '#/alf'
import {Button} from '#/components/Button'
import {useSharedInputStyles} from '#/components/forms/TextField'
import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmile} from '#/components/icons/Emoji'
@@ -199,7 +199,7 @@ export function MessageInput({
</Button>
<TextareaAutosize
ref={textAreaRef}
style={StyleSheet.flatten([
style={flatten([
a.flex_1,
a.px_sm,
a.border_0,
+2 -11
View File
@@ -10,7 +10,6 @@ import {useOnboardingDispatch} from '#/state/shell'
import {Context} from '#/screens/Onboarding/state'
import {
atoms as a,
flatten,
native,
type TextStyleProp,
tokens,
@@ -228,13 +227,7 @@ export function TitleText({
}: React.PropsWithChildren<TextStyleProp>) {
return (
<Text
style={[
a.pb_sm,
a.text_4xl,
a.font_semi_bold,
a.leading_tight,
flatten(style),
]}>
style={[a.pb_sm, a.text_4xl, a.font_semi_bold, a.leading_tight, style]}>
{children}
</Text>
)
@@ -245,7 +238,5 @@ export function DescriptionText({
style,
}: React.PropsWithChildren<TextStyleProp>) {
const t = useTheme()
return (
<P style={[t.atoms.text_contrast_medium, flatten(style)]}>{children}</P>
)
return <P style={[t.atoms.text_contrast_medium, style]}>{children}</P>
}
@@ -481,7 +481,7 @@ function DialogInner({
</Button>
</View>
<RichText value={rt} style={[a.text_md, a.leading_snug]} />
<RichText value={rt} style={[a.text_md]} />
<View style={[a.flex_row, a.gap_sm, a.align_center]}>
{typeof likeCount === 'number' && (
@@ -200,7 +200,7 @@ export function Header({
</ProfileSubpageHeader>
{descriptionRT ? (
<View style={[a.px_lg, a.pt_sm, a.pb_sm, a.gap_md]}>
<RichText value={descriptionRT} style={[a.text_md, a.leading_snug]} />
<RichText value={descriptionRT} style={[a.text_md]} />
</View>
) : null}
</>
@@ -458,9 +458,7 @@ function Header({
</ProfileSubpageHeader>
{!hasSession || richText || joinedAllTimeCount >= 25 ? (
<View style={[a.px_lg, a.pt_md, a.pb_sm, a.gap_md]}>
{richText ? (
<RichText value={richText} style={[a.text_md, a.leading_snug]} />
) : null}
{richText ? <RichText value={richText} style={[a.text_md]} /> : null}
{!hasSession ? (
<Button
label={_(msg`Join Bluesky`)}
+1 -1
View File
@@ -955,7 +955,7 @@ function ExpandableRichTextView({
]}>
<RichText
value={value}
style={[a.text_sm, a.flex_1, a.leading_normal]}
style={[a.text_sm, a.flex_1, a.leading_relaxed]}
authorHandle={authorHandle}
enableTags
numberOfLines={
+2 -2
View File
@@ -1,5 +1,5 @@
import React from 'react'
import {type StyleProp, StyleSheet, View, type ViewStyle} from 'react-native'
import {type StyleProp, View, type ViewStyle} from 'react-native'
import {type AnimatedRef, useAnimatedRef} from 'react-native-reanimated'
import {type AppBskyEmbedImages} from '@atproto/api'
@@ -224,5 +224,5 @@ function noCorners(
if (corners.includes('bottomRight')) {
styles.push({borderBottomRightRadius: 0})
}
return StyleSheet.flatten(styles)
return styles
}
+3 -2
View File
@@ -1,5 +1,5 @@
import React from 'react'
import {StyleSheet, type TextProps} from 'react-native'
import {type TextProps} from 'react-native'
import Svg, {
Defs,
LinearGradient,
@@ -12,6 +12,7 @@ import {Image} from 'expo-image'
import {colors} from '#/lib/styles'
import {useKawaiiMode} from '#/state/preferences/kawaii'
import {flatten} from '#/alf'
const ratio = 57 / 64
@@ -23,7 +24,7 @@ type Props = {
export const Logo = React.forwardRef(function LogoImpl(props: Props, ref) {
const {fill, ...rest} = props
const gradient = fill === 'sky'
const styles = StyleSheet.flatten(props.style)
const styles = flatten(props.style)
const _fill = gradient ? 'url(#sky)' : fill || styles?.color || colors.blue3
// @ts-ignore it's fiiiiine
const size = parseInt(rest.width || 32)