template_0205

This commit is contained in:
Sofio
2026-02-05 13:16:05 +08:00
commit d93e4d9c9f
197 changed files with 52810 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
/* eslint-disable react-native/no-inline-styles */
import { StyleProp, View, ViewStyle } from "react-native"
import { useAppTheme } from "@/theme/context"
import type { ThemedStyle } from "@/theme/types"
import { s } from "@/utils/responsive"
interface DemoDividerProps {
type?: "vertical" | "horizontal"
size?: number
style?: StyleProp<ViewStyle>
line?: boolean
}
/**
* @param {DemoDividerProps} props - The props for the `DemoDivider` component.
* @returns {JSX.Element} The rendered `DemoDivider` component.
*/
export function DemoDivider(props: DemoDividerProps) {
const { type = "horizontal", size = 10, line = false, style: $styleOverride } = props
const { themed } = useAppTheme()
return (
<View
style={[
$divider,
type === "horizontal" && { height: size },
type === "vertical" && { width: size },
$styleOverride,
]}
>
{line && (
<View
style={[
themed($line),
type === "horizontal" && {
width: s(150),
height: 1,
marginStart: s(-75),
marginTop: -1,
},
type === "vertical" && {
height: s(50),
width: 1,
marginTop: s(-25),
marginStart: -1,
},
]}
/>
)}
</View>
)
}
const $divider: ViewStyle = {
flexGrow: 0,
flexShrink: 0,
}
const $line: ThemedStyle<ViewStyle> = ({ colors }) => ({
backgroundColor: colors.border,
position: "absolute",
left: "50%",
top: "50%",
})

View File

@@ -0,0 +1,51 @@
import { ReactNode } from "react"
import { TextStyle, View, ViewStyle } from "react-native"
import { Text } from "@/components/Text"
import type { TxKeyPath } from "@/i18n"
import { translate } from "@/i18n/translate"
import { useAppTheme } from "@/theme/context"
import { $styles } from "@/theme/styles"
import type { ThemedStyle } from "@/theme/types"
import { s } from "@/utils/responsive"
interface DemoUseCaseProps {
name: TxKeyPath
description?: TxKeyPath
layout?: "column" | "row"
itemStyle?: ViewStyle
children: ReactNode
}
/**
* @param {DemoUseCaseProps} props - The props for the `DemoUseCase` component.
* @returns {JSX.Element} The rendered `DemoUseCase` component.
*/
export function DemoUseCase(props: DemoUseCaseProps) {
const { name, description, children, layout = "column", itemStyle = {} } = props
const { themed } = useAppTheme()
return (
<View>
<Text style={themed($name)}>{translate(name)}</Text>
{description && <Text style={themed($description)}>{translate(description)}</Text>}
<View style={[itemStyle, layout === "row" && $styles.row, themed($item)]}>{children}</View>
</View>
)
}
const $description: ThemedStyle<TextStyle> = ({ spacing }) => ({
marginTop: spacing.md,
})
const $item: ThemedStyle<ViewStyle> = ({ colors, spacing }) => ({
backgroundColor: colors.palette.neutral100,
borderRadius: s(8),
padding: spacing.lg,
marginVertical: spacing.md,
})
const $name: ThemedStyle<TextStyle> = ({ typography }) => ({
fontFamily: typography.primary.bold,
})

View File

@@ -0,0 +1,119 @@
import { Pressable, PressableProps, ViewStyle, Platform } from "react-native"
import { useDrawerProgress } from "react-native-drawer-layout"
import Animated, { interpolate, interpolateColor, useAnimatedStyle } from "react-native-reanimated"
import { isRTL } from "@/i18n"
import { useAppTheme } from "@/theme/context"
import { s } from "@/utils/responsive"
interface DrawerIconButtonProps extends PressableProps {}
const AnimatedPressable = Animated.createAnimatedComponent(Pressable)
/**
* @param {DrawerIconButtonProps} props - The props for the `DrawerIconButton` component.
* @returns {JSX.Element} The rendered `DrawerIconButton` component.
*/
export function DrawerIconButton(props: DrawerIconButtonProps) {
const { ...PressableProps } = props
const progress = useDrawerProgress()
const isWeb = Platform.OS === "web"
const {
theme: { colors },
themed,
} = useAppTheme()
const animatedContainerStyles = useAnimatedStyle(() => {
const translateX = interpolate(progress.value, [0, 1], [0, isRTL ? 60 : -60])
return {
transform: [{ translateX }],
}
})
const animatedTopBarStyles = useAnimatedStyle(() => {
const backgroundColor = interpolateColor(progress.value, [0, 1], [colors.text, colors.tint])
const marginStart = interpolate(progress.value, [0, 1], [0, -11.5])
const rotate = interpolate(progress.value, [0, 1], [0, isRTL ? 45 : -45])
const marginBottom = interpolate(progress.value, [0, 1], [0, -2])
const width = interpolate(progress.value, [0, 1], [18, 12])
const marginHorizontal =
isWeb && isRTL
? { marginRight: marginStart }
: {
marginLeft: marginStart,
}
return {
...marginHorizontal,
backgroundColor,
marginBottom,
width,
transform: [{ rotate: `${rotate}deg` }],
}
})
const animatedMiddleBarStyles = useAnimatedStyle(() => {
const backgroundColor = interpolateColor(progress.value, [0, 1], [colors.text, colors.tint])
const width = interpolate(progress.value, [0, 1], [18, 16])
return {
backgroundColor,
width,
}
})
const animatedBottomBarStyles = useAnimatedStyle(() => {
const marginTop = interpolate(progress.value, [0, 1], [4, 2])
const backgroundColor = interpolateColor(progress.value, [0, 1], [colors.text, colors.tint])
const marginStart = interpolate(progress.value, [0, 1], [0, -11.5])
const rotate = interpolate(progress.value, [0, 1], [0, isRTL ? -45 : 45])
const width = interpolate(progress.value, [0, 1], [18, 12])
const marginHorizontal =
isWeb && isRTL
? { marginRight: marginStart }
: {
marginLeft: marginStart,
}
return {
...marginHorizontal,
backgroundColor,
width,
marginTop,
transform: [{ rotate: `${rotate}deg` }],
}
})
return (
<AnimatedPressable {...PressableProps} style={[$container, animatedContainerStyles]}>
<Animated.View style={[$topBar, animatedTopBarStyles]} />
<Animated.View style={[themed($middleBar), animatedMiddleBarStyles]} />
<Animated.View style={[$bottomBar, animatedBottomBarStyles]} />
</AnimatedPressable>
)
}
const barHeight = 2
const $container: ViewStyle = {
alignItems: "center",
height: s(56),
justifyContent: "center",
width: s(56),
}
const $topBar: ViewStyle = {
height: barHeight,
}
const $middleBar: ViewStyle = {
height: barHeight,
marginTop: s(4),
}
const $bottomBar: ViewStyle = {
height: barHeight,
}

View File

@@ -0,0 +1,57 @@
import { forwardRef, ReactElement, ReactNode, useCallback } from "react"
import { ScrollViewProps, SectionList, SectionListProps } from "react-native"
import { KeyboardAwareScrollView } from "react-native-keyboard-controller"
import { DEFAULT_BOTTOM_OFFSET } from "@/components/Screen"
type SectionType<ItemType> = {
name: string
description: string
data: ItemType[]
}
type SectionListWithKeyboardAwareScrollViewProps<ItemType> = SectionListProps<ItemType> & {
/* Optional function to pass a custom scroll component */
renderScrollComponent?: (props: ScrollViewProps) => ReactNode
/* Optional additional offset between TextInput bottom edge and keyboard top edge. See https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/components/keyboard-aware-scroll-view#bottomoffset */
bottomOffset?: number
/* The sections to be rendered in the list */
sections: SectionType<ItemType>[]
/* Function to render the header for each section */
renderSectionHeader: ({ section }: { section: SectionType<ItemType> }) => React.ReactNode
}
function SectionListWithKeyboardAwareScrollView<ItemType = any>(
{
renderScrollComponent,
bottomOffset = DEFAULT_BOTTOM_OFFSET,
contentContainerStyle,
...props
}: SectionListWithKeyboardAwareScrollViewProps<ItemType>,
ref: React.Ref<SectionList<ItemType>>,
): ReactElement {
const defaultRenderScrollComponent = useCallback(
(props: ScrollViewProps) => (
<KeyboardAwareScrollView
contentContainerStyle={contentContainerStyle}
bottomOffset={bottomOffset}
{...props}
/>
),
[contentContainerStyle, bottomOffset],
)
return (
<SectionList
{...props}
ref={ref}
renderScrollComponent={renderScrollComponent ?? defaultRenderScrollComponent}
/>
)
}
export default forwardRef(SectionListWithKeyboardAwareScrollView) as <ItemType = any>(
props: SectionListWithKeyboardAwareScrollViewProps<ItemType> & {
ref?: React.Ref<SectionList<ItemType>>
},
) => ReactElement

View File

