Skip to content

Commit

Permalink
Add TextShadow component (#5851)
Browse files Browse the repository at this point in the history
* Add TextShadow component, add env var to silence design system emoji warnings

* Temporarily default to disabling Android text shadows
  • Loading branch information
christianbaroni authored Jun 14, 2024
1 parent fc0ff05 commit 208856b
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 6 deletions.
1 change: 1 addition & 0 deletions globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,5 @@ declare module 'react-native-dotenv' {
export const RPC_PROXY_API_KEY_DEV: string;
export const REACT_NATIVE_RUDDERSTACK_WRITE_KEY: string;
export const RUDDERSTACK_DATA_PLANE_URL: string;
export const SILENCE_EMOJI_WARNINGS: boolean;
}
8 changes: 5 additions & 3 deletions src/design-system/components/Heading/Heading.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { ElementRef, forwardRef, ReactNode, useEffect, useMemo } from 'react';
import { Text as NativeText } from 'react-native';

import { SILENCE_EMOJI_WARNINGS } from 'react-native-dotenv';
import { IS_DEV, IS_IOS } from '@/env';
import { CustomColor } from '../../color/useForegroundColor';
import { createLineHeightFixNode } from '../../typography/createLineHeightFixNode';
import { nodeHasEmoji, nodeIsString, renderStringWithEmoji } from '../../typography/renderStringWithEmoji';
Expand Down Expand Up @@ -29,7 +30,7 @@ export const Heading = forwardRef<ElementRef<typeof NativeText>, HeadingProps>(f
ref
) {
useEffect(() => {
if (__DEV__) {
if (IS_DEV && !SILENCE_EMOJI_WARNINGS) {
if (!containsEmojiProp && nodeHasEmoji(children)) {
// eslint-disable-next-line no-console
console.log(
Expand All @@ -42,6 +43,7 @@ export const Heading = forwardRef<ElementRef<typeof NativeText>, HeadingProps>(f
);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const headingStyle = useHeadingStyle({ align, color, size, weight });
Expand All @@ -50,7 +52,7 @@ export const Heading = forwardRef<ElementRef<typeof NativeText>, HeadingProps>(f

return (
<NativeText allowFontScaling={false} numberOfLines={numberOfLines} ref={ref} style={headingStyle} testID={testID}>
{ios && containsEmojiProp && nodeIsString(children) ? renderStringWithEmoji(children) : children}
{IS_IOS && containsEmojiProp && nodeIsString(children) ? renderStringWithEmoji(children) : children}
{lineHeightFixNode}
</NativeText>
);
Expand Down
8 changes: 6 additions & 2 deletions src/design-system/components/Text/Text.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { ElementRef, forwardRef, ReactNode, useMemo, useEffect } from 'react';
import { Text as NativeText, StyleProp, TextStyle } from 'react-native';
import { SILENCE_EMOJI_WARNINGS } from 'react-native-dotenv';
import { IS_DEV, IS_IOS } from '@/env';
import { TextColor } from '../../color/palettes';
import { CustomColor } from '../../color/useForegroundColor';
import { createLineHeightFixNode } from '../../typography/createLineHeightFixNode';
Expand Down Expand Up @@ -34,6 +36,7 @@ export type TextProps = {
) & {
style?: StyleProp<TextStyle>;
};

export const Text = forwardRef<ElementRef<typeof NativeText>, TextProps>(function Text(
{
align,
Expand All @@ -53,7 +56,7 @@ export const Text = forwardRef<ElementRef<typeof NativeText>, TextProps>(functio
ref
) {
useEffect(() => {
if (__DEV__) {
if (IS_DEV && !SILENCE_EMOJI_WARNINGS) {
if (!containsEmojiProp && nodeHasEmoji(children)) {
// eslint-disable-next-line no-console
console.log(
Expand All @@ -67,6 +70,7 @@ export const Text = forwardRef<ElementRef<typeof NativeText>, TextProps>(functio
);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const textStyle = useTextStyle({
Expand All @@ -90,7 +94,7 @@ export const Text = forwardRef<ElementRef<typeof NativeText>, TextProps>(functio
testID={testID}
onPress={onPress}
>
{ios && containsEmojiProp && nodeIsString(children) ? renderStringWithEmoji(children) : children}
{IS_IOS && containsEmojiProp && nodeIsString(children) ? renderStringWithEmoji(children) : children}
{lineHeightFixNode}
</NativeText>
);
Expand Down
2 changes: 1 addition & 1 deletion src/design-system/components/TextIcon/TextIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Text, TextSize, TextWeight } from '../Text/Text';

export type TextIconProps = {
align?: 'center' | 'left' | 'right';
children: string | (string | null)[];
children: string | (string | null)[] | React.ReactNode;
color: TextColor | CustomColor;
containerSize?: number;
height?: number;
Expand Down
62 changes: 62 additions & 0 deletions src/design-system/components/TextShadow/TextShadow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { ReactElement, useMemo } from 'react';
import { StyleProp, TextStyle, View, ViewStyle } from 'react-native';
import { IS_ANDROID } from '@/env';
import { opacity } from '@/__swaps__/utils/swaps';
import { useColorMode } from '../../color/ColorMode';
import { useForegroundColor } from '../../color/useForegroundColor';
import { Text, TextProps } from '../Text/Text';

export interface TextShadowProps {
blur?: number;
children: ReactElement<TextProps>;
color?: string;
containerStyle?: StyleProp<ViewStyle>;
disabled?: boolean;
enableInLightMode?: boolean;
shadowOpacity?: number;
textStyle?: StyleProp<TextStyle>;
x?: number;
y?: number;
}

export const TextShadow = ({
blur = 16,
children,
color,
containerStyle,
// ⚠️ TODO: Need to test on Android - defaulting to disabled on Android for now
disabled = IS_ANDROID,
enableInLightMode,
shadowOpacity = 0.6,
textStyle,
x = 0,
y = 0,
}: TextShadowProps) => {
const { isDarkMode } = useColorMode();

const inferredTextColor = useForegroundColor(children.props.color ?? 'label');
const inferredTextSize = children.props.size || '17pt';

const [internalContainerStyle, internalTextStyle] = useMemo(() => {
const extraSpaceForShadow = blur + Math.max(Math.abs(x), Math.abs(y));
return [
{ margin: -extraSpaceForShadow },
{
textShadowColor: opacity(color || inferredTextColor, shadowOpacity),
textShadowOffset: { width: x, height: y },
textShadowRadius: blur,
padding: extraSpaceForShadow,
},
];
}, [blur, color, inferredTextColor, shadowOpacity, x, y]);

return !disabled && (isDarkMode || enableInLightMode) ? (
<View style={[containerStyle, internalContainerStyle]}>
<Text color={{ custom: 'transparent' }} size={inferredTextSize} style={[textStyle, internalTextStyle]} weight="bold">
{children}
</Text>
</View>
) : (
<>{children}</>
);
};
2 changes: 2 additions & 0 deletions src/design-system/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export { Stack } from './components/Stack/Stack';
export { selectTextSizes, Text } from './components/Text/Text';
export { TextIcon } from './components/TextIcon/TextIcon';
export { TextLink } from './components/TextLink/TextLink';
export { TextShadow } from './components/TextShadow/TextShadow';
export { useColorMode } from './color/ColorMode';
export { useForegroundColor } from './color/useForegroundColor';
export { useHeadingStyle } from './components/Heading/useHeadingStyle';
Expand All @@ -47,3 +48,4 @@ export type { StackProps } from './components/Stack/Stack';
export type { TextLinkProps } from './components/TextLink/TextLink';
export type { TextProps } from './components/Text/Text';
export type { TextIconProps } from './components/TextIcon/TextIcon';
export type { TextShadowProps } from './components/TextShadow/TextShadow';

0 comments on commit 208856b

Please sign in to comment.