Поставьте зависимости:
npm install expo-linear-gradient react-native-reanimatedpnpm add expo-linear-gradient react-native-reanimatedyarn add expo-linear-gradient react-native-reanimatedbun add expo-linear-gradient react-native-reanimatedСкопируйте эти файлы в src/shared/components/molecules/Shimmer/:
Проверьте алиас путей. Импорты в коде выше записаны так, как их пишет astra-rn add: @/shared/components, @/shared/utils и @/shared/hooks. Нужен алиас "@/*": ["./src/*"] в tsconfig.json — или поправьте импорты под свои пути.
import { View, Text, StyleSheet, Pressable, ScrollView } from "react-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { StatusBar } from "expo-status-bar";
import { useFonts } from "expo-font";
import { ShimmerGroup, Shimmer } from "@/shared/components/molecules/Shimmer";
import { useMemo, useState } from "react";
import { Showcase, useCustomize } from "~/showcase";
import type { ShimmerPreset } from "@/shared/components/molecules/Shimmer/Shimmer.types";
const PRESETS: ShimmerPreset[] = ["dark", "light", "twitter", "neutral"];
const CUSTOM_COLORS = [
"rgba(88, 28, 135, 1)",
"rgba(147, 51, 234, 1)",
"rgba(232, 121, 249, 1)",
"rgba(147, 51, 234, 1)",
"rgba(88, 28, 135, 1)",
];
const CUSTOM_HEX = ["#581c87", "#9333ea", "#e879f9"];
const CUSTOMIZE = [
{ key: "preset", label: "Пресет", type: "select", options: ["dark", "light", "twitter", "neutral"], default: "dark" },
{ key: "variant", label: "Вид карточки", type: "select", options: ["shimmer", "pulse"], default: "shimmer" },
{ key: "duration", label: "Длительность", type: "slider", min: 300, max: 4000, step: 50, unit: "ms", default: 1200 },
{ key: "opacity", label: "Прозрачность", type: "slider", min: 0.1, max: 1, step: 0.05, default: 0.7 },
{ key: "customDuration", label: "Свои цвета: темп", type: "slider", min: 300, max: 4000, step: 50, unit: "ms", default: 1400 },
{ key: "colorEdge", label: "Цвет краёв", type: "color", default: CUSTOM_HEX[0] },
{ key: "colorMid", label: "Цвет середины", type: "color", default: CUSTOM_HEX[1] },
{ key: "colorPeak", label: "Цвет блика", type: "color", default: CUSTOM_HEX[2] },
{ key: "title", label: "Заголовок", type: "text", default: "Shimmer", maxLength: 40 },
{ key: "subtitle", label: "Подзаголовок", type: "text", default: "Placeholder skeletons while content loads.", maxLength: 80 },
] as const;
export default function App(_$_: Record<string, unknown>) {
const [fontLoaded, fontError] = useFonts({
SfProRounded: require("@/assets/fonts/sf-pro-rounded.ttf"),
HelveticaNowDisplay: require("@/assets/fonts/HelveticaNowDisplayMedium.ttf"),
});
const custom = useCustomize(CUSTOMIZE);
const [presetState, setPreset] = useState<ShimmerPreset>("dark");
const [presetSource, setPresetSource] = useState<string>(custom.preset);
if (presetSource !== custom.preset) {
setPresetSource(custom.preset);
setPreset(custom.preset as ShimmerPreset);
}
const preset = presetState;
const { colorEdge, colorMid, colorPeak } = custom;
const customColors = useMemo(
() =>
colorEdge === CUSTOM_HEX[0] &&
colorMid === CUSTOM_HEX[1] &&
colorPeak === CUSTOM_HEX[2]
? CUSTOM_COLORS
: [colorEdge, colorMid, colorPeak, colorMid, colorEdge],
[colorEdge, colorMid, colorPeak],
);
const customBase = colorEdge === CUSTOM_HEX[0] ? undefined : { backgroundColor: colorEdge };
const display = fontLoaded ? "HelveticaNowDisplay" : undefined;
const text = fontLoaded ? "SfProRounded" : undefined;
return (
<Showcase>
<GestureHandlerRootView style={styles.container}>
<StatusBar style="light" />
<ScrollView
style={{ opacity: fontLoaded || fontError ? 1 : 0 }}
contentContainerStyle={styles.content}
showsVerticalScrollIndicator={false}
>
<Text style={[styles.title, { fontFamily: display }]}>{custom.title}</Text>
<Text style={[styles.subtitle, { fontFamily: text }]}>
{custom.subtitle}
</Text>
<View style={styles.presetRow}>
{PRESETS.map((item) => {
const active = item === preset;
return (
<Pressable
key={item}
onPress={() => setPreset(item)}
style={[styles.presetChip, active && styles.presetChipActive]}
>
<Text
style={[
styles.presetLabel,
active && styles.presetLabelActive,
{ fontFamily: text },
]}
>
{item}
</Text>
</Pressable>
);
})}
</View>
<Text style={[styles.sectionLabel, { fontFamily: text }]}>Card</Text>
<View style={styles.card}>
<ShimmerGroup
preset={preset}
duration={custom.duration}
opacity={custom.opacity}
variant={custom.variant as "shimmer" | "pulse"}
>
<Shimmer style={styles.cover} />
<View style={styles.cardBody}>
<Shimmer style={styles.lineLg} />
<Shimmer style={styles.lineMd} />
<Shimmer style={styles.lineSm} />
</View>
</ShimmerGroup>
</View>
<Text style={[styles.sectionLabel, { fontFamily: text }]}>List</Text>
<View style={styles.card}>
<ShimmerGroup preset={preset} duration={custom.duration}>
{[0, 1, 2].map((row) => (
<View key={row} style={styles.listRow}>
<Shimmer style={styles.avatar} />
<View style={styles.listRowText}>
<Shimmer style={styles.lineMd} />
<Shimmer style={styles.lineSm} />
</View>
<Shimmer style={styles.trailing} />
</View>
))}
</ShimmerGroup>
</View>
<Text style={[styles.sectionLabel, { fontFamily: text }]}>
Variants
</Text>
<View style={styles.card}>
<View style={styles.variantRow}>
<View style={styles.variantCell}>
<Shimmer
preset={preset}
variant="shimmer"
duration={custom.duration}
style={styles.tile}
/>
<Text style={[styles.caption, { fontFamily: text }]}>
shimmer
</Text>
</View>
<View style={styles.variantCell}>
<Shimmer
preset={preset}
variant="pulse"
duration={custom.duration}
style={styles.tile}
/>
<Text style={[styles.caption, { fontFamily: text }]}>
pulse
</Text>
</View>
</View>
</View>
<Text style={[styles.sectionLabel, { fontFamily: text }]}>
Custom colors
</Text>
<View style={styles.card}>
<ShimmerGroup
preset="custom"
shimmerColors={customColors}
duration={custom.customDuration}
>
<Shimmer style={{ ...styles.customTile, ...customBase }} />
<Shimmer style={{ ...styles.customLineLg, ...customBase }} />
<Shimmer style={{ ...styles.customLineMd, ...customBase }} />
</ShimmerGroup>
</View>
<Text style={[styles.sectionLabel, { fontFamily: text }]}>
Directions
</Text>
<View style={styles.card}>
<ShimmerGroup preset={preset} duration={custom.duration}>
<Shimmer direction="leftToRight" style={styles.bar} />
<Shimmer direction="rightToLeft" style={styles.bar} />
<Shimmer direction="topToBottom" style={styles.bar} />
<Shimmer direction="bottomToTop" style={styles.bar} />
</ShimmerGroup>
</View>
</ScrollView>
</GestureHandlerRootView>
</Showcase>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#0a0a0a",
},
content: {
paddingHorizontal: 24,
paddingTop: 72,
paddingBottom: 64,
},
title: {
fontSize: 30,
fontWeight: "600",
color: "#fff",
},
subtitle: {
fontSize: 14,
color: "#777",
marginTop: 6,
},
presetRow: {
flexDirection: "row",
flexWrap: "wrap",
gap: 8,
marginTop: 20,
},
presetChip: {
paddingHorizontal: 14,
paddingVertical: 7,
borderRadius: 999,
backgroundColor: "rgba(255,255,255,0.06)",
},
presetChipActive: {
backgroundColor: "#fff",
},
presetLabel: {
fontSize: 13,
color: "#999",
},
presetLabelActive: {
color: "#000",
},
sectionLabel: {
fontSize: 12,
color: "#555",
textTransform: "uppercase",
letterSpacing: 1,
marginTop: 32,
marginBottom: 12,
},
card: {
backgroundColor: "#141414",
borderRadius: 20,
padding: 16,
gap: 12,
},
cover: {
width: "100%",
height: 140,
borderRadius: 14,
},
cardBody: {
gap: 10,
},
lineLg: {
width: "80%",
height: 18,
borderRadius: 6,
},
lineMd: {
width: "60%",
height: 13,
borderRadius: 5,
},
lineSm: {
width: "40%",
height: 13,
borderRadius: 5,
},
listRow: {
flexDirection: "row",
alignItems: "center",
gap: 12,
},
listRowText: {
flex: 1,
gap: 8,
},
avatar: {
width: 46,
height: 46,
borderRadius: 23,
},
trailing: {
width: 26,
height: 26,
borderRadius: 8,
},
variantRow: {
flexDirection: "row",
gap: 12,
},
variantCell: {
flex: 1,
gap: 8,
alignItems: "center",
},
tile: {
width: "100%",
height: 72,
borderRadius: 14,
},
caption: {
fontSize: 11,
color: "#666",
},
bar: {
width: "100%",
height: 34,
borderRadius: 10,
},
customTile: {
width: "100%",
height: 72,
borderRadius: 14,
backgroundColor: "rgba(88, 28, 135, 1)",
},
customLineLg: {
width: "80%",
height: 18,
borderRadius: 6,
backgroundColor: "rgba(88, 28, 135, 1)",
},
customLineMd: {
width: "60%",
height: 13,
borderRadius: 5,
backgroundColor: "rgba(88, 28, 135, 1)",
},
});isLoading?Тип boolean
shimmerColors?Тип string[]
duration?Тип number
className?@deprecated
Тип string
style?Тип ViewStyle
variant?Тип "shimmer" | "pulse"
direction?Тип ShimmerDirection
preset?Тип ShimmerPreset
opacity?Тип number
children?Тип ReactNode
isLoading?Тип boolean
childrenТип ReactNode
preset?Тип ShimmerPreset
shimmerColors?Тип string[]
duration?Тип number
direction?Тип ShimmerDirection
variant?Тип "shimmer" | "pulse"
opacity?Тип number