@@ -0,0 +1,320 @@
import { FC, ReactElement, useCallback, useEffect, useRef, useState } from "react"
import {
FlatList,
Image,
ImageStyle,
Platform,
SectionList,
TextStyle,
View,
ViewStyle,
} from "react-native"
import { Link, RouteProp, useRoute } from "@react-navigation/native"
import { Drawer } from "react-native-drawer-layout"
import { ListItem } from "@/components/ListItem"
import { Screen } from "@/components/Screen"
import { Text } from "@/components/Text"
import { TxKeyPath, isRTL } from "@/i18n"
import { translate } from "@/i18n/translate"
import { MainTabParamList, MainTabScreenProps } from "@/navigators/navigationTypes"
import { useAppTheme } from "@/theme/context"
import { $styles } from "@/theme/styles"
import type { ThemedStyle } from "@/theme/types"
import { s, fs } from "@/utils/responsive"
import { useSafeAreaInsetsStyle } from "@/utils/useSafeAreaInsetsStyle"
import * as Demos from "./demos"
import { DrawerIconButton } from "./DrawerIconButton"
import SectionListWithKeyboardAwareScrollView from "./SectionListWithKeyboardAwareScrollView"
const logo = require("@assets/images/logo.png")
interface DemoListItem {
item: { name: string; useCases: string[] }
sectionIndex: number
handleScroll?: (sectionIndex: number, itemIndex?: number) => void
}
const slugify = (str: string) =>
str
.toLowerCase()
.trim()
.replace(/[^\w\s-]/g, "")
.replace(/[\s_-]+/g, "-")
.replace(/^-+|-+$/g, "")
/**
* Type-safe utility to check if an unknown object has a valid string property.
* This is particularly useful in React 19 where props are typed as unknown by default.
* The function safely narrows down the type by checking both property existence and type.
* @param props - The unknown props to check.
* @param propName - The name of the property to check.
* @returns Whether the property is a valid string.
*/
function hasValidStringProp(props: unknown, propName: string): boolean {
return (
props !== null &&
typeof props === "object" &&
propName in props &&
typeof (props as Record<string, unknown>)[propName] === "string"
)
}
const WebListItem: FC<DemoListItem> = ({ item, sectionIndex }) => {
const sectionSlug = item.name.toLowerCase()
const { themed } = useAppTheme()
return (
<View>
<Link screen="Showroom" params={{ queryIndex: sectionSlug }} style={themed($menuContainer)}>
<Text preset="bold">{item.name}</Text>
</Link>
{item.useCases.map((u) => {
const itemSlug = slugify(u)
return (
<Link
key={`section${sectionIndex}-${u}`}
screen="Showroom"
params={{ queryIndex: sectionSlug, itemIndex: itemSlug }}
>
<Text>{u}</Text>
</Link>
)
})}
</View>
)
}
const NativeListItem: FC<DemoListItem> = ({ item, sectionIndex, handleScroll }) => {
const { themed } = useAppTheme()
return (
<View>
<Text
onPress={() => handleScroll?.(sectionIndex)}
preset="bold"
style={themed($menuContainer)}
>
{item.name}
</Text>
{item.useCases.map((u, index) => (
<ListItem
key={`section${sectionIndex}-${u}`}
onPress={() => handleScroll?.(sectionIndex, index)}
text={u}
rightIcon={isRTL ? "caretLeft" : "caretRight"}
/>
))}
</View>
)
}
const ShowroomListItem = Platform.select({ web: WebListItem, default: NativeListItem })
const isAndroid = Platform.OS === "android"
export const ShowroomScreen: FC<MainTabScreenProps<"Showroom">> = function ShowroomScreen(_props) {
const [open, setOpen] = useState(false)
const timeout = useRef<ReturnType<typeof setTimeout>>(null)
const listRef = useRef<SectionList>(null)
const menuRef = useRef<FlatList<DemoListItem["item"]>>(null)
const route = useRoute<RouteProp<MainTabParamList, "Showroom">>()
const params = route.params
const { themed, theme } = useAppTheme()
const toggleDrawer = useCallback(() => {
if (!open) {
setOpen(true)
} else {
setOpen(false)
}
}, [open])
const handleScroll = useCallback((sectionIndex: number, itemIndex = 0) => {
try {
listRef.current?.scrollToLocation({
animated: true,
itemIndex,
sectionIndex,
viewPosition: 0.25,
})
} catch (e) {
console.error(e)
}
}, [])
// handle Web links
useEffect(() => {
if (params !== undefined && Object.keys(params).length > 0) {
const demoValues = Object.values(Demos)
const findSectionIndex = demoValues.findIndex(
(x) => x.name.toLowerCase() === params.queryIndex,
)
let findItemIndex = 0
if (params.itemIndex) {
try {
findItemIndex = demoValues[findSectionIndex].data({ themed, theme }).findIndex((u) => {
if (hasValidStringProp(u.props, "name")) {
return slugify(translate((u.props as { name: TxKeyPath }).name)) === params.itemIndex
}
return false
})
} catch (err) {
console.error(err)
}
}
handleScroll(findSectionIndex, findItemIndex)
}
}, [handleScroll, params, theme, themed])
const scrollToIndexFailed = (info: {
index: number
highestMeasuredFrameIndex: number
averageItemLength: number
}) => {
listRef.current?.getScrollResponder()?.scrollToEnd()
timeout.current = setTimeout(
() =>
listRef.current?.scrollToLocation({
animated: true,
itemIndex: info.index,
sectionIndex: 0,
}),
50,
)
}
useEffect(() => {
return () => {
if (timeout.current) {
clearTimeout(timeout.current)
}
}
}, [])
const $drawerInsets = useSafeAreaInsetsStyle(["top"])
return (
<Drawer
open={open}
onOpen={() => setOpen(true)}
onClose={() => setOpen(false)}
drawerType="back"
drawerPosition={isRTL ? "right" : "left"}
renderDrawerContent={() => (
<View style={themed([$drawer, $drawerInsets])}>
<View style={themed($logoContainer)}>
<Image source={logo} style={$logoImage} />
</View>
<FlatList<DemoListItem["item"]>
ref={menuRef}
contentContainerStyle={themed($listContentContainer)}
data={Object.values(Demos).map((d) => ({
name: d.name,
useCases: d.data({ theme, themed }).map((u) => {
if (hasValidStringProp(u.props, "name")) {
return translate((u.props as { name: TxKeyPath }).name)
}
return ""
}),
}))}
keyExtractor={(item) => item.name}
renderItem={({ item, index: sectionIndex }) => (
<ShowroomListItem {...{ item, sectionIndex, handleScroll }} />
)}
/>
</View>
)}
>
<Screen
preset="fixed"
contentContainerStyle={$styles.flex1}
{...(isAndroid ? { KeyboardAvoidingViewProps: { behavior: undefined } } : {})}
>
<DrawerIconButton onPress={toggleDrawer} />
<SectionListWithKeyboardAwareScrollView
ref={listRef}
contentContainerStyle={themed($sectionListContentContainer)}
stickySectionHeadersEnabled={false}
sections={Object.values(Demos).map((d) => ({
name: d.name,
description: d.description,
data: [d.data({ theme, themed })],
}))}
renderItem={({ item, index: sectionIndex }) => (
<View>
{item.map((demo: ReactElement, demoIndex: number) => (
<View key={`${sectionIndex}-${demoIndex}`}>{demo}</View>
))}
</View>
)}
renderSectionFooter={() => <View style={themed($demoUseCasesSpacer)} />}
ListHeaderComponent={
<View style={themed($heading)}>
<Text preset="heading" tx="showroomScreen:jumpStart" />
</View>
}
onScrollToIndexFailed={scrollToIndexFailed}
renderSectionHeader={({ section }) => {
return (
<View>
<Text preset="heading" style={themed($demoItemName)}>
{section.name}
</Text>
<Text style={themed($demoItemDescription)}>{translate(section.description)}</Text>
</View>
)
}}
/>
</Screen>
</Drawer>
)
}
const $drawer: ThemedStyle<ViewStyle> = ({ colors }) => ({
backgroundColor: colors.background,
flex: 1,
})
const $listContentContainer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
paddingHorizontal: spacing.lg,
})
const $sectionListContentContainer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
paddingHorizontal: spacing.lg,
})
const $heading: ThemedStyle<ViewStyle> = ({ spacing }) => ({
marginBottom: spacing.xxxl,
})
const $logoImage: ImageStyle = {
height: s(42),
width: s(77),
}
const $logoContainer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
alignSelf: "flex-start",
justifyContent: "center",
height: s(56),
paddingHorizontal: spacing.lg,
})
const $menuContainer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
paddingBottom: spacing.xs,
paddingTop: spacing.lg,
})
const $demoItemName: ThemedStyle<TextStyle> = ({ spacing }) => ({
fontSize: fs(24),
marginBottom: spacing.md,
})
const $demoItemDescription: ThemedStyle<TextStyle> = ({ spacing }) => ({
marginBottom: spacing.xxl,
})
const $demoUseCasesSpacer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
paddingBottom: spacing.xxl,
})

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,226 @@
/* eslint-disable react/jsx-key */
import { TextStyle, View, ViewStyle } from "react-native"
import { Button } from "@/components/Button"
import { Icon } from "@/components/Icon"
import { Text } from "@/components/Text"
import { translate } from "@/i18n/translate"
import type { ThemedStyle } from "@/theme/types"
import { DemoDivider } from "../DemoDivider"
import { Demo } from "./types"
import { DemoUseCase } from "../DemoUseCase"
const ICON_SIZE = 24
const $customButtonStyle: ThemedStyle<ViewStyle> = ({ colors }) => ({
backgroundColor: colors.error,
height: 100,
})
const $customButtonPressedStyle: ThemedStyle<ViewStyle> = ({ colors }) => ({
backgroundColor: colors.error,
})
const $customButtonTextStyle: ThemedStyle<TextStyle> = ({ colors, typography }) => ({
color: colors.error,
fontFamily: typography.primary.bold,
textDecorationLine: "underline",
textDecorationColor: colors.error,
})
const $customButtonPressedTextStyle: ThemedStyle<TextStyle> = ({ colors }) => ({
color: colors.palette.neutral100,
})
const $customButtonRightAccessoryStyle: ThemedStyle<ViewStyle> = ({ colors }) => ({
width: "53%",
height: "200%",
backgroundColor: colors.error,
position: "absolute",
top: 0,
right: 0,
})
const $disabledOpacity: ViewStyle = { opacity: 0.5 }
const $disabledButtonTextStyle: ThemedStyle<TextStyle> = ({ colors }) => ({
color: colors.palette.neutral100,
textDecorationColor: colors.palette.neutral100,
})
export const DemoButton: Demo = {
name: "Button",
description: "demoButton:description",
data: ({ themed, theme }) => [
<DemoUseCase
name="demoButton:useCase.presets.name"
description="demoButton:useCase.presets.description"
>
<Button>Default - Laboris In Labore</Button>
<DemoDivider />
<Button preset="filled">Filled - Laboris Ex</Button>
<DemoDivider />
<Button preset="reversed">Reversed - Ad Ipsum</Button>
</DemoUseCase>,
<DemoUseCase
name="demoButton:useCase.passingContent.name"
description="demoButton:useCase.passingContent.description"
>
<Button text={translate("demoButton:useCase.passingContent.viaTextProps")} />
<DemoDivider />
<Button tx="showroomScreen:demoViaTxProp" />
<DemoDivider />
<Button>{translate("demoButton:useCase.passingContent.children")}</Button>
<DemoDivider />
<Button
preset="filled"
RightAccessory={(props) => (
<Icon containerStyle={props.style} size={ICON_SIZE} icon="ladybug" />
)}
>
{translate("demoButton:useCase.passingContent.rightAccessory")}
</Button>
<DemoDivider />
<Button
preset="filled"
LeftAccessory={(props) => (
<Icon containerStyle={props.style} size={ICON_SIZE} icon="ladybug" />
)}
>
{translate("demoButton:useCase.passingContent.leftAccessory")}
</Button>
<DemoDivider />
<Button>
<Text>
<Text preset="bold">{translate("demoButton:useCase.passingContent.nestedChildren")}</Text>
{` `}
<Text preset="default">
{translate("demoButton:useCase.passingContent.nestedChildren2")}
</Text>
{` `}
<Text preset="bold">
{translate("demoButton:useCase.passingContent.nestedChildren3")}
</Text>
</Text>
</Button>
<DemoDivider />
<Button
preset="reversed"
RightAccessory={(props) => (
<Icon containerStyle={props.style} size={ICON_SIZE} icon="ladybug" />
)}
LeftAccessory={(props) => (
<Icon containerStyle={props.style} size={ICON_SIZE} icon="ladybug" />
)}
>
{translate("demoButton:useCase.passingContent.multiLine")}
</Button>
</DemoUseCase>,
<DemoUseCase
name="demoButton:useCase.styling.name"
description="demoButton:useCase.styling.description"
>
<Button style={themed($customButtonStyle)}>
{translate("demoButton:useCase.styling.styleContainer")}
</Button>
<DemoDivider />
<Button preset="filled" textStyle={themed($customButtonTextStyle)}>
{translate("demoButton:useCase.styling.styleText")}
</Button>
<DemoDivider />
<Button
preset="reversed"
RightAccessory={() => <View style={themed($customButtonRightAccessoryStyle)} />}
>
{translate("demoButton:useCase.styling.styleAccessories")}
</Button>
<DemoDivider />
<Button
pressedStyle={themed($customButtonPressedStyle)}
pressedTextStyle={themed($customButtonPressedTextStyle)}
RightAccessory={(props) => (
<Icon
containerStyle={props.style}
size={ICON_SIZE}
color={props.pressableState.pressed ? theme.colors.palette.neutral100 : undefined}
icon="ladybug"
/>
)}
>
{translate("demoButton:useCase.styling.pressedState")}
</Button>
</DemoUseCase>,
<DemoUseCase
name="demoButton:useCase.disabling.name"
description="demoButton:useCase.disabling.description"
>
<Button
disabled
disabledStyle={$disabledOpacity}
pressedStyle={themed($customButtonPressedStyle)}
pressedTextStyle={themed($customButtonPressedTextStyle)}
>
{translate("demoButton:useCase.disabling.standard")}
</Button>
<DemoDivider />
<Button
disabled
preset="filled"
disabledStyle={$disabledOpacity}
pressedStyle={themed($customButtonPressedStyle)}
pressedTextStyle={themed($customButtonPressedTextStyle)}
>
{translate("demoButton:useCase.disabling.filled")}
</Button>
<DemoDivider />
<Button
disabled
preset="reversed"
disabledStyle={$disabledOpacity}
pressedStyle={themed($customButtonPressedStyle)}
pressedTextStyle={themed($customButtonPressedTextStyle)}
>
{translate("demoButton:useCase.disabling.reversed")}
</Button>
<DemoDivider />
<Button
disabled
pressedStyle={themed($customButtonPressedStyle)}
pressedTextStyle={themed($customButtonPressedTextStyle)}
RightAccessory={(props) => (
<View
style={
props.disabled
? [themed($customButtonRightAccessoryStyle), $disabledOpacity]
: themed($customButtonRightAccessoryStyle)
}
/>
)}
>
{translate("demoButton:useCase.disabling.accessory")}
</Button>
<DemoDivider />
<Button
disabled
preset="filled"
disabledTextStyle={themed([$customButtonTextStyle, $disabledButtonTextStyle])}
pressedStyle={themed($customButtonPressedStyle)}
pressedTextStyle={themed($customButtonPressedTextStyle)}
>
{translate("demoButton:useCase.disabling.textStyle")}
</Button>
</DemoUseCase>,
],
}

