Рамка, мягкий ореол вокруг карточки (spread) и слабая подсветка фона (spotlight) — радиальные градиенты в Skia с центром под указателем. Свет плавно догоняет курсор или палец и гаснет до idleIntensity, когда указатель уходит.
В комплекте GlowBadge — бейдж с дышащим свечением. Пульс останавливается, когда приложение свёрнуто или в системе включено «Уменьшение движения».
Поставьте зависимости:
npm install @shopify/react-native-skia react-native-gesture-handler react-native-reanimatedpnpm add @shopify/react-native-skia react-native-gesture-handler react-native-reanimatedyarn add @shopify/react-native-skia react-native-gesture-handler react-native-reanimatedbun add @shopify/react-native-skia react-native-gesture-handler react-native-reanimatedСкопируйте эти файлы в src/shared/components/organisms/glow-card/:
Проверьте алиас путей. Импорты в коде выше записаны так, как их пишет astra-rn add: @/shared/components, @/shared/utils и @/shared/hooks. Нужен алиас "@/*": ["./src/*"] в tsconfig.json — или поправьте импорты под свои пути.
import { useRef } from "react";
import { StyleSheet, Text, View } from "react-native";
import { StatusBar } from "expo-status-bar";
import { Ionicons } from "@expo/vector-icons";
import { GlowBadge, GlowCard, type GlowCardHandle } from "@/shared/components/organisms/glow-card";
import { Showcase, useAutoplay, useCustomize } from "~/showcase";
const WIDTH = 320;
const HEIGHT = 230;
const CUSTOMIZE = [
{ key: "title", label: "Заголовок", type: "text", default: "Тариф «Про»", maxLength: 24 },
{ key: "text", label: "Текст", type: "text", default: "Все компоненты, исходники и обновления без ограничений.", maxLength: 90 },
{ key: "badge", label: "Бейдж", type: "text", default: "НОВОЕ", maxLength: 12 },
{ key: "glowColor", label: "Цвет свечения", type: "color", default: "#66d9e8" },
{ key: "badgeColor", label: "Цвет бейджа", type: "color", default: "#66d9e8" },
{ key: "glowRadius", label: "Радиус свечения", type: "slider", min: 60, max: 320, step: 5, unit: "px", default: 170 },
{ key: "spread", label: "Ореол", type: "slider", min: 0, max: 48, step: 1, unit: "px", default: 28 },
{ key: "borderWidth", label: "Толщина рамки", type: "slider", min: 0.5, max: 4, step: 0.5, unit: "px", default: 1.5 },
{ key: "idleIntensity", label: "Свечение в покое", type: "slider", min: 0, max: 1, step: 0.05, default: 0 },
{ key: "radius", label: "Скругление", type: "slider", min: 0, max: 40, step: 1, unit: "px", default: 26 },
] as const;
export default function App() {
const custom = useCustomize(CUSTOMIZE);
const card = useRef<GlowCardHandle>(null);
useAutoplay(async ({ wait }) => {
card.current?.moveTo(0, 0);
await wait(300);
for (const [x, y] of [
[WIDTH, 0],
[WIDTH, HEIGHT],
[0, HEIGHT],
[0, 0],
] as const) {
card.current?.moveTo(x, y);
await wait(800);
}
card.current?.release();
await wait(900);
});
return (
<Showcase>
<View style={styles.container}>
<StatusBar style="light" />
<GlowCard
ref={card}
width={WIDTH}
height={HEIGHT}
radius={custom.radius}
glowColor={custom.glowColor}
glowRadius={custom.glowRadius}
spread={custom.spread}
borderWidth={custom.borderWidth}
idleIntensity={custom.idleIntensity}
>
<View style={styles.body}>
<View style={styles.row}>
<View style={styles.icon}>
<Ionicons name="layers-outline" size={20} color="#f5f2ef" />
</View>
<GlowBadge label={custom.badge} color={custom.badgeColor} />
</View>
<Text style={styles.title}>{custom.title}</Text>
<Text style={styles.text}>{custom.text}</Text>
</View>
</GlowCard>
</View>
</Showcase>
);
}
const styles = StyleSheet.create({
container: { flex: 1, alignItems: "center", justifyContent: "center", gap: 28, overflow: "hidden" },
body: { flex: 1, padding: 22, gap: 10 },
row: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", marginBottom: 14 },
icon: {
width: 42,
height: 42,
borderRadius: 14,
backgroundColor: "#1c1c1c",
borderWidth: 1,
borderColor: "#2a2a2a",
alignItems: "center",
justifyContent: "center",
},
title: { color: "#f5f2ef", fontSize: 22, fontWeight: "700", letterSpacing: -0.4 },
text: { color: "#a5a19d", fontSize: 15, lineHeight: 21 },
});children?Тип ReactNode
width?Тип number
height?Тип number
radius?Тип number
glowColor?Тип string
glowRadius?Тип number
spread?Тип number
borderWidth?Тип number
borderColor?Тип string
backgroundColor?Тип string
spotlight?Тип number
idleIntensity?Тип number
style?Тип StyleProp<ViewStyle>
moveToТип (x: number, y: number) => void
releaseТип () => void
labelТип string
color?Тип string
textColor?Тип string
backgroundColor?Тип string
glow?Тип number
period?Тип number
animated?Тип boolean
style?Тип StyleProp<ViewStyle>
textStyle?Тип StyleProp<TextStyle>