Компоненты/Карточка со свечением

Карточка со свечением

27 сентября 2026

Рамка карточки загорается там, где палец или курсор

Установка

npx astra-rn add glow-card
pnpm dlx astra-rn add glow-card
yarn dlx astra-rn add glow-card
bunx --bun astra-rn add glow-card

Файлы

index.tsx
НазадГрафик активностиДалееТягучий поповер

Как это работает

Рамка, мягкий ореол вокруг карточки (spread) и слабая подсветка фона (spotlight) — радиальные градиенты в Skia с центром под указателем. Свет плавно догоняет курсор или палец и гаснет до idleIntensity, когда указатель уходит.

В комплекте GlowBadge — бейдж с дышащим свечением. Пульс останавливается, когда приложение свёрнуто или в системе включено «Уменьшение движения».

Вручную

Поставьте зависимости:

npm install @shopify/react-native-skia react-native-gesture-handler react-native-reanimated
pnpm add @shopify/react-native-skia react-native-gesture-handler react-native-reanimated
yarn add @shopify/react-native-skia react-native-gesture-handler react-native-reanimated
bun 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>

Методы через ref

Пропс
Описание
moveTo

Тип (x: number, y: number) => void

release

Тип () => void

GlowBadge

Пропс
Описание
label

Тип string

color?

Тип string

textColor?

Тип string

backgroundColor?

Тип string

glow?

Тип number

period?

Тип number

animated?

Тип boolean

style?

Тип StyleProp<ViewStyle>

textStyle?

Тип StyleProp<TextStyle>