View File

@@ -0,0 +1,180 @@
/* eslint-disable react/jsx-key, react-native/no-inline-styles */
import { AutoImage } from "@/components/AutoImage"
import { Button } from "@/components/Button"
import { Card } from "@/components/Card"
import { Icon } from "@/components/Icon"
import { s } from "@/utils/responsive"
import { DemoDivider } from "../DemoDivider"
import { Demo } from "./types"
import { DemoUseCase } from "../DemoUseCase"
export const DemoCard: Demo = {
name: "Card",
description: "demoCard:description",
data: ({ theme }) => [
<DemoUseCase
name="demoCard:useCase.presets.name"
description="demoCard:useCase.presets.description"
>
<Card
headingTx="demoCard:useCase.presets.default.heading"
contentTx="demoCard:useCase.presets.default.content"
footerTx="demoCard:useCase.presets.default.footer"
/>
<DemoDivider />
<Card
headingTx="demoCard:useCase.presets.reversed.heading"
contentTx="demoCard:useCase.presets.reversed.content"
footerTx="demoCard:useCase.presets.reversed.footer"
preset="reversed"
/>
</DemoUseCase>,
<DemoUseCase
name="demoCard:useCase.verticalAlignment.name"
description="demoCard:useCase.verticalAlignment.description"
>
<Card
headingTx="demoCard:useCase.verticalAlignment.top.heading"
contentTx="demoCard:useCase.verticalAlignment.top.content"
footerTx="demoCard:useCase.verticalAlignment.top.footer"
style={{ minHeight: s(160) }}
/>
<DemoDivider />
<Card
headingTx="demoCard:useCase.verticalAlignment.center.heading"
verticalAlignment="center"
preset="reversed"
contentTx="demoCard:useCase.verticalAlignment.center.content"
footerTx="demoCard:useCase.verticalAlignment.center.footer"
style={{ minHeight: s(160) }}
/>
<DemoDivider />
<Card
headingTx="demoCard:useCase.verticalAlignment.spaceBetween.heading"
verticalAlignment="space-between"
contentTx="demoCard:useCase.verticalAlignment.spaceBetween.content"
footerTx="demoCard:useCase.verticalAlignment.spaceBetween.footer"
style={{ minHeight: s(160) }}
/>
<DemoDivider />
<Card
preset="reversed"
headingTx="demoCard:useCase.verticalAlignment.reversed.heading"
verticalAlignment="force-footer-bottom"
contentTx="demoCard:useCase.verticalAlignment.reversed.content"
footerTx="demoCard:useCase.verticalAlignment.reversed.footer"
style={{ minHeight: s(160) }}
/>
</DemoUseCase>,
<DemoUseCase
name="demoCard:useCase.passingContent.name"
description="demoCard:useCase.passingContent.description"
>
<Card
headingTx="demoCard:useCase.passingContent.heading"
contentTx="demoCard:useCase.passingContent.content"
footerTx="demoCard:useCase.passingContent.footer"
/>
<DemoDivider />
<Card
preset="reversed"
headingTx="showroomScreen:demoViaSpecifiedTxProp"
headingTxOptions={{ prop: "heading" }}
contentTx="showroomScreen:demoViaSpecifiedTxProp"
contentTxOptions={{ prop: "content" }}
footerTx="showroomScreen:demoViaSpecifiedTxProp"
footerTxOptions={{ prop: "footer" }}
/>
</DemoUseCase>,
<DemoUseCase
name="demoCard:useCase.customComponent.name"
description="demoCard:useCase.customComponent.description"
>
<Card
HeadingComponent={
<Button
preset="reversed"
text="HeadingComponent"
LeftAccessory={(props) => <Icon containerStyle={props.style} icon="ladybug" />}
/>
}
ContentComponent={
<Button
style={{ marginVertical: theme.spacing.sm }}
text="ContentComponent"
LeftAccessory={(props) => <Icon containerStyle={props.style} icon="ladybug" />}
/>
}
FooterComponent={
<Button
preset="reversed"
text="FooterComponent"
LeftAccessory={(props) => <Icon containerStyle={props.style} icon="ladybug" />}
/>
}
/>
<DemoDivider />
<Card
headingTx="demoCard:useCase.customComponent.rightComponent"
verticalAlignment="center"
RightComponent={
<AutoImage
maxWidth={s(80)}
maxHeight={s(60)}
style={{ alignSelf: "center" }}
source={{
uri: "https://user-images.githubusercontent.com/1775841/184508739-f90d0ce5-7219-42fd-a91f-3382d016eae0.png",
}}
/>
}
/>
<DemoDivider />
<Card
preset="reversed"
headingTx="demoCard:useCase.customComponent.leftComponent"
verticalAlignment="center"
LeftComponent={
<AutoImage
maxWidth={s(80)}
maxHeight={s(60)}
style={{ alignSelf: "center" }}
source={{
uri: "https://user-images.githubusercontent.com/1775841/184508739-f90d0ce5-7219-42fd-a91f-3382d016eae0.png",
}}
/>
}
/>
</DemoUseCase>,
<DemoUseCase
name="demoCard:useCase.style.name"
description="demoCard:useCase.style.description"
>
<Card
headingTx="demoCard:useCase.style.heading"
headingStyle={{ color: theme.colors.error }}
contentTx="demoCard:useCase.style.content"
contentStyle={{
backgroundColor: theme.colors.error,
color: theme.colors.palette.neutral100,
}}
footerTx="demoCard:useCase.style.footer"
footerStyle={{
textDecorationLine: "underline line-through",
textDecorationStyle: "dashed",
color: theme.colors.error,
textDecorationColor: theme.colors.error,
}}
style={{
shadowRadius: s(5),
shadowColor: theme.colors.error,
shadowOpacity: 0.5,
}}
/>
</DemoUseCase>,
],
}

