Секция с заголовком и списком вопросов. По нажатию ответ раскрывается пружинной анимацией высоты, текст проявляется с небольшим сдвигом, а плюс поворачивается в крестик и заливается цветом. Карточки появляются по очереди при первом показе.
Можно разрешить несколько открытых ответов одновременно или разложить вопросы в две колонки. Высота ответа измеряется один раз, а анимация идёт на UI-потоке Reanimated; при «Уменьшении движения» остаются только переходы прозрачности. Работает на iOS, Android и в вебе.
Поставьте зависимости:
npm install react-native-reanimated react-native-svgpnpm add react-native-reanimated react-native-svgyarn add react-native-reanimated react-native-svgbun add react-native-reanimated react-native-svgСкопируйте эти файлы в src/shared/components/organisms/faq-section/:
Проверьте алиас путей. Импорты в коде выше записаны так, как их пишет astra-rn add: @/shared/components, @/shared/utils и @/shared/hooks. Нужен алиас "@/*": ["./src/*"] в tsconfig.json — или поправьте импорты под свои пути.
import React from "react";
import { ScrollView, StyleSheet, View } from "react-native";
import { FaqSection } from "@/shared/components/organisms/faq-section";
import { Showcase, useCustomize } from "~/showcase";
const CUSTOMIZE = [
{ key: "gap", label: "Отступ между вопросами", type: "slider", min: 0, max: 32, step: 1, unit: "px", default: 12 },
{ key: "radius", label: "Скругление карточек", type: "slider", min: 0, max: 32, step: 1, unit: "px", default: 16 },
{ key: "title", label: "Заголовок", type: "text", default: "Частые вопросы", maxLength: 40 },
{ key: "subtitle", label: "Подзаголовок", type: "text", default: "Всё, что стоит знать, прежде чем начать работу.", maxLength: 80 },
{
key: "align",
label: "Выравнивание заголовка",
type: "select",
options: [
{ value: "center", label: "По центру" },
{ value: "left", label: "Слева" },
],
default: "center",
},
{
key: "columns",
label: "Колонки",
type: "select",
options: [
{ value: "1", label: "Одна" },
{ value: "2", label: "Две" },
],
default: "1",
},
{ key: "allowMultiple", label: "Несколько открытых сразу", type: "toggle", default: false },
{ key: "accent", label: "Цвет открытого плюса", type: "color", default: "#f4f4f5" },
] as const;
export default function FaqSectionScreen() {
const custom = useCustomize(CUSTOMIZE);
return (
<Showcase>
<ScrollView style={styles.scroll} contentContainerStyle={styles.container}>
<View style={styles.stage}>
<FaqSection
defaultOpenId="what-is-it"
gap={custom.gap}
radius={custom.radius}
title={custom.title}
subtitle={custom.subtitle}
align={custom.align === "left" ? "left" : "center"}
columns={custom.columns === "2" ? 2 : 1}
allowMultiple={custom.allowMultiple}
accentColor={custom.accent.toLowerCase() === "#f4f4f5" ? undefined : custom.accent}
/>
</View>
</ScrollView>
</Showcase>
);
}
const styles = StyleSheet.create({
scroll: {
flex: 1,
backgroundColor: "#0a0a0a",
},
container: {
flexGrow: 1,
alignItems: "center",
justifyContent: "center",
paddingTop: 56,
paddingBottom: 24,
},
stage: {
width: "100%",
alignItems: "center",
justifyContent: "center",
paddingHorizontal: 16,
paddingVertical: 48,
},
});items?Тип readonly FaqItem[]
title?Тип string
subtitle?Тип string
defaultOpenId?Тип string | null
allowMultiple?Тип boolean
align?Тип "center" | "left"
columns?Тип 1 | 2
gap?Тип number
radius?Тип number
accentColor?Тип string
theme?Тип "dark" | "light"
style?Тип StyleProp<ViewStyle>