Компоненты/Подписка по почте

Подписка по почте

28 сентября 2026

Кнопка с колокольчиком, которая пружинисто раскрывается в поле для почты и показывает загрузку и подтверждение.

Установка

npx astra-rn add email-capture
pnpm dlx astra-rn add email-capture
yarn dlx astra-rn add email-capture
bunx --bun astra-rn add email-capture

Файлы

index.tsx
НазадЭластичная карусельДалееРаскрывающийся вид

В покое это компактная кнопка с колокольчиком, который покачивается при касании. По нажатию кнопка на пружине растягивается в поле ввода почты и сразу ставит в него фокус. После отправки на кнопке появляется спиннер, затем галочка с сообщением об успехе, и через секунду форма сворачивается обратно.

Если onSubmit выбросит ошибку, поле останется открытым и покажет подсказку. Ширина и иконки анимируются на UI-потоке Reanimated; при включённом «Уменьшении движения» пружины заменяются короткими переходами без покачивания. Работает на iOS, Android и в вебе.

Вручную

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

npm install react-native-reanimated react-native-svg
pnpm add react-native-reanimated react-native-svg
yarn add react-native-reanimated react-native-svg
bun add react-native-reanimated react-native-svg

Скопируйте эти файлы в src/shared/components/molecules/email-capture/:

Проверьте алиас путей. Импорты в коде выше записаны так, как их пишет astra-rn add: @/shared/components, @/shared/utils и @/shared/hooks. Нужен алиас "@/*": ["./src/*"] в tsconfig.json — или поправьте импорты под свои пути.

Использование

import React from "react";
import { StyleSheet, View } from "react-native";
import { EmailCapture } from "@/shared/components/molecules/email-capture";
import { Showcase, useCustomize } from "~/showcase";

const CUSTOMIZE = [
  { key: "idleWidth", label: "Ширина кнопки", type: "slider", min: 140, max: 320, step: 2, unit: "px", default: 198 },
  { key: "maxOpenWidth", label: "Ширина поля", type: "slider", min: 260, max: 560, step: 10, unit: "px", default: 400 },
  { key: "delay", label: "Задержка отправки", type: "slider", min: 0, max: 3000, step: 100, unit: "мс", default: 0 },
  { key: "buttonLabel", label: "Текст кнопки", type: "text", default: "Сообщить", maxLength: 20 },
  { key: "placeholder", label: "Подсказка в поле", type: "text", default: "вы@пример.рф", maxLength: 32 },
  { key: "successMessage", label: "Сообщение об успехе", type: "text", default: "Вы в списке", maxLength: 20 },
] as const;

export default function EmailCaptureScreen() {
  const custom = useCustomize(CUSTOMIZE);
  const delay = custom.delay;
  const onSubmit =
    delay > 0 ? () => new Promise<void>((resolve) => setTimeout(resolve, delay)) : undefined;

  return (
    <Showcase>
      <View style={styles.container}>
        <EmailCapture
          placeholder={custom.placeholder}
          buttonLabel={custom.buttonLabel}
          successMessage={custom.successMessage}
          idleWidth={custom.idleWidth}
          maxOpenWidth={custom.maxOpenWidth}
          onSubmit={onSubmit}
        />
      </View>
    </Showcase>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
    paddingHorizontal: 16,
    paddingVertical: 48,
    backgroundColor: "#0a0a0a",
  },
});

Передайте в onSubmit асинхронную функцию: пока она выполняется, кнопка показывает загрузку.

Пропсы

Пропс
Описание
placeholder?

Тип string

buttonLabel?

Тип string

successMessage?

Тип string

idleWidth?

Тип number

maxOpenWidth?

Тип number

onSubmit?

Тип (email: string) => Promise<void> | void

theme?

Тип "dark" | "light"

style?

Тип StyleProp<ViewStyle>