View File

@@ -0,0 +1,77 @@
/* eslint-disable react/jsx-key, react-native/no-inline-styles */
import { EmptyState } from "@/components/EmptyState"
import { s } from "@/utils/responsive"
import { DemoDivider } from "../DemoDivider"
import { Demo } from "./types"
import { DemoUseCase } from "../DemoUseCase"
export const DemoEmptyState: Demo = {
name: "EmptyState",
description: "demoEmptyState:description",
data: ({ theme }) => [
<DemoUseCase
name="demoEmptyState:useCase.presets.name"
description="demoEmptyState:useCase.presets.description"
>
<EmptyState preset="generic" />
</DemoUseCase>,
<DemoUseCase
name="demoEmptyState:useCase.passingContent.name"
description="demoEmptyState:useCase.passingContent.description"
>
<EmptyState
imageSource={require("@assets/images/logo.png")}
headingTx="demoEmptyState:useCase.passingContent.customizeImageHeading"
contentTx="demoEmptyState:useCase.passingContent.customizeImageContent"
/>
<DemoDivider size={30} line />
<EmptyState
headingTx="demoEmptyState:useCase.passingContent.viaHeadingProp"
contentTx="demoEmptyState:useCase.passingContent.viaContentProp"
buttonTx="demoEmptyState:useCase.passingContent.viaButtonProp"
/>
<DemoDivider size={30} line />
<EmptyState
headingTx="showroomScreen:demoViaSpecifiedTxProp"
headingTxOptions={{ prop: "heading" }}
contentTx="showroomScreen:demoViaSpecifiedTxProp"
contentTxOptions={{ prop: "content" }}
buttonTx="showroomScreen:demoViaSpecifiedTxProp"
buttonTxOptions={{ prop: "button" }}
/>
</DemoUseCase>,
<DemoUseCase
name="demoEmptyState:useCase.styling.name"
description="demoEmptyState:useCase.styling.description"
>
<EmptyState
preset="generic"
style={{ backgroundColor: theme.colors.error, paddingVertical: s(20) }}
imageStyle={{ height: s(75), tintColor: theme.colors.palette.neutral100 }}
ImageProps={{ resizeMode: "contain" }}
headingStyle={{
color: theme.colors.palette.neutral100,
textDecorationLine: "underline",
textDecorationColor: theme.colors.palette.neutral100,
}}
contentStyle={{
color: theme.colors.palette.neutral100,
textDecorationLine: "underline",
textDecorationColor: theme.colors.palette.neutral100,
}}
buttonStyle={{ alignSelf: "center", backgroundColor: theme.colors.palette.neutral100 }}
buttonTextStyle={{ color: theme.colors.error }}
ButtonProps={{
preset: "reversed",
}}
/>
</DemoUseCase>,
],
}

View File

@@ -0,0 +1,150 @@
/* eslint-disable react/jsx-key, react-native/no-inline-styles */
import { TextStyle, View, ViewStyle } from "react-native"
import { Header } from "@/components/Header"
import { Icon } from "@/components/Icon"
import { $styles } from "@/theme/styles"
import type { ThemedStyle } from "@/theme/types"
import { s } from "@/utils/responsive"
import { DemoDivider } from "../DemoDivider"
import { Demo } from "./types"
import { DemoUseCase } from "../DemoUseCase"
const $rightAlignTitle: TextStyle = {
textAlign: "right",
}
const $customLeftAction: ThemedStyle<ViewStyle> = ({ colors }) => ({
backgroundColor: colors.error,
flexGrow: 0,
flexBasis: s(100),
height: "100%",
flexWrap: "wrap",
overflow: "hidden",
})
const $customTitle: ThemedStyle<TextStyle> = ({ colors }) => ({
textDecorationLine: "underline line-through",
textDecorationStyle: "dashed",
color: colors.error,
textDecorationColor: colors.error,
})
const $customWhiteTitle: ThemedStyle<TextStyle> = ({ colors }) => ({
color: colors.palette.neutral100,
})
export const DemoHeader: Demo = {
name: "Header",
description: "demoHeader:description",
data: ({ theme, themed }) => [
<DemoUseCase
name="demoHeader:useCase.actionIcons.name"
description="demoHeader:useCase.actionIcons.description"
>
<Header
titleTx="demoHeader:useCase.actionIcons.leftIconTitle"
leftIcon="ladybug"
safeAreaEdges={[]}
/>
<DemoDivider size={24} />
<Header
titleTx="demoHeader:useCase.actionIcons.rightIconTitle"
rightIcon="ladybug"
safeAreaEdges={[]}
/>
<DemoDivider size={24} />
<Header
titleTx="demoHeader:useCase.actionIcons.bothIconsTitle"
leftIcon="ladybug"
rightIcon="ladybug"
safeAreaEdges={[]}
/>
</DemoUseCase>,
<DemoUseCase
name="demoHeader:useCase.actionText.name"
description="demoHeader:useCase.actionText.description"
>
<Header
titleTx="demoHeader:useCase.actionText.leftTxTitle"
leftTx="showroomScreen:demoHeaderTxExample"
safeAreaEdges={[]}
/>
<DemoDivider size={24} />
<Header
titleTx="demoHeader:useCase.actionText.rightTextTitle"
rightText="Yay"
safeAreaEdges={[]}
/>
</DemoUseCase>,
<DemoUseCase
name="demoHeader:useCase.customActionComponents.name"
description="demoHeader:useCase.customActionComponents.description"
>
<Header
titleTx="demoHeader:useCase.customActionComponents.customLeftActionTitle"
titleMode="flex"
titleStyle={$rightAlignTitle}
LeftActionComponent={
<View style={themed([$styles.row, $customLeftAction])}>
{Array.from({ length: 20 }, (x, i) => i).map((i) => (
<Icon key={i} icon="ladybug" color={theme.colors.palette.neutral100} size={s(20)} />
))}
</View>
}
safeAreaEdges={[]}
/>
</DemoUseCase>,
<DemoUseCase
name="demoHeader:useCase.titleModes.name"
description="demoHeader:useCase.titleModes.description"
>
<Header
titleTx="demoHeader:useCase.titleModes.centeredTitle"
leftIcon="ladybug"
rightText="Hooray"
safeAreaEdges={[]}
/>
<DemoDivider size={24} />
<Header
titleTx="demoHeader:useCase.titleModes.flexTitle"
titleMode="flex"
leftIcon="ladybug"
rightText="Hooray"
safeAreaEdges={[]}
/>
</DemoUseCase>,
<DemoUseCase
name="demoHeader:useCase.styling.name"
description="demoHeader:useCase.styling.description"
>
<Header
titleTx="demoHeader:useCase.styling.styledTitle"
titleStyle={themed($customTitle)}
safeAreaEdges={[]}
/>
<DemoDivider size={24} />
<Header
titleTx="demoHeader:useCase.styling.styledWrapperTitle"
titleStyle={themed($customWhiteTitle)}
backgroundColor={theme.colors.error}
style={{ height: s(35) }}
safeAreaEdges={[]}
/>
<DemoDivider size={24} />
<Header
titleTx="demoHeader:useCase.styling.tintedIconsTitle"
titleStyle={themed($customWhiteTitle)}
backgroundColor={theme.colors.error}
leftIcon="ladybug"
leftIconColor={theme.colors.palette.neutral100}
safeAreaEdges={[]}
/>
</DemoUseCase>,
],
}

