├── .gitignore
├── README.md
├── app.json
├── app
├── _layout.tsx
└── index.tsx
├── assets
├── fonts
│ └── SpaceMono-Regular.ttf
└── images
│ ├── adaptive-icon.png
│ ├── favicon.png
│ ├── icon.png
│ ├── partial-react-logo.png
│ ├── react-logo.png
│ ├── react-logo@2x.png
│ ├── react-logo@3x.png
│ └── splash.png
├── babel.config.js
├── components
├── Button.tsx
├── CustomBlurView.tsx
├── FloatingMenu.tsx
└── MenuItem.tsx
├── package-lock.json
├── package.json
├── tsconfig.json
└── types
└── index.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .expo/
3 | dist/
4 | npm-debug.*
5 | *.jks
6 | *.p8
7 | *.p12
8 | *.key
9 | *.mobileprovision
10 | *.orig.*
11 | web-build/
12 |
13 | # macOS
14 | .DS_Store
15 |
16 | # @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
17 | # The following patterns were generated by expo-cli
18 |
19 | expo-env.d.ts
20 | # @end expo-cli
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to your Expo app 👋
2 |
3 | This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
4 |
5 | ## Get started
6 |
7 | 1. Install dependencies
8 |
9 | ```bash
10 | npm install
11 | ```
12 |
13 | 2. Start the app
14 |
15 | ```bash
16 | npx expo start
17 | ```
18 |
19 | In the output, you'll find options to open the app in a
20 |
21 | - [development build](https://docs.expo.dev/develop/development-builds/introduction/)
22 | - [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
23 | - [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
24 | - [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
25 |
26 | You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
27 |
28 | ## Get a fresh project
29 |
30 | When you're ready, run:
31 |
32 | ```bash
33 | npm run reset-project
34 | ```
35 |
36 | This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
37 |
38 | ## Learn more
39 |
40 | To learn more about developing your project with Expo, look at the following resources:
41 |
42 | - [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
43 | - [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
44 |
45 | ## Join the community
46 |
47 | Join our community of developers creating universal apps.
48 |
49 | - [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
50 | - [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
51 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "rn-accordion",
4 | "slug": "rn-accordion",
5 | "version": "1.0.0",
6 | "orientation": "default",
7 | "icon": "./assets/images/icon.png",
8 | "scheme": "myapp",
9 | "userInterfaceStyle": "automatic",
10 | "splash": {
11 | "image": "./assets/images/splash.png",
12 | "resizeMode": "contain",
13 | "backgroundColor": "#ffffff"
14 | },
15 | "ios": {
16 | "supportsTablet": true
17 | },
18 | "android": {
19 | "adaptiveIcon": {
20 | "foregroundImage": "./assets/images/adaptive-icon.png",
21 | "backgroundColor": "#ffffff"
22 | }
23 | },
24 | "web": {
25 | "bundler": "metro",
26 | "output": "static",
27 | "favicon": "./assets/images/favicon.png"
28 | },
29 | "plugins": ["expo-router"],
30 | "experiments": {
31 | "typedRoutes": true
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/_layout.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Stack } from "expo-router";
3 | import {
4 | DarkTheme,
5 | DefaultTheme,
6 | ThemeProvider,
7 | } from "@react-navigation/native";
8 | import "react-native-reanimated";
9 | import { useColorScheme } from "react-native";
10 |
11 | export default function RootLayout() {
12 | const colorScheme = useColorScheme();
13 | return (
14 |
15 |
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/app/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ImageBackground, StyleSheet, View } from "react-native";
3 | import { useTheme } from "@react-navigation/native";
4 | import { Ionicons } from "@expo/vector-icons";
5 | import FloatingMenu from "@/components/FloatingMenu";
6 | import MenuItem from "@/components/MenuItem";
7 |
8 | const Main = () => {
9 | const theme = useTheme();
10 | return (
11 |
17 |
18 |
19 |
20 |
27 | }
28 | title={"Media"}
29 | />
30 |
37 | }
38 | title={"Template"}
39 | />
40 |
47 | }
48 | title={"Event"}
49 | />
50 |
51 |
52 |
55 | }
56 | title={"Celebrate"}
57 | />
58 |
65 | }
66 | title={"Job"}
67 | />
68 |
75 | }
76 | title={"Poll"}
77 | />
78 |
79 |
80 |
87 | }
88 | title={"Document"}
89 | />
90 | }
92 | title={"Services"}
93 | />
94 |
95 |
96 |
97 |
98 |
99 | );
100 | };
101 |
102 | export default Main;
103 |
104 | const styles = StyleSheet.create({
105 | container: {
106 | gap: 20,
107 | },
108 | rows: {
109 | flexDirection: "row",
110 | gap: 20,
111 | },
112 | });
113 |
--------------------------------------------------------------------------------
/assets/fonts/SpaceMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arunabhverma/rn-floating-menu/e973888a9a369c1405b0d045e1d969b9988b251c/assets/fonts/SpaceMono-Regular.ttf
--------------------------------------------------------------------------------
/assets/images/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arunabhverma/rn-floating-menu/e973888a9a369c1405b0d045e1d969b9988b251c/assets/images/adaptive-icon.png
--------------------------------------------------------------------------------
/assets/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arunabhverma/rn-floating-menu/e973888a9a369c1405b0d045e1d969b9988b251c/assets/images/favicon.png
--------------------------------------------------------------------------------
/assets/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arunabhverma/rn-floating-menu/e973888a9a369c1405b0d045e1d969b9988b251c/assets/images/icon.png
--------------------------------------------------------------------------------
/assets/images/partial-react-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arunabhverma/rn-floating-menu/e973888a9a369c1405b0d045e1d969b9988b251c/assets/images/partial-react-logo.png
--------------------------------------------------------------------------------
/assets/images/react-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arunabhverma/rn-floating-menu/e973888a9a369c1405b0d045e1d969b9988b251c/assets/images/react-logo.png
--------------------------------------------------------------------------------
/assets/images/react-logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arunabhverma/rn-floating-menu/e973888a9a369c1405b0d045e1d969b9988b251c/assets/images/react-logo@2x.png
--------------------------------------------------------------------------------
/assets/images/react-logo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arunabhverma/rn-floating-menu/e973888a9a369c1405b0d045e1d969b9988b251c/assets/images/react-logo@3x.png
--------------------------------------------------------------------------------
/assets/images/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arunabhverma/rn-floating-menu/e973888a9a369c1405b0d045e1d969b9988b251c/assets/images/splash.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/components/Button.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Pressable,
3 | PressableProps,
4 | StyleSheet,
5 | Text,
6 | View,
7 | } from "react-native";
8 | import React, { useState } from "react";
9 | import Animated, {
10 | useAnimatedStyle,
11 | withTiming,
12 | } from "react-native-reanimated";
13 |
14 | const Button = (props: PressableProps) => {
15 | const [isPressed, setIsPressed] = useState(false);
16 |
17 | const animatedStyle = useAnimatedStyle(() => {
18 | return {
19 | transform: [
20 | {
21 | scale: isPressed
22 | ? withTiming(0.5, { duration: 200 })
23 | : withTiming(1, { duration: 200 }),
24 | },
25 | ],
26 | };
27 | });
28 |
29 | return (
30 | setIsPressed(true)}
33 | onTouchEnd={() => setIsPressed(false)}
34 | >
35 |
36 | {props.children}
37 |
38 |
39 | );
40 | };
41 |
42 | export default Button;
43 |
--------------------------------------------------------------------------------
/components/CustomBlurView.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Platform,
3 | StyleSheet,
4 | useColorScheme,
5 | useWindowDimensions,
6 | } from "react-native";
7 | import React from "react";
8 | import { BlurView } from "expo-blur";
9 | import { useTheme } from "@react-navigation/native";
10 |
11 | const CustomBlurView = ({ bgColor }: { bgColor?: string }) => {
12 | const tint = useColorScheme();
13 | const theme = useTheme();
14 |
15 | const { width, height } = useWindowDimensions();
16 | return (
17 |
30 | );
31 | };
32 |
33 | export default CustomBlurView;
34 |
--------------------------------------------------------------------------------
/components/FloatingMenu.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactNode, useState } from "react";
2 | import { StyleSheet, useWindowDimensions } from "react-native";
3 | import Animated, {
4 | FadeIn,
5 | FadeOut,
6 | LinearTransition,
7 | useAnimatedStyle,
8 | withSpring,
9 | withTiming,
10 | } from "react-native-reanimated";
11 | import { useSafeAreaInsets } from "react-native-safe-area-context";
12 | import { useTheme } from "@react-navigation/native";
13 | import { Ionicons } from "@expo/vector-icons";
14 | import CustomBlurView from "./CustomBlurView";
15 |
16 | const FloatingMenu = ({ children }: { children: ReactNode }) => {
17 | const { right, bottom } = useSafeAreaInsets();
18 | const { width, height } = useWindowDimensions();
19 | const theme = useTheme();
20 | const [isOpen, setIsOpen] = useState(false);
21 |
22 | const animatedStyle = useAnimatedStyle(() => {
23 | return {
24 | borderRadius: isOpen ? withTiming(20) : withTiming(50),
25 | padding: isOpen ? 15 : 0,
26 | };
27 | }, [isOpen]);
28 |
29 | const iconRotation = useAnimatedStyle(() => {
30 | return {
31 | transform: [
32 | { rotate: isOpen ? withSpring("-45deg") : withSpring("0deg") },
33 | ],
34 | };
35 | });
36 |
37 | return (
38 |
50 |
54 |
55 | {isOpen && (
56 |
62 | {children}
63 |
64 | )}
65 | setIsOpen((prev) => !prev)}
73 | >
74 |
75 |
76 |
77 |
78 |
79 | );
80 | };
81 |
82 | export default FloatingMenu;
83 |
84 | const styles = StyleSheet.create({
85 | iconWrapper: {
86 | width: 60,
87 | aspectRatio: 1,
88 | borderRadius: 30,
89 | justifyContent: "center",
90 | alignItems: "center",
91 | overflow: "hidden",
92 | },
93 | childrenWrapper: {
94 | paddingBottom: 30,
95 | flex: 1,
96 | },
97 | containerWrapper: {
98 | justifyContent: "center",
99 | alignItems: "flex-end",
100 | overflow: "hidden",
101 | },
102 | mainContainerWrapper: {
103 | position: "absolute",
104 | },
105 | });
106 |
--------------------------------------------------------------------------------
/components/MenuItem.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { StyleSheet, Text, View } from "react-native";
3 | import { useTheme } from "@react-navigation/native";
4 | import { MenuItemsType } from "@/types";
5 | import Button from "./Button";
6 |
7 | const MenuItem = ({ icon, title }: MenuItemsType) => {
8 | const theme = useTheme();
9 | return (
10 |
11 |
12 |
13 | {title}
14 |
15 |
16 | );
17 | };
18 |
19 | export default MenuItem;
20 |
21 | const styles = StyleSheet.create({
22 | container: {
23 | alignItems: "center",
24 | width: 80,
25 | gap: 5,
26 | },
27 | iconContainer: {
28 | width: 60,
29 | backgroundColor: "rgba(0,0,0,0.1)",
30 | aspectRatio: 1,
31 | justifyContent: "center",
32 | alignItems: "center",
33 | borderRadius: 30,
34 | },
35 | textStyle: {
36 | fontSize: 13,
37 | fontWeight: "500",
38 | },
39 | });
40 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rn-accordion",
3 | "main": "expo-router/entry",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start",
7 | "reset-project": "node ./scripts/reset-project.js",
8 | "android": "expo start --android",
9 | "ios": "expo start --ios",
10 | "web": "expo start --web",
11 | "test": "jest --watchAll",
12 | "lint": "expo lint"
13 | },
14 | "jest": {
15 | "preset": "jest-expo"
16 | },
17 | "dependencies": {
18 | "@expo/vector-icons": "^14.0.2",
19 | "@react-navigation/native": "^6.0.2",
20 | "expo": "~51.0.18",
21 | "expo-constants": "~16.0.2",
22 | "expo-font": "~12.0.7",
23 | "expo-linking": "~6.3.1",
24 | "expo-router": "~3.5.17",
25 | "expo-splash-screen": "~0.27.5",
26 | "expo-status-bar": "~1.12.1",
27 | "expo-system-ui": "~3.0.7",
28 | "expo-web-browser": "~13.0.3",
29 | "react": "18.2.0",
30 | "react-dom": "18.2.0",
31 | "react-native": "0.74.3",
32 | "react-native-gesture-handler": "~2.16.1",
33 | "react-native-reanimated": "~3.10.1",
34 | "react-native-safe-area-context": "4.10.1",
35 | "react-native-screens": "3.31.1",
36 | "react-native-web": "~0.19.10",
37 | "expo-blur": "~13.0.2"
38 | },
39 | "devDependencies": {
40 | "@babel/core": "^7.20.0",
41 | "@types/jest": "^29.5.12",
42 | "@types/react": "~18.2.45",
43 | "@types/react-test-renderer": "^18.0.7",
44 | "jest": "^29.2.1",
45 | "jest-expo": "~51.0.3",
46 | "react-test-renderer": "18.2.0",
47 | "typescript": "~5.3.3"
48 | },
49 | "private": true
50 | }
51 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo/tsconfig.base",
3 | "compilerOptions": {
4 | "strict": true,
5 | "paths": {
6 | "@/*": [
7 | "./*"
8 | ]
9 | }
10 | },
11 | "include": [
12 | "**/*.ts",
13 | "**/*.tsx",
14 | ".expo/types/**/*.ts",
15 | "expo-env.d.ts"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/types/index.ts:
--------------------------------------------------------------------------------
1 | import { IconProps } from "@expo/vector-icons/build/createIconSet";
2 |
3 | export type MenuItemsType = {
4 | icon: IconProps;
5 | title: string;
6 | };
7 |
--------------------------------------------------------------------------------