Поставьте зависимости:
npm install @expo/vector-icons expo-blur react-native-reanimatedpnpm add @expo/vector-icons expo-blur react-native-reanimatedyarn add @expo/vector-icons expo-blur react-native-reanimatedbun add @expo/vector-icons expo-blur react-native-reanimatedСкопируйте эти файлы в src/shared/components/molecules/fan-menu/:
Проверьте алиас путей. Импорты в коде выше записаны так, как их пишет astra-rn add: @/shared/components, @/shared/utils и @/shared/hooks. Нужен алиас "@/*": ["./src/*"] в tsconfig.json — или поправьте импорты под свои пути.
import React, { useRef, useState } from "react";
import { Platform, StyleSheet, View, useWindowDimensions } from "react-native";
import { Feather } from "@expo/vector-icons";
import { FanMenu, FanItemDirection, FanPosition } from "@/shared/components/molecules/fan-menu";
import { Showcase, useAutoplay, useCustomize } from "~/showcase";
const ICON_STYLE = { width: 15 } as const;
const isWeb = Platform.OS === "web";
const ITEMS = [
{ value: "learning", label: "Learning", icon: "book-open" },
{ value: "document", label: "Document", icon: "file-text" },
{ value: "music", label: "Music", icon: "music" },
{ value: "video", label: "Video", icon: "film" },
{ value: "image", label: "Image", icon: "image" },
] as const;
const CUSTOMIZE = [
{
key: "label1",
label: "Пункт 1",
type: "text",
default: "Learning",
maxLength: 16,
},
{
key: "label2",
label: "Пункт 2",
type: "text",
default: "Document",
maxLength: 16,
},
{
key: "label3",
label: "Пункт 3",
type: "text",
default: "Music",
maxLength: 16,
},
{
key: "label4",
label: "Пункт 4",
type: "text",
default: "Video",
maxLength: 16,
},
{
key: "label5",
label: "Пункт 5",
type: "text",
default: "Image",
maxLength: 16,
},
{ key: "iconColor", label: "Цвет иконок", type: "color", default: "#1d1d1f" },
{
key: "itemDirection",
label: "Сторона",
type: "select",
options: [
{ value: "left", label: "Влево" },
{ value: "right", label: "Вправо" },
{ value: "none", label: "По центру" },
],
default: "left",
},
{
key: "spread",
label: "Разброс",
type: "slider",
min: 0,
max: 20,
step: 0.5,
default: 5,
},
{
key: "spacing",
label: "Шаг",
type: "slider",
min: 40,
max: 120,
step: 1,
unit: "px",
default: 70,
},
{
key: "tilt",
label: "Наклон",
type: "slider",
min: 0,
max: 30,
step: 1,
unit: "°",
default: 6,
},
{
key: "stagger",
label: "Каскад",
type: "slider",
min: 0,
max: 150,
step: 5,
unit: "ms",
default: 25,
},
{
key: "holdMs",
label: "Показ",
type: "slider",
min: 600,
max: 5000,
step: 100,
unit: "ms",
default: 1700,
},
] as const;
export default function FanMenuScreen() {
const [open, setOpen] = useState<boolean>(false);
const custom = useCustomize(CUSTOMIZE);
const holdRef = useRef(custom.holdMs);
holdRef.current = custom.holdMs;
const labels = [
custom.label1,
custom.label2,
custom.label3,
custom.label4,
custom.label5,
];
const { height } = useWindowDimensions();
const lift = Math.max(120, Math.min(400, height - 385));
useAutoplay(async ({ wait }) => {
await wait(300);
setOpen(true);
await wait(holdRef.current);
setOpen(false);
await wait(1200);
});
return (
<Showcase>
<View style={styles.stage} pointerEvents="box-none">
<FanMenu
open={open}
onOpenChange={setOpen}
position={FanPosition.BottomCenter}
itemDirection={custom.itemDirection as FanItemDirection}
spread={custom.spread}
spacing={custom.spacing}
tilt={custom.tilt}
style={{
bottom: lift,
}}
stagger={custom.stagger}
>
{ITEMS.map((item, index) => (
<FanMenu.Item
key={item.value}
value={item.value}
style={{
paddingHorizontal: 12,
}}
onPress={isWeb ? undefined : (v) => alert(v + " Pressed")}
>
<FanMenu.Icon>
<Feather
name={item.icon}
size={15}
color={custom.iconColor}
style={ICON_STYLE}
/>
</FanMenu.Icon>
<FanMenu.Label>{labels[index]}</FanMenu.Label>
</FanMenu.Item>
))}
</FanMenu>
</View>
</Showcase>
);
}
const styles = StyleSheet.create({
stage: {
...StyleSheet.absoluteFillObject,
overflow: "hidden",
},
});childrenТип ReactNode
open?Тип boolean
defaultOpen?Тип boolean
onOpenChange?Тип (open: boolean) => void
onOpen?Тип () => void
onClose?Тип () => void
position?Тип TFanPosition
offset?Тип TFanOffset
direction?Тип TFanDirection
itemDirection?Тип TItemDirection
spacing?Тип number
spread?Тип number
tilt?Тип number
stagger?Тип number
springConfig?Тип WithSpringConfig
buttonSize?Тип number
closeOnBackdropPress?Тип boolean
style?Тип StyleProp<ViewStyle>