View File

@@ -0,0 +1,109 @@
/* eslint-disable react/jsx-key */
import { TextStyle, View, ViewStyle } from "react-native"
import { Icon, iconRegistry, type IconTypes } from "@/components/Icon"
import { Text } from "@/components/Text"
import { $styles } from "@/theme/styles"
import type { ThemedStyle } from "@/theme/types"
import { Demo } from "./types"
import { DemoUseCase } from "../DemoUseCase"
const $demoIconContainer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
padding: spacing.xs,
})
const $iconTile: ThemedStyle<ViewStyle> = ({ spacing }) => ({
width: "33.333%",
alignItems: "center",
paddingVertical: spacing.xs,
})
const $iconTileLabel: ThemedStyle<TextStyle> = ({ colors, spacing }) => ({
marginTop: spacing.xxs,
color: colors.textDim,
})
const $customIconContainer: ThemedStyle<ViewStyle> = ({ colors, spacing }) => ({
padding: spacing.md,
backgroundColor: colors.palette.angry500,
})
export const DemoIcon: Demo = {
name: "Icon",
description: "demoIcon:description",
data: ({ theme, themed }) => [
<DemoUseCase
name="demoIcon:useCase.icons.name"
description="demoIcon:useCase.icons.description"
layout="row"
itemStyle={$styles.flexWrap}
>
{Object.keys(iconRegistry).map((icon) => (
<View key={icon} style={themed($iconTile)}>
<Icon icon={icon as IconTypes} color={theme.colors.tint} size={35} />
<Text size="xs" style={themed($iconTileLabel)}>
{icon}
</Text>
</View>
))}
</DemoUseCase>,
<DemoUseCase
name="demoIcon:useCase.size.name"
description="demoIcon:useCase.size.description"
layout="row"
>
<Icon icon="ladybug" containerStyle={themed($demoIconContainer)} />
<Icon icon="ladybug" size={35} containerStyle={themed($demoIconContainer)} />
<Icon icon="ladybug" size={50} containerStyle={themed($demoIconContainer)} />
<Icon icon="ladybug" size={75} containerStyle={themed($demoIconContainer)} />
</DemoUseCase>,
<DemoUseCase
name="demoIcon:useCase.color.name"
description="demoIcon:useCase.color.description"
layout="row"
>
<Icon
icon="ladybug"
color={theme.colors.palette.accent500}
containerStyle={themed($demoIconContainer)}
/>
<Icon
icon="ladybug"
color={theme.colors.palette.primary500}
containerStyle={themed($demoIconContainer)}
/>
<Icon
icon="ladybug"
color={theme.colors.palette.secondary500}
containerStyle={themed($demoIconContainer)}
/>
<Icon
icon="ladybug"
color={theme.colors.palette.neutral700}
containerStyle={themed($demoIconContainer)}
/>
<Icon
icon="ladybug"
color={theme.colors.palette.angry500}
containerStyle={themed($demoIconContainer)}
/>
</DemoUseCase>,
<DemoUseCase
name="demoIcon:useCase.styling.name"
description="demoIcon:useCase.styling.description"
layout="row"
>
<Icon
icon="ladybug"
color={theme.colors.palette.neutral100}
size={40}
containerStyle={themed($customIconContainer)}
/>
</DemoUseCase>,
],
}

View File

@@ -0,0 +1,217 @@
/* eslint-disable react/jsx-key */
import { TextStyle, View, ViewStyle } from "react-native"
import { FlatList } from "react-native-gesture-handler"
import { Icon } from "@/components/Icon"
import { ListItem } from "@/components/ListItem"
import { Text } from "@/components/Text"
import { translate } from "@/i18n/translate"
import { $styles } from "@/theme/styles"
import type { ThemedStyle } from "@/theme/types"
import { s } from "@/utils/responsive"
import { DemoDivider } from "../DemoDivider"
import { Demo } from "./types"
import { DemoUseCase } from "../DemoUseCase"
const listData =
`Tempor Id Ea Aliqua Pariatur Aliquip. Irure Minim Voluptate Consectetur Consequat Sint Esse Proident Irure. Nostrud Elit Veniam Nostrud Excepteur Minim Deserunt Quis Dolore Velit Nulla Irure Voluptate Tempor. Occaecat Amet Laboris Nostrud Qui Do Quis Lorem Ex Elit Fugiat Deserunt. In Pariatur Excepteur Exercitation Ex Incididunt Qui Mollit Dolor Sit Non. Culpa Officia Minim Cillum Exercitation Voluptate Proident Laboris Et Est Reprehenderit Quis Pariatur Nisi`
.split(".")
.map((item) => item.trim())
const $customLeft: ThemedStyle<ViewStyle> = ({ colors }) => ({
backgroundColor: colors.error,
flexGrow: 0,
flexBasis: s(60),
height: "100%",
flexWrap: "wrap",
overflow: "hidden",
})
const $customTextStyle: ThemedStyle<TextStyle> = ({ colors }) => ({
color: colors.error,
})
const $customTouchableStyle: ThemedStyle<ViewStyle> = ({ colors }) => ({
backgroundColor: colors.error,
})
const $customContainerStyle: ThemedStyle<ViewStyle> = ({ colors }) => ({
borderTopWidth: 5,
borderTopColor: colors.palette.neutral100,
})
const $listStyle: ThemedStyle<ViewStyle> = ({ colors, spacing }) => ({
height: s(148),
paddingHorizontal: spacing.xs,
backgroundColor: colors.palette.neutral200,
})
export const DemoListItem: Demo = {
name: "ListItem",
description: "demoListItem:description",
data: ({ theme, themed }) => [
<DemoUseCase
name="demoListItem:useCase.height.name"
description="demoListItem:useCase.height.description"
>
<ListItem topSeparator>{translate("demoListItem:useCase.height.defaultHeight")}</ListItem>
<ListItem topSeparator height={s(100)}>
{translate("demoListItem:useCase.height.customHeight")}
</ListItem>
<ListItem topSeparator>{translate("demoListItem:useCase.height.textHeight")}</ListItem>
<ListItem topSeparator bottomSeparator TextProps={{ numberOfLines: 1 }}>
{translate("demoListItem:useCase.height.longText")}
</ListItem>
</DemoUseCase>,
<DemoUseCase
name="demoListItem:useCase.separators.name"
description="demoListItem:useCase.separators.description"
>
<ListItem topSeparator>{translate("demoListItem:useCase.separators.topSeparator")}</ListItem>
<DemoDivider size={40} />
<ListItem topSeparator bottomSeparator>
{translate("demoListItem:useCase.separators.topAndBottomSeparator")}
</ListItem>
<DemoDivider size={40} />
<ListItem bottomSeparator>
{translate("demoListItem:useCase.separators.bottomSeparator")}
</ListItem>
</DemoUseCase>,
<DemoUseCase
name="demoListItem:useCase.icons.name"
description="demoListItem:useCase.icons.description"
>
<ListItem topSeparator leftIcon="ladybug">
{translate("demoListItem:useCase.icons.leftIcon")}
</ListItem>
<ListItem topSeparator rightIcon="ladybug">
{translate("demoListItem:useCase.icons.rightIcon")}
</ListItem>
<ListItem topSeparator bottomSeparator rightIcon="ladybug" leftIcon="ladybug">
{translate("demoListItem:useCase.icons.leftRightIcons")}
</ListItem>
</DemoUseCase>,
<DemoUseCase
name="demoListItem:useCase.customLeftRight.name"
description="demoListItem:useCase.customLeftRight.description"
>
<ListItem
topSeparator
LeftComponent={
<View style={themed([$styles.row, $customLeft, { marginEnd: theme.spacing.md }])}>
{Array.from({ length: 9 }, (x, i) => i).map((i) => (
<Icon key={i} icon="ladybug" color={theme.colors.palette.neutral100} size={s(20)} />
))}
</View>
}
>
{translate("demoListItem:useCase.customLeftRight.customLeft")}
</ListItem>
<ListItem
topSeparator
bottomSeparator
RightComponent={
<View style={themed([$styles.row, $customLeft, { marginStart: theme.spacing.md }])}>
{Array.from({ length: 9 }, (x, i) => i).map((i) => (
<Icon key={i} icon="ladybug" color={theme.colors.palette.neutral100} size={s(20)} />
))}
</View>
}
>
{translate("demoListItem:useCase.customLeftRight.customRight")}
</ListItem>
</DemoUseCase>,
<DemoUseCase
name="demoListItem:useCase.passingContent.name"
description="demoListItem:useCase.passingContent.description"
>
<ListItem topSeparator text={translate("demoListItem:useCase.passingContent.children")} />
<ListItem topSeparator tx="showroomScreen:demoViaTxProp" />
<ListItem topSeparator>{translate("demoListItem:useCase.passingContent.children")}</ListItem>
<ListItem topSeparator bottomSeparator>
<Text>
<Text preset="bold">
{translate("demoListItem:useCase.passingContent.nestedChildren1")}
</Text>
{` `}
<Text preset="default">
{translate("demoListItem:useCase.passingContent.nestedChildren2")}
</Text>
</Text>
</ListItem>
</DemoUseCase>,
<DemoUseCase
name="demoListItem:useCase.listIntegration.name"
description="demoListItem:useCase.listIntegration.description"
>
<View style={themed($listStyle)}>
<FlatList<string>
data={listData}
keyExtractor={(item, index) => `${item}-${index}`}
renderItem={({ item, index }) => (
<ListItem
text={item}
rightIcon="caretRight"
TextProps={{ numberOfLines: 1 }}
topSeparator={index !== 0}
/>
)}
/>
</View>
</DemoUseCase>,
<DemoUseCase
name="demoListItem:useCase.styling.name"
description="demoListItem:useCase.styling.description"
>
<ListItem topSeparator textStyle={themed($customTextStyle)}>
{translate("demoListItem:useCase.styling.styledText")}
</ListItem>
<ListItem
topSeparator
textStyle={{ color: theme.colors.palette.neutral100 }}
style={themed($customTouchableStyle)}
>
{translate("demoListItem:useCase.styling.styledText")}
</ListItem>
<ListItem
topSeparator
textStyle={{ color: theme.colors.palette.neutral100 }}
style={themed($customTouchableStyle)}
containerStyle={themed($customContainerStyle)}
>
{translate("demoListItem:useCase.styling.styledContainer")}
</ListItem>
<ListItem
topSeparator
textStyle={{ color: theme.colors.palette.neutral100 }}
style={themed($customTouchableStyle)}
containerStyle={themed($customContainerStyle)}
rightIcon="ladybug"
leftIcon="ladybug"
rightIconColor={theme.colors.palette.neutral100}
leftIconColor={theme.colors.palette.neutral100}
>
{translate("demoListItem:useCase.styling.tintedIcons")}
</ListItem>
</DemoUseCase>,
],
}

View File

@@ -0,0 +1,142 @@
/* eslint-disable react/jsx-key, react-native/no-inline-styles */
import { Text } from "@/components/Text"
import { translate } from "@/i18n/translate"
import { DemoDivider } from "../DemoDivider"
import { Demo } from "./types"
import { DemoUseCase } from "../DemoUseCase"
export const DemoText: Demo = {
name: "Text",
description: "demoText:description",
data: ({ theme }) => [
<DemoUseCase
name="demoText:useCase.presets.name"
description="demoText:useCase.presets.description"
>
<Text>{translate("demoText:useCase.presets.default")}</Text>
<DemoDivider />
<Text preset="bold">{translate("demoText:useCase.presets.bold")}</Text>
<DemoDivider />
<Text preset="subheading">{translate("demoText:useCase.presets.subheading")}</Text>
<DemoDivider />
<Text preset="heading">{translate("demoText:useCase.presets.heading")}</Text>
</DemoUseCase>,
<DemoUseCase
name="demoText:useCase.sizes.name"
description="demoText:useCase.sizes.description"
>
<Text size="xs">{translate("demoText:useCase.sizes.xs")}</Text>
<DemoDivider />
<Text size="sm">{translate("demoText:useCase.sizes.sm")}</Text>
<DemoDivider />
<Text size="md">{translate("demoText:useCase.sizes.md")}</Text>
<DemoDivider />
<Text size="lg">{translate("demoText:useCase.sizes.lg")}</Text>
<DemoDivider />
<Text size="xl">{translate("demoText:useCase.sizes.xl")}</Text>
<DemoDivider />
<Text size="xxl">{translate("demoText:useCase.sizes.xxl")}</Text>
</DemoUseCase>,
<DemoUseCase
name="demoText:useCase.weights.name"
description="demoText:useCase.weights.description"
>
<Text weight="light">{translate("demoText:useCase.weights.light")}</Text>
<DemoDivider />
<Text weight="normal">{translate("demoText:useCase.weights.normal")}</Text>
<DemoDivider />
<Text weight="medium">{translate("demoText:useCase.weights.medium")}</Text>
<DemoDivider />
<Text weight="semiBold">{translate("demoText:useCase.weights.semibold")}</Text>
<DemoDivider />
<Text weight="bold">{translate("demoText:useCase.weights.bold")}</Text>
</DemoUseCase>,
<DemoUseCase
name="demoText:useCase.passingContent.name"
description="demoText:useCase.passingContent.description"
>
<Text text={translate("demoText:useCase.passingContent.viaText")} />
<DemoDivider />
<Text>
<Text tx="demoText:useCase.passingContent.viaTx" />
<Text tx="showroomScreen:lorem2Sentences" />
</Text>
<DemoDivider />
<Text>{translate("demoText:useCase.passingContent.children")}</Text>
<DemoDivider />
<Text>
<Text>{translate("demoText:useCase.passingContent.nestedChildren")}</Text>
<Text preset="bold">{translate("demoText:useCase.passingContent.nestedChildren2")}</Text>
{` `}
<Text preset="default">{translate("demoText:useCase.passingContent.nestedChildren3")}</Text>
{` `}
<Text preset="bold"> {translate("demoText:useCase.passingContent.nestedChildren4")}</Text>
</Text>
</DemoUseCase>,
<DemoUseCase
name="demoText:useCase.styling.name"
description="demoText:useCase.styling.description"
>
<Text>
<Text style={{ color: theme.colors.error }}>
{translate("demoText:useCase.styling.text")}
</Text>
{` `}
<Text
style={{
color: theme.colors.palette.neutral100,
backgroundColor: theme.colors.error,
}}
>
{translate("demoText:useCase.styling.text2")}
</Text>
{` `}
<Text
style={{
textDecorationLine: "underline line-through",
textDecorationStyle: "dashed",
color: theme.colors.error,
textDecorationColor: theme.colors.error,
}}
>
{translate("demoText:useCase.styling.text3")}
</Text>
</Text>
</DemoUseCase>,
],
}

View File

@@ -0,0 +1,231 @@
/* eslint-disable react/jsx-key */
import { TextStyle, ViewStyle } from "react-native"
import { Icon } from "@/components/Icon"
import { TextField } from "@/components/TextField"
import type { ThemedStyle } from "@/theme/types"
import { DemoDivider } from "../DemoDivider"
import { Demo } from "./types"
import { DemoUseCase } from "../DemoUseCase"
const $customInputStyle: ThemedStyle<TextStyle> = ({ colors }) => ({
backgroundColor: colors.error,
color: colors.palette.neutral100,
})
const $customInputWrapperStyle: ThemedStyle<ViewStyle> = ({ colors }) => ({
backgroundColor: colors.error,
borderColor: colors.palette.neutral800,
})
const $customContainerStyle: ThemedStyle<ViewStyle> = ({ colors }) => ({
backgroundColor: colors.error,
})
const $customLabelAndHelperStyle: ThemedStyle<TextStyle> = ({ colors }) => ({
color: colors.palette.neutral100,
})
const $customInputWithAbsoluteAccessoriesStyle: ThemedStyle<ViewStyle> = ({ spacing }) => ({
marginHorizontal: spacing.xxl,
})
const $customLeftAccessoryStyle: ThemedStyle<ViewStyle> = ({ colors }) => ({
backgroundColor: colors.error,
position: "absolute",
left: 0,
})
const $customRightAccessoryStyle: ThemedStyle<ViewStyle> = ({ colors }) => ({
backgroundColor: colors.error,
position: "absolute",
right: 0,
})
export const DemoTextField: Demo = {
name: "TextField",
description: "demoTextField:description",
data: ({ themed }) => [
<DemoUseCase
name="demoTextField:useCase.statuses.name"
description="demoTextField:useCase.statuses.description"
>
<TextField
value="Labore occaecat in id eu commodo aliquip occaecat veniam officia pariatur."
labelTx="demoTextField:useCase.statuses.noStatus.label"
labelTxOptions={{ prop: "label" }}
helperTx="demoTextField:useCase.statuses.noStatus.helper"
helperTxOptions={{ prop: "helper" }}
placeholderTx="demoTextField:useCase.statuses.noStatus.placeholder"
placeholderTxOptions={{ prop: "placeholder" }}
/>
<DemoDivider size={24} />
<TextField
status="error"
value="Est Lorem duis sunt sunt duis proident minim elit dolore incididunt pariatur eiusmod anim cillum."
labelTx="demoTextField:useCase.statuses.error.label"
labelTxOptions={{ prop: "label" }}
helperTx="demoTextField:useCase.statuses.error.helper"
helperTxOptions={{ prop: "helper" }}
placeholderTx="demoTextField:useCase.statuses.error.placeholder"
placeholderTxOptions={{ prop: "placeholder" }}
/>
<DemoDivider size={24} />
<TextField
status="disabled"
value="Eu ipsum mollit non minim voluptate nulla fugiat aliqua ullamco aute consectetur nulla nulla amet."
labelTx="demoTextField:useCase.statuses.disabled.label"
labelTxOptions={{ prop: "label" }}
helperTx="demoTextField:useCase.statuses.disabled.helper"
helperTxOptions={{ prop: "helper" }}
placeholderTx="demoTextField:useCase.statuses.disabled.placeholder"
placeholderTxOptions={{ prop: "placeholder" }}
/>
</DemoUseCase>,
<DemoUseCase
name="demoTextField:useCase.passingContent.name"
description="demoTextField:useCase.passingContent.description"
>
<TextField
labelTx="demoTextField:useCase.passingContent.viaLabel.labelTx"
labelTxOptions={{ prop: "label" }}
helperTx="demoTextField:useCase.passingContent.viaLabel.helper"
helperTxOptions={{ prop: "helper" }}
placeholderTx="demoTextField:useCase.passingContent.viaLabel.placeholder"
placeholderTxOptions={{ prop: "placeholder" }}
/>
<DemoDivider size={24} />
<TextField
labelTx="showroomScreen:demoViaSpecifiedTxProp"
labelTxOptions={{ prop: "label" }}
helperTx="showroomScreen:demoViaSpecifiedTxProp"
helperTxOptions={{ prop: "helper" }}
placeholderTx="showroomScreen:demoViaSpecifiedTxProp"
placeholderTxOptions={{ prop: "placeholder" }}
/>
<DemoDivider size={24} />
<TextField
value="Reprehenderit Lorem magna non consequat ullamco cupidatat."
labelTx="demoTextField:useCase.passingContent.rightAccessory.label"
labelTxOptions={{ prop: "label" }}
helperTx="demoTextField:useCase.passingContent.rightAccessory.helper"
helperTxOptions={{ prop: "helper" }}
RightAccessory={(props) => <Icon icon="ladybug" containerStyle={props.style} size={21} />}
/>
<DemoDivider size={24} />
<TextField
labelTx="demoTextField:useCase.passingContent.leftAccessory.label"
labelTxOptions={{ prop: "label" }}
helperTx="demoTextField:useCase.passingContent.leftAccessory.helper"
helperTxOptions={{ prop: "helper" }}
value="Eiusmod exercitation mollit elit magna occaecat eiusmod Lorem minim veniam."
LeftAccessory={(props) => <Icon icon="ladybug" containerStyle={props.style} size={21} />}
/>
<DemoDivider size={24} />
<TextField
labelTx="demoTextField:useCase.passingContent.supportsMultiline.label"
labelTxOptions={{ prop: "label" }}
helperTx="demoTextField:useCase.passingContent.supportsMultiline.helper"
helperTxOptions={{ prop: "helper" }}
value="Eiusmod exercitation mollit elit magna occaecat eiusmod Lorem minim veniam. Laborum Lorem velit velit minim irure ad in ut adipisicing consectetur."
multiline
RightAccessory={(props) => <Icon icon="ladybug" containerStyle={props.style} size={21} />}
/>
</DemoUseCase>,
<DemoUseCase
name="demoTextField:useCase.styling.name"
description="demoTextField:useCase.styling.description"
>
<TextField
labelTx="demoTextField:useCase.styling.styleInput.label"
labelTxOptions={{ prop: "label" }}
helperTx="demoTextField:useCase.styling.styleInput.helper"
helperTxOptions={{ prop: "helper" }}
value="Laborum cupidatat aliquip sunt sunt voluptate sint sit proident sunt mollit exercitation ullamco ea elit."
style={themed($customInputStyle)}
/>
<DemoDivider size={24} />
<TextField
labelTx="demoTextField:useCase.styling.styleInputWrapper.label"
labelTxOptions={{ prop: "label" }}
helperTx="demoTextField:useCase.styling.styleInputWrapper.helper"
helperTxOptions={{ prop: "helper" }}
value="Aute velit esse dolore pariatur exercitation irure nulla do sunt in duis mollit duis et."
inputWrapperStyle={themed($customInputWrapperStyle)}
style={themed($customInputStyle)}
/>
<DemoDivider size={24} />
<TextField
labelTx="demoTextField:useCase.styling.styleContainer.label"
labelTxOptions={{ prop: "label" }}
helperTx="demoTextField:useCase.styling.styleContainer.helper"
helperTxOptions={{ prop: "helper" }}
value="Aliquip proident commodo adipisicing non adipisicing Lorem excepteur ullamco voluptate laborum."
style={themed($customInputStyle)}
containerStyle={themed($customContainerStyle)}
inputWrapperStyle={themed($customInputWrapperStyle)}
/>
<DemoDivider size={24} />
<TextField
labelTx="demoTextField:useCase.styling.styleLabel.label"
labelTxOptions={{ prop: "label" }}
helperTx="demoTextField:useCase.styling.styleLabel.helper"
helperTxOptions={{ prop: "helper" }}
value="Ex culpa in consectetur dolor irure velit."
style={themed($customInputStyle)}
containerStyle={themed($customContainerStyle)}
inputWrapperStyle={themed($customInputWrapperStyle)}
HelperTextProps={{ style: themed($customLabelAndHelperStyle) }}
LabelTextProps={{ style: themed($customLabelAndHelperStyle) }}
/>
<DemoDivider size={24} />
<TextField
labelTx="demoTextField:useCase.styling.styleAccessories.label"
labelTxOptions={{ prop: "label" }}
helperTx="demoTextField:useCase.styling.styleAccessories.helper"
helperTxOptions={{ prop: "helper" }}
value="Aute nisi dolore fugiat anim mollit nulla ex minim ipsum ex elit."
style={themed($customInputWithAbsoluteAccessoriesStyle)}
LeftAccessory={() => (
<Icon
icon="ladybug"
containerStyle={themed($customLeftAccessoryStyle)}
color="white"
size={41}
/>
)}
RightAccessory={() => (
<Icon
icon="ladybug"
containerStyle={themed($customRightAccessoryStyle)}
color="white"
size={41}
/>
)}
/>
</DemoUseCase>,
],
}

View File

@@ -0,0 +1,348 @@
/* eslint-disable react/jsx-key, react-native/no-inline-styles */
import { useState } from "react"
import { TextStyle, View, ViewStyle } from "react-native"
import { Text } from "@/components/Text"
import { Checkbox, CheckboxToggleProps } from "@/components/Toggle/Checkbox"
import { Radio, RadioToggleProps } from "@/components/Toggle/Radio"
import { Switch, SwitchToggleProps } from "@/components/Toggle/Switch"
import { translate } from "@/i18n/translate"
import { $styles } from "@/theme/styles"
import type { ThemedStyle } from "@/theme/types"
import { s } from "@/utils/responsive"
import { DemoDivider } from "../DemoDivider"
import { Demo } from "./types"
import { DemoUseCase } from "../DemoUseCase"
function ControlledCheckbox(props: CheckboxToggleProps) {
const [value, setValue] = useState(props.value || false)
return <Checkbox {...props} value={value} onPress={() => setValue(!value)} />
}
function ControlledRadio(props: RadioToggleProps) {
const [value, setValue] = useState(props.value || false)
return <Radio {...props} value={value} onPress={() => setValue(!value)} />
}
function ControlledSwitch(props: SwitchToggleProps) {
const [value, setValue] = useState(props.value || false)
return <Switch {...props} value={value} onPress={() => setValue(!value)} />
}
const $centeredOneThirdCol: ViewStyle = {
width: "33.33333%",
alignItems: "center",
justifyContent: "center",
}
const $centeredText: ThemedStyle<TextStyle> = ({ spacing }) => ({
textAlign: "center",
width: "100%",
marginTop: spacing.xs,
})
export const DemoToggle: Demo = {
name: "Toggle",
description: "demoToggle:description",
data: ({ theme, themed }) => [
<DemoUseCase
name="demoToggle:useCase.variants.name"
description="demoToggle:useCase.variants.description"
>
<ControlledCheckbox
labelTx="demoToggle:useCase.variants.checkbox.label"
helperTx="demoToggle:useCase.variants.checkbox.helper"
/>
<DemoDivider size={24} />
<ControlledRadio
labelTx="demoToggle:useCase.variants.radio.label"
helperTx="demoToggle:useCase.variants.radio.helper"
/>
<DemoDivider size={24} />
<ControlledSwitch
labelTx="demoToggle:useCase.variants.switch.label"
helperTx="demoToggle:useCase.variants.switch.helper"
/>
</DemoUseCase>,
<DemoUseCase
name="demoToggle:useCase.statuses.name"
description="demoToggle:useCase.statuses.description"
layout="row"
itemStyle={$styles.flexWrap}
>
<ControlledCheckbox containerStyle={$centeredOneThirdCol} />
<ControlledRadio containerStyle={$centeredOneThirdCol} />
<ControlledSwitch containerStyle={$centeredOneThirdCol} />
<DemoDivider style={{ width: "100%" }} />
<ControlledCheckbox value containerStyle={$centeredOneThirdCol} />
<ControlledRadio value containerStyle={$centeredOneThirdCol} />
<ControlledSwitch value containerStyle={$centeredOneThirdCol} />
<Text preset="formHelper" style={themed($centeredText)}>
{translate("demoToggle:useCase.statuses.noStatus")}
</Text>
<DemoDivider size={24} style={{ width: "100%" }} />
<ControlledCheckbox status="error" containerStyle={$centeredOneThirdCol} />
<ControlledRadio status="error" containerStyle={$centeredOneThirdCol} />
<ControlledSwitch status="error" containerStyle={$centeredOneThirdCol} />
<DemoDivider style={{ width: "100%" }} />
<ControlledCheckbox value status="error" containerStyle={$centeredOneThirdCol} />
<ControlledRadio value status="error" containerStyle={$centeredOneThirdCol} />
<ControlledSwitch value status="error" containerStyle={$centeredOneThirdCol} />
<Text preset="formHelper" style={themed($centeredText)}>
{translate("demoToggle:useCase.statuses.errorStatus")}
</Text>
<DemoDivider size={24} style={{ width: "100%" }} />
<ControlledCheckbox status="disabled" containerStyle={$centeredOneThirdCol} />
<ControlledRadio status="disabled" containerStyle={$centeredOneThirdCol} />
<ControlledSwitch status="disabled" containerStyle={$centeredOneThirdCol} />
<DemoDivider style={{ width: "100%" }} />
<ControlledCheckbox value status="disabled" containerStyle={$centeredOneThirdCol} />
<ControlledRadio value status="disabled" containerStyle={$centeredOneThirdCol} />
<ControlledSwitch value status="disabled" containerStyle={$centeredOneThirdCol} />
<Text preset="formHelper" style={themed($centeredText)}>
{translate("demoToggle:useCase.statuses.disabledStatus")}
</Text>
</DemoUseCase>,
<DemoUseCase
name="demoToggle:useCase.passingContent.name"
description="demoToggle:useCase.passingContent.description"
>
<ControlledCheckbox
value
labelTx="demoToggle:useCase.passingContent.useCase.checkBox.label"
helperTx="demoToggle:useCase.passingContent.useCase.checkBox.helper"
/>
<DemoDivider size={24} />
<ControlledRadio
value
labelTx="showroomScreen:demoViaSpecifiedTxProp"
labelTxOptions={{ prop: "label" }}
helperTx="showroomScreen:demoViaSpecifiedTxProp"
helperTxOptions={{ prop: "helper" }}
/>
<DemoDivider size={24} />
<ControlledCheckbox
value
labelTx="demoToggle:useCase.passingContent.useCase.checkBoxMultiLine.helper"
editable={false}
/>
<DemoDivider size={24} />
<ControlledRadio
value
labelTx="demoToggle:useCase.passingContent.useCase.radioChangeSides.helper"
labelPosition="left"
/>
<DemoDivider size={24} />
<ControlledCheckbox
value
status="error"
icon="ladybug"
labelTx="demoToggle:useCase.passingContent.useCase.customCheckBox.label"
/>
<DemoDivider size={24} />
<ControlledSwitch
value
accessibilityMode="text"
labelTx="demoToggle:useCase.passingContent.useCase.switch.label"
status="error"
helperTx="demoToggle:useCase.passingContent.useCase.switch.helper"
/>
<DemoDivider size={24} />
<ControlledSwitch
value
labelPosition="left"
accessibilityMode="icon"
labelTx="demoToggle:useCase.passingContent.useCase.switchAid.label"
/>
</DemoUseCase>,
<DemoUseCase
name="demoToggle:useCase.styling.name"
description="demoToggle:useCase.styling.description"
layout="row"
itemStyle={$styles.flexWrap}
>
<ControlledCheckbox
containerStyle={$centeredOneThirdCol}
inputOuterStyle={{
width: s(50),
height: s(50),
backgroundColor: theme.colors.palette.accent300,
borderColor: theme.colors.palette.accent500,
}}
/>
<ControlledRadio
containerStyle={$centeredOneThirdCol}
inputOuterStyle={{
width: s(50),
height: s(50),
borderRadius: s(25),
backgroundColor: theme.colors.palette.accent300,
borderColor: theme.colors.palette.accent500,
}}
/>
<ControlledSwitch
containerStyle={$centeredOneThirdCol}
inputOuterStyle={{
width: s(70),
height: s(50),
borderRadius: s(25),
backgroundColor: theme.colors.palette.accent300,
borderColor: theme.colors.palette.accent500,
}}
/>
<Text preset="formHelper" style={themed($centeredText)}>
{translate("demoToggle:useCase.styling.outerWrapper")}
</Text>
<DemoDivider style={{ width: "100%" }} />
<ControlledCheckbox
value
containerStyle={$centeredOneThirdCol}
inputOuterStyle={{
width: s(50),
height: s(50),
backgroundColor: theme.colors.palette.accent300,
borderColor: theme.colors.palette.accent500,
}}
inputInnerStyle={{
backgroundColor: theme.colors.palette.accent500,
}}
/>
<ControlledRadio
value
containerStyle={$centeredOneThirdCol}
inputOuterStyle={{
width: s(50),
height: s(50),
borderRadius: s(25),
backgroundColor: theme.colors.palette.accent300,
borderColor: theme.colors.palette.accent500,
}}
inputInnerStyle={{
backgroundColor: theme.colors.palette.accent500,
}}
/>
<ControlledSwitch
value
containerStyle={$centeredOneThirdCol}
inputOuterStyle={{
width: s(70),
height: s(50),
borderRadius: s(25),
backgroundColor: theme.colors.palette.accent300,
borderColor: theme.colors.palette.accent500,
}}
inputInnerStyle={{
backgroundColor: theme.colors.palette.accent500,
paddingLeft: s(10),
paddingRight: s(10),
}}
/>
<Text preset="formHelper" style={themed($centeredText)}>
{translate("demoToggle:useCase.styling.innerWrapper")}
</Text>
<DemoDivider style={{ width: "100%" }} />
<ControlledCheckbox
value
icon="ladybug"
containerStyle={$centeredOneThirdCol}
inputOuterStyle={{
width: s(50),
height: s(50),
backgroundColor: theme.colors.palette.accent300,
borderColor: theme.colors.palette.accent500,
}}
inputInnerStyle={{
backgroundColor: theme.colors.palette.accent500,
}}
/>
<ControlledRadio
value
containerStyle={$centeredOneThirdCol}
inputOuterStyle={{
width: s(50),
height: s(50),
borderRadius: s(25),
backgroundColor: theme.colors.palette.accent300,
borderColor: theme.colors.palette.accent500,
}}
inputInnerStyle={{
backgroundColor: theme.colors.palette.accent500,
}}
inputDetailStyle={{
backgroundColor: theme.colors.tint,
height: s(36),
width: s(36),
borderRadius: s(18),
}}
/>
<ControlledSwitch
value
containerStyle={$centeredOneThirdCol}
inputOuterStyle={{
width: s(70),
height: s(50),
borderRadius: s(25),
backgroundColor: theme.colors.palette.accent300,
borderColor: theme.colors.palette.accent500,
}}
inputInnerStyle={{
backgroundColor: theme.colors.tint,
paddingLeft: s(10),
paddingRight: s(10),
}}
inputDetailStyle={{
backgroundColor: theme.colors.palette.accent300,
height: s(36),
width: s(18),
borderRadius: s(36),
}}
accessibilityMode="icon"
/>
<Text preset="formHelper" style={themed($centeredText)}>
{translate("demoToggle:useCase.styling.inputDetail")}
</Text>
<DemoDivider size={32} style={{ width: "100%" }} />
<View style={{ width: "100%" }}>
<ControlledRadio
value
labelTx="demoToggle:useCase.styling.labelTx"
LabelTextProps={{ size: "xs", weight: "bold" }}
status="error"
labelStyle={{
backgroundColor: theme.colors.error,
color: theme.colors.palette.neutral100,
paddingHorizontal: s(5),
}}
/>
</View>
<DemoDivider size={24} style={{ width: "100%" }} />
<View style={{ width: "100%" }}>
<ControlledRadio
value
labelPosition="left"
containerStyle={{ padding: s(10), backgroundColor: theme.colors.error }}
labelTx="demoToggle:useCase.styling.styleContainer"
status="error"
labelStyle={{ color: theme.colors.palette.neutral100 }}
/>
</View>
</DemoUseCase>,
],
}

View File

@@ -0,0 +1,10 @@
export * from "./DemoIcon"
export * from "./DemoTextField"
export * from "./DemoToggle"
export * from "./DemoButton"
export * from "./DemoListItem"
export * from "./DemoCard"
export * from "./DemoAutoImage"
export * from "./DemoText"
export * from "./DemoHeader"
export * from "./DemoEmptyState"

View File

@@ -0,0 +1,10 @@
import { ReactElement } from "react"
import { TxKeyPath } from "@/i18n"
import type { Theme } from "@/theme/types"
export interface Demo {
name: string
description: TxKeyPath
data: ({ themed, theme }: { themed: any; theme: Theme }) => ReactElement[]
}